summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarius Renn <renn@google.com>2011-05-25 13:40:38 -0700
committerMarius Renn <renn@google.com>2011-05-25 13:40:38 -0700
commit6acb9a7ea3d7564944e12cbc73a857b88c1301ee (patch)
tree86a91daa82fe6241059f79f5e91b7f6a72d11769
parent58393d4eb582b3d88f46b88a459dfbbf853af5e4 (diff)
downloadopencv-6acb9a7ea3d7564944e12cbc73a857b88c1301ee.tar.gz
Adding OpenCV 1.1 Framework.
Change-Id: If5aa88f70483b73873000051f9b13a0bd0adec10
-rw-r--r--Android.mk282
-rw-r--r--Application.mk3
-rw-r--r--LICENSE_Android_NDK12
-rw-r--r--LICENSE_OpenCV36
-rw-r--r--MODULE_LICENSE_BSD0
-rw-r--r--NOTICE880
-rw-r--r--README.rdoc76
-rw-r--r--VERSION.txt4
-rw-r--r--WLNonFileByteStream.cpp150
-rw-r--r--WLNonFileByteStream.h51
-rw-r--r--cv/include/cv.h1482
-rw-r--r--cv/include/cv.hpp409
-rw-r--r--cv/include/cvcompat.h1080
-rw-r--r--cv/include/cvstreams.h93
-rw-r--r--cv/include/cvtypes.h386
-rw-r--r--cv/src/_cv.h118
-rw-r--r--cv/src/_cvgeom.h93
-rw-r--r--cv/src/_cvimgproc.h123
-rw-r--r--cv/src/_cvipp.h759
-rw-r--r--cv/src/_cvkdtree.hpp461
-rw-r--r--cv/src/_cvlist.h373
-rw-r--r--cv/src/_cvmatrix.h405
-rw-r--r--cv/src/cvaccum.cpp786
-rw-r--r--cv/src/cvadapthresh.cpp144
-rw-r--r--cv/src/cvapprox.cpp1064
-rw-r--r--cv/src/cvcalccontrasthistogram.cpp385
-rw-r--r--cv/src/cvcalcimagehomography.cpp120
-rw-r--r--cv/src/cvcalibinit.cpp2091
-rw-r--r--cv/src/cvcalibration.cpp2683
-rw-r--r--cv/src/cvcamshift.cpp300
-rw-r--r--cv/src/cvcanny.cpp357
-rw-r--r--cv/src/cvcolor.cpp2551
-rw-r--r--cv/src/cvcondens.cpp284
-rw-r--r--cv/src/cvcontours.cpp1557
-rw-r--r--cv/src/cvcontourtree.cpp804
-rw-r--r--cv/src/cvconvhull.cpp851
-rw-r--r--cv/src/cvcorner.cpp706
-rw-r--r--cv/src/cvcornersubpix.cpp268
-rw-r--r--cv/src/cvderiv.cpp879
-rw-r--r--cv/src/cvdistransform.cpp859
-rw-r--r--cv/src/cvdominants.cpp407
-rw-r--r--cv/src/cvemd.cpp1164
-rw-r--r--cv/src/cvfeatureselect.cpp234
-rw-r--r--cv/src/cvfilter.cpp2710
-rw-r--r--cv/src/cvfloodfill.cpp1160
-rw-r--r--cv/src/cvfundam.cpp1438
-rw-r--r--cv/src/cvgeometry.cpp593
-rw-r--r--cv/src/cvhaar.cpp2328
-rw-r--r--cv/src/cvhistogram.cpp2513
-rw-r--r--cv/src/cvhough.cpp1161
-rw-r--r--cv/src/cvimgwarp.cpp2272
-rw-r--r--cv/src/cvinpaint.cpp821
-rw-r--r--cv/src/cvkalman.cpp241
-rw-r--r--cv/src/cvkdtree.cpp283
-rw-r--r--cv/src/cvlinefit.cpp727
-rw-r--r--cv/src/cvlkpyramid.cpp1394
-rw-r--r--cv/src/cvmatchcontours.cpp398
-rw-r--r--cv/src/cvmoments.cpp687
-rw-r--r--cv/src/cvmorph.cpp1173
-rw-r--r--cv/src/cvmotempl.cpp517
-rw-r--r--cv/src/cvoptflowbm.cpp610
-rw-r--r--cv/src/cvoptflowhs.cpp535
-rw-r--r--cv/src/cvoptflowlk.cpp611
-rw-r--r--cv/src/cvpgh.cpp363
-rw-r--r--cv/src/cvposit.cpp378
-rw-r--r--cv/src/cvprecomp.cpp44
-rw-r--r--cv/src/cvpyramids.cpp1284
-rw-r--r--cv/src/cvpyrsegmentation.cpp1883
-rw-r--r--cv/src/cvrotcalipers.cpp474
-rw-r--r--cv/src/cvsamplers.cpp894
-rw-r--r--cv/src/cvsegmentation.cpp552
-rw-r--r--cv/src/cvshapedescr.cpp1356
-rw-r--r--cv/src/cvsmooth.cpp1530
-rw-r--r--cv/src/cvsnakes.cpp438
-rw-r--r--cv/src/cvstereobm.cpp681
-rw-r--r--cv/src/cvstereogc.cpp960
-rw-r--r--cv/src/cvsubdivision2d.cpp850
-rw-r--r--cv/src/cvsumpixels.cpp435
-rw-r--r--cv/src/cvsurf.cpp562
-rw-r--r--cv/src/cvswitcher.cpp59
-rw-r--r--cv/src/cvtables.cpp214
-rw-r--r--cv/src/cvtemplmatch.cpp536
-rw-r--r--cv/src/cvthresh.cpp495
-rw-r--r--cv/src/cvundistort.cpp491
-rw-r--r--cv/src/cvutils.cpp540
-rw-r--r--cv/src/mycvHaarDetectObjects.cpp1572
-rw-r--r--cvaux/include/cvaux.h1574
-rw-r--r--cvaux/include/cvaux.hpp144
-rw-r--r--cvaux/include/cvmat.hpp2326
-rw-r--r--cvaux/include/cvvidsurv.hpp1324
-rw-r--r--cvaux/src/_cvaux.h73
-rw-r--r--cvaux/src/_cvfacedetection.h412
-rw-r--r--cvaux/src/_cvvectrack.h163
-rw-r--r--cvaux/src/_cvvm.h298
-rw-r--r--cvaux/src/camshift.cpp285
-rw-r--r--cvaux/src/cv3dtracker.cpp588
-rw-r--r--cvaux/src/cvaux.cpp44
-rw-r--r--cvaux/src/cvauxutils.cpp44
-rw-r--r--cvaux/src/cvbgfg_acmmm2003.cpp740
-rw-r--r--cvaux/src/cvbgfg_codebook.cpp362
-rw-r--r--cvaux/src/cvbgfg_common.cpp124
-rw-r--r--cvaux/src/cvbgfg_gaussmix.cpp597
-rw-r--r--cvaux/src/cvcalibfilter.cpp906
-rw-r--r--cvaux/src/cvclique.cpp709
-rw-r--r--cvaux/src/cvcorrespond.cpp403
-rw-r--r--cvaux/src/cvcorrimages.cpp1152
-rw-r--r--cvaux/src/cvcreatehandmask.cpp138
-rw-r--r--cvaux/src/cvdpstereo.cpp554
-rw-r--r--cvaux/src/cveigenobjects.cpp1811
-rw-r--r--cvaux/src/cvepilines.cpp3722
-rw-r--r--cvaux/src/cvface.cpp354
-rw-r--r--cvaux/src/cvfacedetection.cpp486
-rw-r--r--cvaux/src/cvfacetemplate.cpp86
-rw-r--r--cvaux/src/cvfindface.cpp68
-rw-r--r--cvaux/src/cvfindhandregion.cpp645
-rw-r--r--cvaux/src/cvhmm.cpp1770
-rw-r--r--cvaux/src/cvhmm1d.cpp1151
-rw-r--r--cvaux/src/cvhmmobs.cpp634
-rw-r--r--cvaux/src/cvlcm.cpp724
-rw-r--r--cvaux/src/cvlee.cpp4718
-rw-r--r--cvaux/src/cvlevmar.cpp320
-rw-r--r--cvaux/src/cvlevmarprojbandle.cpp1783
-rw-r--r--cvaux/src/cvlevmartrif.cpp497
-rw-r--r--cvaux/src/cvlines.cpp483
-rw-r--r--cvaux/src/cvlmeds.cpp1766
-rw-r--r--cvaux/src/cvmat.cpp879
-rw-r--r--cvaux/src/cvmorphcontours.cpp855
-rw-r--r--cvaux/src/cvmorphing.cpp396
-rw-r--r--cvaux/src/cvprewarp.cpp168
-rw-r--r--cvaux/src/cvscanlines.cpp2033
-rw-r--r--cvaux/src/cvsegment.cpp585
-rw-r--r--cvaux/src/cvsubdiv2.cpp187
-rw-r--r--cvaux/src/cvtexture.cpp648
-rw-r--r--cvaux/src/cvtrifocal.cpp2792
-rw-r--r--cvaux/src/cvvecfacetracking.cpp975
-rw-r--r--cvaux/src/cvvideo.cpp84
-rw-r--r--cvaux/src/decomppoly.cpp629
-rw-r--r--cvaux/src/enmin.cpp1381
-rw-r--r--cvaux/src/extendededges.cpp268
-rw-r--r--cvaux/src/precomp.cpp42
-rw-r--r--cvjni.cpp796
-rw-r--r--cvjni.h342
-rw-r--r--cxcore/include/cvver.h55
-rw-r--r--cxcore/include/cvwimage.h621
-rw-r--r--cxcore/include/cxcore.h1780
-rw-r--r--cxcore/include/cxcore.hpp375
-rw-r--r--cxcore/include/cxerror.h189
-rw-r--r--cxcore/include/cxmisc.h918
-rw-r--r--cxcore/include/cxtypes.h1780
-rw-r--r--cxcore/src/_cxcore.h346
-rw-r--r--cxcore/src/_cxipp.h646
-rw-r--r--cxcore/src/cxalloc.cpp135
-rw-r--r--cxcore/src/cxarithm.cpp2050
-rw-r--r--cxcore/src/cxarray.cpp3701
-rw-r--r--cxcore/src/cxcmp.cpp1557
-rw-r--r--cxcore/src/cxconvert.cpp1788
-rw-r--r--cxcore/src/cxcopy.cpp1042
-rw-r--r--cxcore/src/cxdatastructs.cpp4009
-rw-r--r--cxcore/src/cxdrawing.cpp2597
-rw-r--r--cxcore/src/cxdxt.cpp3003
-rw-r--r--cxcore/src/cxerror.cpp460
-rw-r--r--cxcore/src/cximage.cpp397
-rw-r--r--cxcore/src/cxjacobieigens.cpp431
-rw-r--r--cxcore/src/cxlogic.cpp696
-rw-r--r--cxcore/src/cxlut.cpp324
-rw-r--r--cxcore/src/cxmathfuncs.cpp1998
-rw-r--r--cxcore/src/cxmatmul.cpp3378
-rw-r--r--cxcore/src/cxmatrix.cpp2006
-rw-r--r--cxcore/src/cxmean.cpp481
-rw-r--r--cxcore/src/cxmeansdv.cpp799
-rw-r--r--cxcore/src/cxminmaxloc.cpp452
-rw-r--r--cxcore/src/cxnorm.cpp1417
-rw-r--r--cxcore/src/cxouttext.cpp3345
-rw-r--r--cxcore/src/cxpersistence.cpp5250
-rw-r--r--cxcore/src/cxprecomp.cpp44
-rw-r--r--cxcore/src/cxrand.cpp600
-rw-r--r--cxcore/src/cxsumpixels.cpp1015
-rw-r--r--cxcore/src/cxsvd.cpp1622
-rw-r--r--cxcore/src/cxswitcher.cpp816
-rw-r--r--cxcore/src/cxtables.cpp210
-rw-r--r--cxcore/src/cxutils.cpp1206
-rw-r--r--libopencv.mk11
-rw-r--r--ml/include/ml.h1564
-rw-r--r--ml/src/_ml.h354
-rw-r--r--ml/src/ml.cpp41
-rw-r--r--ml/src/ml_inner_functions.cpp1953
-rw-r--r--ml/src/mlann_mlp.cpp1520
-rw-r--r--ml/src/mlboost.cpp1655
-rw-r--r--ml/src/mlcnn.cpp1675
-rw-r--r--ml/src/mlem.cpp1110
-rw-r--r--ml/src/mlestimate.cpp728
-rw-r--r--ml/src/mlknearest.cpp401
-rw-r--r--ml/src/mlnbayes.cpp569
-rw-r--r--ml/src/mlrtrees.cpp693
-rw-r--r--ml/src/mlsvm.cpp2689
-rw-r--r--ml/src/mltestset.cpp170
-rw-r--r--ml/src/mltree.cpp3412
-rw-r--r--otherlibs/highgui/_highgui.h85
-rw-r--r--otherlibs/highgui/bitstrm.cpp1106
-rw-r--r--otherlibs/highgui/bitstrm.h272
-rw-r--r--otherlibs/highgui/cvcap.cpp93
-rw-r--r--otherlibs/highgui/cvcap_socket.cpp302
-rw-r--r--otherlibs/highgui/dummy.cpp1
-rw-r--r--otherlibs/highgui/grfmt_base.cpp305
-rw-r--r--otherlibs/highgui/grfmt_base.h163
-rw-r--r--otherlibs/highgui/grfmt_bmp.cpp551
-rw-r--r--otherlibs/highgui/grfmt_bmp.h107
-rw-r--r--otherlibs/highgui/grfmt_exr.cpp737
-rw-r--r--otherlibs/highgui/grfmt_exr.h116
-rw-r--r--otherlibs/highgui/grfmt_imageio.cpp396
-rw-r--r--otherlibs/highgui/grfmt_imageio.h60
-rw-r--r--otherlibs/highgui/grfmt_jpeg.cpp1866
-rw-r--r--otherlibs/highgui/grfmt_jpeg.h214
-rw-r--r--otherlibs/highgui/grfmt_jpeg2000.cpp502
-rw-r--r--otherlibs/highgui/grfmt_jpeg2000.h115
-rw-r--r--otherlibs/highgui/grfmt_png.cpp333
-rw-r--r--otherlibs/highgui/grfmt_png.h103
-rw-r--r--otherlibs/highgui/grfmt_pxm.cpp510
-rw-r--r--otherlibs/highgui/grfmt_pxm.h103
-rw-r--r--otherlibs/highgui/grfmt_sunras.cpp442
-rw-r--r--otherlibs/highgui/grfmt_sunras.h113
-rw-r--r--otherlibs/highgui/grfmt_tiff.cpp826
-rw-r--r--otherlibs/highgui/grfmt_tiff.h178
-rw-r--r--otherlibs/highgui/grfmts.h56
-rw-r--r--otherlibs/highgui/highgui.h385
-rw-r--r--otherlibs/highgui/image.cpp255
-rw-r--r--otherlibs/highgui/loadsave.cpp555
-rw-r--r--otherlibs/highgui/precomp.cpp43
-rw-r--r--otherlibs/highgui/utils.cpp668
-rw-r--r--otherlibs/highgui/utils.h116
230 files changed, 195332 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..a78e602
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,282 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libcxcore
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/cxcore/include
+LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%)
+LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -ldl
+
+LOCAL_SRC_FILES := \
+ cxcore/src/cxalloc.cpp \
+ cxcore/src/cxarithm.cpp \
+ cxcore/src/cxarray.cpp \
+ cxcore/src/cxcmp.cpp \
+ cxcore/src/cxconvert.cpp \
+ cxcore/src/cxcopy.cpp \
+ cxcore/src/cxdatastructs.cpp \
+ cxcore/src/cxdrawing.cpp \
+ cxcore/src/cxdxt.cpp \
+ cxcore/src/cxerror.cpp \
+ cxcore/src/cximage.cpp \
+ cxcore/src/cxjacobieigens.cpp \
+ cxcore/src/cxlogic.cpp \
+ cxcore/src/cxlut.cpp \
+ cxcore/src/cxmathfuncs.cpp \
+ cxcore/src/cxmatmul.cpp \
+ cxcore/src/cxmatrix.cpp \
+ cxcore/src/cxmean.cpp \
+ cxcore/src/cxmeansdv.cpp \
+ cxcore/src/cxminmaxloc.cpp \
+ cxcore/src/cxnorm.cpp \
+ cxcore/src/cxouttext.cpp \
+ cxcore/src/cxpersistence.cpp \
+ cxcore/src/cxprecomp.cpp \
+ cxcore/src/cxrand.cpp \
+ cxcore/src/cxsumpixels.cpp \
+ cxcore/src/cxsvd.cpp \
+ cxcore/src/cxswitcher.cpp \
+ cxcore/src/cxtables.cpp \
+ cxcore/src/cxutils.cpp
+
+include $(BUILD_STATIC_LIBRARY)
+
+
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libcv
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/cxcore/include \
+ $(LOCAL_PATH)/cxcore/src \
+ $(LOCAL_PATH)/cv/include
+LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%)
+LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -ldl
+
+LOCAL_SRC_FILES := \
+ cv/src/cvaccum.cpp \
+ cv/src/cvadapthresh.cpp \
+ cv/src/cvapprox.cpp \
+ cv/src/cvcalccontrasthistogram.cpp \
+ cv/src/cvcalcimagehomography.cpp \
+ cv/src/cvcalibinit.cpp \
+ cv/src/cvcalibration.cpp \
+ cv/src/cvcamshift.cpp \
+ cv/src/cvcanny.cpp \
+ cv/src/cvcolor.cpp \
+ cv/src/cvcondens.cpp \
+ cv/src/cvcontours.cpp \
+ cv/src/cvcontourtree.cpp \
+ cv/src/cvconvhull.cpp \
+ cv/src/cvcorner.cpp \
+ cv/src/cvcornersubpix.cpp \
+ cv/src/cvderiv.cpp \
+ cv/src/cvdistransform.cpp \
+ cv/src/cvdominants.cpp \
+ cv/src/cvemd.cpp \
+ cv/src/cvfeatureselect.cpp \
+ cv/src/cvfilter.cpp \
+ cv/src/cvfloodfill.cpp \
+ cv/src/cvfundam.cpp \
+ cv/src/cvgeometry.cpp \
+ cv/src/cvhaar.cpp \
+ cv/src/cvhistogram.cpp \
+ cv/src/cvhough.cpp \
+ cv/src/cvimgwarp.cpp \
+ cv/src/cvinpaint.cpp \
+ cv/src/cvkalman.cpp \
+ cv/src/cvlinefit.cpp \
+ cv/src/cvlkpyramid.cpp \
+ cv/src/cvmatchcontours.cpp \
+ cv/src/cvmoments.cpp \
+ cv/src/cvmorph.cpp \
+ cv/src/cvmotempl.cpp \
+ cv/src/cvoptflowbm.cpp \
+ cv/src/cvoptflowhs.cpp \
+ cv/src/cvoptflowlk.cpp \
+ cv/src/cvpgh.cpp \
+ cv/src/cvposit.cpp \
+ cv/src/cvprecomp.cpp \
+ cv/src/cvpyramids.cpp \
+ cv/src/cvpyrsegmentation.cpp \
+ cv/src/cvrotcalipers.cpp \
+ cv/src/cvsamplers.cpp \
+ cv/src/cvsegmentation.cpp \
+ cv/src/cvshapedescr.cpp \
+ cv/src/cvsmooth.cpp \
+ cv/src/cvsnakes.cpp \
+ cv/src/cvstereobm.cpp \
+ cv/src/cvstereogc.cpp \
+ cv/src/cvsubdivision2d.cpp \
+ cv/src/cvsumpixels.cpp \
+ cv/src/cvsurf.cpp \
+ cv/src/cvswitcher.cpp \
+ cv/src/cvtables.cpp \
+ cv/src/cvtemplmatch.cpp \
+ cv/src/cvthresh.cpp \
+ cv/src/cvundistort.cpp \
+ cv/src/cvutils.cpp \
+ cv/src/mycvHaarDetectObjects.cpp
+# cv/src/cvkdtree.cpp \
+
+include $(BUILD_STATIC_LIBRARY)
+
+
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libcvaux
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/cv/src \
+ $(LOCAL_PATH)/cv/include \
+ $(LOCAL_PATH)/cxcore/include \
+ $(LOCAL_PATH)/cvaux/include
+LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%)
+LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -ldl
+
+LOCAL_SRC_FILES := \
+ cvaux/src/camshift.cpp \
+ cvaux/src/cvaux.cpp \
+ cvaux/src/cvauxutils.cpp \
+ cvaux/src/cvbgfg_acmmm2003.cpp \
+ cvaux/src/cvbgfg_codebook.cpp \
+ cvaux/src/cvbgfg_common.cpp \
+ cvaux/src/cvbgfg_gaussmix.cpp \
+ cvaux/src/cvcalibfilter.cpp \
+ cvaux/src/cvclique.cpp \
+ cvaux/src/cvcorrespond.cpp \
+ cvaux/src/cvcorrimages.cpp \
+ cvaux/src/cvcreatehandmask.cpp \
+ cvaux/src/cvdpstereo.cpp \
+ cvaux/src/cveigenobjects.cpp \
+ cvaux/src/cvepilines.cpp \
+ cvaux/src/cvface.cpp \
+ cvaux/src/cvfacedetection.cpp \
+ cvaux/src/cvfacetemplate.cpp \
+ cvaux/src/cvfindface.cpp \
+ cvaux/src/cvfindhandregion.cpp \
+ cvaux/src/cvhmm.cpp \
+ cvaux/src/cvhmm1d.cpp \
+ cvaux/src/cvhmmobs.cpp \
+ cvaux/src/cvlcm.cpp \
+ cvaux/src/cvlee.cpp \
+ cvaux/src/cvlevmar.cpp \
+ cvaux/src/cvlevmarprojbandle.cpp \
+ cvaux/src/cvlevmartrif.cpp \
+ cvaux/src/cvlines.cpp \
+ cvaux/src/cvlmeds.cpp \
+ cvaux/src/cvmat.cpp \
+ cvaux/src/cvmorphcontours.cpp \
+ cvaux/src/cvmorphing.cpp \
+ cvaux/src/cvprewarp.cpp \
+ cvaux/src/cvscanlines.cpp \
+ cvaux/src/cvsegment.cpp \
+ cvaux/src/cvsubdiv2.cpp \
+ cvaux/src/cvtexture.cpp \
+ cvaux/src/cvtrifocal.cpp \
+ cvaux/src/cvvecfacetracking.cpp \
+ cvaux/src/cvvideo.cpp \
+ cvaux/src/decomppoly.cpp \
+ cvaux/src/enmin.cpp \
+ cvaux/src/extendededges.cpp \
+ cvaux/src/precomp.cpp
+# cvaux/src/cv3dtracker.cpp \
+
+include $(BUILD_STATIC_LIBRARY)
+
+
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libcvml
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/cv/src \
+ $(LOCAL_PATH)/cv/include \
+ $(LOCAL_PATH)/cxcore/include \
+ $(LOCAL_PATH)/ml/include
+LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%)
+LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -ldl
+
+LOCAL_SRC_FILES := \
+ ml/src/ml.cpp \
+ ml/src/mlann_mlp.cpp \
+ ml/src/mlboost.cpp \
+ ml/src/mlcnn.cpp \
+ ml/src/mlem.cpp \
+ ml/src/mlestimate.cpp \
+ ml/src/mlknearest.cpp \
+ ml/src/mlnbayes.cpp \
+ ml/src/mlrtrees.cpp \
+ ml/src/mlsvm.cpp \
+ ml/src/mltestset.cpp \
+ ml/src/mltree.cpp \
+ ml/src/ml_inner_functions.cpp
+
+include $(BUILD_STATIC_LIBRARY)
+
+
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libcvhighgui
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/cv/src \
+ $(LOCAL_PATH)/cv/include \
+ $(LOCAL_PATH)/cxcore/include \
+ $(LOCAL_PATH)/otherlibs/highgui \
+ external/jpeg
+
+LOCAL_SHARED_LIBRARIES += libjpeg
+
+LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%) -DHAVE_JPEG
+LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -ldl -ljpeg
+
+LOCAL_SRC_FILES := \
+ otherlibs/highgui/bitstrm.cpp \
+ otherlibs/highgui/grfmt_base.cpp \
+ otherlibs/highgui/grfmt_bmp.cpp \
+ otherlibs/highgui/grfmt_exr.cpp \
+ otherlibs/highgui/grfmt_imageio.cpp \
+ otherlibs/highgui/grfmt_jpeg.cpp \
+ otherlibs/highgui/grfmt_jpeg2000.cpp \
+ otherlibs/highgui/grfmt_png.cpp \
+ otherlibs/highgui/grfmt_pxm.cpp \
+ otherlibs/highgui/grfmt_sunras.cpp \
+ otherlibs/highgui/grfmt_tiff.cpp \
+ otherlibs/highgui/image.cpp \
+ otherlibs/highgui/loadsave.cpp \
+ otherlibs/highgui/precomp.cpp \
+ otherlibs/highgui/utils.cpp \
+ otherlibs/highgui/cvcap.cpp \
+ otherlibs/highgui/cvcap_socket.cpp
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libopencv
+LOCAL_MODULE_TAGS := optional
+
+include $(LOCAL_PATH)/libopencv.mk
+
+LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%)
+LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -ldl -llog \
+ -L$(TARGET_OUT) -lcxcore -lcv -lcvaux -lcvml -lcvhighgui
+
+
+LOCAL_SRC_FILES := \
+ WLNonFileByteStream.cpp
+
+
+LOCAL_STATIC_LIBRARIES := libcxcore libcv libcvaux libcvml libcvhighgui
+
+include $(BUILD_STATIC_LIBRARY)
+
diff --git a/Application.mk b/Application.mk
new file mode 100644
index 0000000..c3278bc
--- /dev/null
+++ b/Application.mk
@@ -0,0 +1,3 @@
+APP_BUILD_SCRIPT := $(call my-dir)/Android.mk
+APP_PROJECT_PATH := $(call my-dir)/tests/VideoEmulation
+APP_MODULES := cxcore cv cvaux cvml cvhighgui opencv
diff --git a/LICENSE_Android_NDK b/LICENSE_Android_NDK
new file mode 100644
index 0000000..6d379b3
--- /dev/null
+++ b/LICENSE_Android_NDK
@@ -0,0 +1,12 @@
+OpenCV for Android NDK
+Copyright (c) 2006-2009 SIProp Project http://www.siprop.org/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
diff --git a/LICENSE_OpenCV b/LICENSE_OpenCV
new file mode 100644
index 0000000..3f81081
--- /dev/null
+++ b/LICENSE_OpenCV
@@ -0,0 +1,36 @@
+IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+
+By downloading, copying, installing or using the software you agree to this license.
+If you do not agree to this license, do not download, install,
+copy or use the software.
+
+
+ Intel License Agreement
+ For Open Source Computer Vision Library
+
+Copyright (C) 2000-2006, Intel Corporation, all rights reserved.
+Third party copyrights are property of their respective owners.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistribution's of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistribution's in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * The name of Intel Corporation may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are disclaimed.
+In no event shall the Intel Corporation or contributors be liable for any direct,
+indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused
+and on any theory of liability, whether in contract, strict liability,
+or tort (including negligence or otherwise) arising in any way out of
+the use of this software, even if advised of the possibility of such damage.
diff --git a/MODULE_LICENSE_BSD b/MODULE_LICENSE_BSD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_BSD
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..cf95e3c
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,880 @@
+IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+
+By downloading, copying, installing or using the software you agree to this license.
+If you do not agree to this license, do not download, install,
+copy or use the software.
+
+
+ Intel License Agreement
+ For Open Source Computer Vision Library
+
+Copyright (C) 2000-2006, Intel Corporation, all rights reserved.
+Third party copyrights are property of their respective owners.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistribution's of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistribution's in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * The name of Intel Corporation may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are disclaimed.
+In no event shall the Intel Corporation or contributors be liable for any direct,
+indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused
+and on any theory of liability, whether in contract, strict liability,
+or tort (including negligence or otherwise) arising in any way out of
+the use of this software, even if advised of the possibility of such damage.
+
+####################################################################################################
+
+OpenCV for Android NDK
+Copyright (c) 2006-2009 SIProp Project http://www.siprop.org/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+
+####################################################################################################
+
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+
+####################################################################################################
+
+ * Copyright© 2008, Liu Liu All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ * The name of Contributor may not be used to endorse or
+ * promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+
+####################################################################################################
+
+///////////////////////////////////////////////////////////////////////////////
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to
+// this license. If you do not agree to this license, do not download,
+// install, copy or use the software.
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2008, Google, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation or contributors may not be used to endorse
+// or promote products derived from this software without specific
+// prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is"
+// and any express or implied warranties, including, but not limited to, the
+// implied warranties of merchantability and fitness for a particular purpose
+// are disclaimed. In no event shall the Intel Corporation or contributors be
+// liable for any direct, indirect, incidental, special, exemplary, or
+// consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+
+####################################################################################################
+
+// * Copyright (c) 1992, 1993
+// * The Regents of the University of California. All rights reserved.
+// *
+// * Redistribution and use in source and binary forms, with or without
+// * modification, are permitted provided that the following conditions
+// * are met:
+// * 1. Redistributions of source code must retain the above copyright
+// * notice, this list of conditions and the following disclaimer.
+// * 2. Redistributions in binary form must reproduce the above copyright
+// * notice, this list of conditions and the following disclaimer in the
+// * documentation and/or other materials provided with the distribution.
+// * 3. All advertising materials mentioning features or use of this software
+// * must display the following acknowledgement:
+// * This product includes software developed by the University of
+// * California, Berkeley and its contributors.
+// * 4. Neither the name of the University nor the names of its contributors
+// * may be used to endorse or promote products derived from this software
+// * without specific prior written permission.
+// *
+// * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+// * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+// * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// * SUCH DAMAGE.
+
+####################################################################################################
+
+/********************************* COPYRIGHT NOTICE *******************************\
+ Original code for Bayer->BGR/RGB conversion is provided by Dirk Schaefer
+ from MD-Mathematische Dienste GmbH. Below is the copyright notice:
+
+ IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ By downloading, copying, installing or using the software you agree
+ to this license. If you do not agree to this license, do not download,
+ install, copy or use the software.
+
+ Contributors License Agreement:
+
+ Copyright (c) 2002,
+ MD-Mathematische Dienste GmbH
+ Im Defdahl 5-10
+ 44141 Dortmund
+ Germany
+ www.md-it.de
+
+ Redistribution and use in source and binary forms,
+ with or without modification, are permitted provided
+ that the following conditions are met:
+
+ Redistributions of source code must retain
+ the above copyright notice, this list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ The name of Contributor may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ THE POSSIBILITY OF SUCH DAMAGE.
+\**********************************************************************************/
+####################################################################################################
+
+/****************************************************************************************\
+ COPYRIGHT NOTICE
+ ----------------
+
+ The code has been derived from libsvm library (version 2.6)
+ (http://www.csie.ntu.edu.tw/~cjlin/libsvm).
+
+ Here is the orignal copyright:
+------------------------------------------------------------------------------------------
+ Copyright (c) 2000-2003 Chih-Chung Chang and Chih-Jen Lin
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither name of copyright holders nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************************/
+####################################################################################################
+
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+####################################################################################################
+
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective icvers.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+####################################################################################################
+
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2002, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+####################################################################################################
+
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright( C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+//(including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort(including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+####################################################################################################
+
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2008, Xavier Delacour, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+####################################################################################################
+
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright( C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+//(including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort(including negligence or otherwise) arising in any way out of
+// the use of this software, even ifadvised of the possibility of such damage.
+//
+//M*/
+####################################################################################################
+
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+####################################################################################################
+
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2008, Nils Hasler, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+####################################################################################################
+
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+####################################################################################################
+
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+####################################################################################################
+
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+####################################################################################################
+
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+####################################################################################################
+
+ Copyright (C) 1978-1999 Ken Turkowski. <turk@computer.org>
+
+ All rights reserved.
+
+ Warranty Information
+ Even though I have reviewed this software, I make no warranty
+ or representation, either express or implied, with respect to this
+ software, its quality, accuracy, merchantability, or fitness for a
+ particular purpose. As a result, this software is provided "as is,"
+ and you, its user, are assuming the entire risk as to its quality
+ and accuracy.
+
+ This code may be used and freely distributed as long as it includes
+ this copyright notice and the above warranty information.
+
+####################################################################################################
+
+ The algorithms developed and implemented by Vezhnevets Vldimir
+ aka Dead Moroz (vvp@graphics.cs.msu.ru)
+ See http://graphics.cs.msu.su/en/research/calibration/opencv.html
+ for detailed information.
+
+ Reliability additions and modifications made by Philip Gruebele.
+ <a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
+
+ Some further improvements for detection of partially ocluded boards at non-ideal
+ lighting conditions have been made by Alex Bovyrin and Kurt Kolonige
+
+####################################################################################################
+
+ Copyright (C) 1981-1999 Ken Turkowski. <turk@computer.org>
+
+ All rights reserved.
+
+ Warranty Information
+ Even though I have reviewed this software, I make no warranty
+ or representation, either express or implied, with respect to this
+ software, its quality, accuracy, merchantability, or fitness for a
+ particular purpose. As a result, this software is provided "as is,"
+ and you, its user, are assuming the entire risk as to its quality
+ and accuracy.
+
+ This code may be used and freely distributed as long as it includes
+ this copyright notice and the above warranty information.
+
+####################################################################################################
+
+ An implementation of the Earth Movers Distance.
+ Based of the solution for the Transportation problem as described in
+ "Introduction to Mathematical Programming" by F. S. Hillier and
+ G. J. Lieberman, McGraw-Hill, 1990.
+
+ Copyright (C) 1998 Yossi Rubner
+ Computer Science Department, Stanford University
+ E-Mail: rubner@cs.stanford.edu URL: http://vision.stanford.edu/~rubner
+ ==========================================================================
+
+####################################################################################################
+
+ * Constant-time median filtering -- http://nomis80.org/ctmf.html
+ * Copyright (C) 2006 Simon Perreault
+ *
+ * Contact:
+ * Laboratoire de vision et systemes numeriques
+ * Pavillon Adrien-Pouliot
+ * Universite Laval
+ * Sainte-Foy, Quebec, Canada
+ * G1K 7P4
+ *
+ * perreaul@gel.ulaval.ca
+
+####################################################################################################
+
+/********************************* COPYRIGHT NOTICE *******************************\
+ The function for RGB to Lab conversion is based on the MATLAB script
+ RGB2Lab.m translated by Mark Ruzon from C code by Yossi Rubner, 23 September 1997.
+ See the page [http://vision.stanford.edu/~ruzon/software/rgblab.html]
+\**********************************************************************************/
+####################################################################################################
+
+/****************************************************************************************\
+ This part of the file implements JPEG codec on base of IJG libjpeg library,
+ in particular, this is the modified example.doc from libjpeg package.
+ See otherlibs/_graphics/readme.txt for copyright notice.
+\****************************************************************************************/
+####################################################################################################
+
+/****************************************************************************************\
+ A part of the file implements TIFF reader on base of libtiff library
+ (see otherlibs/_graphics/readme.txt for copyright notice)
+\****************************************************************************************/
+####################################################################################################
+
+/*
+ * The following definitions (until #endif)
+ * is an extract from IPL headers.
+ * Copyright (c) 1995 Intel Corporation.
+ */
+####################################################################################################
+
diff --git a/README.rdoc b/README.rdoc
new file mode 100644
index 0000000..a68cf71
--- /dev/null
+++ b/README.rdoc
@@ -0,0 +1,76 @@
+= OpenCV-Android
+
+Dedicated to providing an optimized port of OpenCV for the Google Android OS.
+
+== Requirements
+
+In order to use OpenCV-Android, you will need to download and install both the Android SDK and NDK version 1.6. It may or may not work with a higher version. It has been confirmed that this doesn't work with older versions, so please use 1.6 or higher.
+
+In addition to having the SDK or NDK you will also need to have one of the following:
+* An Android Phone Dev Phone (Might work with other phones, has not been tested)
+* A newer version of the QuickTime Java Libraries
+
+For those of you running on the emulator, I built a very simple Socket-based Camera server that will send images over a socket connection. This uses the QuickTime libraries which are present by default on Mac OS X, but I haven't tested on other OSes. If it doesn't work for you, you can always try the original WebcamBroadcaster I derived mine from which uses the JMF (which doesn't work with Mac OS X, hence the QTWebcamBroadcaster):
+http://www.tomgibara.com/android/camera-source
+
+== Build
+
+Building is quite simple. I'm going to assume that you are familiar with Android if you are reading this and keep it rather short.
+
+* Create a symbolic link from the directory where you pulled the OpenCV-Android repository to your [ANDROID_NDK_ROOT]/apps/ directory. Examples:
+ ln -s ~/Source/OpenCV-Android opencv
+
+* From the [ANDROID_NDK_ROOT] run:
+ build/host-setup.sh
+
+* Now run:
+ make APP=opencv
+
+By default, this will build the opencv library and push it into:
+[OPENCV_ANDROID_ROOT]/tests/VideoEmulation/libs
+
+You can change where the lib is delivered by modifying the APP_PROJECT_PATH in:
+[OPENCV_ANDROID_ROOT]/Application.mk
+
+Once you have built the OpenCV library, you can now build and [OPENCV_ANDROID_ROOT]/tests/VideoEmulation.
+
+<b>NOTE:</b> If you plan to use the Socket Camera, you will need to build and run the [OPENCV_ANDROID_ROOT]/tests/QTWebcamBroadcaster first. Also, if you use Eclipse to develop Android, there are already projects defined for both of these applications. You can simply import them into your workspace.
+
+== Setup
+
+If you want to test face tracking, then you need to have a Haar Classifier Cascade XML. I have provided one for use and it is stored in:
+tests/haarcascade_frontalface_alt.xml
+
+Before attempting to run the VideoEmulator application, you must first copy this XML file into the emulator in the following location:
+/data/data/org.siprop.opencv/files/haarcascade_frontalface_alt.xml
+
+Currently, this is a hard-coded path that we look up. Hopefully, this can be remedied in a future version.
+
+== Run
+
+In order to use the VideoEmulator, you have to use the emulator (hence the name.) If you have a Dev Phone, you can play around with the old 'OpenCVSample' test or modify the VideoEmulator to support a real camera. This is something we will work on resolving in the future.
+
+Using the emulator there are two slightly different 'flavors' of running. Both are socket based cameras, but one is written in C++ and emulates a real OpenCV Capture while the other (loosely) emulates a camera implementation in Java. The C++ version is the default as it is slightly faster and takes a little less memory. Also, the ultimate goal is to hook up with a real camera in C++ so that we don't have to pass huge amounts of data (images) back and forth through the JNI interface.
+
+<b>NOTE:</b> For all of these examples you cannot use localhost or 127.0.0.1 as your address for the socket camera. The reason is because when the client is running on the Android emulator, both of these map to Android's localhost, not the machine you are running the emulator on. This means you have to be connected to a network in order to use the socket camera, a limitation.
+
+=== C++
+
+Since this is the default, we have made it pretty easy...
+
+* Start the WebcamBroadcaster - this is a socket server that grabs images from your camera and serves them up
+* Start the VideoEmulator - this runs the Android application that allows you to try out the various pieces implemented thus far
+* Once the application comes up, you will have to configure for your machine address and port for the socket camera to work.
+* Leave Use C++ SocketCapture CHECKED!
+* Choose which test you want to run.
+
+=== Java
+
+To use Java, you have to make a small code change. Eventually we will make this a configurable option without having to make a code change. The reason is because when we send data over a socket from Java to Java it is faster to send serialized buffered images. However, when we send data to C++, we have to send a raw byte array.
+
+* Modify the WebcamBroadcaster by changing the default value assigned to RAW to false.
+* Start the WebcamBroadcaster - this is a socket server that grabs images from your camera and serves them up
+* Start the VideoEmulator - this runs the Android application that allows you to try out the various pieces implemented thus far
+* Once the application comes up, you will have to configure for your machine address and port for the socket camera to work.
+* UNCHECK Use C++ SocketCapture!
+* Choose which test you want to run.
diff --git a/VERSION.txt b/VERSION.txt
new file mode 100644
index 0000000..0230522
--- /dev/null
+++ b/VERSION.txt
@@ -0,0 +1,4 @@
+This is OpenCV version 1.1 for Android. It was obtained at http://opencv.willowgarage.com/.
+
+Please note that due to platform and project constraints this is NOT the latest version of OpenCV!
+
diff --git a/WLNonFileByteStream.cpp b/WLNonFileByteStream.cpp
new file mode 100644
index 0000000..138c174
--- /dev/null
+++ b/WLNonFileByteStream.cpp
@@ -0,0 +1,150 @@
+/*
+OpenCV for Android NDK
+Copyright (c) 2006-2009 SIProp Project http://www.siprop.org/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+#include "WLNonFileByteStream.h"
+
+///////////////////////////// WLNonFileByteStream ///////////////////////////////////
+
+WLNonFileByteStream::WLNonFileByteStream()
+{
+ m_start = m_end = m_current = 0;
+ _size = 0;
+ m_is_opened = false;
+}
+
+
+WLNonFileByteStream::~WLNonFileByteStream()
+{
+ Deallocate();
+}
+
+
+void WLNonFileByteStream::Allocate(int data_size)
+{
+ if(!m_start)
+ m_start = new uchar[data_size];
+
+ m_end = m_start + data_size;
+ m_current = m_start;
+}
+
+void WLNonFileByteStream::Deallocate()
+{
+ if(m_start)
+ {
+ delete [] m_start;
+ m_start = 0;
+ }
+}
+
+bool WLNonFileByteStream::Open(int data_size)
+{
+ Close();
+ Allocate(data_size);
+
+ m_is_opened = true;
+ m_current = m_start;
+ _size = data_size;
+
+ return true;
+}
+
+
+void WLNonFileByteStream::Close()
+{
+ m_is_opened = false;
+ Deallocate();
+}
+
+
+void WLNonFileByteStream::PutByte( int val )
+{
+ *m_current++ = (uchar)val;
+}
+
+
+void WLNonFileByteStream::PutBytes( const void* buffer, int count )
+{
+ uchar* data = (uchar*)buffer;
+
+ assert( data && m_current && count >= 0 );
+
+ while( count )
+ {
+ int l = (int)(m_end - m_current);
+
+ if( l > count )
+ l = count;
+
+ if( l > 0 )
+ {
+ memcpy( m_current, data, l );
+ m_current += l;
+ data += l;
+ count -= l;
+ }
+ }
+}
+
+
+void WLNonFileByteStream::PutWord( int val )
+{
+ uchar *current = m_current;
+
+ if( current+1 < m_end )
+ {
+ current[0] = (uchar)val;
+ current[1] = (uchar)(val >> 8);
+ m_current = current + 2;
+ }
+ else
+ {
+ PutByte(val);
+ PutByte(val >> 8);
+ }
+}
+
+
+void WLNonFileByteStream::PutDWord( int val )
+{
+ uchar *current = m_current;
+
+ if( current+3 < m_end )
+ {
+ current[0] = (uchar)val;
+ current[1] = (uchar)(val >> 8);
+ current[2] = (uchar)(val >> 16);
+ current[3] = (uchar)(val >> 24);
+ m_current = current + 4;
+ }
+ else
+ {
+ PutByte(val);
+ PutByte(val >> 8);
+ PutByte(val >> 16);
+ PutByte(val >> 24);
+ }
+}
+
+
+uchar* WLNonFileByteStream::GetByte()
+{
+ return m_start;
+}
+
+int WLNonFileByteStream::GetSize()
+{
+ return _size;
+}
+
diff --git a/WLNonFileByteStream.h b/WLNonFileByteStream.h
new file mode 100644
index 0000000..5ae8b75
--- /dev/null
+++ b/WLNonFileByteStream.h
@@ -0,0 +1,51 @@
+/*
+OpenCV for Android NDK
+Copyright (c) 2006-2009 SIProp Project http://www.siprop.org/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+#ifndef _WLNonFileByteStream_H_
+#define _WLNonFileByteStream_H_
+
+#include <stdio.h>
+#include "cv.h"
+#include "cxcore.h"
+#include "cvaux.h"
+#include "highgui.h"
+#include "ml.h"
+#include "utils.h"
+
+class WLNonFileByteStream {
+public:
+ WLNonFileByteStream();
+ ~WLNonFileByteStream();
+
+ bool Open(int data_size);
+ void Close();
+ void PutByte( int val );
+ void PutBytes( const void* buffer, int count );
+ void PutWord( int val );
+ void PutDWord( int val );
+ uchar* GetByte();
+ int GetSize();
+
+protected:
+ void Allocate(int data_size);
+ void Deallocate();
+ int _size;
+ uchar* m_start;
+ uchar* m_end;
+ uchar* m_current;
+ bool m_is_opened;
+
+};
+
+#endif/*_WLNonFileByteStream_H_*/
diff --git a/cv/include/cv.h b/cv/include/cv.h
new file mode 100644
index 0000000..02ec454
--- /dev/null
+++ b/cv/include/cv.h
@@ -0,0 +1,1482 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+
+#ifndef _CV_H_
+#define _CV_H_
+
+#ifdef __IPL_H__
+#define HAVE_IPL
+#endif
+
+#ifndef SKIP_INCLUDES
+ #if defined(_CH_)
+ #pragma package <chopencv>
+ #include <chdl.h>
+ LOAD_CHDL(cv)
+ #endif
+#endif
+
+#include "cxcore.h"
+#include "cvtypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/****************************************************************************************\
+* Image Processing *
+\****************************************************************************************/
+
+/* Copies source 2D array inside of the larger destination array and
+ makes a border of the specified type (IPL_BORDER_*) around the copied area. */
+CVAPI(void) cvCopyMakeBorder( const CvArr* src, CvArr* dst, CvPoint offset,
+ int bordertype, CvScalar value CV_DEFAULT(cvScalarAll(0)));
+
+#define CV_BLUR_NO_SCALE 0
+#define CV_BLUR 1
+#define CV_GAUSSIAN 2
+#define CV_MEDIAN 3
+#define CV_BILATERAL 4
+
+/* Smoothes array (removes noise) */
+CVAPI(void) cvSmooth( const CvArr* src, CvArr* dst,
+ int smoothtype CV_DEFAULT(CV_GAUSSIAN),
+ int size1 CV_DEFAULT(3),
+ int size2 CV_DEFAULT(0),
+ double sigma1 CV_DEFAULT(0),
+ double sigma2 CV_DEFAULT(0));
+
+/* Convolves the image with the kernel */
+CVAPI(void) cvFilter2D( const CvArr* src, CvArr* dst, const CvMat* kernel,
+ CvPoint anchor CV_DEFAULT(cvPoint(-1,-1)));
+
+/* Finds integral image: SUM(X,Y) = sum(x<X,y<Y)I(x,y) */
+CVAPI(void) cvIntegral( const CvArr* image, CvArr* sum,
+ CvArr* sqsum CV_DEFAULT(NULL),
+ CvArr* tilted_sum CV_DEFAULT(NULL));
+
+/*
+ Smoothes the input image with gaussian kernel and then down-samples it.
+ dst_width = floor(src_width/2)[+1],
+ dst_height = floor(src_height/2)[+1]
+*/
+CVAPI(void) cvPyrDown( const CvArr* src, CvArr* dst,
+ int filter CV_DEFAULT(CV_GAUSSIAN_5x5) );
+
+/*
+ Up-samples image and smoothes the result with gaussian kernel.
+ dst_width = src_width*2,
+ dst_height = src_height*2
+*/
+CVAPI(void) cvPyrUp( const CvArr* src, CvArr* dst,
+ int filter CV_DEFAULT(CV_GAUSSIAN_5x5) );
+
+/* Builds pyramid for an image */
+CVAPI(CvMat**) cvCreatePyramid( const CvArr* img, int extra_layers, double rate,
+ const CvSize* layer_sizes CV_DEFAULT(0),
+ CvArr* bufarr CV_DEFAULT(0),
+ int calc CV_DEFAULT(1),
+ int filter CV_DEFAULT(CV_GAUSSIAN_5x5) );
+
+/* Releases pyramid */
+CVAPI(void) cvReleasePyramid( CvMat*** pyramid, int extra_layers );
+
+
+/* Splits color or grayscale image into multiple connected components
+ of nearly the same color/brightness using modification of Burt algorithm.
+ comp with contain a pointer to sequence (CvSeq)
+ of connected components (CvConnectedComp) */
+CVAPI(void) cvPyrSegmentation( IplImage* src, IplImage* dst,
+ CvMemStorage* storage, CvSeq** comp,
+ int level, double threshold1,
+ double threshold2 );
+
+/* Filters image using meanshift algorithm */
+CVAPI(void) cvPyrMeanShiftFiltering( const CvArr* src, CvArr* dst,
+ double sp, double sr, int max_level CV_DEFAULT(1),
+ CvTermCriteria termcrit CV_DEFAULT(cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS,5,1)));
+
+/* Segments image using seed "markers" */
+CVAPI(void) cvWatershed( const CvArr* image, CvArr* markers );
+
+#define CV_INPAINT_NS 0
+#define CV_INPAINT_TELEA 1
+
+/* Inpaints the selected region in the image */
+CVAPI(void) cvInpaint( const CvArr* src, const CvArr* inpaint_mask,
+ CvArr* dst, double inpaintRange, int flags );
+
+#define CV_SCHARR -1
+#define CV_MAX_SOBEL_KSIZE 7
+
+/* Calculates an image derivative using generalized Sobel
+ (aperture_size = 1,3,5,7) or Scharr (aperture_size = -1) operator.
+ Scharr can be used only for the first dx or dy derivative */
+CVAPI(void) cvSobel( const CvArr* src, CvArr* dst,
+ int xorder, int yorder,
+ int aperture_size CV_DEFAULT(3));
+
+/* Calculates the image Laplacian: (d2/dx + d2/dy)I */
+CVAPI(void) cvLaplace( const CvArr* src, CvArr* dst,
+ int aperture_size CV_DEFAULT(3) );
+
+/* Constants for color conversion */
+#define CV_BGR2BGRA 0
+#define CV_RGB2RGBA CV_BGR2BGRA
+
+#define CV_BGRA2BGR 1
+#define CV_RGBA2RGB CV_BGRA2BGR
+
+#define CV_BGR2RGBA 2
+#define CV_RGB2BGRA CV_BGR2RGBA
+
+#define CV_RGBA2BGR 3
+#define CV_BGRA2RGB CV_RGBA2BGR
+
+#define CV_BGR2RGB 4
+#define CV_RGB2BGR CV_BGR2RGB
+
+#define CV_BGRA2RGBA 5
+#define CV_RGBA2BGRA CV_BGRA2RGBA
+
+#define CV_BGR2GRAY 6
+#define CV_RGB2GRAY 7
+#define CV_GRAY2BGR 8
+#define CV_GRAY2RGB CV_GRAY2BGR
+#define CV_GRAY2BGRA 9
+#define CV_GRAY2RGBA CV_GRAY2BGRA
+#define CV_BGRA2GRAY 10
+#define CV_RGBA2GRAY 11
+
+#define CV_BGR2BGR565 12
+#define CV_RGB2BGR565 13
+#define CV_BGR5652BGR 14
+#define CV_BGR5652RGB 15
+#define CV_BGRA2BGR565 16
+#define CV_RGBA2BGR565 17
+#define CV_BGR5652BGRA 18
+#define CV_BGR5652RGBA 19
+
+#define CV_GRAY2BGR565 20
+#define CV_BGR5652GRAY 21
+
+#define CV_BGR2BGR555 22
+#define CV_RGB2BGR555 23
+#define CV_BGR5552BGR 24
+#define CV_BGR5552RGB 25
+#define CV_BGRA2BGR555 26
+#define CV_RGBA2BGR555 27
+#define CV_BGR5552BGRA 28
+#define CV_BGR5552RGBA 29
+
+#define CV_GRAY2BGR555 30
+#define CV_BGR5552GRAY 31
+
+#define CV_BGR2XYZ 32
+#define CV_RGB2XYZ 33
+#define CV_XYZ2BGR 34
+#define CV_XYZ2RGB 35
+
+#define CV_BGR2YCrCb 36
+#define CV_RGB2YCrCb 37
+#define CV_YCrCb2BGR 38
+#define CV_YCrCb2RGB 39
+
+#define CV_BGR2HSV 40
+#define CV_RGB2HSV 41
+
+#define CV_BGR2Lab 44
+#define CV_RGB2Lab 45
+
+#define CV_BayerBG2BGR 46
+#define CV_BayerGB2BGR 47
+#define CV_BayerRG2BGR 48
+#define CV_BayerGR2BGR 49
+
+#define CV_BayerBG2RGB CV_BayerRG2BGR
+#define CV_BayerGB2RGB CV_BayerGR2BGR
+#define CV_BayerRG2RGB CV_BayerBG2BGR
+#define CV_BayerGR2RGB CV_BayerGB2BGR
+
+#define CV_BGR2Luv 50
+#define CV_RGB2Luv 51
+#define CV_BGR2HLS 52
+#define CV_RGB2HLS 53
+
+#define CV_HSV2BGR 54
+#define CV_HSV2RGB 55
+
+#define CV_Lab2BGR 56
+#define CV_Lab2RGB 57
+#define CV_Luv2BGR 58
+#define CV_Luv2RGB 59
+#define CV_HLS2BGR 60
+#define CV_HLS2RGB 61
+
+#define CV_COLORCVT_MAX 100
+
+/* Converts input array pixels from one color space to another */
+CVAPI(void) cvCvtColor( const CvArr* src, CvArr* dst, int code );
+
+#define CV_INTER_NN 0
+#define CV_INTER_LINEAR 1
+#define CV_INTER_CUBIC 2
+#define CV_INTER_AREA 3
+
+#define CV_WARP_FILL_OUTLIERS 8
+#define CV_WARP_INVERSE_MAP 16
+
+/* Resizes image (input array is resized to fit the destination array) */
+CVAPI(void) cvResize( const CvArr* src, CvArr* dst,
+ int interpolation CV_DEFAULT( CV_INTER_LINEAR ));
+
+/* Warps image with affine transform */
+CVAPI(void) cvWarpAffine( const CvArr* src, CvArr* dst, const CvMat* map_matrix,
+ int flags CV_DEFAULT(CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS),
+ CvScalar fillval CV_DEFAULT(cvScalarAll(0)) );
+
+/* Computes affine transform matrix for mapping src[i] to dst[i] (i=0,1,2) */
+CVAPI(CvMat*) cvGetAffineTransform( const CvPoint2D32f * src,
+ const CvPoint2D32f * dst,
+ CvMat * map_matrix );
+
+/* Computes rotation_matrix matrix */
+CVAPI(CvMat*) cv2DRotationMatrix( CvPoint2D32f center, double angle,
+ double scale, CvMat* map_matrix );
+
+/* Warps image with perspective (projective) transform */
+CVAPI(void) cvWarpPerspective( const CvArr* src, CvArr* dst, const CvMat* map_matrix,
+ int flags CV_DEFAULT(CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS),
+ CvScalar fillval CV_DEFAULT(cvScalarAll(0)) );
+
+/* Computes perspective transform matrix for mapping src[i] to dst[i] (i=0,1,2,3) */
+CVAPI(CvMat*) cvGetPerspectiveTransform( const CvPoint2D32f* src,
+ const CvPoint2D32f* dst,
+ CvMat* map_matrix );
+
+/* Performs generic geometric transformation using the specified coordinate maps */
+CVAPI(void) cvRemap( const CvArr* src, CvArr* dst,
+ const CvArr* mapx, const CvArr* mapy,
+ int flags CV_DEFAULT(CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS),
+ CvScalar fillval CV_DEFAULT(cvScalarAll(0)) );
+
+/* Converts mapx & mapy from floating-point to integer formats for cvRemap */
+CVAPI(void) cvConvertMaps( const CvArr* mapx, const CvArr* mapy,
+ CvArr* mapxy, CvArr* mapalpha );
+
+/* Performs forward or inverse log-polar image transform */
+CVAPI(void) cvLogPolar( const CvArr* src, CvArr* dst,
+ CvPoint2D32f center, double M,
+ int flags CV_DEFAULT(CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS));
+
+#define CV_SHAPE_RECT 0
+#define CV_SHAPE_CROSS 1
+#define CV_SHAPE_ELLIPSE 2
+#define CV_SHAPE_CUSTOM 100
+
+/* creates structuring element used for morphological operations */
+CVAPI(IplConvKernel*) cvCreateStructuringElementEx(
+ int cols, int rows, int anchor_x, int anchor_y,
+ int shape, int* values CV_DEFAULT(NULL) );
+
+/* releases structuring element */
+CVAPI(void) cvReleaseStructuringElement( IplConvKernel** element );
+
+/* erodes input image (applies minimum filter) one or more times.
+ If element pointer is NULL, 3x3 rectangular element is used */
+CVAPI(void) cvErode( const CvArr* src, CvArr* dst,
+ IplConvKernel* element CV_DEFAULT(NULL),
+ int iterations CV_DEFAULT(1) );
+
+/* dilates input image (applies maximum filter) one or more times.
+ If element pointer is NULL, 3x3 rectangular element is used */
+CVAPI(void) cvDilate( const CvArr* src, CvArr* dst,
+ IplConvKernel* element CV_DEFAULT(NULL),
+ int iterations CV_DEFAULT(1) );
+
+#define CV_MOP_OPEN 2
+#define CV_MOP_CLOSE 3
+#define CV_MOP_GRADIENT 4
+#define CV_MOP_TOPHAT 5
+#define CV_MOP_BLACKHAT 6
+
+/* Performs complex morphological transformation */
+CVAPI(void) cvMorphologyEx( const CvArr* src, CvArr* dst,
+ CvArr* temp, IplConvKernel* element,
+ int operation, int iterations CV_DEFAULT(1) );
+
+/* Calculates all spatial and central moments up to the 3rd order */
+CVAPI(void) cvMoments( const CvArr* arr, CvMoments* moments, int binary CV_DEFAULT(0));
+
+/* Retrieve particular spatial, central or normalized central moments */
+CVAPI(double) cvGetSpatialMoment( CvMoments* moments, int x_order, int y_order );
+CVAPI(double) cvGetCentralMoment( CvMoments* moments, int x_order, int y_order );
+CVAPI(double) cvGetNormalizedCentralMoment( CvMoments* moments,
+ int x_order, int y_order );
+
+/* Calculates 7 Hu's invariants from precalculated spatial and central moments */
+CVAPI(void) cvGetHuMoments( CvMoments* moments, CvHuMoments* hu_moments );
+
+/*********************************** data sampling **************************************/
+
+/* Fetches pixels that belong to the specified line segment and stores them to the buffer.
+ Returns the number of retrieved points. */
+CVAPI(int) cvSampleLine( const CvArr* image, CvPoint pt1, CvPoint pt2, void* buffer,
+ int connectivity CV_DEFAULT(8));
+
+/* Retrieves the rectangular image region with specified center from the input array.
+ dst(x,y) <- src(x + center.x - dst_width/2, y + center.y - dst_height/2).
+ Values of pixels with fractional coordinates are retrieved using bilinear interpolation*/
+CVAPI(void) cvGetRectSubPix( const CvArr* src, CvArr* dst, CvPoint2D32f center );
+
+
+/* Retrieves quadrangle from the input array.
+ matrixarr = ( a11 a12 | b1 ) dst(x,y) <- src(A[x y]' + b)
+ ( a21 a22 | b2 ) (bilinear interpolation is used to retrieve pixels
+ with fractional coordinates)
+*/
+CVAPI(void) cvGetQuadrangleSubPix( const CvArr* src, CvArr* dst,
+ const CvMat* map_matrix );
+
+/* Methods for comparing two array */
+#define CV_TM_SQDIFF 0
+#define CV_TM_SQDIFF_NORMED 1
+#define CV_TM_CCORR 2
+#define CV_TM_CCORR_NORMED 3
+#define CV_TM_CCOEFF 4
+#define CV_TM_CCOEFF_NORMED 5
+
+/* Measures similarity between template and overlapped windows in the source image
+ and fills the resultant image with the measurements */
+CVAPI(void) cvMatchTemplate( const CvArr* image, const CvArr* templ,
+ CvArr* result, int method );
+
+/* Computes earth mover distance between
+ two weighted point sets (called signatures) */
+CVAPI(float) cvCalcEMD2( const CvArr* signature1,
+ const CvArr* signature2,
+ int distance_type,
+ CvDistanceFunction distance_func CV_DEFAULT(NULL),
+ const CvArr* cost_matrix CV_DEFAULT(NULL),
+ CvArr* flow CV_DEFAULT(NULL),
+ float* lower_bound CV_DEFAULT(NULL),
+ void* userdata CV_DEFAULT(NULL));
+
+/****************************************************************************************\
+* Contours retrieving *
+\****************************************************************************************/
+
+/* Retrieves outer and optionally inner boundaries of white (non-zero) connected
+ components in the black (zero) background */
+CVAPI(int) cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour,
+ int header_size CV_DEFAULT(sizeof(CvContour)),
+ int mode CV_DEFAULT(CV_RETR_LIST),
+ int method CV_DEFAULT(CV_CHAIN_APPROX_SIMPLE),
+ CvPoint offset CV_DEFAULT(cvPoint(0,0)));
+
+
+/* Initalizes contour retrieving process.
+ Calls cvStartFindContours.
+ Calls cvFindNextContour until null pointer is returned
+ or some other condition becomes true.
+ Calls cvEndFindContours at the end. */
+CVAPI(CvContourScanner) cvStartFindContours( CvArr* image, CvMemStorage* storage,
+ int header_size CV_DEFAULT(sizeof(CvContour)),
+ int mode CV_DEFAULT(CV_RETR_LIST),
+ int method CV_DEFAULT(CV_CHAIN_APPROX_SIMPLE),
+ CvPoint offset CV_DEFAULT(cvPoint(0,0)));
+
+/* Retrieves next contour */
+CVAPI(CvSeq*) cvFindNextContour( CvContourScanner scanner );
+
+
+/* Substitutes the last retrieved contour with the new one
+ (if the substitutor is null, the last retrieved contour is removed from the tree) */
+CVAPI(void) cvSubstituteContour( CvContourScanner scanner, CvSeq* new_contour );
+
+
+/* Releases contour scanner and returns pointer to the first outer contour */
+CVAPI(CvSeq*) cvEndFindContours( CvContourScanner* scanner );
+
+/* Approximates a single Freeman chain or a tree of chains to polygonal curves */
+CVAPI(CvSeq*) cvApproxChains( CvSeq* src_seq, CvMemStorage* storage,
+ int method CV_DEFAULT(CV_CHAIN_APPROX_SIMPLE),
+ double parameter CV_DEFAULT(0),
+ int minimal_perimeter CV_DEFAULT(0),
+ int recursive CV_DEFAULT(0));
+
+
+/* Initalizes Freeman chain reader.
+ The reader is used to iteratively get coordinates of all the chain points.
+ If the Freeman codes should be read as is, a simple sequence reader should be used */
+CVAPI(void) cvStartReadChainPoints( CvChain* chain, CvChainPtReader* reader );
+
+/* Retrieves the next chain point */
+CVAPI(CvPoint) cvReadChainPoint( CvChainPtReader* reader );
+
+
+/****************************************************************************************\
+* Motion Analysis *
+\****************************************************************************************/
+
+/************************************ optical flow ***************************************/
+
+/* Calculates optical flow for 2 images using classical Lucas & Kanade algorithm */
+CVAPI(void) cvCalcOpticalFlowLK( const CvArr* prev, const CvArr* curr,
+ CvSize win_size, CvArr* velx, CvArr* vely );
+
+/* Calculates optical flow for 2 images using block matching algorithm */
+CVAPI(void) cvCalcOpticalFlowBM( const CvArr* prev, const CvArr* curr,
+ CvSize block_size, CvSize shift_size,
+ CvSize max_range, int use_previous,
+ CvArr* velx, CvArr* vely );
+
+/* Calculates Optical flow for 2 images using Horn & Schunck algorithm */
+CVAPI(void) cvCalcOpticalFlowHS( const CvArr* prev, const CvArr* curr,
+ int use_previous, CvArr* velx, CvArr* vely,
+ double lambda, CvTermCriteria criteria );
+
+#define CV_LKFLOW_PYR_A_READY 1
+#define CV_LKFLOW_PYR_B_READY 2
+#define CV_LKFLOW_INITIAL_GUESSES 4
+#define CV_LKFLOW_GET_MIN_EIGENVALS 8
+
+/* It is Lucas & Kanade method, modified to use pyramids.
+ Also it does several iterations to get optical flow for
+ every point at every pyramid level.
+ Calculates optical flow between two images for certain set of points (i.e.
+ it is a "sparse" optical flow, which is opposite to the previous 3 methods) */
+CVAPI(void) cvCalcOpticalFlowPyrLK( const CvArr* prev, const CvArr* curr,
+ CvArr* prev_pyr, CvArr* curr_pyr,
+ const CvPoint2D32f* prev_features,
+ CvPoint2D32f* curr_features,
+ int count,
+ CvSize win_size,
+ int level,
+ char* status,
+ float* track_error,
+ CvTermCriteria criteria,
+ int flags );
+
+
+/* Modification of a previous sparse optical flow algorithm to calculate
+ affine flow */
+CVAPI(void) cvCalcAffineFlowPyrLK( const CvArr* prev, const CvArr* curr,
+ CvArr* prev_pyr, CvArr* curr_pyr,
+ const CvPoint2D32f* prev_features,
+ CvPoint2D32f* curr_features,
+ float* matrices, int count,
+ CvSize win_size, int level,
+ char* status, float* track_error,
+ CvTermCriteria criteria, int flags );
+
+/* Estimate rigid transformation between 2 images or 2 point sets */
+CVAPI(int) cvEstimateRigidTransform( const CvArr* A, const CvArr* B,
+ CvMat* M, int full_affine );
+
+/********************************* motion templates *************************************/
+
+/****************************************************************************************\
+* All the motion template functions work only with single channel images. *
+* Silhouette image must have depth IPL_DEPTH_8U or IPL_DEPTH_8S *
+* Motion history image must have depth IPL_DEPTH_32F, *
+* Gradient mask - IPL_DEPTH_8U or IPL_DEPTH_8S, *
+* Motion orientation image - IPL_DEPTH_32F *
+* Segmentation mask - IPL_DEPTH_32F *
+* All the angles are in degrees, all the times are in milliseconds *
+\****************************************************************************************/
+
+/* Updates motion history image given motion silhouette */
+CVAPI(void) cvUpdateMotionHistory( const CvArr* silhouette, CvArr* mhi,
+ double timestamp, double duration );
+
+/* Calculates gradient of the motion history image and fills
+ a mask indicating where the gradient is valid */
+CVAPI(void) cvCalcMotionGradient( const CvArr* mhi, CvArr* mask, CvArr* orientation,
+ double delta1, double delta2,
+ int aperture_size CV_DEFAULT(3));
+
+/* Calculates average motion direction within a selected motion region
+ (region can be selected by setting ROIs and/or by composing a valid gradient mask
+ with the region mask) */
+CVAPI(double) cvCalcGlobalOrientation( const CvArr* orientation, const CvArr* mask,
+ const CvArr* mhi, double timestamp,
+ double duration );
+
+/* Splits a motion history image into a few parts corresponding to separate independent motions
+ (e.g. left hand, right hand) */
+CVAPI(CvSeq*) cvSegmentMotion( const CvArr* mhi, CvArr* seg_mask,
+ CvMemStorage* storage,
+ double timestamp, double seg_thresh );
+
+/*********************** Background statistics accumulation *****************************/
+
+/* Adds image to accumulator */
+CVAPI(void) cvAcc( const CvArr* image, CvArr* sum,
+ const CvArr* mask CV_DEFAULT(NULL) );
+
+/* Adds squared image to accumulator */
+CVAPI(void) cvSquareAcc( const CvArr* image, CvArr* sqsum,
+ const CvArr* mask CV_DEFAULT(NULL) );
+
+/* Adds a product of two images to accumulator */
+CVAPI(void) cvMultiplyAcc( const CvArr* image1, const CvArr* image2, CvArr* acc,
+ const CvArr* mask CV_DEFAULT(NULL) );
+
+/* Adds image to accumulator with weights: acc = acc*(1-alpha) + image*alpha */
+CVAPI(void) cvRunningAvg( const CvArr* image, CvArr* acc, double alpha,
+ const CvArr* mask CV_DEFAULT(NULL) );
+
+
+/****************************************************************************************\
+* Tracking *
+\****************************************************************************************/
+
+/* Implements CAMSHIFT algorithm - determines object position, size and orientation
+ from the object histogram back project (extension of meanshift) */
+CVAPI(int) cvCamShift( const CvArr* prob_image, CvRect window,
+ CvTermCriteria criteria, CvConnectedComp* comp,
+ CvBox2D* box CV_DEFAULT(NULL) );
+
+/* Implements MeanShift algorithm - determines object position
+ from the object histogram back project */
+CVAPI(int) cvMeanShift( const CvArr* prob_image, CvRect window,
+ CvTermCriteria criteria, CvConnectedComp* comp );
+
+/* Creates ConDensation filter state */
+CVAPI(CvConDensation*) cvCreateConDensation( int dynam_params,
+ int measure_params,
+ int sample_count );
+
+/* Releases ConDensation filter state */
+CVAPI(void) cvReleaseConDensation( CvConDensation** condens );
+
+/* Updates ConDensation filter by time (predict future state of the system) */
+CVAPI(void) cvConDensUpdateByTime( CvConDensation* condens);
+
+/* Initializes ConDensation filter samples */
+CVAPI(void) cvConDensInitSampleSet( CvConDensation* condens, CvMat* lower_bound, CvMat* upper_bound );
+
+/* Creates Kalman filter and sets A, B, Q, R and state to some initial values */
+CVAPI(CvKalman*) cvCreateKalman( int dynam_params, int measure_params,
+ int control_params CV_DEFAULT(0));
+
+/* Releases Kalman filter state */
+CVAPI(void) cvReleaseKalman( CvKalman** kalman);
+
+/* Updates Kalman filter by time (predicts future state of the system) */
+CVAPI(const CvMat*) cvKalmanPredict( CvKalman* kalman,
+ const CvMat* control CV_DEFAULT(NULL));
+
+/* Updates Kalman filter by measurement
+ (corrects state of the system and internal matrices) */
+CVAPI(const CvMat*) cvKalmanCorrect( CvKalman* kalman, const CvMat* measurement );
+
+/****************************************************************************************\
+* Planar subdivisions *
+\****************************************************************************************/
+
+/* Initializes Delaunay triangulation */
+CVAPI(void) cvInitSubdivDelaunay2D( CvSubdiv2D* subdiv, CvRect rect );
+
+/* Creates new subdivision */
+CVAPI(CvSubdiv2D*) cvCreateSubdiv2D( int subdiv_type, int header_size,
+ int vtx_size, int quadedge_size,
+ CvMemStorage* storage );
+
+/************************* high-level subdivision functions ***************************/
+
+/* Simplified Delaunay diagram creation */
+CV_INLINE CvSubdiv2D* cvCreateSubdivDelaunay2D( CvRect rect, CvMemStorage* storage )
+{
+ CvSubdiv2D* subdiv = cvCreateSubdiv2D( CV_SEQ_KIND_SUBDIV2D, sizeof(*subdiv),
+ sizeof(CvSubdiv2DPoint), sizeof(CvQuadEdge2D), storage );
+
+ cvInitSubdivDelaunay2D( subdiv, rect );
+ return subdiv;
+}
+
+
+/* Inserts new point to the Delaunay triangulation */
+CVAPI(CvSubdiv2DPoint*) cvSubdivDelaunay2DInsert( CvSubdiv2D* subdiv, CvPoint2D32f pt);
+
+/* Locates a point within the Delaunay triangulation (finds the edge
+ the point is left to or belongs to, or the triangulation point the given
+ point coinsides with */
+CVAPI(CvSubdiv2DPointLocation) cvSubdiv2DLocate(
+ CvSubdiv2D* subdiv, CvPoint2D32f pt,
+ CvSubdiv2DEdge* edge,
+ CvSubdiv2DPoint** vertex CV_DEFAULT(NULL) );
+
+/* Calculates Voronoi tesselation (i.e. coordinates of Voronoi points) */
+CVAPI(void) cvCalcSubdivVoronoi2D( CvSubdiv2D* subdiv );
+
+
+/* Removes all Voronoi points from the tesselation */
+CVAPI(void) cvClearSubdivVoronoi2D( CvSubdiv2D* subdiv );
+
+
+/* Finds the nearest to the given point vertex in subdivision. */
+CVAPI(CvSubdiv2DPoint*) cvFindNearestPoint2D( CvSubdiv2D* subdiv, CvPoint2D32f pt );
+
+
+/************ Basic quad-edge navigation and operations ************/
+
+CV_INLINE CvSubdiv2DEdge cvSubdiv2DNextEdge( CvSubdiv2DEdge edge )
+{
+ return CV_SUBDIV2D_NEXT_EDGE(edge);
+}
+
+
+CV_INLINE CvSubdiv2DEdge cvSubdiv2DRotateEdge( CvSubdiv2DEdge edge, int rotate )
+{
+ return (edge & ~3) + ((edge + rotate) & 3);
+}
+
+CV_INLINE CvSubdiv2DEdge cvSubdiv2DSymEdge( CvSubdiv2DEdge edge )
+{
+ return edge ^ 2;
+}
+
+CV_INLINE CvSubdiv2DEdge cvSubdiv2DGetEdge( CvSubdiv2DEdge edge, CvNextEdgeType type )
+{
+ CvQuadEdge2D* e = (CvQuadEdge2D*)(edge & ~3);
+ edge = e->next[(edge + (int)type) & 3];
+ return (edge & ~3) + ((edge + ((int)type >> 4)) & 3);
+}
+
+
+CV_INLINE CvSubdiv2DPoint* cvSubdiv2DEdgeOrg( CvSubdiv2DEdge edge )
+{
+ CvQuadEdge2D* e = (CvQuadEdge2D*)(edge & ~3);
+ return (CvSubdiv2DPoint*)e->pt[edge & 3];
+}
+
+
+CV_INLINE CvSubdiv2DPoint* cvSubdiv2DEdgeDst( CvSubdiv2DEdge edge )
+{
+ CvQuadEdge2D* e = (CvQuadEdge2D*)(edge & ~3);
+ return (CvSubdiv2DPoint*)e->pt[(edge + 2) & 3];
+}
+
+
+CV_INLINE double cvTriangleArea( CvPoint2D32f a, CvPoint2D32f b, CvPoint2D32f c )
+{
+ return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
+}
+
+
+/****************************************************************************************\
+* Contour Processing and Shape Analysis *
+\****************************************************************************************/
+
+#define CV_POLY_APPROX_DP 0
+
+/* Approximates a single polygonal curve (contour) or
+ a tree of polygonal curves (contours) */
+CVAPI(CvSeq*) cvApproxPoly( const void* src_seq,
+ int header_size, CvMemStorage* storage,
+ int method, double parameter,
+ int parameter2 CV_DEFAULT(0));
+
+#define CV_DOMINANT_IPAN 1
+
+/* Finds high-curvature points of the contour */
+CVAPI(CvSeq*) cvFindDominantPoints( CvSeq* contour, CvMemStorage* storage,
+ int method CV_DEFAULT(CV_DOMINANT_IPAN),
+ double parameter1 CV_DEFAULT(0),
+ double parameter2 CV_DEFAULT(0),
+ double parameter3 CV_DEFAULT(0),
+ double parameter4 CV_DEFAULT(0));
+
+/* Calculates perimeter of a contour or length of a part of contour */
+CVAPI(double) cvArcLength( const void* curve,
+ CvSlice slice CV_DEFAULT(CV_WHOLE_SEQ),
+ int is_closed CV_DEFAULT(-1));
+#define cvContourPerimeter( contour ) cvArcLength( contour, CV_WHOLE_SEQ, 1 )
+
+/* Calculates contour boundning rectangle (update=1) or
+ just retrieves pre-calculated rectangle (update=0) */
+CVAPI(CvRect) cvBoundingRect( CvArr* points, int update CV_DEFAULT(0) );
+
+/* Calculates area of a contour or contour segment */
+CVAPI(double) cvContourArea( const CvArr* contour,
+ CvSlice slice CV_DEFAULT(CV_WHOLE_SEQ));
+
+/* Finds minimum area rotated rectangle bounding a set of points */
+CVAPI(CvBox2D) cvMinAreaRect2( const CvArr* points,
+ CvMemStorage* storage CV_DEFAULT(NULL));
+
+/* Finds minimum enclosing circle for a set of points */
+CVAPI(int) cvMinEnclosingCircle( const CvArr* points,
+ CvPoint2D32f* center, float* radius );
+
+#define CV_CONTOURS_MATCH_I1 1
+#define CV_CONTOURS_MATCH_I2 2
+#define CV_CONTOURS_MATCH_I3 3
+
+/* Compares two contours by matching their moments */
+CVAPI(double) cvMatchShapes( const void* object1, const void* object2,
+ int method, double parameter CV_DEFAULT(0));
+
+/* Builds hierarhical representation of a contour */
+CVAPI(CvContourTree*) cvCreateContourTree( const CvSeq* contour,
+ CvMemStorage* storage,
+ double threshold );
+
+/* Reconstruct (completelly or partially) contour a from contour tree */
+CVAPI(CvSeq*) cvContourFromContourTree( const CvContourTree* tree,
+ CvMemStorage* storage,
+ CvTermCriteria criteria );
+
+/* Compares two contour trees */
+#define CV_CONTOUR_TREES_MATCH_I1 1
+
+CVAPI(double) cvMatchContourTrees( const CvContourTree* tree1,
+ const CvContourTree* tree2,
+ int method, double threshold );
+
+/* Calculates histogram of a contour */
+CVAPI(void) cvCalcPGH( const CvSeq* contour, CvHistogram* hist );
+
+#define CV_CLOCKWISE 1
+#define CV_COUNTER_CLOCKWISE 2
+
+/* Calculates exact convex hull of 2d point set */
+CVAPI(CvSeq*) cvConvexHull2( const CvArr* input,
+ void* hull_storage CV_DEFAULT(NULL),
+ int orientation CV_DEFAULT(CV_CLOCKWISE),
+ int return_points CV_DEFAULT(0));
+
+/* Checks whether the contour is convex or not (returns 1 if convex, 0 if not) */
+CVAPI(int) cvCheckContourConvexity( const CvArr* contour );
+
+/* Finds convexity defects for the contour */
+CVAPI(CvSeq*) cvConvexityDefects( const CvArr* contour, const CvArr* convexhull,
+ CvMemStorage* storage CV_DEFAULT(NULL));
+
+/* Fits ellipse into a set of 2d points */
+CVAPI(CvBox2D) cvFitEllipse2( const CvArr* points );
+
+/* Finds minimum rectangle containing two given rectangles */
+CVAPI(CvRect) cvMaxRect( const CvRect* rect1, const CvRect* rect2 );
+
+/* Finds coordinates of the box vertices */
+CVAPI(void) cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] );
+
+/* Initializes sequence header for a matrix (column or row vector) of points -
+ a wrapper for cvMakeSeqHeaderForArray (it does not initialize bounding rectangle!!!) */
+CVAPI(CvSeq*) cvPointSeqFromMat( int seq_kind, const CvArr* mat,
+ CvContour* contour_header,
+ CvSeqBlock* block );
+
+/* Checks whether the point is inside polygon, outside, on an edge (at a vertex).
+ Returns positive, negative or zero value, correspondingly.
+ Optionally, measures a signed distance between
+ the point and the nearest polygon edge (measure_dist=1) */
+CVAPI(double) cvPointPolygonTest( const CvArr* contour,
+ CvPoint2D32f pt, int measure_dist );
+
+/****************************************************************************************\
+* Histogram functions *
+\****************************************************************************************/
+
+/* Creates new histogram */
+CVAPI(CvHistogram*) cvCreateHist( int dims, int* sizes, int type,
+ float** ranges CV_DEFAULT(NULL),
+ int uniform CV_DEFAULT(1));
+
+/* Assignes histogram bin ranges */
+CVAPI(void) cvSetHistBinRanges( CvHistogram* hist, float** ranges,
+ int uniform CV_DEFAULT(1));
+
+/* Creates histogram header for array */
+CVAPI(CvHistogram*) cvMakeHistHeaderForArray(
+ int dims, int* sizes, CvHistogram* hist,
+ float* data, float** ranges CV_DEFAULT(NULL),
+ int uniform CV_DEFAULT(1));
+
+/* Releases histogram */
+CVAPI(void) cvReleaseHist( CvHistogram** hist );
+
+/* Clears all the histogram bins */
+CVAPI(void) cvClearHist( CvHistogram* hist );
+
+/* Finds indices and values of minimum and maximum histogram bins */
+CVAPI(void) cvGetMinMaxHistValue( const CvHistogram* hist,
+ float* min_value, float* max_value,
+ int* min_idx CV_DEFAULT(NULL),
+ int* max_idx CV_DEFAULT(NULL));
+
+
+/* Normalizes histogram by dividing all bins by sum of the bins, multiplied by <factor>.
+ After that sum of histogram bins is equal to <factor> */
+CVAPI(void) cvNormalizeHist( CvHistogram* hist, double factor );
+
+
+/* Clear all histogram bins that are below the threshold */
+CVAPI(void) cvThreshHist( CvHistogram* hist, double threshold );
+
+#define CV_COMP_CORREL 0
+#define CV_COMP_CHISQR 1
+#define CV_COMP_INTERSECT 2
+#define CV_COMP_BHATTACHARYYA 3
+
+/* Compares two histogram */
+CVAPI(double) cvCompareHist( const CvHistogram* hist1,
+ const CvHistogram* hist2,
+ int method);
+
+/* Copies one histogram to another. Destination histogram is created if
+ the destination pointer is NULL */
+CVAPI(void) cvCopyHist( const CvHistogram* src, CvHistogram** dst );
+
+
+/* Calculates bayesian probabilistic histograms
+ (each or src and dst is an array of <number> histograms */
+CVAPI(void) cvCalcBayesianProb( CvHistogram** src, int number,
+ CvHistogram** dst);
+
+/* Calculates array histogram */
+CVAPI(void) cvCalcArrHist( CvArr** arr, CvHistogram* hist,
+ int accumulate CV_DEFAULT(0),
+ const CvArr* mask CV_DEFAULT(NULL) );
+
+CV_INLINE void cvCalcHist( IplImage** image, CvHistogram* hist,
+ int accumulate CV_DEFAULT(0),
+ const CvArr* mask CV_DEFAULT(NULL) )
+{
+ cvCalcArrHist( (CvArr**)image, hist, accumulate, mask );
+}
+
+/* Calculates back project */
+CVAPI(void) cvCalcArrBackProject( CvArr** image, CvArr* dst,
+ const CvHistogram* hist );
+#define cvCalcBackProject(image, dst, hist) cvCalcArrBackProject((CvArr**)image, dst, hist)
+
+
+/* Does some sort of template matching but compares histograms of
+ template and each window location */
+CVAPI(void) cvCalcArrBackProjectPatch( CvArr** image, CvArr* dst, CvSize range,
+ CvHistogram* hist, int method,
+ double factor );
+#define cvCalcBackProjectPatch( image, dst, range, hist, method, factor ) \
+ cvCalcArrBackProjectPatch( (CvArr**)image, dst, range, hist, method, factor )
+
+
+/* calculates probabilistic density (divides one histogram by another) */
+CVAPI(void) cvCalcProbDensity( const CvHistogram* hist1, const CvHistogram* hist2,
+ CvHistogram* dst_hist, double scale CV_DEFAULT(255) );
+
+/* equalizes histogram of 8-bit single-channel image */
+CVAPI(void) cvEqualizeHist( const CvArr* src, CvArr* dst );
+
+
+#define CV_VALUE 1
+#define CV_ARRAY 2
+/* Updates active contour in order to minimize its cummulative
+ (internal and external) energy. */
+CVAPI(void) cvSnakeImage( const IplImage* image, CvPoint* points,
+ int length, float* alpha,
+ float* beta, float* gamma,
+ int coeff_usage, CvSize win,
+ CvTermCriteria criteria, int calc_gradient CV_DEFAULT(1));
+
+/* Calculates the cooficients of the homography matrix */
+CVAPI(void) cvCalcImageHomography( float* line, CvPoint3D32f* center,
+ float* intrinsic, float* homography );
+
+#define CV_DIST_MASK_3 3
+#define CV_DIST_MASK_5 5
+#define CV_DIST_MASK_PRECISE 0
+
+/* Applies distance transform to binary image */
+CVAPI(void) cvDistTransform( const CvArr* src, CvArr* dst,
+ int distance_type CV_DEFAULT(CV_DIST_L2),
+ int mask_size CV_DEFAULT(3),
+ const float* mask CV_DEFAULT(NULL),
+ CvArr* labels CV_DEFAULT(NULL));
+
+
+/* Types of thresholding */
+#define CV_THRESH_BINARY 0 /* value = value > threshold ? max_value : 0 */
+#define CV_THRESH_BINARY_INV 1 /* value = value > threshold ? 0 : max_value */
+#define CV_THRESH_TRUNC 2 /* value = value > threshold ? threshold : value */
+#define CV_THRESH_TOZERO 3 /* value = value > threshold ? value : 0 */
+#define CV_THRESH_TOZERO_INV 4 /* value = value > threshold ? 0 : value */
+#define CV_THRESH_MASK 7
+
+#define CV_THRESH_OTSU 8 /* use Otsu algorithm to choose the optimal threshold value;
+ combine the flag with one of the above CV_THRESH_* values */
+
+/* Applies fixed-level threshold to grayscale image.
+ This is a basic operation applied before retrieving contours */
+CVAPI(double) cvThreshold( const CvArr* src, CvArr* dst,
+ double threshold, double max_value,
+ int threshold_type );
+
+#define CV_ADAPTIVE_THRESH_MEAN_C 0
+#define CV_ADAPTIVE_THRESH_GAUSSIAN_C 1
+
+/* Applies adaptive threshold to grayscale image.
+ The two parameters for methods CV_ADAPTIVE_THRESH_MEAN_C and
+ CV_ADAPTIVE_THRESH_GAUSSIAN_C are:
+ neighborhood size (3, 5, 7 etc.),
+ and a constant subtracted from mean (...,-3,-2,-1,0,1,2,3,...) */
+CVAPI(void) cvAdaptiveThreshold( const CvArr* src, CvArr* dst, double max_value,
+ int adaptive_method CV_DEFAULT(CV_ADAPTIVE_THRESH_MEAN_C),
+ int threshold_type CV_DEFAULT(CV_THRESH_BINARY),
+ int block_size CV_DEFAULT(3),
+ double param1 CV_DEFAULT(5));
+
+#define CV_FLOODFILL_FIXED_RANGE (1 << 16)
+#define CV_FLOODFILL_MASK_ONLY (1 << 17)
+
+/* Fills the connected component until the color difference gets large enough */
+CVAPI(void) cvFloodFill( CvArr* image, CvPoint seed_point,
+ CvScalar new_val, CvScalar lo_diff CV_DEFAULT(cvScalarAll(0)),
+ CvScalar up_diff CV_DEFAULT(cvScalarAll(0)),
+ CvConnectedComp* comp CV_DEFAULT(NULL),
+ int flags CV_DEFAULT(4),
+ CvArr* mask CV_DEFAULT(NULL));
+
+/****************************************************************************************\
+* Feature detection *
+\****************************************************************************************/
+
+#define CV_CANNY_L2_GRADIENT (1 << 31)
+
+/* Runs canny edge detector */
+CVAPI(void) cvCanny( const CvArr* image, CvArr* edges, double threshold1,
+ double threshold2, int aperture_size CV_DEFAULT(3) );
+
+/* Calculates constraint image for corner detection
+ Dx^2 * Dyy + Dxx * Dy^2 - 2 * Dx * Dy * Dxy.
+ Applying threshold to the result gives coordinates of corners */
+CVAPI(void) cvPreCornerDetect( const CvArr* image, CvArr* corners,
+ int aperture_size CV_DEFAULT(3) );
+
+/* Calculates eigen values and vectors of 2x2
+ gradient covariation matrix at every image pixel */
+CVAPI(void) cvCornerEigenValsAndVecs( const CvArr* image, CvArr* eigenvv,
+ int block_size, int aperture_size CV_DEFAULT(3) );
+
+/* Calculates minimal eigenvalue for 2x2 gradient covariation matrix at
+ every image pixel */
+CVAPI(void) cvCornerMinEigenVal( const CvArr* image, CvArr* eigenval,
+ int block_size, int aperture_size CV_DEFAULT(3) );
+
+/* Harris corner detector:
+ Calculates det(M) - k*(trace(M)^2), where M is 2x2 gradient covariation matrix for each pixel */
+CVAPI(void) cvCornerHarris( const CvArr* image, CvArr* harris_responce,
+ int block_size, int aperture_size CV_DEFAULT(3),
+ double k CV_DEFAULT(0.04) );
+
+/* Adjust corner position using some sort of gradient search */
+CVAPI(void) cvFindCornerSubPix( const CvArr* image, CvPoint2D32f* corners,
+ int count, CvSize win, CvSize zero_zone,
+ CvTermCriteria criteria );
+
+/* Finds a sparse set of points within the selected region
+ that seem to be easy to track */
+CVAPI(void) cvGoodFeaturesToTrack( const CvArr* image, CvArr* eig_image,
+ CvArr* temp_image, CvPoint2D32f* corners,
+ int* corner_count, double quality_level,
+ double min_distance,
+ const CvArr* mask CV_DEFAULT(NULL),
+ int block_size CV_DEFAULT(3),
+ int use_harris CV_DEFAULT(0),
+ double k CV_DEFAULT(0.04) );
+
+#define CV_HOUGH_STANDARD 0
+#define CV_HOUGH_PROBABILISTIC 1
+#define CV_HOUGH_MULTI_SCALE 2
+#define CV_HOUGH_GRADIENT 3
+
+/* Finds lines on binary image using one of several methods.
+ line_storage is either memory storage or 1 x <max number of lines> CvMat, its
+ number of columns is changed by the function.
+ method is one of CV_HOUGH_*;
+ rho, theta and threshold are used for each of those methods;
+ param1 ~ line length, param2 ~ line gap - for probabilistic,
+ param1 ~ srn, param2 ~ stn - for multi-scale */
+CVAPI(CvSeq*) cvHoughLines2( CvArr* image, void* line_storage, int method,
+ double rho, double theta, int threshold,
+ double param1 CV_DEFAULT(0), double param2 CV_DEFAULT(0));
+
+/* Finds circles in the image */
+CVAPI(CvSeq*) cvHoughCircles( CvArr* image, void* circle_storage,
+ int method, double dp, double min_dist,
+ double param1 CV_DEFAULT(100),
+ double param2 CV_DEFAULT(100),
+ int min_radius CV_DEFAULT(0),
+ int max_radius CV_DEFAULT(0));
+
+/* Fits a line into set of 2d or 3d points in a robust way (M-estimator technique) */
+CVAPI(void) cvFitLine( const CvArr* points, int dist_type, double param,
+ double reps, double aeps, float* line );
+
+
+
+struct CvFeatureTree;
+
+/* Constructs kd-tree from set of feature descriptors */
+CVAPI(struct CvFeatureTree*) cvCreateFeatureTree(CvMat* desc);
+
+/* Release kd-tree */
+CVAPI(void) cvReleaseFeatureTree(struct CvFeatureTree* tr);
+
+/* Searches kd-tree for k nearest neighbors of given reference points,
+ searching at most emax leaves. */
+CVAPI(void) cvFindFeatures(struct CvFeatureTree* tr, CvMat* desc,
+ CvMat* results, CvMat* dist, int k CV_DEFAULT(2), int emax CV_DEFAULT(20));
+
+/* Search kd-tree for all points that are inlier to given rect region. */
+CVAPI(int) cvFindFeaturesBoxed(struct CvFeatureTree* tr,
+ CvMat* bounds_min, CvMat* bounds_max,
+ CvMat* results);
+
+typedef struct CvSURFPoint
+{
+ CvPoint2D32f pt;
+ int laplacian;
+ int size;
+ float dir;
+ float hessian;
+} CvSURFPoint;
+
+CV_INLINE CvSURFPoint cvSURFPoint( CvPoint2D32f pt, int laplacian,
+ int size, float dir CV_DEFAULT(0),
+ float hessian CV_DEFAULT(0))
+{
+ CvSURFPoint kp;
+ kp.pt = pt;
+ kp.laplacian = laplacian;
+ kp.size = size;
+ kp.dir = dir;
+ kp.hessian = hessian;
+ return kp;
+}
+
+typedef struct CvSURFParams
+{
+ int extended;
+ double hessianThreshold;
+
+ int nOctaves;
+ int nOctaveLayers;
+}
+CvSURFParams;
+
+CVAPI(CvSURFParams) cvSURFParams( double hessianThreshold, int extended CV_DEFAULT(0) );
+CVAPI(void) cvExtractSURF( const CvArr* img, const CvArr* mask,
+ CvSeq** keypoints, CvSeq** descriptors,
+ CvMemStorage* storage, CvSURFParams params );
+
+/****************************************************************************************\
+* Haar-like Object Detection functions *
+\****************************************************************************************/
+
+/* Loads haar classifier cascade from a directory.
+ It is obsolete: convert your cascade to xml and use cvLoad instead */
+CVAPI(CvHaarClassifierCascade*) cvLoadHaarClassifierCascade(
+ const char* directory, CvSize orig_window_size);
+
+CVAPI(void) cvReleaseHaarClassifierCascade( CvHaarClassifierCascade** cascade );
+
+#define CV_HAAR_DO_CANNY_PRUNING 1
+#define CV_HAAR_SCALE_IMAGE 2
+#define CV_HAAR_FIND_BIGGEST_OBJECT 4
+#define CV_HAAR_DO_ROUGH_SEARCH 8
+
+CVAPI(CvSeq*) cvHaarDetectObjects( const CvArr* image,
+ CvHaarClassifierCascade* cascade,
+ CvMemStorage* storage, double scale_factor CV_DEFAULT(1.1),
+ int min_neighbors CV_DEFAULT(3), int flags CV_DEFAULT(0),
+ CvSize min_size CV_DEFAULT(cvSize(0,0)));
+
+/* sets images for haar classifier cascade */
+CVAPI(void) cvSetImagesForHaarClassifierCascade( CvHaarClassifierCascade* cascade,
+ const CvArr* sum, const CvArr* sqsum,
+ const CvArr* tilted_sum, double scale );
+
+/* runs the cascade on the specified window */
+CVAPI(int) cvRunHaarClassifierCascade( CvHaarClassifierCascade* cascade,
+ CvPoint pt, int start_stage CV_DEFAULT(0));
+
+
+/* Alternate version that uses ints instead of floats */
+CVAPI(CvSeq*) mycvHaarDetectObjects( const CvArr* image,
+ CvHaarClassifierCascade* cascade,
+ CvMemStorage* storage, double scale_factor CV_DEFAULT(1.1),
+ int min_neighbors CV_DEFAULT(3), int flags CV_DEFAULT(0),
+ CvSize min_size CV_DEFAULT(cvSize(0,0)));
+
+CVAPI(void) mycvSetImagesForHaarClassifierCascade( CvHaarClassifierCascade* cascade,
+ const CvArr* sum, const CvArr* sqsum,
+ const CvArr* tilted_sum, double scale );
+
+CVAPI(int) mycvRunHaarClassifierCascade( CvHaarClassifierCascade* cascade,
+ CvPoint pt, int start_stage CV_DEFAULT(0));
+
+/****************************************************************************************\
+* Camera Calibration, Pose Estimation and Stereo *
+\****************************************************************************************/
+
+/* Transforms the input image to compensate lens distortion */
+CVAPI(void) cvUndistort2( const CvArr* src, CvArr* dst,
+ const CvMat* camera_matrix,
+ const CvMat* distortion_coeffs );
+
+/* Computes transformation map from intrinsic camera parameters
+ that can used by cvRemap */
+CVAPI(void) cvInitUndistortMap( const CvMat* camera_matrix,
+ const CvMat* distortion_coeffs,
+ CvArr* mapx, CvArr* mapy );
+
+/* Computes undistortion+rectification map for a head of stereo camera */
+CVAPI(void) cvInitUndistortRectifyMap( const CvMat* camera_matrix,
+ const CvMat* dist_coeffs,
+ const CvMat *R, const CvMat* new_camera_matrix,
+ CvArr* mapx, CvArr* mapy );
+
+/* Computes the original (undistorted) feature coordinates
+ from the observed (distorted) coordinates */
+CVAPI(void) cvUndistortPoints( const CvMat* src, CvMat* dst,
+ const CvMat* camera_matrix,
+ const CvMat* dist_coeffs,
+ const CvMat* R CV_DEFAULT(0),
+ const CvMat* P CV_DEFAULT(0));
+
+/* Converts rotation vector to rotation matrix or vice versa */
+CVAPI(int) cvRodrigues2( const CvMat* src, CvMat* dst,
+ CvMat* jacobian CV_DEFAULT(0) );
+
+#define CV_LMEDS 4
+#define CV_RANSAC 8
+
+/* Finds perspective transformation between the object plane and image (view) plane */
+CVAPI(int) cvFindHomography( const CvMat* src_points,
+ const CvMat* dst_points,
+ CvMat* homography,
+ int method CV_DEFAULT(0),
+ double ransacReprojThreshold CV_DEFAULT(0),
+ CvMat* mask CV_DEFAULT(0));
+
+/* Computes RQ decomposition for 3x3 matrices */
+CVAPI(void) cvRQDecomp3x3( const CvMat *matrixM, CvMat *matrixR, CvMat *matrixQ,
+ CvMat *matrixQx CV_DEFAULT(NULL),
+ CvMat *matrixQy CV_DEFAULT(NULL),
+ CvMat *matrixQz CV_DEFAULT(NULL),
+ CvPoint3D64f *eulerAngles CV_DEFAULT(NULL));
+
+/* Computes projection matrix decomposition */
+CVAPI(void) cvDecomposeProjectionMatrix( const CvMat *projMatr, CvMat *calibMatr,
+ CvMat *rotMatr, CvMat *posVect,
+ CvMat *rotMatrX CV_DEFAULT(NULL),
+ CvMat *rotMatrY CV_DEFAULT(NULL),
+ CvMat *rotMatrZ CV_DEFAULT(NULL),
+ CvPoint3D64f *eulerAngles CV_DEFAULT(NULL));
+
+/* Computes d(AB)/dA and d(AB)/dB */
+CVAPI(void) cvCalcMatMulDeriv( const CvMat* A, const CvMat* B, CvMat* dABdA, CvMat* dABdB );
+
+/* Computes r3 = rodrigues(rodrigues(r2)*rodrigues(r1)),
+ t3 = rodrigues(r2)*t1 + t2 and the respective derivatives */
+CVAPI(void) cvComposeRT( const CvMat* _rvec1, const CvMat* _tvec1,
+ const CvMat* _rvec2, const CvMat* _tvec2,
+ CvMat* _rvec3, CvMat* _tvec3,
+ CvMat* dr3dr1 CV_DEFAULT(0), CvMat* dr3dt1 CV_DEFAULT(0),
+ CvMat* dr3dr2 CV_DEFAULT(0), CvMat* dr3dt2 CV_DEFAULT(0),
+ CvMat* dt3dr1 CV_DEFAULT(0), CvMat* dt3dt1 CV_DEFAULT(0),
+ CvMat* dt3dr2 CV_DEFAULT(0), CvMat* dt3dt2 CV_DEFAULT(0) );
+
+/* Projects object points to the view plane using
+ the specified extrinsic and intrinsic camera parameters */
+CVAPI(void) cvProjectPoints2( const CvMat* object_points, const CvMat* rotation_vector,
+ const CvMat* translation_vector, const CvMat* camera_matrix,
+ const CvMat* distortion_coeffs, CvMat* image_points,
+ CvMat* dpdrot CV_DEFAULT(NULL), CvMat* dpdt CV_DEFAULT(NULL),
+ CvMat* dpdf CV_DEFAULT(NULL), CvMat* dpdc CV_DEFAULT(NULL),
+ CvMat* dpddist CV_DEFAULT(NULL),
+ double aspect_ratio CV_DEFAULT(0));
+
+/* Finds extrinsic camera parameters from
+ a few known corresponding point pairs and intrinsic parameters */
+CVAPI(void) cvFindExtrinsicCameraParams2( const CvMat* object_points,
+ const CvMat* image_points,
+ const CvMat* camera_matrix,
+ const CvMat* distortion_coeffs,
+ CvMat* rotation_vector,
+ CvMat* translation_vector );
+
+/* Computes initial estimate of the intrinsic camera parameters
+ in case of planar calibration target (e.g. chessboard) */
+CVAPI(void) cvInitIntrinsicParams2D( const CvMat* object_points,
+ const CvMat* image_points,
+ const CvMat* npoints, CvSize image_size,
+ CvMat* camera_matrix,
+ double aspect_ratio CV_DEFAULT(1.) );
+
+#define CV_CALIB_CB_ADAPTIVE_THRESH 1
+#define CV_CALIB_CB_NORMALIZE_IMAGE 2
+#define CV_CALIB_CB_FILTER_QUADS 4
+
+/* Detects corners on a chessboard calibration pattern */
+CVAPI(int) cvFindChessboardCorners( const void* image, CvSize pattern_size,
+ CvPoint2D32f* corners,
+ int* corner_count CV_DEFAULT(NULL),
+ int flags CV_DEFAULT(CV_CALIB_CB_ADAPTIVE_THRESH+
+ CV_CALIB_CB_NORMALIZE_IMAGE) );
+
+/* Draws individual chessboard corners or the whole chessboard detected */
+CVAPI(void) cvDrawChessboardCorners( CvArr* image, CvSize pattern_size,
+ CvPoint2D32f* corners,
+ int count, int pattern_was_found );
+
+#define CV_CALIB_USE_INTRINSIC_GUESS 1
+#define CV_CALIB_FIX_ASPECT_RATIO 2
+#define CV_CALIB_FIX_PRINCIPAL_POINT 4
+#define CV_CALIB_ZERO_TANGENT_DIST 8
+#define CV_CALIB_FIX_FOCAL_LENGTH 16
+#define CV_CALIB_FIX_K1 32
+#define CV_CALIB_FIX_K2 64
+#define CV_CALIB_FIX_K3 128
+
+/* Finds intrinsic and extrinsic camera parameters
+ from a few views of known calibration pattern */
+CVAPI(void) cvCalibrateCamera2( const CvMat* object_points,
+ const CvMat* image_points,
+ const CvMat* point_counts,
+ CvSize image_size,
+ CvMat* camera_matrix,
+ CvMat* distortion_coeffs,
+ CvMat* rotation_vectors CV_DEFAULT(NULL),
+ CvMat* translation_vectors CV_DEFAULT(NULL),
+ int flags CV_DEFAULT(0) );
+
+/* Computes various useful characteristics of the camera from the data computed by
+ cvCalibrateCamera2 */
+CVAPI(void) cvCalibrationMatrixValues( const CvMat *camera_matrix,
+ CvSize image_size,
+ double aperture_width CV_DEFAULT(0),
+ double aperture_height CV_DEFAULT(0),
+ double *fovx CV_DEFAULT(NULL),
+ double *fovy CV_DEFAULT(NULL),
+ double *focal_length CV_DEFAULT(NULL),
+ CvPoint2D64f *principal_point CV_DEFAULT(NULL),
+ double *pixel_aspect_ratio CV_DEFAULT(NULL));
+
+#define CV_CALIB_FIX_INTRINSIC 256
+#define CV_CALIB_SAME_FOCAL_LENGTH 512
+
+/* Computes the transformation from one camera coordinate system to another one
+ from a few correspondent views of the same calibration target. Optionally, calibrates
+ both cameras */
+CVAPI(void) cvStereoCalibrate( const CvMat* object_points, const CvMat* image_points1,
+ const CvMat* image_points2, const CvMat* npoints,
+ CvMat* camera_matrix1, CvMat* dist_coeffs1,
+ CvMat* camera_matrix2, CvMat* dist_coeffs2,
+ CvSize image_size, CvMat* R, CvMat* T,
+ CvMat* E CV_DEFAULT(0), CvMat* F CV_DEFAULT(0),
+ CvTermCriteria term_crit CV_DEFAULT(cvTermCriteria(
+ CV_TERMCRIT_ITER+CV_TERMCRIT_EPS,30,1e-6)),
+ int flags CV_DEFAULT(CV_CALIB_FIX_INTRINSIC) );
+
+#define CV_CALIB_ZERO_DISPARITY 1024
+
+/* Computes 3D rotations (+ optional shift) for each camera coordinate system to make both
+ views parallel (=> to make all the epipolar lines horizontal or vertical) */
+CVAPI(void) cvStereoRectify( const CvMat* camera_matrix1, const CvMat* camera_matrix2,
+ const CvMat* dist_coeffs1, const CvMat* dist_coeffs2,
+ CvSize image_size, const CvMat* R, const CvMat* T,
+ CvMat* R1, CvMat* R2, CvMat* P1, CvMat* P2,
+ CvMat* Q CV_DEFAULT(0),
+ int flags CV_DEFAULT(CV_CALIB_ZERO_DISPARITY) );
+
+/* Computes rectification transformations for uncalibrated pair of images using a set
+ of point correspondences */
+CVAPI(int) cvStereoRectifyUncalibrated( const CvMat* points1, const CvMat* points2,
+ const CvMat* F, CvSize img_size,
+ CvMat* H1, CvMat* H2,
+ double threshold CV_DEFAULT(5));
+
+typedef struct CvPOSITObject CvPOSITObject;
+
+/* Allocates and initializes CvPOSITObject structure before doing cvPOSIT */
+CVAPI(CvPOSITObject*) cvCreatePOSITObject( CvPoint3D32f* points, int point_count );
+
+
+/* Runs POSIT (POSe from ITeration) algorithm for determining 3d position of
+ an object given its model and projection in a weak-perspective case */
+CVAPI(void) cvPOSIT( CvPOSITObject* posit_object, CvPoint2D32f* image_points,
+ double focal_length, CvTermCriteria criteria,
+ CvMatr32f rotation_matrix, CvVect32f translation_vector);
+
+/* Releases CvPOSITObject structure */
+CVAPI(void) cvReleasePOSITObject( CvPOSITObject** posit_object );
+
+/* updates the number of RANSAC iterations */
+CVAPI(int) cvRANSACUpdateNumIters( double p, double err_prob,
+ int model_points, int max_iters );
+
+CVAPI(void) cvConvertPointsHomogeneous( const CvMat* src, CvMat* dst );
+
+/* Calculates fundamental matrix given a set of corresponding points */
+#define CV_FM_7POINT 1
+#define CV_FM_8POINT 2
+#define CV_FM_LMEDS_ONLY CV_LMEDS
+#define CV_FM_RANSAC_ONLY CV_RANSAC
+#define CV_FM_LMEDS CV_LMEDS
+#define CV_FM_RANSAC CV_RANSAC
+CVAPI(int) cvFindFundamentalMat( const CvMat* points1, const CvMat* points2,
+ CvMat* fundamental_matrix,
+ int method CV_DEFAULT(CV_FM_RANSAC),
+ double param1 CV_DEFAULT(3.), double param2 CV_DEFAULT(0.99),
+ CvMat* status CV_DEFAULT(NULL) );
+
+/* For each input point on one of images
+ computes parameters of the corresponding
+ epipolar line on the other image */
+CVAPI(void) cvComputeCorrespondEpilines( const CvMat* points,
+ int which_image,
+ const CvMat* fundamental_matrix,
+ CvMat* correspondent_lines );
+
+/* stereo correspondence parameters and functions */
+
+#define CV_STEREO_BM_NORMALIZED_RESPONSE 0
+
+/* Block matching algorithm structure */
+typedef struct CvStereoBMState
+{
+ // pre-filtering (normalization of input images)
+ int preFilterType; // =CV_STEREO_BM_NORMALIZED_RESPONSE now
+ int preFilterSize; // averaging window size: ~5x5..21x21
+ int preFilterCap; // the output of pre-filtering is clipped by [-preFilterCap,preFilterCap]
+
+ // correspondence using Sum of Absolute Difference (SAD)
+ int SADWindowSize; // ~5x5..21x21
+ int minDisparity; // minimum disparity (can be negative)
+ int numberOfDisparities; // maximum disparity - minimum disparity (> 0)
+
+ // post-filtering
+ int textureThreshold; // the disparity is only computed for pixels
+ // with textured enough neighborhood
+ int uniquenessRatio; // accept the computed disparity d* only if
+ // SAD(d) >= SAD(d*)*(1 + uniquenessRatio/100.)
+ // for any d != d*+/-1 within the search range.
+ int speckleWindowSize; // disparity variation window
+ int speckleRange; // acceptable range of variation in window
+
+ // temporary buffers
+ CvMat* preFilteredImg0;
+ CvMat* preFilteredImg1;
+ CvMat* slidingSumBuf;
+}
+CvStereoBMState;
+
+#define CV_STEREO_BM_BASIC 0
+#define CV_STEREO_BM_FISH_EYE 1
+#define CV_STEREO_BM_NARROW 2
+
+CVAPI(CvStereoBMState*) cvCreateStereoBMState(int preset CV_DEFAULT(CV_STEREO_BM_BASIC),
+ int numberOfDisparities CV_DEFAULT(0));
+
+CVAPI(void) cvReleaseStereoBMState( CvStereoBMState** state );
+
+CVAPI(void) cvFindStereoCorrespondenceBM( const CvArr* left, const CvArr* right,
+ CvArr* disparity, CvStereoBMState* state );
+
+/* Kolmogorov-Zabin stereo-correspondence algorithm (a.k.a. KZ1) */
+#define CV_STEREO_GC_OCCLUDED SHRT_MAX
+
+typedef struct CvStereoGCState
+{
+ int Ithreshold;
+ int interactionRadius;
+ float K, lambda, lambda1, lambda2;
+ int occlusionCost;
+ int minDisparity;
+ int numberOfDisparities;
+ int maxIters;
+
+ CvMat* left;
+ CvMat* right;
+ CvMat* dispLeft;
+ CvMat* dispRight;
+ CvMat* ptrLeft;
+ CvMat* ptrRight;
+ CvMat* vtxBuf;
+ CvMat* edgeBuf;
+}
+CvStereoGCState;
+
+CVAPI(CvStereoGCState*) cvCreateStereoGCState( int numberOfDisparities, int maxIters );
+CVAPI(void) cvReleaseStereoGCState( CvStereoGCState** state );
+
+CVAPI(void) cvFindStereoCorrespondenceGC( const CvArr* left, const CvArr* right,
+ CvArr* disparityLeft, CvArr* disparityRight,
+ CvStereoGCState* state,
+ int useDisparityGuess CV_DEFAULT(0) );
+
+/* Reprojects the computed disparity image to the 3D space using the specified 4x4 matrix */
+CVAPI(void) cvReprojectImageTo3D( const CvArr* disparityImage,
+ CvArr* _3dImage, const CvMat* Q );
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+#include "cv.hpp"
+#endif
+
+/****************************************************************************************\
+* Backward compatibility *
+\****************************************************************************************/
+
+#ifndef CV_NO_BACKWARD_COMPATIBILITY
+#include "cvcompat.h"
+#endif
+
+#endif /*_CV_H_*/
diff --git a/cv/include/cv.hpp b/cv/include/cv.hpp
new file mode 100644
index 0000000..882c946
--- /dev/null
+++ b/cv/include/cv.hpp
@@ -0,0 +1,409 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _CV_HPP_
+#define _CV_HPP_
+
+#ifdef __cplusplus
+
+/****************************************************************************************\
+* CvBaseImageFilter: Base class for filtering operations *
+\****************************************************************************************/
+
+#define CV_WHOLE 0
+#define CV_START 1
+#define CV_END 2
+#define CV_MIDDLE 4
+#define CV_ISOLATED_ROI 8
+
+typedef void (*CvRowFilterFunc)( const uchar* src, uchar* dst, void* params );
+typedef void (*CvColumnFilterFunc)( uchar** src, uchar* dst, int dst_step, int count, void* params );
+
+class CV_EXPORTS CvBaseImageFilter
+{
+public:
+ CvBaseImageFilter();
+ /* calls init() */
+ CvBaseImageFilter( int _max_width, int _src_type, int _dst_type,
+ bool _is_separable, CvSize _ksize,
+ CvPoint _anchor=cvPoint(-1,-1),
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+ virtual ~CvBaseImageFilter();
+
+ /* initializes the class for processing an image of maximal width _max_width,
+ input image has data type _src_type, the output will have _dst_type.
+ _is_separable != 0 if the filter is separable
+ (specific behaviour is defined in a derived class), 0 otherwise.
+ _ksize and _anchor specify the kernel size and the anchor point. _anchor=(-1,-1) means
+ that the anchor is at the center.
+ to get interpolate pixel values outside the image _border_mode=IPL_BORDER_*** is used,
+ _border_value specify the pixel value in case of IPL_BORDER_CONSTANT border mode.
+ before initialization clear() is called if necessary.
+ */
+ virtual void init( int _max_width, int _src_type, int _dst_type,
+ bool _is_separable, CvSize _ksize,
+ CvPoint _anchor=cvPoint(-1,-1),
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+ /* releases all the internal buffers.
+ for the further use of the object, init() needs to be called. */
+ virtual void clear();
+ /* processes input image or a part of it.
+ input is represented either as matrix (CvMat* src)
+ or a list of row pointers (uchar** src2).
+ in the later case width, _src_y1 and _src_y2 are used to specify the size.
+ _dst is the output image/matrix.
+ _src_roi specifies the roi inside the input image to process,
+ (0,0,-1,-1) denotes the whole image.
+ _dst_origin is the upper-left corner of the filtered roi within the output image.
+ _phase is either CV_START, or CV_END, or CV_MIDDLE, or CV_START|CV_END, or CV_WHOLE,
+ which is the same as CV_START|CV_END.
+ CV_START means that the input is the first (top) stripe of the processed image [roi],
+ CV_END - the input is the last (bottom) stripe of the processed image [roi],
+ CV_MIDDLE - the input is neither first nor last stripe.
+ CV_WHOLE - the input is the whole processed image [roi].
+ */
+ virtual int process( const CvMat* _src, CvMat* _dst,
+ CvRect _src_roi=cvRect(0,0,-1,-1),
+ CvPoint _dst_origin=cvPoint(0,0), int _flags=0 );
+ /* retrieve various parameters of the filtering object */
+ int get_src_type() const { return src_type; }
+ int get_dst_type() const { return dst_type; }
+ int get_work_type() const { return work_type; }
+ CvSize get_kernel_size() const { return ksize; }
+ CvPoint get_anchor() const { return anchor; }
+ int get_width() const { return prev_x_range.end_index - prev_x_range.start_index; }
+ CvRowFilterFunc get_x_filter_func() const { return x_func; }
+ CvColumnFilterFunc get_y_filter_func() const { return y_func; }
+
+protected:
+ /* initializes work_type, buf_size and max_rows */
+ virtual void get_work_params();
+ /* it is called (not always) from process when _phase=CV_START or CV_WHOLE.
+ the method initializes ring buffer (buf_end, buf_head, buf_tail, buf_count, rows),
+ prev_width, prev_x_range, const_row, border_tab, border_tab_sz* */
+ virtual void start_process( CvSlice x_range, int width );
+ /* forms pointers to "virtual rows" above or below the processed roi using the specified
+ border mode */
+ virtual void make_y_border( int row_count, int top_rows, int bottom_rows );
+
+ virtual int fill_cyclic_buffer( const uchar* src, int src_step,
+ int y, int y1, int y2 );
+
+ enum { ALIGN=32 };
+
+ int max_width;
+ /* currently, work_type must be the same as src_type in case of non-separable filters */
+ int min_depth, src_type, dst_type, work_type;
+
+ /* pointers to convolution functions, initialized by init method.
+ for non-separable filters only y_conv should be set */
+ CvRowFilterFunc x_func;
+ CvColumnFilterFunc y_func;
+
+ uchar* buffer;
+ uchar** rows;
+ int top_rows, bottom_rows, max_rows;
+ uchar *buf_start, *buf_end, *buf_head, *buf_tail;
+ int buf_size, buf_step, buf_count, buf_max_count;
+
+ bool is_separable;
+ CvSize ksize;
+ CvPoint anchor;
+ int max_ky, border_mode;
+ CvScalar border_value;
+ uchar* const_row;
+ int* border_tab;
+ int border_tab_sz1, border_tab_sz;
+
+ CvSlice prev_x_range;
+ int prev_width;
+};
+
+
+/* Derived class, for linear separable filtering. */
+class CV_EXPORTS CvSepFilter : public CvBaseImageFilter
+{
+public:
+ CvSepFilter();
+ CvSepFilter( int _max_width, int _src_type, int _dst_type,
+ const CvMat* _kx, const CvMat* _ky,
+ CvPoint _anchor=cvPoint(-1,-1),
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+ virtual ~CvSepFilter();
+
+ virtual void init( int _max_width, int _src_type, int _dst_type,
+ const CvMat* _kx, const CvMat* _ky,
+ CvPoint _anchor=cvPoint(-1,-1),
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+ virtual void init_deriv( int _max_width, int _src_type, int _dst_type,
+ int dx, int dy, int aperture_size, int flags=0 );
+ virtual void init_gaussian( int _max_width, int _src_type, int _dst_type,
+ int gaussian_size, double sigma );
+
+ /* dummy method to avoid compiler warnings */
+ virtual void init( int _max_width, int _src_type, int _dst_type,
+ bool _is_separable, CvSize _ksize,
+ CvPoint _anchor=cvPoint(-1,-1),
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+
+ virtual void clear();
+ const CvMat* get_x_kernel() const { return kx; }
+ const CvMat* get_y_kernel() const { return ky; }
+ int get_x_kernel_flags() const { return kx_flags; }
+ int get_y_kernel_flags() const { return ky_flags; }
+
+ enum { GENERIC=0, ASYMMETRICAL=1, SYMMETRICAL=2, POSITIVE=4, SUM_TO_1=8, INTEGER=16 };
+ enum { NORMALIZE_KERNEL=1, FLIP_KERNEL=2 };
+
+ static void init_gaussian_kernel( CvMat* kernel, double sigma=-1 );
+ static void init_sobel_kernel( CvMat* _kx, CvMat* _ky, int dx, int dy, int flags=0 );
+ static void init_scharr_kernel( CvMat* _kx, CvMat* _ky, int dx, int dy, int flags=0 );
+
+protected:
+ CvMat *kx, *ky;
+ int kx_flags, ky_flags;
+};
+
+
+/* Derived class, for linear non-separable filtering. */
+class CV_EXPORTS CvLinearFilter : public CvBaseImageFilter
+{
+public:
+ CvLinearFilter();
+ CvLinearFilter( int _max_width, int _src_type, int _dst_type,
+ const CvMat* _kernel,
+ CvPoint _anchor=cvPoint(-1,-1),
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+ virtual ~CvLinearFilter();
+
+ virtual void init( int _max_width, int _src_type, int _dst_type,
+ const CvMat* _kernel,
+ CvPoint _anchor=cvPoint(-1,-1),
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+
+ /* dummy method to avoid compiler warnings */
+ virtual void init( int _max_width, int _src_type, int _dst_type,
+ bool _is_separable, CvSize _ksize,
+ CvPoint _anchor=cvPoint(-1,-1),
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+
+ virtual void clear();
+ const CvMat* get_kernel() const { return kernel; }
+ uchar* get_kernel_sparse_buf() { return k_sparse; }
+ int get_kernel_sparse_count() const { return k_sparse_count; }
+
+protected:
+ CvMat *kernel;
+ uchar* k_sparse;
+ int k_sparse_count;
+};
+
+
+/* Box filter ("all 1's", optionally normalized) filter. */
+class CV_EXPORTS CvBoxFilter : public CvBaseImageFilter
+{
+public:
+ CvBoxFilter();
+ CvBoxFilter( int _max_width, int _src_type, int _dst_type,
+ bool _normalized, CvSize _ksize,
+ CvPoint _anchor=cvPoint(-1,-1),
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+ virtual void init( int _max_width, int _src_type, int _dst_type,
+ bool _normalized, CvSize _ksize,
+ CvPoint _anchor=cvPoint(-1,-1),
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+
+ virtual ~CvBoxFilter();
+ bool is_normalized() const { return normalized; }
+ double get_scale() const { return scale; }
+ uchar* get_sum_buf() { return sum; }
+ int* get_sum_count_ptr() { return &sum_count; }
+
+protected:
+ virtual void start_process( CvSlice x_range, int width );
+
+ uchar* sum;
+ int sum_count;
+ bool normalized;
+ double scale;
+};
+
+
+/* Laplacian operator: (d2/dx + d2/dy)I. */
+class CV_EXPORTS CvLaplaceFilter : public CvSepFilter
+{
+public:
+ CvLaplaceFilter();
+ CvLaplaceFilter( int _max_width, int _src_type, int _dst_type,
+ bool _normalized, int _ksize,
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+ virtual ~CvLaplaceFilter();
+ virtual void init( int _max_width, int _src_type, int _dst_type,
+ bool _normalized, int _ksize,
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+
+ /* dummy methods to avoid compiler warnings */
+ virtual void init( int _max_width, int _src_type, int _dst_type,
+ bool _is_separable, CvSize _ksize,
+ CvPoint _anchor=cvPoint(-1,-1),
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+
+ virtual void init( int _max_width, int _src_type, int _dst_type,
+ const CvMat* _kx, const CvMat* _ky,
+ CvPoint _anchor=cvPoint(-1,-1),
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+
+ bool is_normalized() const { return normalized; }
+ bool is_basic_laplacian() const { return basic_laplacian; }
+protected:
+ void get_work_params();
+
+ bool basic_laplacian;
+ bool normalized;
+};
+
+
+/* basic morphological operations: erosion & dilation */
+class CV_EXPORTS CvMorphology : public CvBaseImageFilter
+{
+public:
+ CvMorphology();
+ CvMorphology( int _operation, int _max_width, int _src_dst_type,
+ int _element_shape, CvMat* _element,
+ CvSize _ksize=cvSize(0,0), CvPoint _anchor=cvPoint(-1,-1),
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+ virtual ~CvMorphology();
+ virtual void init( int _operation, int _max_width, int _src_dst_type,
+ int _element_shape, CvMat* _element,
+ CvSize _ksize=cvSize(0,0), CvPoint _anchor=cvPoint(-1,-1),
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+
+ /* dummy method to avoid compiler warnings */
+ virtual void init( int _max_width, int _src_type, int _dst_type,
+ bool _is_separable, CvSize _ksize,
+ CvPoint _anchor=cvPoint(-1,-1),
+ int _border_mode=IPL_BORDER_REPLICATE,
+ CvScalar _border_value=cvScalarAll(0) );
+
+ virtual void clear();
+ const CvMat* get_element() const { return element; }
+ int get_element_shape() const { return el_shape; }
+ int get_operation() const { return operation; }
+ uchar* get_element_sparse_buf() { return el_sparse; }
+ int get_element_sparse_count() const { return el_sparse_count; }
+
+ enum { RECT=0, CROSS=1, ELLIPSE=2, CUSTOM=100, BINARY = 0, GRAYSCALE=256 };
+ enum { ERODE=0, DILATE=1 };
+
+ static void init_binary_element( CvMat* _element, int _element_shape,
+ CvPoint _anchor=cvPoint(-1,-1) );
+protected:
+
+ void start_process( CvSlice x_range, int width );
+ int fill_cyclic_buffer( const uchar* src, int src_step,
+ int y0, int y1, int y2 );
+ uchar* el_sparse;
+ int el_sparse_count;
+
+ CvMat *element;
+ int el_shape;
+ int operation;
+};
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+struct CV_EXPORTS CvLevMarq
+{
+ CvLevMarq();
+ CvLevMarq( int nparams, int nerrs, CvTermCriteria criteria=
+ cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,DBL_EPSILON),
+ bool completeSymmFlag=false );
+ ~CvLevMarq();
+ void init( int nparams, int nerrs, CvTermCriteria criteria=
+ cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,DBL_EPSILON),
+ bool completeSymmFlag=false );
+ bool update( const CvMat*& param, CvMat*& J, CvMat*& err );
+ bool updateAlt( const CvMat*& param, CvMat*& JtJ, CvMat*& JtErr, double*& errNorm );
+
+ void clear();
+ void step();
+ enum { DONE=0, STARTED=1, CALC_J=2, CHECK_ERR=3 };
+
+ CvMat* mask;
+ CvMat* prevParam;
+ CvMat* param;
+ CvMat* J;
+ CvMat* err;
+ CvMat* JtJ;
+ CvMat* JtJN;
+ CvMat* JtErr;
+ CvMat* JtJV;
+ CvMat* JtJW;
+ double prevErrNorm, errNorm;
+ int lambdaLg10;
+ CvTermCriteria criteria;
+ int state;
+ int iters;
+ bool completeSymmFlag;
+};
+
+#endif /* __cplusplus */
+
+#endif /* _CV_HPP_ */
+
+/* End of file. */
diff --git a/cv/include/cvcompat.h b/cv/include/cvcompat.h
new file mode 100644
index 0000000..976a711
--- /dev/null
+++ b/cv/include/cvcompat.h
@@ -0,0 +1,1080 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright( C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+//(including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort(including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/*
+ A few macros and definitions for backward compatibility
+ with the previous versions of OpenCV. They are obsolete and
+ are likely to be removed in future. To check whether your code
+ uses any of these, define CV_NO_BACKWARD_COMPATIBILITY before
+ including cv.h.
+*/
+
+#ifndef _CVCOMPAT_H_
+#define _CVCOMPAT_H_
+
+#include <string.h>
+
+#ifdef __cplusplus
+ #define CV_UNREFERENCED(arg)
+#else
+ #define CV_UNREFERENCED(arg) arg
+#endif
+
+#define CvMatType int
+#define CvDisMaskType int
+#define CvMatArray CvMat
+
+#define CvThreshType int
+#define CvAdaptiveThreshMethod int
+#define CvCompareMethod int
+#define CvFontFace int
+#define CvPolyApproxMethod int
+#define CvContoursMatchMethod int
+#define CvContourTreesMatchMethod int
+#define CvCoeffType int
+#define CvRodriguesType int
+#define CvElementShape int
+#define CvMorphOp int
+#define CvTemplMatchMethod int
+
+#define CvPoint2D64d CvPoint2D64f
+#define CvPoint3D64d CvPoint3D64f
+
+#define CV_MAT32F CV_32FC1
+#define CV_MAT3x1_32F CV_32FC1
+#define CV_MAT4x1_32F CV_32FC1
+#define CV_MAT3x3_32F CV_32FC1
+#define CV_MAT4x4_32F CV_32FC1
+
+#define CV_MAT64D CV_64FC1
+#define CV_MAT3x1_64D CV_64FC1
+#define CV_MAT4x1_64D CV_64FC1
+#define CV_MAT3x3_64D CV_64FC1
+#define CV_MAT4x4_64D CV_64FC1
+
+#define IPL_GAUSSIAN_5x5 7
+#define CvBox2D32f CvBox2D
+
+/* allocation/deallocation macros */
+#define cvCreateImageData cvCreateData
+#define cvReleaseImageData cvReleaseData
+#define cvSetImageData cvSetData
+#define cvGetImageRawData cvGetRawData
+
+#define cvmAlloc cvCreateData
+#define cvmFree cvReleaseData
+#define cvmAllocArray cvCreateData
+#define cvmFreeArray cvReleaseData
+
+#define cvIntegralImage cvIntegral
+#define cvMatchContours cvMatchShapes
+
+CV_INLINE CvMat cvMatArray( int rows, int cols, int type,
+ int count, void* data CV_DEFAULT(0))
+{
+ return cvMat( rows*count, cols, type, data );
+}
+
+#define cvUpdateMHIByTime cvUpdateMotionHistory
+
+#define cvAccMask cvAcc
+#define cvSquareAccMask cvSquareAcc
+#define cvMultiplyAccMask cvMultiplyAcc
+#define cvRunningAvgMask(imgY, imgU, mask, alpha) cvRunningAvg(imgY, imgU, alpha, mask)
+
+#define cvSetHistThresh cvSetHistBinRanges
+#define cvCalcHistMask(img, mask, hist, doNotClear) cvCalcHist(img, hist, doNotClear, mask)
+
+CV_INLINE double cvMean( const CvArr* image, const CvArr* mask CV_DEFAULT(0))
+{
+ CvScalar mean = cvAvg( image, mask );
+ return mean.val[0];
+}
+
+
+CV_INLINE double cvSumPixels( const CvArr* image )
+{
+ CvScalar scalar = cvSum( image );
+ return scalar.val[0];
+}
+
+CV_INLINE void cvMean_StdDev( const CvArr* image, double* mean, double* sdv,
+ const CvArr* mask CV_DEFAULT(0))
+{
+ CvScalar _mean, _sdv;
+ cvAvgSdv( image, &_mean, &_sdv, mask );
+
+ if( mean )
+ *mean = _mean.val[0];
+
+ if( sdv )
+ *sdv = _sdv.val[0];
+}
+
+
+CV_INLINE void cvmPerspectiveProject( const CvMat* mat, const CvArr* src, CvArr* dst )
+{
+ CvMat tsrc, tdst;
+
+ cvReshape( src, &tsrc, 3, 0 );
+ cvReshape( dst, &tdst, 3, 0 );
+
+ cvPerspectiveTransform( &tsrc, &tdst, mat );
+}
+
+
+CV_INLINE void cvFillImage( CvArr* mat, double color )
+{
+ cvSet( mat, cvColorToScalar(color, cvGetElemType(mat)), 0 );
+}
+
+
+#define cvCvtPixToPlane cvSplit
+#define cvCvtPlaneToPix cvMerge
+
+typedef struct CvRandState
+{
+ CvRNG state; /* RNG state (the current seed and carry)*/
+ int disttype; /* distribution type */
+ CvScalar param[2]; /* parameters of RNG */
+}
+CvRandState;
+
+
+/* Changes RNG range while preserving RNG state */
+CV_INLINE void cvRandSetRange( CvRandState* state, double param1,
+ double param2, int index CV_DEFAULT(-1))
+{
+ if( !state )
+ {
+ cvError( CV_StsNullPtr, "cvRandSetRange", "Null pointer to RNG state", "cvcompat.h", 0 );
+ return;
+ }
+
+ if( (unsigned)(index + 1) > 4 )
+ {
+ cvError( CV_StsOutOfRange, "cvRandSetRange", "index is not in -1..3", "cvcompat.h", 0 );
+ return;
+ }
+
+ if( index < 0 )
+ {
+ state->param[0].val[0] = state->param[0].val[1] =
+ state->param[0].val[2] = state->param[0].val[3] = param1;
+ state->param[1].val[0] = state->param[1].val[1] =
+ state->param[1].val[2] = state->param[1].val[3] = param2;
+ }
+ else
+ {
+ state->param[0].val[index] = param1;
+ state->param[1].val[index] = param2;
+ }
+}
+
+
+CV_INLINE void cvRandInit( CvRandState* state, double param1,
+ double param2, int seed,
+ int disttype CV_DEFAULT(CV_RAND_UNI))
+{
+ if( !state )
+ {
+ cvError( CV_StsNullPtr, "cvRandInit", "Null pointer to RNG state", "cvcompat.h", 0 );
+ return;
+ }
+
+ if( disttype != CV_RAND_UNI && disttype != CV_RAND_NORMAL )
+ {
+ cvError( CV_StsBadFlag, "cvRandInit", "Unknown distribution type", "cvcompat.h", 0 );
+ return;
+ }
+
+ state->state = (uint64)(seed ? seed : -1);
+ state->disttype = disttype;
+ cvRandSetRange( state, param1, param2, -1 );
+}
+
+
+/* Fills array with random numbers */
+CV_INLINE void cvRand( CvRandState* state, CvArr* arr )
+{
+ if( !state )
+ {
+ cvError( CV_StsNullPtr, "cvRand", "Null pointer to RNG state", "cvcompat.h", 0 );
+ return;
+ }
+ cvRandArr( &state->state, arr, state->disttype, state->param[0], state->param[1] );
+}
+
+#define cvRandNext( _state ) cvRandInt( &(_state)->state )
+
+CV_INLINE void cvbRand( CvRandState* state, float* dst, int len )
+{
+ CvMat mat = cvMat( 1, len, CV_32F, (void*)dst );
+ cvRand( state, &mat );
+}
+
+
+CV_INLINE void cvbCartToPolar( const float* y, const float* x,
+ float* magnitude, float* angle, int len )
+{
+ CvMat mx = cvMat( 1, len, CV_32F, (void*)x );
+ CvMat my = mx;
+ CvMat mm = mx;
+ CvMat ma = mx;
+
+ my.data.fl = (float*)y;
+ mm.data.fl = (float*)magnitude;
+ ma.data.fl = (float*)angle;
+
+ cvCartToPolar( &mx, &my, &mm, angle ? &ma : NULL, 1 );
+}
+
+
+CV_INLINE void cvbFastArctan( const float* y, const float* x,
+ float* angle, int len )
+{
+ CvMat mx = cvMat( 1, len, CV_32F, (void*)x );
+ CvMat my = mx;
+ CvMat ma = mx;
+
+ my.data.fl = (float*)y;
+ ma.data.fl = (float*)angle;
+
+ cvCartToPolar( &mx, &my, NULL, &ma, 1 );
+}
+
+
+CV_INLINE void cvbSqrt( const float* x, float* y, int len )
+{
+ CvMat mx = cvMat( 1, len, CV_32F, (void*)x );
+ CvMat my = mx;
+ my.data.fl = (float*)y;
+
+ cvPow( &mx, &my, 0.5 );
+}
+
+
+CV_INLINE void cvbInvSqrt( const float* x, float* y, int len )
+{
+ CvMat mx = cvMat( 1, len, CV_32F, (void*)x );
+ CvMat my = mx;
+ my.data.fl = (float*)y;
+
+ cvPow( &mx, &my, -0.5 );
+}
+
+
+CV_INLINE void cvbReciprocal( const float* x, float* y, int len )
+{
+ CvMat mx = cvMat( 1, len, CV_32F, (void*)x );
+ CvMat my = mx;
+ my.data.fl = (float*)y;
+
+ cvPow( &mx, &my, -1 );
+}
+
+
+CV_INLINE void cvbFastExp( const float* x, double* y, int len )
+{
+ CvMat mx = cvMat( 1, len, CV_32F, (void*)x );
+ CvMat my = cvMat( 1, len, CV_64F, y );
+ cvExp( &mx, &my );
+}
+
+
+CV_INLINE void cvbFastLog( const double* x, float* y, int len )
+{
+ CvMat mx = cvMat( 1, len, CV_64F, (void*)x );
+ CvMat my = cvMat( 1, len, CV_32F, y );
+ cvLog( &mx, &my );
+}
+
+
+CV_INLINE CvRect cvContourBoundingRect( void* point_set, int update CV_DEFAULT(0))
+{
+ return cvBoundingRect( point_set, update );
+}
+
+
+CV_INLINE double cvPseudoInverse( const CvArr* src, CvArr* dst )
+{
+ return cvInvert( src, dst, CV_SVD );
+}
+
+#define cvPseudoInv cvPseudoInverse
+
+#define cvContourMoments( contour, moments ) \
+ cvMoments( contour, moments, 0 )
+
+#define cvGetPtrAt cvPtr2D
+#define cvGetAt cvGet2D
+#define cvSetAt(arr,val,y,x) cvSet2D((arr),(y),(x),(val))
+
+#define cvMeanMask cvMean
+#define cvMean_StdDevMask(img,mask,mean,sdv) cvMean_StdDev(img,mean,sdv,mask)
+
+#define cvNormMask(imgA,imgB,mask,normType) cvNorm(imgA,imgB,normType,mask)
+
+#define cvMinMaxLocMask(img, mask, min_val, max_val, min_loc, max_loc) \
+ cvMinMaxLoc(img, min_val, max_val, min_loc, max_loc, mask)
+
+#define cvRemoveMemoryManager cvSetMemoryManager
+
+#define cvmSetZero( mat ) cvSetZero( mat )
+#define cvmSetIdentity( mat ) cvSetIdentity( mat )
+#define cvmAdd( src1, src2, dst ) cvAdd( src1, src2, dst, 0 )
+#define cvmSub( src1, src2, dst ) cvSub( src1, src2, dst, 0 )
+#define cvmCopy( src, dst ) cvCopy( src, dst, 0 )
+#define cvmMul( src1, src2, dst ) cvMatMulAdd( src1, src2, 0, dst )
+#define cvmTranspose( src, dst ) cvT( src, dst )
+#define cvmInvert( src, dst ) cvInv( src, dst )
+#define cvmMahalanobis(vec1, vec2, mat) cvMahalanobis( vec1, vec2, mat )
+#define cvmDotProduct( vec1, vec2 ) cvDotProduct( vec1, vec2 )
+#define cvmCrossProduct(vec1, vec2,dst) cvCrossProduct( vec1, vec2, dst )
+#define cvmTrace( mat ) (cvTrace( mat )).val[0]
+#define cvmMulTransposed( src, dst, order ) cvMulTransposed( src, dst, order )
+#define cvmEigenVV( mat, evec, eval, eps) cvEigenVV( mat, evec, eval, eps )
+#define cvmDet( mat ) cvDet( mat )
+#define cvmScale( src, dst, scale ) cvScale( src, dst, scale )
+
+#define cvCopyImage( src, dst ) cvCopy( src, dst, 0 )
+#define cvReleaseMatHeader cvReleaseMat
+
+/* Calculates exact convex hull of 2d point set */
+CV_INLINE void cvConvexHull( CvPoint* points, int num_points,
+ CvRect* CV_UNREFERENCED(bound_rect),
+ int orientation, int* hull, int* hullsize )
+{
+ CvMat points1 = cvMat( 1, num_points, CV_32SC2, points );
+ CvMat hull1 = cvMat( 1, num_points, CV_32SC1, hull );
+
+ cvConvexHull2( &points1, &hull1, orientation, 0 );
+ *hullsize = hull1.cols;
+}
+
+/* Calculates exact convex hull of 2d point set stored in a sequence */
+#define cvContourConvexHull( contour, orientation, storage ) \
+ cvConvexHull2( contour, storage, orientation )
+
+/* Calculates approximate convex hull of 2d point set */
+#define cvConvexHullApprox( points, num_points, bound_rect, bandwidth, \
+ orientation, hull, hullsize ) \
+cvConvexHull( points, num_points, bound_rect, orientation, hull, hullsize )
+
+/* Calculates approximate convex hull of 2d point set stored in a sequence */
+#define cvContourConvexHullApprox( contour, bandwidth, orientation, storage ) \
+ cvConvexHull2( contour, storage, orientation )
+
+
+CV_INLINE void cvMinAreaRect( CvPoint* points, int n,
+ int CV_UNREFERENCED(left), int CV_UNREFERENCED(bottom),
+ int CV_UNREFERENCED(right), int CV_UNREFERENCED(top),
+ CvPoint2D32f* anchor,
+ CvPoint2D32f* vect1,
+ CvPoint2D32f* vect2 )
+{
+ CvMat mat = cvMat( 1, n, CV_32SC2, points );
+ CvBox2D box = cvMinAreaRect2( &mat, 0 );
+ CvPoint2D32f pt[4];
+
+ cvBoxPoints( box, pt );
+ *anchor = pt[0];
+ vect1->x = pt[1].x - pt[0].x;
+ vect1->y = pt[1].y - pt[0].y;
+ vect2->x = pt[3].x - pt[0].x;
+ vect2->y = pt[3].y - pt[0].y;
+
+ CV_UNREFERENCED( (left, bottom, right, top) );
+}
+
+typedef int CvDisType;
+typedef int CvChainApproxMethod;
+typedef int CvContourRetrievalMode;
+
+CV_INLINE void cvFitLine3D( CvPoint3D32f* points, int count, int dist,
+ void *param, float reps, float aeps, float* line )
+{
+ CvMat mat = cvMat( 1, count, CV_32FC3, points );
+ float _param = param != NULL ? *(float*)param : 0.f;
+ assert( dist != CV_DIST_USER );
+ cvFitLine( &mat, dist, _param, reps, aeps, line );
+}
+
+/* Fits a line into set of 2d points in a robust way (M-estimator technique) */
+CV_INLINE void cvFitLine2D( CvPoint2D32f* points, int count, int dist,
+ void *param, float reps, float aeps, float* line )
+{
+ CvMat mat = cvMat( 1, count, CV_32FC2, points );
+ float _param = param != NULL ? *(float*)param : 0.f;
+ assert( dist != CV_DIST_USER );
+ cvFitLine( &mat, dist, _param, reps, aeps, line );
+}
+
+
+CV_INLINE void cvFitEllipse( const CvPoint2D32f* points, int count, CvBox2D* box )
+{
+ CvMat mat = cvMat( 1, count, CV_32FC2, (void*)points );
+ *box = cvFitEllipse2( &mat );
+}
+
+/* Projects 2d points to one of standard coordinate planes
+ (i.e. removes one of coordinates) */
+CV_INLINE void cvProject3D( CvPoint3D32f* points3D, int count,
+ CvPoint2D32f* points2D,
+ int xIndx CV_DEFAULT(0),
+ int yIndx CV_DEFAULT(1))
+{
+ CvMat src = cvMat( 1, count, CV_32FC3, points3D );
+ CvMat dst = cvMat( 1, count, CV_32FC2, points2D );
+ float m[6] = {0,0,0,0,0,0};
+ CvMat M = cvMat( 2, 3, CV_32F, m );
+
+ assert( (unsigned)xIndx < 3 && (unsigned)yIndx < 3 );
+ m[xIndx] = m[yIndx+3] = 1.f;
+
+ cvTransform( &src, &dst, &M, NULL );
+}
+
+
+/* Retrieves value of the particular bin
+ of x-dimensional (x=1,2,3,...) histogram */
+#define cvQueryHistValue_1D( hist, idx0 ) \
+ ((float)cvGetReal1D( (hist)->bins, (idx0)))
+#define cvQueryHistValue_2D( hist, idx0, idx1 ) \
+ ((float)cvGetReal2D( (hist)->bins, (idx0), (idx1)))
+#define cvQueryHistValue_3D( hist, idx0, idx1, idx2 ) \
+ ((float)cvGetReal3D( (hist)->bins, (idx0), (idx1), (idx2)))
+#define cvQueryHistValue_nD( hist, idx ) \
+ ((float)cvGetRealND( (hist)->bins, (idx)))
+
+/* Returns pointer to the particular bin of x-dimesional histogram.
+ For sparse histogram the bin is created if it didn't exist before */
+#define cvGetHistValue_1D( hist, idx0 ) \
+ ((float*)cvPtr1D( (hist)->bins, (idx0), 0))
+#define cvGetHistValue_2D( hist, idx0, idx1 ) \
+ ((float*)cvPtr2D( (hist)->bins, (idx0), (idx1), 0))
+#define cvGetHistValue_3D( hist, idx0, idx1, idx2 ) \
+ ((float*)cvPtr3D( (hist)->bins, (idx0), (idx1), (idx2), 0))
+#define cvGetHistValue_nD( hist, idx ) \
+ ((float*)cvPtrND( (hist)->bins, (idx), 0))
+
+
+#define CV_IS_SET_ELEM_EXISTS CV_IS_SET_ELEM
+
+
+CV_INLINE int cvHoughLines( CvArr* image, double rho,
+ double theta, int threshold,
+ float* lines, int linesNumber )
+{
+ CvMat linesMat = cvMat( 1, linesNumber, CV_32FC2, lines );
+ cvHoughLines2( image, &linesMat, CV_HOUGH_STANDARD,
+ rho, theta, threshold, 0, 0 );
+
+ return linesMat.cols;
+}
+
+
+CV_INLINE int cvHoughLinesP( CvArr* image, double rho,
+ double theta, int threshold,
+ int lineLength, int lineGap,
+ int* lines, int linesNumber )
+{
+ CvMat linesMat = cvMat( 1, linesNumber, CV_32SC4, lines );
+ cvHoughLines2( image, &linesMat, CV_HOUGH_PROBABILISTIC,
+ rho, theta, threshold, lineLength, lineGap );
+
+ return linesMat.cols;
+}
+
+
+CV_INLINE int cvHoughLinesSDiv( CvArr* image, double rho, int srn,
+ double theta, int stn, int threshold,
+ float* lines, int linesNumber )
+{
+ CvMat linesMat = cvMat( 1, linesNumber, CV_32FC2, lines );
+ cvHoughLines2( image, &linesMat, CV_HOUGH_MULTI_SCALE,
+ rho, theta, threshold, srn, stn );
+
+ return linesMat.cols;
+}
+
+
+/* Find fundamental matrix */
+CV_INLINE void cvFindFundamentalMatrix( int* points1, int* points2,
+ int numpoints, int CV_UNREFERENCED(method), float* matrix )
+{
+ CvMat* pointsMat1;
+ CvMat* pointsMat2;
+ CvMat fundMatr = cvMat(3,3,CV_32F,matrix);
+ int i, curr = 0;
+
+ pointsMat1 = cvCreateMat(3,numpoints,CV_64F);
+ pointsMat2 = cvCreateMat(3,numpoints,CV_64F);
+
+ for( i = 0; i < numpoints; i++ )
+ {
+ cvmSet(pointsMat1,0,i,points1[curr]);//x
+ cvmSet(pointsMat1,1,i,points1[curr+1]);//y
+ cvmSet(pointsMat1,2,i,1.0);
+
+ cvmSet(pointsMat2,0,i,points2[curr]);//x
+ cvmSet(pointsMat2,1,i,points2[curr+1]);//y
+ cvmSet(pointsMat2,2,i,1.0);
+ curr += 2;
+ }
+
+ cvFindFundamentalMat(pointsMat1,pointsMat2,&fundMatr,CV_FM_RANSAC,1,0.99,0);
+
+ cvReleaseMat(&pointsMat1);
+ cvReleaseMat(&pointsMat2);
+}
+
+
+
+CV_INLINE int
+cvFindChessBoardCornerGuesses( const void* arr, void* CV_UNREFERENCED(thresharr),
+ CvMemStorage * CV_UNREFERENCED(storage),
+ CvSize pattern_size, CvPoint2D32f * corners,
+ int *corner_count )
+{
+ return cvFindChessboardCorners( arr, pattern_size, corners,
+ corner_count, CV_CALIB_CB_ADAPTIVE_THRESH );
+}
+
+
+/* Calibrates camera using multiple views of calibration pattern */
+CV_INLINE void cvCalibrateCamera( int image_count, int* _point_counts,
+ CvSize image_size, CvPoint2D32f* _image_points, CvPoint3D32f* _object_points,
+ float* _distortion_coeffs, float* _camera_matrix, float* _translation_vectors,
+ float* _rotation_matrices, int flags )
+{
+ int i, total = 0;
+ CvMat point_counts = cvMat( image_count, 1, CV_32SC1, _point_counts );
+ CvMat image_points, object_points;
+ CvMat dist_coeffs = cvMat( 4, 1, CV_32FC1, _distortion_coeffs );
+ CvMat camera_matrix = cvMat( 3, 3, CV_32FC1, _camera_matrix );
+ CvMat rotation_matrices = cvMat( image_count, 9, CV_32FC1, _rotation_matrices );
+ CvMat translation_vectors = cvMat( image_count, 3, CV_32FC1, _translation_vectors );
+
+ for( i = 0; i < image_count; i++ )
+ total += _point_counts[i];
+
+ image_points = cvMat( total, 1, CV_32FC2, _image_points );
+ object_points = cvMat( total, 1, CV_32FC3, _object_points );
+
+ cvCalibrateCamera2( &object_points, &image_points, &point_counts, image_size,
+ &camera_matrix, &dist_coeffs, &rotation_matrices, &translation_vectors,
+ flags );
+}
+
+
+CV_INLINE void cvCalibrateCamera_64d( int image_count, int* _point_counts,
+ CvSize image_size, CvPoint2D64f* _image_points, CvPoint3D64f* _object_points,
+ double* _distortion_coeffs, double* _camera_matrix, double* _translation_vectors,
+ double* _rotation_matrices, int flags )
+{
+ int i, total = 0;
+ CvMat point_counts = cvMat( image_count, 1, CV_32SC1, _point_counts );
+ CvMat image_points, object_points;
+ CvMat dist_coeffs = cvMat( 4, 1, CV_64FC1, _distortion_coeffs );
+ CvMat camera_matrix = cvMat( 3, 3, CV_64FC1, _camera_matrix );
+ CvMat rotation_matrices = cvMat( image_count, 9, CV_64FC1, _rotation_matrices );
+ CvMat translation_vectors = cvMat( image_count, 3, CV_64FC1, _translation_vectors );
+
+ for( i = 0; i < image_count; i++ )
+ total += _point_counts[i];
+
+ image_points = cvMat( total, 1, CV_64FC2, _image_points );
+ object_points = cvMat( total, 1, CV_64FC3, _object_points );
+
+ cvCalibrateCamera2( &object_points, &image_points, &point_counts, image_size,
+ &camera_matrix, &dist_coeffs, &rotation_matrices, &translation_vectors,
+ flags );
+}
+
+
+
+/* Find 3d position of object given intrinsic camera parameters,
+ 3d model of the object and projection of the object into view plane */
+CV_INLINE void cvFindExtrinsicCameraParams( int point_count,
+ CvSize CV_UNREFERENCED(image_size), CvPoint2D32f* _image_points,
+ CvPoint3D32f* _object_points, float* focal_length,
+ CvPoint2D32f principal_point, float* _distortion_coeffs,
+ float* _rotation_vector, float* _translation_vector )
+{
+ CvMat image_points = cvMat( point_count, 1, CV_32FC2, _image_points );
+ CvMat object_points = cvMat( point_count, 1, CV_32FC3, _object_points );
+ CvMat dist_coeffs = cvMat( 4, 1, CV_32FC1, _distortion_coeffs );
+ float a[9];
+ CvMat camera_matrix = cvMat( 3, 3, CV_32FC1, a );
+ CvMat rotation_vector = cvMat( 1, 1, CV_32FC3, _rotation_vector );
+ CvMat translation_vector = cvMat( 1, 1, CV_32FC3, _translation_vector );
+
+ a[0] = focal_length[0]; a[4] = focal_length[1];
+ a[2] = principal_point.x; a[5] = principal_point.y;
+ a[1] = a[3] = a[6] = a[7] = 0.f;
+ a[8] = 1.f;
+
+ cvFindExtrinsicCameraParams2( &object_points, &image_points, &camera_matrix,
+ &dist_coeffs, &rotation_vector, &translation_vector );
+}
+
+
+/* Variant of the previous function that takes double-precision parameters */
+CV_INLINE void cvFindExtrinsicCameraParams_64d( int point_count,
+ CvSize CV_UNREFERENCED(image_size), CvPoint2D64f* _image_points,
+ CvPoint3D64f* _object_points, double* focal_length,
+ CvPoint2D64f principal_point, double* _distortion_coeffs,
+ double* _rotation_vector, double* _translation_vector )
+{
+ CvMat image_points = cvMat( point_count, 1, CV_64FC2, _image_points );
+ CvMat object_points = cvMat( point_count, 1, CV_64FC3, _object_points );
+ CvMat dist_coeffs = cvMat( 4, 1, CV_64FC1, _distortion_coeffs );
+ double a[9];
+ CvMat camera_matrix = cvMat( 3, 3, CV_64FC1, a );
+ CvMat rotation_vector = cvMat( 1, 1, CV_64FC3, _rotation_vector );
+ CvMat translation_vector = cvMat( 1, 1, CV_64FC3, _translation_vector );
+
+ a[0] = focal_length[0]; a[4] = focal_length[1];
+ a[2] = principal_point.x; a[5] = principal_point.y;
+ a[1] = a[3] = a[6] = a[7] = 0.;
+ a[8] = 1.;
+
+ cvFindExtrinsicCameraParams2( &object_points, &image_points, &camera_matrix,
+ &dist_coeffs, &rotation_vector, &translation_vector );
+}
+
+
+/* Rodrigues transform */
+#define CV_RODRIGUES_M2V 0
+#define CV_RODRIGUES_V2M 1
+
+/* Converts rotation_matrix matrix to rotation_matrix vector or vice versa */
+CV_INLINE void cvRodrigues( CvMat* rotation_matrix, CvMat* rotation_vector,
+ CvMat* jacobian, int conv_type )
+{
+ if( conv_type == CV_RODRIGUES_V2M )
+ cvRodrigues2( rotation_vector, rotation_matrix, jacobian );
+ else
+ cvRodrigues2( rotation_matrix, rotation_vector, jacobian );
+}
+
+
+/* Does reprojection of 3d object points to the view plane */
+CV_INLINE void cvProjectPoints( int point_count, CvPoint3D64f* _object_points,
+ double* _rotation_vector, double* _translation_vector,
+ double* focal_length, CvPoint2D64f principal_point,
+ double* _distortion, CvPoint2D64f* _image_points,
+ double* _deriv_points_rotation_matrix,
+ double* _deriv_points_translation_vect,
+ double* _deriv_points_focal,
+ double* _deriv_points_principal_point,
+ double* _deriv_points_distortion_coeffs )
+{
+ CvMat object_points = cvMat( point_count, 1, CV_64FC3, _object_points );
+ CvMat image_points = cvMat( point_count, 1, CV_64FC2, _image_points );
+ CvMat rotation_vector = cvMat( 3, 1, CV_64FC1, _rotation_vector );
+ CvMat translation_vector = cvMat( 3, 1, CV_64FC1, _translation_vector );
+ double a[9];
+ CvMat camera_matrix = cvMat( 3, 3, CV_64FC1, a );
+ CvMat dist_coeffs = cvMat( 4, 1, CV_64FC1, _distortion );
+ CvMat dpdr = cvMat( 2*point_count, 3, CV_64FC1, _deriv_points_rotation_matrix );
+ CvMat dpdt = cvMat( 2*point_count, 3, CV_64FC1, _deriv_points_translation_vect );
+ CvMat dpdf = cvMat( 2*point_count, 2, CV_64FC1, _deriv_points_focal );
+ CvMat dpdc = cvMat( 2*point_count, 2, CV_64FC1, _deriv_points_principal_point );
+ CvMat dpdk = cvMat( 2*point_count, 4, CV_64FC1, _deriv_points_distortion_coeffs );
+
+ a[0] = focal_length[0]; a[4] = focal_length[1];
+ a[2] = principal_point.x; a[5] = principal_point.y;
+ a[1] = a[3] = a[6] = a[7] = 0.;
+ a[8] = 1.;
+
+ cvProjectPoints2( &object_points, &rotation_vector, &translation_vector,
+ &camera_matrix, &dist_coeffs, &image_points,
+ &dpdr, &dpdt, &dpdf, &dpdc, &dpdk, 0 );
+}
+
+
+/* Simpler version of the previous function */
+CV_INLINE void cvProjectPointsSimple( int point_count, CvPoint3D64f* _object_points,
+ double* _rotation_matrix, double* _translation_vector,
+ double* _camera_matrix, double* _distortion, CvPoint2D64f* _image_points )
+{
+ CvMat object_points = cvMat( point_count, 1, CV_64FC3, _object_points );
+ CvMat image_points = cvMat( point_count, 1, CV_64FC2, _image_points );
+ CvMat rotation_matrix = cvMat( 3, 3, CV_64FC1, _rotation_matrix );
+ CvMat translation_vector = cvMat( 3, 1, CV_64FC1, _translation_vector );
+ CvMat camera_matrix = cvMat( 3, 3, CV_64FC1, _camera_matrix );
+ CvMat dist_coeffs = cvMat( 4, 1, CV_64FC1, _distortion );
+
+ cvProjectPoints2( &object_points, &rotation_matrix, &translation_vector,
+ &camera_matrix, &dist_coeffs, &image_points,
+ 0, 0, 0, 0, 0, 0 );
+}
+
+
+CV_INLINE void cvUnDistortOnce( const CvArr* src, CvArr* dst,
+ const float* intrinsic_matrix,
+ const float* distortion_coeffs,
+ int CV_UNREFERENCED(interpolate) )
+{
+ CvMat _a = cvMat( 3, 3, CV_32F, (void*)intrinsic_matrix );
+ CvMat _k = cvMat( 4, 1, CV_32F, (void*)distortion_coeffs );
+ cvUndistort2( src, dst, &_a, &_k );
+}
+
+
+/* the two functions below have quite hackerish implementations, use with care
+ (or, which is better, switch to cvUndistortInitMap and cvRemap instead */
+CV_INLINE void cvUnDistortInit( const CvArr* CV_UNREFERENCED(src),
+ CvArr* undistortion_map,
+ const float* A, const float* k,
+ int CV_UNREFERENCED(interpolate) )
+{
+ union { uchar* ptr; float* fl; } data;
+ CvSize sz;
+ cvGetRawData( undistortion_map, &data.ptr, 0, &sz );
+ assert( sz.width >= 8 );
+ /* just save the intrinsic parameters to the map */
+ data.fl[0] = A[0]; data.fl[1] = A[4];
+ data.fl[2] = A[2]; data.fl[3] = A[5];
+ data.fl[4] = k[0]; data.fl[5] = k[1];
+ data.fl[6] = k[2]; data.fl[7] = k[3];
+}
+
+CV_INLINE void cvUnDistort( const CvArr* src, CvArr* dst,
+ const CvArr* undistortion_map,
+ int CV_UNREFERENCED(interpolate) )
+{
+ union { uchar* ptr; float* fl; } data;
+ float a[] = {0,0,0,0,0,0,0,0,1};
+ CvSize sz;
+ cvGetRawData( undistortion_map, &data.ptr, 0, &sz );
+ assert( sz.width >= 8 );
+ a[0] = data.fl[0]; a[4] = data.fl[1];
+ a[2] = data.fl[2]; a[5] = data.fl[3];
+ cvUnDistortOnce( src, dst, a, data.fl + 4, 1 );
+}
+
+
+CV_INLINE float cvCalcEMD( const float* signature1, int size1,
+ const float* signature2, int size2,
+ int dims, int dist_type CV_DEFAULT(CV_DIST_L2),
+ CvDistanceFunction dist_func CV_DEFAULT(0),
+ float* lower_bound CV_DEFAULT(0),
+ void* user_param CV_DEFAULT(0))
+{
+ CvMat sign1 = cvMat( size1, dims + 1, CV_32FC1, (void*)signature1 );
+ CvMat sign2 = cvMat( size2, dims + 1, CV_32FC1, (void*)signature2 );
+
+ return cvCalcEMD2( &sign1, &sign2, dist_type, dist_func, 0, 0, lower_bound, user_param );
+}
+
+
+CV_INLINE void cvKMeans( int num_clusters, float** samples,
+ int num_samples, int vec_size,
+ CvTermCriteria termcrit, int* cluster_idx )
+{
+ CvMat* samples_mat = cvCreateMat( num_samples, vec_size, CV_32FC1 );
+ CvMat cluster_idx_mat = cvMat( num_samples, 1, CV_32SC1, cluster_idx );
+ int i;
+ for( i = 0; i < num_samples; i++ )
+ memcpy( samples_mat->data.fl + i*vec_size, samples[i], vec_size*sizeof(float));
+ cvKMeans2( samples_mat, num_clusters, &cluster_idx_mat, termcrit );
+ cvReleaseMat( &samples_mat );
+}
+
+
+CV_INLINE void cvStartScanGraph( CvGraph* graph, CvGraphScanner* scanner,
+ CvGraphVtx* vtx CV_DEFAULT(NULL),
+ int mask CV_DEFAULT(CV_GRAPH_ALL_ITEMS))
+{
+ CvGraphScanner* temp_scanner;
+
+ if( !scanner )
+ cvError( CV_StsNullPtr, "cvStartScanGraph", "Null scanner pointer", "cvcompat.h", 0 );
+
+ temp_scanner = cvCreateGraphScanner( graph, vtx, mask );
+ *scanner = *temp_scanner;
+ cvFree( &temp_scanner );
+}
+
+
+CV_INLINE void cvEndScanGraph( CvGraphScanner* scanner )
+{
+ if( !scanner )
+ cvError( CV_StsNullPtr, "cvEndScanGraph", "Null scanner pointer", "cvcompat.h", 0 );
+
+ if( scanner->stack )
+ {
+ CvGraphScanner* temp_scanner = (CvGraphScanner*)cvAlloc( sizeof(*temp_scanner) );
+ *temp_scanner = *scanner;
+ cvReleaseGraphScanner( &temp_scanner );
+ memset( scanner, 0, sizeof(*scanner) );
+ }
+}
+
+
+#define cvKalmanUpdateByTime cvKalmanPredict
+#define cvKalmanUpdateByMeasurement cvKalmanCorrect
+
+/* old drawing functions */
+CV_INLINE void cvLineAA( CvArr* img, CvPoint pt1, CvPoint pt2,
+ double color, int scale CV_DEFAULT(0))
+{
+ cvLine( img, pt1, pt2, cvColorToScalar(color, cvGetElemType(img)), 1, CV_AA, scale );
+}
+
+CV_INLINE void cvCircleAA( CvArr* img, CvPoint center, int radius,
+ double color, int scale CV_DEFAULT(0) )
+{
+ cvCircle( img, center, radius, cvColorToScalar(color, cvGetElemType(img)), 1, CV_AA, scale );
+}
+
+CV_INLINE void cvEllipseAA( CvArr* img, CvPoint center, CvSize axes,
+ double angle, double start_angle,
+ double end_angle, double color,
+ int scale CV_DEFAULT(0) )
+{
+ cvEllipse( img, center, axes, angle, start_angle, end_angle,
+ cvColorToScalar(color, cvGetElemType(img)), 1, CV_AA, scale );
+}
+
+CV_INLINE void cvPolyLineAA( CvArr* img, CvPoint** pts, int* npts, int contours,
+ int is_closed, double color, int scale CV_DEFAULT(0) )
+{
+ cvPolyLine( img, pts, npts, contours, is_closed,
+ cvColorToScalar(color, cvGetElemType(img)),
+ 1, CV_AA, scale );
+}
+
+
+#define cvMake2DPoints cvConvertPointsHomogeneous
+#define cvMake3DPoints cvConvertPointsHomogeneous
+
+#define cvWarpPerspectiveQMatrix cvGetPerspectiveTransform
+
+#define cvConvertPointsHomogenious cvConvertPointsHomogeneous
+
+/****************************************************************************************\
+* Pixel Access Macros *
+\****************************************************************************************/
+
+typedef struct _CvPixelPosition8u
+{
+ uchar* currline; /* pointer to the start of the current pixel line */
+ uchar* topline; /* pointer to the start of the top pixel line */
+ uchar* bottomline; /* pointer to the start of the first line */
+ /* which is below the image */
+ int x; /* current x coordinate ( in pixels ) */
+ int width; /* width of the image ( in pixels ) */
+ int height; /* height of the image ( in pixels ) */
+ int step; /* distance between lines ( in elements of single */
+ /* plane ) */
+ int step_arr[3]; /* array: ( 0, -step, step ). It is used for */
+ /* vertical moving */
+} CvPixelPosition8u;
+
+/* this structure differs from the above only in data type */
+typedef struct _CvPixelPosition8s
+{
+ schar* currline;
+ schar* topline;
+ schar* bottomline;
+ int x;
+ int width;
+ int height;
+ int step;
+ int step_arr[3];
+} CvPixelPosition8s;
+
+/* this structure differs from the CvPixelPosition8u only in data type */
+typedef struct _CvPixelPosition32f
+{
+ float* currline;
+ float* topline;
+ float* bottomline;
+ int x;
+ int width;
+ int height;
+ int step;
+ int step_arr[3];
+} CvPixelPosition32f;
+
+
+/* Initialize one of the CvPixelPosition structures. */
+/* pos - initialized structure */
+/* origin - pointer to the left-top corner of the ROI */
+/* step - width of the whole image in bytes */
+/* roi - width & height of the ROI */
+/* x, y - initial position */
+#define CV_INIT_PIXEL_POS(pos, origin, _step, roi, _x, _y, orientation) \
+ ( \
+ (pos).step = (_step)/sizeof((pos).currline[0]) * (orientation ? -1 : 1), \
+ (pos).width = (roi).width, \
+ (pos).height = (roi).height, \
+ (pos).bottomline = (origin) + (pos).step*(pos).height, \
+ (pos).topline = (origin) - (pos).step, \
+ (pos).step_arr[0] = 0, \
+ (pos).step_arr[1] = -(pos).step, \
+ (pos).step_arr[2] = (pos).step, \
+ (pos).x = (_x), \
+ (pos).currline = (origin) + (pos).step*(_y) )
+
+
+/* Move to specified point ( absolute shift ) */
+/* pos - position structure */
+/* x, y - coordinates of the new position */
+/* cs - number of the image channels */
+#define CV_MOVE_TO( pos, _x, _y, cs ) \
+((pos).currline = (_y) >= 0 && (_y) < (pos).height ? (pos).topline + ((_y)+1)*(pos).step : 0, \
+ (pos).x = (_x) >= 0 && (_x) < (pos).width ? (_x) : 0, (pos).currline + (_x) * (cs) )
+
+/* Get current coordinates */
+/* pos - position structure */
+/* x, y - coordinates of the new position */
+/* cs - number of the image channels */
+#define CV_GET_CURRENT( pos, cs ) ((pos).currline + (pos).x * (cs))
+
+/* Move by one pixel relatively to current position */
+/* pos - position structure */
+/* cs - number of the image channels */
+
+/* left */
+#define CV_MOVE_LEFT( pos, cs ) \
+ ( --(pos).x >= 0 ? (pos).currline + (pos).x*(cs) : 0 )
+
+/* right */
+#define CV_MOVE_RIGHT( pos, cs ) \
+ ( ++(pos).x < (pos).width ? (pos).currline + (pos).x*(cs) : 0 )
+
+/* up */
+#define CV_MOVE_UP( pos, cs ) \
+ (((pos).currline -= (pos).step) != (pos).topline ? (pos).currline + (pos).x*(cs) : 0 )
+
+/* down */
+#define CV_MOVE_DOWN( pos, cs ) \
+ (((pos).currline += (pos).step) != (pos).bottomline ? (pos).currline + (pos).x*(cs) : 0 )
+
+/* left up */
+#define CV_MOVE_LU( pos, cs ) ( CV_MOVE_LEFT(pos, cs), CV_MOVE_UP(pos, cs))
+
+/* right up */
+#define CV_MOVE_RU( pos, cs ) ( CV_MOVE_RIGHT(pos, cs), CV_MOVE_UP(pos, cs))
+
+/* left down */
+#define CV_MOVE_LD( pos, cs ) ( CV_MOVE_LEFT(pos, cs), CV_MOVE_DOWN(pos, cs))
+
+/* right down */
+#define CV_MOVE_RD( pos, cs ) ( CV_MOVE_RIGHT(pos, cs), CV_MOVE_DOWN(pos, cs))
+
+
+
+/* Move by one pixel relatively to current position with wrapping when the position */
+/* achieves image boundary */
+/* pos - position structure */
+/* cs - number of the image channels */
+
+/* left */
+#define CV_MOVE_LEFT_WRAP( pos, cs ) \
+ ((pos).currline + ( --(pos).x >= 0 ? (pos).x : ((pos).x = (pos).width-1))*(cs))
+
+/* right */
+#define CV_MOVE_RIGHT_WRAP( pos, cs ) \
+ ((pos).currline + ( ++(pos).x < (pos).width ? (pos).x : ((pos).x = 0))*(cs) )
+
+/* up */
+#define CV_MOVE_UP_WRAP( pos, cs ) \
+ ((((pos).currline -= (pos).step) != (pos).topline ? \
+ (pos).currline : ((pos).currline = (pos).bottomline - (pos).step)) + (pos).x*(cs) )
+
+/* down */
+#define CV_MOVE_DOWN_WRAP( pos, cs ) \
+ ((((pos).currline += (pos).step) != (pos).bottomline ? \
+ (pos).currline : ((pos).currline = (pos).topline + (pos).step)) + (pos).x*(cs) )
+
+/* left up */
+#define CV_MOVE_LU_WRAP( pos, cs ) ( CV_MOVE_LEFT_WRAP(pos, cs), CV_MOVE_UP_WRAP(pos, cs))
+/* right up */
+#define CV_MOVE_RU_WRAP( pos, cs ) ( CV_MOVE_RIGHT_WRAP(pos, cs), CV_MOVE_UP_WRAP(pos, cs))
+/* left down */
+#define CV_MOVE_LD_WRAP( pos, cs ) ( CV_MOVE_LEFT_WRAP(pos, cs), CV_MOVE_DOWN_WRAP(pos, cs))
+/* right down */
+#define CV_MOVE_RD_WRAP( pos, cs ) ( CV_MOVE_RIGHT_WRAP(pos, cs), CV_MOVE_DOWN_WRAP(pos, cs))
+
+/* Numeric constants which used for moving in arbitrary direction */
+#define CV_SHIFT_NONE 2
+#define CV_SHIFT_LEFT 1
+#define CV_SHIFT_RIGHT 3
+#define CV_SHIFT_UP 6
+#define CV_SHIFT_DOWN 10
+#define CV_SHIFT_LU 5
+#define CV_SHIFT_RU 7
+#define CV_SHIFT_LD 9
+#define CV_SHIFT_RD 11
+
+/* Move by one pixel in specified direction */
+/* pos - position structure */
+/* shift - direction ( it's value must be one of the CV_SHIFT_… constants ) */
+/* cs - number of the image channels */
+#define CV_MOVE_PARAM( pos, shift, cs ) \
+ ( (pos).currline += (pos).step_arr[(shift)>>2], (pos).x += ((shift)&3)-2, \
+ ((pos).currline != (pos).topline && (pos).currline != (pos).bottomline && \
+ (pos).x >= 0 && (pos).x < (pos).width) ? (pos).currline + (pos).x*(cs) : 0 )
+
+/* Move by one pixel in specified direction with wrapping when the */
+/* position achieves image boundary */
+/* pos - position structure */
+/* shift - direction ( it's value must be one of the CV_SHIFT_… constants ) */
+/* cs - number of the image channels */
+#define CV_MOVE_PARAM_WRAP( pos, shift, cs ) \
+ ( (pos).currline += (pos).step_arr[(shift)>>2], \
+ (pos).currline = ((pos).currline == (pos).topline ? \
+ (pos).bottomline - (pos).step : \
+ (pos).currline == (pos).bottomline ? \
+ (pos).topline + (pos).step : (pos).currline), \
+ \
+ (pos).x += ((shift)&3)-2, \
+ (pos).x = ((pos).x < 0 ? (pos).width-1 : (pos).x >= (pos).width ? 0 : (pos).x), \
+ \
+ (pos).currline + (pos).x*(cs) )
+
+#endif/*_CVCOMPAT_H_*/
diff --git a/cv/include/cvstreams.h b/cv/include/cvstreams.h
new file mode 100644
index 0000000..0bb205d
--- /dev/null
+++ b/cv/include/cvstreams.h
@@ -0,0 +1,93 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _CVSTREAMS_H_
+#define _CVSTREAMS_H_
+
+#ifdef WIN32
+#include <streams.h> /* !!! IF YOU'VE GOT AN ERROR HERE, PLEASE READ BELOW !!! */
+/***************** How to get Visual Studio understand streams.h ****************\
+
+You need DirectShow SDK that is now a part of Platform SDK
+(Windows Server 2003 SP1 SDK or later),
+and DirectX SDK (2006 April or later).
+
+1. Download the Platform SDK from
+ http://www.microsoft.com/msdownload/platformsdk/sdkupdate/
+ and DirectX SDK from msdn.microsoft.com/directx/
+ (They are huge, but you can download it by parts).
+ If it doesn't work for you, consider HighGUI that can capture video via VFW or MIL
+
+2. Install Platform SDK together with DirectShow SDK.
+ Install DirectX (with or without sample code).
+
+3. Build baseclasses.
+ See <PlatformSDKInstallFolder>\samples\multimedia\directshow\readme.txt.
+
+4. Copy the built libraries (called strmbase.lib and strmbasd.lib
+ in Release and Debug versions, respectively) to
+ <PlatformSDKInstallFolder>\lib.
+
+5. In Developer Studio add the following paths:
+ <DirectXSDKInstallFolder>\include
+ <PlatformSDKInstallFolder>\include
+ <PlatformSDKInstallFolder>\samples\multimedia\directshow\baseclasses
+ to the includes' search path
+ (at Tools->Options->Directories->Include files in case of Visual Studio 6.0,
+ at Tools->Options->Projects and Solutions->VC++ Directories->Include files in case
+ of Visual Studio 2005)
+ Add
+ <DirectXSDKInstallFolder>\lib
+ <PlatformSDKInstallFolder>\lib
+ to the libraries' search path (in the same dialog, ...->"Library files" page)
+
+ NOTE: PUT THE ADDED LINES ON THE VERY TOP OF THE LISTS, OTHERWISE YOU MAY STILL GET
+ COMPILER OR LINKER ERRORS. This is necessary, because Visual Studio
+ may include older versions of the same headers and libraries.
+
+6. Now you can build OpenCV DirectShow filters.
+
+\***********************************************************************************/
+
+#endif
+
+#endif /*_CVSTREAMS_H_*/
+
diff --git a/cv/include/cvtypes.h b/cv/include/cvtypes.h
new file mode 100644
index 0000000..e45cae2
--- /dev/null
+++ b/cv/include/cvtypes.h
@@ -0,0 +1,386 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _CVTYPES_H_
+#define _CVTYPES_H_
+
+#ifndef SKIP_INCLUDES
+ #include <assert.h>
+ #include <stdlib.h>
+#endif
+
+/* spatial and central moments */
+typedef struct CvMoments
+{
+ double m00, m10, m01, m20, m11, m02, m30, m21, m12, m03; /* spatial moments */
+ double mu20, mu11, mu02, mu30, mu21, mu12, mu03; /* central moments */
+ double inv_sqrt_m00; /* m00 != 0 ? 1/sqrt(m00) : 0 */
+}
+CvMoments;
+
+/* Hu invariants */
+typedef struct CvHuMoments
+{
+ double hu1, hu2, hu3, hu4, hu5, hu6, hu7; /* Hu invariants */
+}
+CvHuMoments;
+
+/**************************** Connected Component **************************************/
+
+typedef struct CvConnectedComp
+{
+ double area; /* area of the connected component */
+ CvScalar value; /* average color of the connected component */
+ CvRect rect; /* ROI of the component */
+ CvSeq* contour; /* optional component boundary
+ (the contour might have child contours corresponding to the holes)*/
+}
+CvConnectedComp;
+
+/*
+Internal structure that is used for sequental retrieving contours from the image.
+It supports both hierarchical and plane variants of Suzuki algorithm.
+*/
+typedef struct _CvContourScanner* CvContourScanner;
+
+/* contour retrieval mode */
+#define CV_RETR_EXTERNAL 0
+#define CV_RETR_LIST 1
+#define CV_RETR_CCOMP 2
+#define CV_RETR_TREE 3
+
+/* contour approximation method */
+#define CV_CHAIN_CODE 0
+#define CV_CHAIN_APPROX_NONE 1
+#define CV_CHAIN_APPROX_SIMPLE 2
+#define CV_CHAIN_APPROX_TC89_L1 3
+#define CV_CHAIN_APPROX_TC89_KCOS 4
+#define CV_LINK_RUNS 5
+
+/* Freeman chain reader state */
+typedef struct CvChainPtReader
+{
+ CV_SEQ_READER_FIELDS()
+ char code;
+ CvPoint pt;
+ schar deltas[8][2];
+}
+CvChainPtReader;
+
+/* initializes 8-element array for fast access to 3x3 neighborhood of a pixel */
+#define CV_INIT_3X3_DELTAS( deltas, step, nch ) \
+ ((deltas)[0] = (nch), (deltas)[1] = -(step) + (nch), \
+ (deltas)[2] = -(step), (deltas)[3] = -(step) - (nch), \
+ (deltas)[4] = -(nch), (deltas)[5] = (step) - (nch), \
+ (deltas)[6] = (step), (deltas)[7] = (step) + (nch))
+
+/* Contour tree header */
+typedef struct CvContourTree
+{
+ CV_SEQUENCE_FIELDS()
+ CvPoint p1; /* the first point of the binary tree root segment */
+ CvPoint p2; /* the last point of the binary tree root segment */
+}
+CvContourTree;
+
+/* Finds a sequence of convexity defects of given contour */
+typedef struct CvConvexityDefect
+{
+ CvPoint* start; /* point of the contour where the defect begins */
+ CvPoint* end; /* point of the contour where the defect ends */
+ CvPoint* depth_point; /* the farthest from the convex hull point within the defect */
+ float depth; /* distance between the farthest point and the convex hull */
+}
+CvConvexityDefect;
+
+/************ Data structures and related enumerations for Planar Subdivisions ************/
+
+typedef size_t CvSubdiv2DEdge;
+
+#define CV_QUADEDGE2D_FIELDS() \
+ int flags; \
+ struct CvSubdiv2DPoint* pt[4]; \
+ CvSubdiv2DEdge next[4];
+
+#define CV_SUBDIV2D_POINT_FIELDS()\
+ int flags; \
+ CvSubdiv2DEdge first; \
+ CvPoint2D32f pt;
+
+#define CV_SUBDIV2D_VIRTUAL_POINT_FLAG (1 << 30)
+
+typedef struct CvQuadEdge2D
+{
+ CV_QUADEDGE2D_FIELDS()
+}
+CvQuadEdge2D;
+
+typedef struct CvSubdiv2DPoint
+{
+ CV_SUBDIV2D_POINT_FIELDS()
+}
+CvSubdiv2DPoint;
+
+#define CV_SUBDIV2D_FIELDS() \
+ CV_GRAPH_FIELDS() \
+ int quad_edges; \
+ int is_geometry_valid; \
+ CvSubdiv2DEdge recent_edge; \
+ CvPoint2D32f topleft; \
+ CvPoint2D32f bottomright;
+
+typedef struct CvSubdiv2D
+{
+ CV_SUBDIV2D_FIELDS()
+}
+CvSubdiv2D;
+
+
+typedef enum CvSubdiv2DPointLocation
+{
+ CV_PTLOC_ERROR = -2,
+ CV_PTLOC_OUTSIDE_RECT = -1,
+ CV_PTLOC_INSIDE = 0,
+ CV_PTLOC_VERTEX = 1,
+ CV_PTLOC_ON_EDGE = 2
+}
+CvSubdiv2DPointLocation;
+
+typedef enum CvNextEdgeType
+{
+ CV_NEXT_AROUND_ORG = 0x00,
+ CV_NEXT_AROUND_DST = 0x22,
+ CV_PREV_AROUND_ORG = 0x11,
+ CV_PREV_AROUND_DST = 0x33,
+ CV_NEXT_AROUND_LEFT = 0x13,
+ CV_NEXT_AROUND_RIGHT = 0x31,
+ CV_PREV_AROUND_LEFT = 0x20,
+ CV_PREV_AROUND_RIGHT = 0x02
+}
+CvNextEdgeType;
+
+/* get the next edge with the same origin point (counterwise) */
+#define CV_SUBDIV2D_NEXT_EDGE( edge ) (((CvQuadEdge2D*)((edge) & ~3))->next[(edge)&3])
+
+
+/* Defines for Distance Transform */
+#define CV_DIST_USER -1 /* User defined distance */
+#define CV_DIST_L1 1 /* distance = |x1-x2| + |y1-y2| */
+#define CV_DIST_L2 2 /* the simple euclidean distance */
+#define CV_DIST_C 3 /* distance = max(|x1-x2|,|y1-y2|) */
+#define CV_DIST_L12 4 /* L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1)) */
+#define CV_DIST_FAIR 5 /* distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998 */
+#define CV_DIST_WELSCH 6 /* distance = c^2/2(1-exp(-(x/c)^2)), c = 2.9846 */
+#define CV_DIST_HUBER 7 /* distance = |x|<c ? x^2/2 : c(|x|-c/2), c=1.345 */
+
+
+/* Filters used in pyramid decomposition */
+typedef enum CvFilter
+{
+ CV_GAUSSIAN_5x5 = 7
+}
+CvFilter;
+
+/****************************************************************************************/
+/* Older definitions */
+/****************************************************************************************/
+
+typedef float* CvVect32f;
+typedef float* CvMatr32f;
+typedef double* CvVect64d;
+typedef double* CvMatr64d;
+
+typedef struct CvMatrix3
+{
+ float m[3][3];
+}
+CvMatrix3;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef float (CV_CDECL * CvDistanceFunction)( const float* a, const float* b, void* user_param );
+
+#ifdef __cplusplus
+}
+#endif
+
+typedef struct CvConDensation
+{
+ int MP;
+ int DP;
+ float* DynamMatr; /* Matrix of the linear Dynamics system */
+ float* State; /* Vector of State */
+ int SamplesNum; /* Number of the Samples */
+ float** flSamples; /* arr of the Sample Vectors */
+ float** flNewSamples; /* temporary array of the Sample Vectors */
+ float* flConfidence; /* Confidence for each Sample */
+ float* flCumulative; /* Cumulative confidence */
+ float* Temp; /* Temporary vector */
+ float* RandomSample; /* RandomVector to update sample set */
+ struct CvRandState* RandS; /* Array of structures to generate random vectors */
+}
+CvConDensation;
+
+/*
+standard Kalman filter (in G. Welch' and G. Bishop's notation):
+
+ x(k)=A*x(k-1)+B*u(k)+w(k) p(w)~N(0,Q)
+ z(k)=H*x(k)+v(k), p(v)~N(0,R)
+*/
+typedef struct CvKalman
+{
+ int MP; /* number of measurement vector dimensions */
+ int DP; /* number of state vector dimensions */
+ int CP; /* number of control vector dimensions */
+
+ /* backward compatibility fields */
+#if 1
+ float* PosterState; /* =state_pre->data.fl */
+ float* PriorState; /* =state_post->data.fl */
+ float* DynamMatr; /* =transition_matrix->data.fl */
+ float* MeasurementMatr; /* =measurement_matrix->data.fl */
+ float* MNCovariance; /* =measurement_noise_cov->data.fl */
+ float* PNCovariance; /* =process_noise_cov->data.fl */
+ float* KalmGainMatr; /* =gain->data.fl */
+ float* PriorErrorCovariance;/* =error_cov_pre->data.fl */
+ float* PosterErrorCovariance;/* =error_cov_post->data.fl */
+ float* Temp1; /* temp1->data.fl */
+ float* Temp2; /* temp2->data.fl */
+#endif
+
+ CvMat* state_pre; /* predicted state (x'(k)):
+ x(k)=A*x(k-1)+B*u(k) */
+ CvMat* state_post; /* corrected state (x(k)):
+ x(k)=x'(k)+K(k)*(z(k)-H*x'(k)) */
+ CvMat* transition_matrix; /* state transition matrix (A) */
+ CvMat* control_matrix; /* control matrix (B)
+ (it is not used if there is no control)*/
+ CvMat* measurement_matrix; /* measurement matrix (H) */
+ CvMat* process_noise_cov; /* process noise covariance matrix (Q) */
+ CvMat* measurement_noise_cov; /* measurement noise covariance matrix (R) */
+ CvMat* error_cov_pre; /* priori error estimate covariance matrix (P'(k)):
+ P'(k)=A*P(k-1)*At + Q)*/
+ CvMat* gain; /* Kalman gain matrix (K(k)):
+ K(k)=P'(k)*Ht*inv(H*P'(k)*Ht+R)*/
+ CvMat* error_cov_post; /* posteriori error estimate covariance matrix (P(k)):
+ P(k)=(I-K(k)*H)*P'(k) */
+ CvMat* temp1; /* temporary matrices */
+ CvMat* temp2;
+ CvMat* temp3;
+ CvMat* temp4;
+ CvMat* temp5;
+}
+CvKalman;
+
+
+/*********************** Haar-like Object Detection structures **************************/
+#define CV_HAAR_MAGIC_VAL 0x42500000
+#define CV_TYPE_NAME_HAAR "opencv-haar-classifier"
+
+#define CV_IS_HAAR_CLASSIFIER( haar ) \
+ ((haar) != NULL && \
+ (((const CvHaarClassifierCascade*)(haar))->flags & CV_MAGIC_MASK)==CV_HAAR_MAGIC_VAL)
+
+#define CV_HAAR_FEATURE_MAX 3
+
+typedef struct CvHaarFeature
+{
+ int tilted;
+ struct
+ {
+ CvRect r;
+ float weight;
+ } rect[CV_HAAR_FEATURE_MAX];
+}
+CvHaarFeature;
+
+typedef struct CvHaarClassifier
+{
+ int count;
+ CvHaarFeature* haar_feature;
+ float* threshold;
+ int* left;
+ int* right;
+ float* alpha;
+}
+CvHaarClassifier;
+
+typedef struct CvHaarStageClassifier
+{
+ int count;
+ float threshold;
+ CvHaarClassifier* classifier;
+
+ int next;
+ int child;
+ int parent;
+}
+CvHaarStageClassifier;
+
+typedef struct CvHidHaarClassifierCascade CvHidHaarClassifierCascade;
+
+typedef struct CvHaarClassifierCascade
+{
+ int flags;
+ int count;
+ CvSize orig_window_size;
+ CvSize real_window_size;
+ double scale;
+ CvHaarStageClassifier* stage_classifier;
+ CvHidHaarClassifierCascade* hid_cascade;
+}
+CvHaarClassifierCascade;
+
+typedef struct CvAvgComp
+{
+ CvRect rect;
+ int neighbors;
+}
+CvAvgComp;
+
+struct CvFeatureTree;
+
+#endif /*_CVTYPES_H_*/
+
+/* End of file. */
diff --git a/cv/src/_cv.h b/cv/src/_cv.h
new file mode 100644
index 0000000..4687bc3
--- /dev/null
+++ b/cv/src/_cv.h
@@ -0,0 +1,118 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _CV_INTERNAL_H_
+#define _CV_INTERNAL_H_
+
+#if defined _MSC_VER && _MSC_VER >= 1200
+ /* disable warnings related to inline functions */
+ #pragma warning( disable: 4711 4710 4514 )
+#endif
+
+#include "cv.h"
+#include "cxmisc.h"
+#include <math.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <float.h>
+
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+
+#ifdef __BORLANDC__
+ #define WIN32
+ #define CV_DLL
+ #undef _CV_ALWAYS_PROFILE_
+ #define _CV_ALWAYS_NO_PROFILE_
+#endif
+
+/* helper tables */
+extern const uchar icvSaturate8u_cv[];
+#define CV_FAST_CAST_8U(t) (assert(-256 <= (t) || (t) <= 512), icvSaturate8u_cv[(t)+256])
+#define CV_CALC_MIN_8U(a,b) (a) -= CV_FAST_CAST_8U((a) - (b))
+#define CV_CALC_MAX_8U(a,b) (a) += CV_FAST_CAST_8U((b) - (a))
+
+// -256.f ... 511.f
+extern const float icv8x32fTab_cv[];
+#define CV_8TO32F(x) icv8x32fTab_cv[(x)+256]
+
+// (-128.f)^2 ... (255.f)^2
+extern const float icv8x32fSqrTab[];
+#define CV_8TO32F_SQR(x) icv8x32fSqrTab[(x)+128]
+
+CV_INLINE CvDataType icvDepthToDataType( int type );
+CV_INLINE CvDataType icvDepthToDataType( int type )
+{
+ return (CvDataType)(
+ ((((int)cv8u)|((int)cv8s << 4)|((int)cv16u << 8)|
+ ((int)cv16s << 12)|((int)cv32s << 16)|((int)cv32f << 20)|
+ ((int)cv64f << 24)) >> CV_MAT_DEPTH(type)*4) & 15);
+}
+
+#define CV_HIST_DEFAULT_TYPE CV_32F
+
+CV_EXTERN_C_FUNCPTR( void (CV_CDECL * CvWriteNodeFunction)(void* seq,void* node) )
+
+#define _CvConvState CvFilterState
+
+typedef struct CvPyramid
+{
+ uchar **ptr;
+ CvSize *sz;
+ double *rate;
+ int *step;
+ uchar *state;
+ int level;
+}
+CvPyramid;
+
+#include "_cvipp.h"
+#include "_cvmatrix.h"
+#include "_cvgeom.h"
+#include "_cvimgproc.h"
+
+// default face cascade
+//extern const char* icvDefaultFaceCascade[];
+
+#endif /*_CV_INTERNAL_H_*/
diff --git a/cv/src/_cvgeom.h b/cv/src/_cvgeom.h
new file mode 100644
index 0000000..e2849aa
--- /dev/null
+++ b/cv/src/_cvgeom.h
@@ -0,0 +1,93 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _CV_GEOM_H_
+#define _CV_GEOM_H_
+
+/* Finds distance between two points */
+CV_INLINE float icvDistanceL2_32f( CvPoint2D32f pt1, CvPoint2D32f pt2 )
+{
+ float dx = pt2.x - pt1.x;
+ float dy = pt2.y - pt1.y;
+
+ return cvSqrt( dx*dx + dy*dy );
+}
+
+
+int icvIntersectLines( double x1, double dx1, double y1, double dy1,
+ double x2, double dx2, double y2, double dy2,
+ double* t2 );
+
+
+void icvCreateCenterNormalLine( CvSubdiv2DEdge edge, double* a, double* b, double* c );
+
+void icvIntersectLines3( double* a0, double* b0, double* c0,
+ double* a1, double* b1, double* c1,
+ CvPoint2D32f* point );
+
+
+#define _CV_BINTREE_LIST() \
+ struct _CvTrianAttr* prev_v; /* pointer to the parent element on the previous level of the tree */ \
+ struct _CvTrianAttr* next_v1; /* pointer to the child element on the next level of the tree */ \
+ struct _CvTrianAttr* next_v2; /* pointer to the child element on the next level of the tree */
+
+typedef struct _CvTrianAttr
+{
+ CvPoint pt; /* Coordinates x and y of the vertex which don't lie on the base line LMIAT */
+ char sign; /* sign of the triangle */
+ double area; /* area of the triangle */
+ double r1; /* The ratio of the height of triangle to the base of the triangle */
+ double r2; /* The ratio of the projection of the left side of the triangle on the base to the base */
+ _CV_BINTREE_LIST() /* structure double list */
+}
+_CvTrianAttr;
+
+
+/* curvature: 0 - 1-curvature, 1 - k-cosine curvature. */
+CvStatus icvApproximateChainTC89( CvChain* chain,
+ int header_size,
+ CvMemStorage* storage,
+ CvSeq** contour,
+ int method );
+
+#endif /*_IPCVGEOM_H_*/
+
+/* End of file. */
diff --git a/cv/src/_cvimgproc.h b/cv/src/_cvimgproc.h
new file mode 100644
index 0000000..bccb873
--- /dev/null
+++ b/cv/src/_cvimgproc.h
@@ -0,0 +1,123 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _CV_IMG_PROC_H_
+#define _CV_IMG_PROC_H_
+
+#define CV_COPY( dst, src, len, idx ) \
+ for( (idx) = 0; (idx) < (len); (idx)++) (dst)[idx] = (src)[idx]
+
+#define CV_SET( dst, val, len, idx ) \
+ for( (idx) = 0; (idx) < (len); (idx)++) (dst)[idx] = (val)
+
+/* performs convolution of 2d floating-point array with 3x1, 1x3 or separable 3x3 mask */
+void icvSepConvSmall3_32f( float* src, int src_step, float* dst, int dst_step,
+ CvSize src_size, const float* kx, const float* ky, float* buffer );
+
+typedef CvStatus (CV_STDCALL * CvSobelFixedIPPFunc)
+( const void* src, int srcstep, void* dst, int dststep, CvSize roi, int aperture );
+
+typedef CvStatus (CV_STDCALL * CvFilterFixedIPPFunc)
+( const void* src, int srcstep, void* dst, int dststep, CvSize roi );
+
+#undef CV_CALC_MIN
+#define CV_CALC_MIN(a, b) if((a) > (b)) (a) = (b)
+
+#undef CV_CALC_MAX
+#define CV_CALC_MAX(a, b) if((a) < (b)) (a) = (b)
+
+#define CV_MORPH_ALIGN 4
+
+#define CV_WHOLE 0
+#define CV_START 1
+#define CV_END 2
+#define CV_MIDDLE 4
+
+void
+icvCrossCorr( const CvArr* _img, const CvArr* _templ,
+ CvArr* _corr, CvPoint anchor=cvPoint(0,0) );
+
+CvStatus CV_STDCALL
+icvCopyReplicateBorder_8u( const uchar* src, int srcstep, CvSize srcroi,
+ uchar* dst, int dststep, CvSize dstroi,
+ int left, int right, int cn, const uchar* value = 0 );
+
+CvMat* icvIPPFilterInit( const CvMat* src, int stripe_size, CvSize ksize );
+
+int icvIPPFilterNextStripe( const CvMat* src, CvMat* temp, int y,
+ CvSize ksize, CvPoint anchor );
+
+int icvIPPSepFilter( const CvMat* src, CvMat* dst, const CvMat* kernelX,
+ const CvMat* kernelY, CvPoint anchor );
+
+#define ICV_WARP_SHIFT 10
+#define ICV_WARP_MASK ((1 << ICV_WARP_SHIFT) - 1)
+
+#define ICV_LINEAR_TAB_SIZE (ICV_WARP_MASK+1)
+extern float icvLinearCoeffs[(ICV_LINEAR_TAB_SIZE+1)*2];
+void icvInitLinearCoeffTab();
+
+#define ICV_CUBIC_TAB_SIZE (ICV_WARP_MASK+1)
+extern float icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE+1)*2];
+
+void icvInitCubicCoeffTab();
+
+CvStatus CV_STDCALL icvGetRectSubPix_8u_C1R
+( const uchar* src, int src_step, CvSize src_size,
+ uchar* dst, int dst_step, CvSize win_size, CvPoint2D32f center );
+CvStatus CV_STDCALL icvGetRectSubPix_8u32f_C1R
+( const uchar* src, int src_step, CvSize src_size,
+ float* dst, int dst_step, CvSize win_size, CvPoint2D32f center );
+CvStatus CV_STDCALL icvGetRectSubPix_32f_C1R
+( const float* src, int src_step, CvSize src_size,
+ float* dst, int dst_step, CvSize win_size, CvPoint2D32f center );
+
+CvStatus CV_STDCALL icvGetQuadrangleSubPix_8u_C1R
+( const uchar* src, int src_step, CvSize src_size,
+ uchar* dst, int dst_step, CvSize win_size, const float *matrix );
+CvStatus CV_STDCALL icvGetQuadrangleSubPix_8u32f_C1R
+( const uchar* src, int src_step, CvSize src_size,
+ float* dst, int dst_step, CvSize win_size, const float *matrix );
+CvStatus CV_STDCALL icvGetQuadrangleSubPix_32f_C1R
+( const float* src, int src_step, CvSize src_size,
+ float* dst, int dst_step, CvSize win_size, const float *matrix );
+
+#endif /*_CV_INTERNAL_H_*/
diff --git a/cv/src/_cvipp.h b/cv/src/_cvipp.h
new file mode 100644
index 0000000..47fd1c6
--- /dev/null
+++ b/cv/src/_cvipp.h
@@ -0,0 +1,759 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _CV_IPP_H_
+#define _CV_IPP_H_
+
+/****************************************************************************************\
+* Creating Borders *
+\****************************************************************************************/
+
+#define IPCV_COPY_BORDER( bordertype, flavor ) \
+IPCVAPI_EX( CvStatus, icvCopy##bordertype##Border_##flavor##R, \
+ "ippiCopy" #bordertype "Border_" #flavor "R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const void* pSrc, int srcStep, CvSize srcRoiSize, void* pDst, int dstStep, \
+ CvSize dstRoiSize, int topBorderHeight, int leftBorderWidth )) \
+ \
+IPCVAPI_EX( CvStatus, icvCopy##bordertype##Border_##flavor##IR, \
+ "ippiCopy" #bordertype "Border_" #flavor "IR", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const void* pSrc, int srcDstStep, CvSize srcRoiSize, \
+ CvSize dstRoiSize, int topBorderHeight, int leftBorderWidth ))
+
+IPCV_COPY_BORDER( Replicate, 8u_C1 )
+IPCV_COPY_BORDER( Replicate, 16s_C1 )
+IPCV_COPY_BORDER( Replicate, 8u_C3 )
+IPCV_COPY_BORDER( Replicate, 32s_C1 )
+IPCV_COPY_BORDER( Replicate, 16s_C3 )
+IPCV_COPY_BORDER( Replicate, 16s_C4 )
+IPCV_COPY_BORDER( Replicate, 32s_C3 )
+IPCV_COPY_BORDER( Replicate, 32s_C4 )
+
+/****************************************************************************************\
+* Moments *
+\****************************************************************************************/
+
+#define IPCV_MOMENTS( suffix, ipp_suffix, cn ) \
+IPCVAPI_EX( CvStatus, icvMoments##suffix##_C##cn##R, \
+"ippiMoments" #ipp_suffix "_C" #cn "R", CV_PLUGINS1(CV_PLUGIN_IPPI),\
+( const void* img, int step, CvSize size, void* momentstate ))
+
+IPCV_MOMENTS( _8u, 64f_8u, 1 )
+IPCV_MOMENTS( _32f, 64f_32f, 1 )
+
+#undef IPCV_MOMENTS
+
+IPCVAPI_EX( CvStatus, icvMomentInitAlloc_64f,
+ "ippiMomentInitAlloc_64f", CV_PLUGINS1(CV_PLUGIN_IPPI),
+ (void** momentstate, CvHintAlgorithm hint ))
+
+IPCVAPI_EX( CvStatus, icvMomentFree_64f,
+ "ippiMomentFree_64f", CV_PLUGINS1(CV_PLUGIN_IPPI),
+ (void* momentstate ))
+
+IPCVAPI_EX( CvStatus, icvGetSpatialMoment_64f,
+ "ippiGetSpatialMoment_64f", CV_PLUGINS1(CV_PLUGIN_IPPI),
+ (const void* momentstate, int mOrd, int nOrd,
+ int nChannel, CvPoint roiOffset, double* value ))
+
+/****************************************************************************************\
+* Background differencing *
+\****************************************************************************************/
+
+/////////////////////////////////// Accumulation /////////////////////////////////////////
+
+#define IPCV_ACCUM( flavor, arrtype, acctype ) \
+IPCVAPI_EX( CvStatus, icvAdd_##flavor##_C1IR, \
+ "ippiAdd_" #flavor "_C1IR", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const arrtype* src, int srcstep, acctype* dst, int dststep, CvSize size )) \
+IPCVAPI_EX( CvStatus, icvAddSquare_##flavor##_C1IR, \
+ "ippiAddSquare_" #flavor "_C1IR", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const arrtype* src, int srcstep, acctype* dst, int dststep, CvSize size )) \
+IPCVAPI_EX( CvStatus, icvAddProduct_##flavor##_C1IR, \
+ "ippiAddProduct_" #flavor "_C1IR", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const arrtype* src1, int srcstep1, const arrtype* src2, int srcstep2, \
+ acctype* dst, int dststep, CvSize size )) \
+IPCVAPI_EX( CvStatus, icvAddWeighted_##flavor##_C1IR, \
+ "ippiAddWeighted_" #flavor "_C1IR", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const arrtype* src, int srcstep, acctype* dst, int dststep, \
+ CvSize size, acctype alpha )) \
+ \
+IPCVAPI_EX( CvStatus, icvAdd_##flavor##_C1IMR, \
+ "ippiAdd_" #flavor "_C1IMR", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const arrtype* src, int srcstep, const uchar* mask, int maskstep, \
+ acctype* dst, int dststep, CvSize size )) \
+IPCVAPI_EX( CvStatus, icvAddSquare_##flavor##_C1IMR, \
+ "ippiAddSquare_" #flavor "_C1IMR", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const arrtype* src, int srcstep, const uchar* mask, int maskstep, \
+ acctype* dst, int dststep, CvSize size )) \
+IPCVAPI_EX( CvStatus, icvAddProduct_##flavor##_C1IMR, \
+ "ippiAddProduct_" #flavor "_C1IMR", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const arrtype* src1, int srcstep1, const arrtype* src2, int srcstep2, \
+ const uchar* mask, int maskstep, acctype* dst, int dststep, CvSize size )) \
+IPCVAPI_EX( CvStatus, icvAddWeighted_##flavor##_C1IMR, \
+ "ippiAddWeighted_" #flavor "_C1IMR", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const arrtype* src, int srcstep, const uchar* mask, int maskstep, \
+ acctype* dst, int dststep, CvSize size, acctype alpha )) \
+ \
+IPCVAPI_EX( CvStatus, icvAdd_##flavor##_C3IMR, \
+ "ippiAdd_" #flavor "_C3IMR", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const arrtype* src, int srcstep, const uchar* mask, int maskstep, \
+ acctype* dst, int dststep, CvSize size )) \
+IPCVAPI_EX( CvStatus, icvAddSquare_##flavor##_C3IMR, \
+ "ippiAddSquare_" #flavor "_C3IMR", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const arrtype* src, int srcstep, const uchar* mask, int maskstep, \
+ acctype* dst, int dststep, CvSize size )) \
+IPCVAPI_EX( CvStatus, icvAddProduct_##flavor##_C3IMR, \
+ "ippiAddProduct_" #flavor "_C3IMR", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const arrtype* src1, int srcstep1, const arrtype* src2, int srcstep2, \
+ const uchar* mask, int maskstep, acctype* dst, int dststep, CvSize size )) \
+IPCVAPI_EX( CvStatus, icvAddWeighted_##flavor##_C3IMR, \
+ "ippiAddWeighted_" #flavor "_C3IMR", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const arrtype* src, int srcstep, const uchar* mask, int maskstep, \
+ acctype* dst, int dststep, CvSize size, acctype alpha ))
+
+IPCV_ACCUM( 8u32f, uchar, float )
+IPCV_ACCUM( 32f, float, float )
+
+#undef IPCV_ACCUM
+
+/****************************************************************************************\
+* Pyramids *
+\****************************************************************************************/
+
+IPCVAPI_EX( CvStatus, icvPyrDownGetBufSize_Gauss5x5,
+ "ippiPyrDownGetBufSize_Gauss5x5", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( int roiWidth, CvDataType dataType, int channels, int* bufSize ))
+
+IPCVAPI_EX( CvStatus, icvPyrUpGetBufSize_Gauss5x5,
+ "ippiPyrUpGetBufSize_Gauss5x5", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( int roiWidth, CvDataType dataType, int channels, int* bufSize ))
+
+#define ICV_PYRDOWN( flavor, cn ) \
+IPCVAPI_EX( CvStatus, icvPyrDown_Gauss5x5_##flavor##_C##cn##R, \
+"ippiPyrDown_Gauss5x5_" #flavor "_C" #cn "R", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+( const void* pSrc, int srcStep, void* pDst, int dstStep, \
+ CvSize roiSize, void* pBuffer ))
+
+#define ICV_PYRUP( flavor, cn ) \
+IPCVAPI_EX( CvStatus, icvPyrUp_Gauss5x5_##flavor##_C##cn##R, \
+"ippiPyrUp_Gauss5x5_" #flavor "_C" #cn "R", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+( const void* pSrc, int srcStep, void* pDst, int dstStep, \
+ CvSize roiSize, void* pBuffer ))
+
+ICV_PYRDOWN( 8u, 1 )
+ICV_PYRDOWN( 8u, 3 )
+ICV_PYRDOWN( 32f, 1 )
+ICV_PYRDOWN( 32f, 3 )
+
+ICV_PYRUP( 8u, 1 )
+ICV_PYRUP( 8u, 3 )
+ICV_PYRUP( 32f, 1 )
+ICV_PYRUP( 32f, 3 )
+
+#undef ICV_PYRDOWN
+#undef ICV_PYRUP
+
+/****************************************************************************************\
+* Geometric Transformations *
+\****************************************************************************************/
+
+#define IPCV_RESIZE( flavor, cn ) \
+IPCVAPI_EX( CvStatus, icvResize_##flavor##_C##cn##R, \
+ "ippiResize_" #flavor "_C" #cn "R", CV_PLUGINS1(CV_PLUGIN_IPPI),\
+ (const void* src, CvSize srcsize, int srcstep, CvRect srcroi, \
+ void* dst, int dststep, CvSize dstroi, \
+ double xfactor, double yfactor, int interpolation ))
+
+IPCV_RESIZE( 8u, 1 )
+IPCV_RESIZE( 8u, 3 )
+IPCV_RESIZE( 8u, 4 )
+
+IPCV_RESIZE( 16u, 1 )
+IPCV_RESIZE( 16u, 3 )
+IPCV_RESIZE( 16u, 4 )
+
+IPCV_RESIZE( 32f, 1 )
+IPCV_RESIZE( 32f, 3 )
+IPCV_RESIZE( 32f, 4 )
+
+#undef IPCV_RESIZE
+
+#define IPCV_WARPAFFINE_BACK( flavor, cn ) \
+IPCVAPI_EX( CvStatus, icvWarpAffineBack_##flavor##_C##cn##R, \
+ "ippiWarpAffineBack_" #flavor "_C" #cn "R", CV_PLUGINS1(CV_PLUGIN_IPPI),\
+ (const void* src, CvSize srcsize, int srcstep, CvRect srcroi, \
+ void* dst, int dststep, CvRect dstroi, \
+ const double* coeffs, int interpolate ))
+
+IPCV_WARPAFFINE_BACK( 8u, 1 )
+IPCV_WARPAFFINE_BACK( 8u, 3 )
+IPCV_WARPAFFINE_BACK( 8u, 4 )
+
+IPCV_WARPAFFINE_BACK( 32f, 1 )
+IPCV_WARPAFFINE_BACK( 32f, 3 )
+IPCV_WARPAFFINE_BACK( 32f, 4 )
+
+#undef IPCV_WARPAFFINE_BACK
+
+#define IPCV_WARPPERSPECTIVE_BACK( flavor, cn ) \
+IPCVAPI_EX( CvStatus, icvWarpPerspectiveBack_##flavor##_C##cn##R, \
+ "ippiWarpPerspectiveBack_" #flavor "_C" #cn "R", CV_PLUGINS1(CV_PLUGIN_IPPI),\
+ (const void* src, CvSize srcsize, int srcstep, CvRect srcroi, \
+ void* dst, int dststep, CvRect dstroi, \
+ const double* coeffs, int interpolate ))
+
+IPCV_WARPPERSPECTIVE_BACK( 8u, 1 )
+IPCV_WARPPERSPECTIVE_BACK( 8u, 3 )
+IPCV_WARPPERSPECTIVE_BACK( 8u, 4 )
+
+IPCV_WARPPERSPECTIVE_BACK( 32f, 1 )
+IPCV_WARPPERSPECTIVE_BACK( 32f, 3 )
+IPCV_WARPPERSPECTIVE_BACK( 32f, 4 )
+
+#undef IPCV_WARPPERSPECTIVE_BACK
+
+
+#define IPCV_WARPPERSPECTIVE( flavor, cn ) \
+IPCVAPI_EX( CvStatus, icvWarpPerspective_##flavor##_C##cn##R, \
+ "ippiWarpPerspective_" #flavor "_C" #cn "R", CV_PLUGINS1(CV_PLUGIN_IPPI),\
+ (const void* src, CvSize srcsize, int srcstep, CvRect srcroi, \
+ void* dst, int dststep, CvRect dstroi, \
+ const double* coeffs, int interpolate ))
+
+IPCV_WARPPERSPECTIVE( 8u, 1 )
+IPCV_WARPPERSPECTIVE( 8u, 3 )
+IPCV_WARPPERSPECTIVE( 8u, 4 )
+
+IPCV_WARPPERSPECTIVE( 32f, 1 )
+IPCV_WARPPERSPECTIVE( 32f, 3 )
+IPCV_WARPPERSPECTIVE( 32f, 4 )
+
+#undef IPCV_WARPPERSPECTIVE
+
+#define IPCV_REMAP( flavor, cn ) \
+IPCVAPI_EX( CvStatus, icvRemap_##flavor##_C##cn##R, \
+ "ippiRemap_" #flavor "_C" #cn "R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const void* src, CvSize srcsize, int srcstep, CvRect srcroi, \
+ const float* xmap, int xmapstep, const float* ymap, int ymapstep, \
+ void* dst, int dststep, CvSize dstsize, int interpolation ))
+
+IPCV_REMAP( 8u, 1 )
+IPCV_REMAP( 8u, 3 )
+IPCV_REMAP( 8u, 4 )
+
+IPCV_REMAP( 32f, 1 )
+IPCV_REMAP( 32f, 3 )
+IPCV_REMAP( 32f, 4 )
+
+#undef IPCV_REMAP
+
+/****************************************************************************************\
+* Morphology *
+\****************************************************************************************/
+
+#define IPCV_MORPHOLOGY( minmaxtype, morphtype, flavor, cn ) \
+IPCVAPI_EX( CvStatus, icv##morphtype##Rect_##flavor##_C##cn##R, \
+ "ippiFilter" #minmaxtype "BorderReplicate_" #flavor "_C" #cn "R", \
+ CV_PLUGINS1(CV_PLUGIN_IPPCV), ( const void* src, int srcstep, void* dst, \
+ int dststep, CvSize roi, CvSize esize, CvPoint anchor, void* buffer )) \
+IPCVAPI_EX( CvStatus, icv##morphtype##Rect_GetBufSize_##flavor##_C##cn##R, \
+ "ippiFilter" #minmaxtype "GetBufferSize_" #flavor "_C" #cn "R", \
+ CV_PLUGINS1(CV_PLUGIN_IPPCV), ( int width, CvSize esize, int* bufsize )) \
+ \
+IPCVAPI_EX( CvStatus, icv##morphtype##_##flavor##_C##cn##R, \
+ "ippi" #morphtype "BorderReplicate_" #flavor "_C" #cn "R", \
+ CV_PLUGINS1(CV_PLUGIN_IPPCV), ( const void* src, int srcstep, \
+ void* dst, int dststep, CvSize roi, int bordertype, void* morphstate ))
+
+IPCV_MORPHOLOGY( Min, Erode, 8u, 1 )
+IPCV_MORPHOLOGY( Min, Erode, 8u, 3 )
+IPCV_MORPHOLOGY( Min, Erode, 8u, 4 )
+IPCV_MORPHOLOGY( Min, Erode, 16u, 1 )
+IPCV_MORPHOLOGY( Min, Erode, 16u, 3 )
+IPCV_MORPHOLOGY( Min, Erode, 16u, 4 )
+IPCV_MORPHOLOGY( Min, Erode, 32f, 1 )
+IPCV_MORPHOLOGY( Min, Erode, 32f, 3 )
+IPCV_MORPHOLOGY( Min, Erode, 32f, 4 )
+IPCV_MORPHOLOGY( Max, Dilate, 8u, 1 )
+IPCV_MORPHOLOGY( Max, Dilate, 8u, 3 )
+IPCV_MORPHOLOGY( Max, Dilate, 8u, 4 )
+IPCV_MORPHOLOGY( Max, Dilate, 16u, 1 )
+IPCV_MORPHOLOGY( Max, Dilate, 16u, 3 )
+IPCV_MORPHOLOGY( Max, Dilate, 16u, 4 )
+IPCV_MORPHOLOGY( Max, Dilate, 32f, 1 )
+IPCV_MORPHOLOGY( Max, Dilate, 32f, 3 )
+IPCV_MORPHOLOGY( Max, Dilate, 32f, 4 )
+
+#undef IPCV_MORPHOLOGY
+
+#define IPCV_MORPHOLOGY_INIT_ALLOC( flavor, cn ) \
+IPCVAPI_EX( CvStatus, icvMorphInitAlloc_##flavor##_C##cn##R, \
+ "ippiMorphologyInitAlloc_" #flavor "_C" #cn "R", \
+ CV_PLUGINS1(CV_PLUGIN_IPPCV), ( int width, const uchar* element, \
+ CvSize esize, CvPoint anchor, void** morphstate ))
+
+IPCV_MORPHOLOGY_INIT_ALLOC( 8u, 1 )
+IPCV_MORPHOLOGY_INIT_ALLOC( 8u, 3 )
+IPCV_MORPHOLOGY_INIT_ALLOC( 8u, 4 )
+IPCV_MORPHOLOGY_INIT_ALLOC( 16u, 1 )
+IPCV_MORPHOLOGY_INIT_ALLOC( 16u, 3 )
+IPCV_MORPHOLOGY_INIT_ALLOC( 16u, 4 )
+IPCV_MORPHOLOGY_INIT_ALLOC( 32f, 1 )
+IPCV_MORPHOLOGY_INIT_ALLOC( 32f, 3 )
+IPCV_MORPHOLOGY_INIT_ALLOC( 32f, 4 )
+
+#undef IPCV_MORPHOLOGY_INIT_ALLOC
+
+IPCVAPI_EX( CvStatus, icvMorphFree, "ippiMorphologyFree",
+ CV_PLUGINS1(CV_PLUGIN_IPPCV), ( void* morphstate ))
+
+
+/****************************************************************************************\
+* Smoothing Filters *
+\****************************************************************************************/
+
+#define IPCV_FILTER_MEDIAN( flavor, cn ) \
+IPCVAPI_EX( CvStatus, icvFilterMedian_##flavor##_C##cn##R, \
+ "ippiFilterMedian_" #flavor "_C" #cn "R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const void* src, int srcstep, void* dst, int dststep, \
+ CvSize roi, CvSize ksize, CvPoint anchor ))
+
+IPCV_FILTER_MEDIAN( 8u, 1 )
+IPCV_FILTER_MEDIAN( 8u, 3 )
+IPCV_FILTER_MEDIAN( 8u, 4 )
+
+#define IPCV_FILTER_BOX( flavor, cn ) \
+IPCVAPI_EX( CvStatus, icvFilterBox_##flavor##_C##cn##R, \
+ "ippiFilterBox_" #flavor "_C" #cn "R", 0/*CV_PLUGINS1(CV_PLUGIN_IPPI)*/,\
+ ( const void* src, int srcstep, void* dst, int dststep, \
+ CvSize roi, CvSize ksize, CvPoint anchor ))
+
+IPCV_FILTER_BOX( 8u, 1 )
+IPCV_FILTER_BOX( 8u, 3 )
+IPCV_FILTER_BOX( 8u, 4 )
+IPCV_FILTER_BOX( 32f, 1 )
+IPCV_FILTER_BOX( 32f, 3 )
+IPCV_FILTER_BOX( 32f, 4 )
+
+#undef IPCV_FILTER_BOX
+
+/****************************************************************************************\
+* Derivative Filters *
+\****************************************************************************************/
+
+#define IPCV_FILTER_SOBEL_BORDER( suffix, flavor, srctype ) \
+IPCVAPI_EX( CvStatus, icvFilterSobel##suffix##GetBufSize_##flavor##_C1R, \
+ "ippiFilterSobel" #suffix "GetBufferSize_" #flavor "_C1R", \
+ CV_PLUGINS1(CV_PLUGIN_IPPCV), ( CvSize roi, int masksize, int* buffersize )) \
+IPCVAPI_EX( CvStatus, icvFilterSobel##suffix##Border_##flavor##_C1R, \
+ "ippiFilterSobel" #suffix "Border_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const void* src, int srcstep, void* dst, int dststep, CvSize roi, int masksize, \
+ int bordertype, srctype bordervalue, void* buffer ))
+
+IPCV_FILTER_SOBEL_BORDER( NegVert, 8u16s, uchar )
+IPCV_FILTER_SOBEL_BORDER( Horiz, 8u16s, uchar )
+IPCV_FILTER_SOBEL_BORDER( VertSecond, 8u16s, uchar )
+IPCV_FILTER_SOBEL_BORDER( HorizSecond, 8u16s, uchar )
+IPCV_FILTER_SOBEL_BORDER( Cross, 8u16s, uchar )
+
+IPCV_FILTER_SOBEL_BORDER( NegVert, 32f, float )
+IPCV_FILTER_SOBEL_BORDER( Horiz, 32f, float )
+IPCV_FILTER_SOBEL_BORDER( VertSecond, 32f, float )
+IPCV_FILTER_SOBEL_BORDER( HorizSecond, 32f, float )
+IPCV_FILTER_SOBEL_BORDER( Cross, 32f, float )
+
+#undef IPCV_FILTER_SOBEL_BORDER
+
+#define IPCV_FILTER_SCHARR_BORDER( suffix, flavor, srctype ) \
+IPCVAPI_EX( CvStatus, icvFilterScharr##suffix##GetBufSize_##flavor##_C1R, \
+ "ippiFilterScharr" #suffix "GetBufferSize_" #flavor "_C1R", \
+ CV_PLUGINS1(CV_PLUGIN_IPPCV), ( CvSize roi, int* buffersize )) \
+IPCVAPI_EX( CvStatus, icvFilterScharr##suffix##Border_##flavor##_C1R, \
+ "ippiFilterScharr" #suffix "Border_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const void* src, int srcstep, void* dst, int dststep, CvSize roi, \
+ int bordertype, srctype bordervalue, void* buffer ))
+
+IPCV_FILTER_SCHARR_BORDER( Vert, 8u16s, uchar )
+IPCV_FILTER_SCHARR_BORDER( Horiz, 8u16s, uchar )
+
+IPCV_FILTER_SCHARR_BORDER( Vert, 32f, float )
+IPCV_FILTER_SCHARR_BORDER( Horiz, 32f, float )
+
+#undef IPCV_FILTER_SCHARR_BORDER
+
+
+#define IPCV_FILTER_LAPLACIAN_BORDER( flavor, srctype ) \
+IPCVAPI_EX( CvStatus, icvFilterLaplacianGetBufSize_##flavor##_C1R, \
+ "ippiFilterLaplacianGetBufferSize_" #flavor "_C1R", \
+ CV_PLUGINS1(CV_PLUGIN_IPPCV), ( CvSize roi, int masksize, int* buffersize )) \
+IPCVAPI_EX( CvStatus, icvFilterLaplacianBorder_##flavor##_C1R, \
+ "ippiFilterLaplacianBorder_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const void* src, int srcstep, void* dst, int dststep, CvSize roi, int masksize, \
+ int bordertype, srctype bordervalue, void* buffer ))
+
+IPCV_FILTER_LAPLACIAN_BORDER( 8u16s, uchar )
+IPCV_FILTER_LAPLACIAN_BORDER( 32f, float )
+
+#undef IPCV_FILTER_LAPLACIAN_BORDER
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define IPCV_FILTER_SOBEL( suffix, ipp_suffix, flavor ) \
+IPCVAPI_EX( CvStatus, icvFilterSobel##suffix##_##flavor##_C1R, \
+ "ippiFilterSobel" #ipp_suffix "_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const void* src, int srcstep, void* dst, int dststep, CvSize roi, int aperture ))
+
+IPCV_FILTER_SOBEL( Vert, Vert, 8u16s )
+IPCV_FILTER_SOBEL( Horiz, Horiz, 8u16s )
+IPCV_FILTER_SOBEL( VertSecond, VertSecond, 8u16s )
+IPCV_FILTER_SOBEL( HorizSecond, HorizSecond, 8u16s )
+IPCV_FILTER_SOBEL( Cross, Cross, 8u16s )
+
+IPCV_FILTER_SOBEL( Vert, VertMask, 32f )
+IPCV_FILTER_SOBEL( Horiz, HorizMask, 32f )
+IPCV_FILTER_SOBEL( VertSecond, VertSecond, 32f )
+IPCV_FILTER_SOBEL( HorizSecond, HorizSecond, 32f )
+IPCV_FILTER_SOBEL( Cross, Cross, 32f )
+
+#undef IPCV_FILTER_SOBEL
+
+#define IPCV_FILTER_SCHARR( suffix, ipp_suffix, flavor ) \
+IPCVAPI_EX( CvStatus, icvFilterScharr##suffix##_##flavor##_C1R, \
+ "ippiFilterScharr" #ipp_suffix "_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const void* src, int srcstep, void* dst, int dststep, CvSize roi ))
+
+IPCV_FILTER_SCHARR( Vert, Vert, 8u16s )
+IPCV_FILTER_SCHARR( Horiz, Horiz, 8u16s )
+IPCV_FILTER_SCHARR( Vert, Vert, 32f )
+IPCV_FILTER_SCHARR( Horiz, Horiz, 32f )
+
+#undef IPCV_FILTER_SCHARR
+
+/****************************************************************************************\
+* Generic Filters *
+\****************************************************************************************/
+
+#define IPCV_FILTER( suffix, ipp_suffix, cn, ksizetype, anchortype ) \
+IPCVAPI_EX( CvStatus, icvFilter##suffix##_C##cn##R, \
+ "ippiFilter" #ipp_suffix "_C" #cn "R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const void* src, int srcstep, void* dst, int dststep, CvSize size, \
+ const float* kernel, ksizetype ksize, anchortype anchor ))
+
+IPCV_FILTER( _8u, 32f_8u, 1, CvSize, CvPoint )
+IPCV_FILTER( _8u, 32f_8u, 3, CvSize, CvPoint )
+IPCV_FILTER( _8u, 32f_8u, 4, CvSize, CvPoint )
+
+IPCV_FILTER( _16s, 32f_16s, 1, CvSize, CvPoint )
+IPCV_FILTER( _16s, 32f_16s, 3, CvSize, CvPoint )
+IPCV_FILTER( _16s, 32f_16s, 4, CvSize, CvPoint )
+
+IPCV_FILTER( _32f, _32f, 1, CvSize, CvPoint )
+IPCV_FILTER( _32f, _32f, 3, CvSize, CvPoint )
+IPCV_FILTER( _32f, _32f, 4, CvSize, CvPoint )
+
+IPCV_FILTER( Column_8u, Column32f_8u, 1, int, int )
+IPCV_FILTER( Column_8u, Column32f_8u, 3, int, int )
+IPCV_FILTER( Column_8u, Column32f_8u, 4, int, int )
+
+IPCV_FILTER( Column_16s, Column32f_16s, 1, int, int )
+IPCV_FILTER( Column_16s, Column32f_16s, 3, int, int )
+IPCV_FILTER( Column_16s, Column32f_16s, 4, int, int )
+
+IPCV_FILTER( Column_32f, Column_32f, 1, int, int )
+IPCV_FILTER( Column_32f, Column_32f, 3, int, int )
+IPCV_FILTER( Column_32f, Column_32f, 4, int, int )
+
+IPCV_FILTER( Row_8u, Row32f_8u, 1, int, int )
+IPCV_FILTER( Row_8u, Row32f_8u, 3, int, int )
+IPCV_FILTER( Row_8u, Row32f_8u, 4, int, int )
+
+IPCV_FILTER( Row_16s, Row32f_16s, 1, int, int )
+IPCV_FILTER( Row_16s, Row32f_16s, 3, int, int )
+IPCV_FILTER( Row_16s, Row32f_16s, 4, int, int )
+
+IPCV_FILTER( Row_32f, Row_32f, 1, int, int )
+IPCV_FILTER( Row_32f, Row_32f, 3, int, int )
+IPCV_FILTER( Row_32f, Row_32f, 4, int, int )
+
+#undef IPCV_FILTER
+
+
+/****************************************************************************************\
+* Color Transformations *
+\****************************************************************************************/
+
+#define IPCV_COLOR( funcname, ipp_funcname, flavor ) \
+IPCVAPI_EX( CvStatus, icv##funcname##_##flavor##_C3R, \
+ "ippi" #ipp_funcname "_" #flavor "_C3R," \
+ "ippi" #ipp_funcname "_" #flavor "_C3R", \
+ CV_PLUGINS2(CV_PLUGIN_IPPI,CV_PLUGIN_IPPCC), \
+ ( const void* src, int srcstep, void* dst, int dststep, CvSize size ))
+
+IPCV_COLOR( RGB2XYZ, RGBToXYZ, 8u )
+IPCV_COLOR( RGB2XYZ, RGBToXYZ, 16u )
+IPCV_COLOR( RGB2XYZ, RGBToXYZ, 32f )
+IPCV_COLOR( XYZ2RGB, XYZToRGB, 8u )
+IPCV_COLOR( XYZ2RGB, XYZToRGB, 16u )
+IPCV_COLOR( XYZ2RGB, XYZToRGB, 32f )
+
+IPCV_COLOR( RGB2HSV, RGBToHSV, 8u )
+IPCV_COLOR( HSV2RGB, HSVToRGB, 8u )
+
+IPCV_COLOR( RGB2HLS, RGBToHLS, 8u )
+IPCV_COLOR( RGB2HLS, RGBToHLS, 32f )
+IPCV_COLOR( HLS2RGB, HLSToRGB, 8u )
+IPCV_COLOR( HLS2RGB, HLSToRGB, 32f )
+
+IPCV_COLOR( BGR2Lab, BGRToLab, 8u )
+IPCV_COLOR( Lab2BGR, LabToBGR, 8u )
+
+IPCV_COLOR( RGB2Luv, RGBToLUV, 8u )
+/*IPCV_COLOR( RGB2Luv, RGBToLUV, 32f )*/
+IPCV_COLOR( Luv2RGB, LUVToRGB, 8u )
+/*IPCV_COLOR( Luv2RGB, LUVToRGB, 32f )*/
+
+/****************************************************************************************\
+* Motion Templates *
+\****************************************************************************************/
+
+IPCVAPI_EX( CvStatus, icvUpdateMotionHistory_8u32f_C1IR,
+ "ippiUpdateMotionHistory_8u32f_C1IR", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( const uchar* silIm, int silStep, float* mhiIm, int mhiStep,
+ CvSize size,float timestamp, float mhi_duration ))
+
+/****************************************************************************************\
+* Template Matching *
+\****************************************************************************************/
+
+#define ICV_MATCHTEMPLATE( flavor, arrtype ) \
+IPCVAPI_EX( CvStatus, icvCrossCorrValid_Norm_##flavor##_C1R, \
+ "ippiCrossCorrValid_Norm_" #flavor "_C1R", \
+ CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const arrtype* pSrc, int srcStep, CvSize srcRoiSize, \
+ const arrtype* pTpl, int tplStep, CvSize tplRoiSize, \
+ float* pDst, int dstStep )) \
+IPCVAPI_EX( CvStatus, icvCrossCorrValid_NormLevel_##flavor##_C1R, \
+ "ippiCrossCorrValid_NormLevel_" #flavor "_C1R", \
+ CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const arrtype* pSrc, int srcStep, CvSize srcRoiSize, \
+ const arrtype* pTpl, int tplStep, CvSize tplRoiSize, \
+ float* pDst, int dstStep )) \
+IPCVAPI_EX( CvStatus, icvSqrDistanceValid_Norm_##flavor##_C1R, \
+ "ippiSqrDistanceValid_Norm_" #flavor "_C1R", \
+ CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const arrtype* pSrc, int srcStep, CvSize srcRoiSize, \
+ const arrtype* pTpl, int tplStep, CvSize tplRoiSize, \
+ float* pDst, int dstStep ))
+
+ICV_MATCHTEMPLATE( 8u32f, uchar )
+ICV_MATCHTEMPLATE( 32f, float )
+
+/****************************************************************************************/
+/* Distance Transform */
+/****************************************************************************************/
+
+IPCVAPI_EX(CvStatus, icvDistanceTransform_3x3_8u32f_C1R,
+ "ippiDistanceTransform_3x3_8u32f_C1R", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( const uchar* pSrc, int srcStep, float* pDst,
+ int dstStep, CvSize roiSize, const float* pMetrics ))
+
+IPCVAPI_EX(CvStatus, icvDistanceTransform_5x5_8u32f_C1R,
+ "ippiDistanceTransform_5x5_8u32f_C1R", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( const uchar* pSrc, int srcStep, float* pDst,
+ int dstStep, CvSize roiSize, const float* pMetrics ))
+
+IPCVAPI_EX(CvStatus, icvDistanceTransform_3x3_8u_C1IR,
+ "ippiDistanceTransform_3x3_8u_C1IR", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( uchar* pSrc, int srcStep, CvSize roiSize, const int* pMetrics ))
+
+IPCVAPI_EX(CvStatus, icvDistanceTransform_3x3_8u_C1R,
+ "ippiDistanceTransform_3x3_8u_C1R", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( const uchar* pSrc, int srcStep, uchar* pDst,
+ int dstStep, CvSize roiSize, const int* pMetrics ))
+
+/****************************************************************************************\
+* Thresholding functions *
+\****************************************************************************************/
+
+IPCVAPI_EX( CvStatus, icvCompareC_8u_C1R_cv,
+ "ippiCompareC_8u_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI),
+ ( const uchar* src1, int srcstep1, uchar scalar,
+ uchar* dst, int dststep, CvSize size, int cmp_op ))
+IPCVAPI_EX( CvStatus, icvAndC_8u_C1R,
+ "ippiAndC_8u_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI),
+ ( const uchar* src1, int srcstep1, uchar scalar,
+ uchar* dst, int dststep, CvSize size ))
+IPCVAPI_EX( CvStatus, icvThreshold_GTVal_8u_C1R,
+ "ippiThreshold_GTVal_8u_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI),
+ ( const uchar* pSrc, int srcstep, uchar* pDst, int dststep,
+ CvSize size, uchar threshold, uchar value ))
+IPCVAPI_EX( CvStatus, icvThreshold_GTVal_32f_C1R,
+ "ippiThreshold_GTVal_32f_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI),
+ ( const float* pSrc, int srcstep, float* pDst, int dststep,
+ CvSize size, float threshold, float value ))
+IPCVAPI_EX( CvStatus, icvThreshold_LTVal_8u_C1R,
+ "ippiThreshold_LTVal_8u_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI),
+ ( const uchar* pSrc, int srcstep, uchar* pDst, int dststep,
+ CvSize size, uchar threshold, uchar value ))
+IPCVAPI_EX( CvStatus, icvThreshold_LTVal_32f_C1R,
+ "ippiThreshold_LTVal_32f_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI),
+ ( const float* pSrc, int srcstep, float* pDst, int dststep,
+ CvSize size, float threshold, float value ))
+
+/****************************************************************************************\
+* Canny Edge Detector *
+\****************************************************************************************/
+
+IPCVAPI_EX( CvStatus, icvCannyGetSize, "ippiCannyGetSize", 0/*CV_PLUGINS1(CV_PLUGIN_IPPCV)*/,
+ ( CvSize roiSize, int* bufferSize ))
+
+IPCVAPI_EX( CvStatus, icvCanny_16s8u_C1R, "ippiCanny_16s8u_C1R", 0/*CV_PLUGINS1(CV_PLUGIN_IPPCV)*/,
+ ( const short* pSrcDx, int srcDxStep, const short* pSrcDy, int srcDyStep,
+ uchar* pDstEdges, int dstEdgeStep, CvSize roiSize, float lowThresh,
+ float highThresh, void* pBuffer ))
+
+
+/****************************************************************************************\
+* Radial Distortion Removal *
+\****************************************************************************************/
+
+IPCVAPI_EX( CvStatus, icvUndistortGetSize, "ippiUndistortGetSize",
+ CV_PLUGINS1(CV_PLUGIN_IPPCV), ( CvSize roiSize, int *pBufsize ))
+
+IPCVAPI_EX( CvStatus, icvCreateMapCameraUndistort_32f_C1R,
+ "ippiCreateMapCameraUndistort_32f_C1R", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ (float *pxMap, int xStep, float *pyMap, int yStep, CvSize roiSize,
+ float fx, float fy, float cx, float cy, float k1, float k2,
+ float p1, float p2, uchar *pBuffer ))
+
+#define ICV_UNDISTORT_RADIAL( flavor, cn, arrtype ) \
+IPCVAPI_EX( CvStatus, icvUndistortRadial_##flavor##_C##cn##R, \
+ "ippiUndistortRadial_" #flavor "_C" #cn "R", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const arrtype* pSrc, int srcStep, uchar* pDst, int dstStep, CvSize roiSize, \
+ float fx, float fy, float cx, float cy, float k1, float k2, uchar *pBuffer ))
+
+ICV_UNDISTORT_RADIAL( 8u, 1, uchar )
+ICV_UNDISTORT_RADIAL( 8u, 3, uchar )
+
+#undef ICV_UNDISTORT_RADIAL
+
+/****************************************************************************************\
+* Subpixel-accurate rectangle extraction *
+\****************************************************************************************/
+
+#define ICV_COPY_SUBPIX( flavor, cn, srctype, dsttype ) \
+IPCVAPI_EX( CvStatus, icvCopySubpix_##flavor##_C##cn##R, \
+ "ippiCopySubpix_" #flavor "_C" #cn "R", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+ ( const srctype* pSrc, int srcStep, dsttype* pDst, int dstStep, \
+ CvSize size, float dx, float dy ))
+
+ICV_COPY_SUBPIX( 8u, 1, uchar, uchar )
+ICV_COPY_SUBPIX( 8u32f, 1, uchar, float )
+//ICV_COPY_SUBPIX( 32f, 1, float, float )
+
+IPCVAPI_EX( CvStatus, icvCopySubpix_32f_C1R,
+ "ippiCopySubpix_32f_C1R", 0,
+ ( const float* pSrc, int srcStep, float* pDst, int dstStep,
+ CvSize size, float dx, float dy ))
+
+#undef ICV_COPY_SUBPIX
+
+/****************************************************************************************\
+* Lucas-Kanade Optical Flow *
+\****************************************************************************************/
+
+IPCVAPI_EX( CvStatus, icvOpticalFlowPyrLKInitAlloc_8u_C1R,
+ "ippiOpticalFlowPyrLKInitAlloc_8u_C1R", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( void** ppState, CvSize roiSize, int winSize, int hint ))
+
+IPCVAPI_EX( CvStatus, icvOpticalFlowPyrLKFree_8u_C1R,
+ "ippiOpticalFlowPyrLKFree_8u_C1R", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( void* pState ))
+
+IPCVAPI_EX( CvStatus, icvOpticalFlowPyrLK_8u_C1R,
+ "ippiOpticalFlowPyrLK_8u_C1R", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( CvPyramid *pPyr1, CvPyramid *pPyr2,
+ const float *pPrev, float* pNext, char *pStatus,
+ float *pError, int numFeat, int winSize,
+ int maxLev, int maxIter, float threshold, void* state ))
+
+
+/****************************************************************************************\
+* Haar Object Detector *
+\****************************************************************************************/
+
+IPCVAPI_EX( CvStatus, icvIntegral_8u32s_C1R,
+ "ippiIntegral_8u32s_C1R", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( const uchar* pSrc, int srcStep, int* pDst, int dstStep,
+ CvSize roiSize, int val ))
+
+IPCVAPI_EX( CvStatus, icvSqrIntegral_8u32s64f_C1R,
+ "ippiSqrIntegral_8u32s64f_C1R", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( const uchar* pSrc, int srcStep,
+ int* pDst, int dstStep, double* pSqr, int sqrStep,
+ CvSize roiSize, int val, double valSqr ))
+
+IPCVAPI_EX( CvStatus, icvRectStdDev_32f_C1R,
+ "ippiRectStdDev_32f_C1R", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( const float* pSrc, int srcStep,
+ const double* pSqr, int sqrStep, float* pDst, int dstStep,
+ CvSize roiSize, CvRect rect ))
+
+IPCVAPI_EX( CvStatus, icvHaarClassifierInitAlloc_32f,
+ "ippiHaarClassifierInitAlloc_32f", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( void **pState, const CvRect* pFeature, const float* pWeight,
+ const float* pThreshold, const float* pVal1,
+ const float* pVal2, const int* pNum, int length ))
+
+IPCVAPI_EX( CvStatus, icvHaarClassifierFree_32f,
+ "ippiHaarClassifierFree_32f", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( void *pState ))
+
+IPCVAPI_EX( CvStatus, icvApplyHaarClassifier_32f_C1R,
+ "ippiApplyHaarClassifier_32f_C1R", CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( const float* pSrc, int srcStep, const float* pNorm,
+ int normStep, uchar* pMask, int maskStep,
+ CvSize roi, int *pPositive, float threshold,
+ void *pState ))
+
+#endif /*_CV_IPP_H_*/
+
diff --git a/cv/src/_cvkdtree.hpp b/cv/src/_cvkdtree.hpp
new file mode 100644
index 0000000..2d34622
--- /dev/null
+++ b/cv/src/_cvkdtree.hpp
@@ -0,0 +1,461 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2008, Xavier Delacour, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+// 2008-05-13, Xavier Delacour <xavier.delacour@gmail.com>
+
+#ifndef __cv_kdtree_h__
+#define __cv_kdtree_h__
+
+#include "_cv.h"
+
+#include <vector>
+#include <algorithm>
+#include <limits>
+#include <iostream>
+#include "assert.h"
+#include "math.h"
+
+// J.S. Beis and D.G. Lowe. Shape indexing using approximate nearest-neighbor search in highdimensional spaces. In Proc. IEEE Conf. Comp. Vision Patt. Recog., pages 1000--1006, 1997. http://citeseer.ist.psu.edu/beis97shape.html
+#undef __deref
+#undef __valuetype
+
+template < class __valuetype, class __deref >
+class CvKDTree {
+public:
+ typedef __deref deref_type;
+ typedef typename __deref::scalar_type scalar_type;
+ typedef typename __deref::accum_type accum_type;
+
+private:
+ struct node {
+ int dim; // split dimension; >=0 for nodes, -1 for leaves
+ __valuetype value; // if leaf, value of leaf
+ int left, right; // node indices of left and right branches
+ scalar_type boundary; // left if deref(value,dim)<=boundary, otherwise right
+ };
+ typedef std::vector < node > node_array;
+
+ __deref deref; // requires operator() (__valuetype lhs,int dim)
+
+ node_array nodes; // node storage
+ int point_dim; // dimension of points (the k in kd-tree)
+ int root_node; // index of root node, -1 if empty tree
+
+ // for given set of point indices, compute dimension of highest variance
+ template < class __instype, class __valuector >
+ int dimension_of_highest_variance(__instype * first, __instype * last,
+ __valuector ctor) {
+ assert(last - first > 0);
+
+ accum_type maxvar = -std::numeric_limits < accum_type >::max();
+ int maxj = -1;
+ for (int j = 0; j < point_dim; ++j) {
+ accum_type mean = 0;
+ for (__instype * k = first; k < last; ++k)
+ mean += deref(ctor(*k), j);
+ mean /= last - first;
+ accum_type var = 0;
+ for (__instype * k = first; k < last; ++k) {
+ accum_type diff = accum_type(deref(ctor(*k), j)) - mean;
+ var += diff * diff;
+ }
+ var /= last - first;
+
+ assert(maxj != -1 || var >= maxvar);
+
+ if (var >= maxvar) {
+ maxvar = var;
+ maxj = j;
+ }
+ }
+
+ return maxj;
+ }
+
+ // given point indices and dimension, find index of median; (almost) modifies [first,last)
+ // such that points_in[first,median]<=point[median], points_in(median,last)>point[median].
+ // implemented as partial quicksort; expected linear perf.
+ template < class __instype, class __valuector >
+ __instype * median_partition(__instype * first, __instype * last,
+ int dim, __valuector ctor) {
+ assert(last - first > 0);
+ __instype *k = first + (last - first) / 2;
+ median_partition(first, last, k, dim, ctor);
+ return k;
+ }
+
+ template < class __instype, class __valuector >
+ struct median_pr {
+ const __instype & pivot;
+ int dim;
+ __deref deref;
+ __valuector ctor;
+ median_pr(const __instype & _pivot, int _dim, __deref _deref, __valuector _ctor)
+ : pivot(_pivot), dim(_dim), deref(_deref), ctor(_ctor) {
+ }
+ bool operator() (const __instype & lhs) const {
+ return deref(ctor(lhs), dim) <= deref(ctor(pivot), dim);
+ }
+ };
+
+ template < class __instype, class __valuector >
+ void median_partition(__instype * first, __instype * last,
+ __instype * k, int dim, __valuector ctor) {
+ int pivot = (last - first) / 2;
+
+ std::swap(first[pivot], last[-1]);
+ __instype *middle = std::partition(first, last - 1,
+ median_pr < __instype, __valuector >
+ (last[-1], dim, deref, ctor));
+ std::swap(*middle, last[-1]);
+
+ if (middle < k)
+ median_partition(middle + 1, last, k, dim, ctor);
+ else if (middle > k)
+ median_partition(first, middle, k, dim, ctor);
+ }
+
+ // insert given points into the tree; return created node
+ template < class __instype, class __valuector >
+ int insert(__instype * first, __instype * last, __valuector ctor) {
+ if (first == last)
+ return -1;
+ else {
+
+ int dim = dimension_of_highest_variance(first, last, ctor);
+ __instype *median = median_partition(first, last, dim, ctor);
+
+ __instype *split = median;
+ for (; split != last && deref(ctor(*split), dim) ==
+ deref(ctor(*median), dim); ++split);
+
+ if (split == last) { // leaf
+ int nexti = -1;
+ for (--split; split >= first; --split) {
+ int i = nodes.size();
+ node & n = *nodes.insert(nodes.end(), node());
+ n.dim = -1;
+ n.value = ctor(*split);
+ n.left = -1;
+ n.right = nexti;
+ nexti = i;
+ }
+
+ return nexti;
+ } else { // node
+ int i = nodes.size();
+ // note that recursive insert may invalidate this ref
+ node & n = *nodes.insert(nodes.end(), node());
+
+ n.dim = dim;
+ n.boundary = deref(ctor(*median), dim);
+
+ int left = insert(first, split, ctor);
+ nodes[i].left = left;
+ int right = insert(split, last, ctor);
+ nodes[i].right = right;
+
+ return i;
+ }
+ }
+ }
+
+ // run to leaf; linear search for p;
+ // if found, remove paths to empty leaves on unwind
+ bool remove(int *i, const __valuetype & p) {
+ if (*i == -1)
+ return false;
+ node & n = nodes[*i];
+ bool r;
+
+ if (n.dim >= 0) { // node
+ if (deref(p, n.dim) <= n.boundary) // left
+ r = remove(&n.left, p);
+ else // right
+ r = remove(&n.right, p);
+
+ // if terminal, remove this node
+ if (n.left == -1 && n.right == -1)
+ *i = -1;
+
+ return r;
+ } else { // leaf
+ if (n.value == p) {
+ *i = n.right;
+ return true;
+ } else
+ return remove(&n.right, p);
+ }
+ }
+
+public:
+ struct identity_ctor {
+ const __valuetype & operator() (const __valuetype & rhs) const {
+ return rhs;
+ }
+ };
+
+ // initialize an empty tree
+ CvKDTree(__deref _deref = __deref())
+ : deref(_deref), root_node(-1) {
+ }
+ // given points, initialize a balanced tree
+ CvKDTree(__valuetype * first, __valuetype * last, int _point_dim,
+ __deref _deref = __deref())
+ : deref(_deref) {
+ set_data(first, last, _point_dim, identity_ctor());
+ }
+ // given points, initialize a balanced tree
+ template < class __instype, class __valuector >
+ CvKDTree(__instype * first, __instype * last, int _point_dim,
+ __valuector ctor, __deref _deref = __deref())
+ : deref(_deref) {
+ set_data(first, last, _point_dim, ctor);
+ }
+
+ void set_deref(__deref _deref) {
+ deref = _deref;
+ }
+
+ void set_data(__valuetype * first, __valuetype * last, int _point_dim) {
+ set_data(first, last, _point_dim, identity_ctor());
+ }
+ template < class __instype, class __valuector >
+ void set_data(__instype * first, __instype * last, int _point_dim,
+ __valuector ctor) {
+ point_dim = _point_dim;
+ nodes.clear();
+ nodes.reserve(last - first);
+ root_node = insert(first, last, ctor);
+ }
+
+ int dims() const {
+ return point_dim;
+ }
+
+ // remove the given point
+ bool remove(const __valuetype & p) {
+ return remove(&root_node, p);
+ }
+
+ void print() const {
+ print(root_node);
+ }
+ void print(int i, int indent = 0) const {
+ if (i == -1)
+ return;
+ for (int j = 0; j < indent; ++j)
+ std::cout << " ";
+ const node & n = nodes[i];
+ if (n.dim >= 0) {
+ std::cout << "node " << i << ", left " << nodes[i].left << ", right " <<
+ nodes[i].right << ", dim " << nodes[i].dim << ", boundary " <<
+ nodes[i].boundary << std::endl;
+ print(n.left, indent + 3);
+ print(n.right, indent + 3);
+ } else
+ std::cout << "leaf " << i << ", value = " << nodes[i].value << std::endl;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////
+ // bbf search
+public:
+ struct bbf_nn { // info on found neighbors (approx k nearest)
+ const __valuetype *p; // nearest neighbor
+ accum_type dist; // distance from d to query point
+ bbf_nn(const __valuetype & _p, accum_type _dist)
+ : p(&_p), dist(_dist) {
+ }
+ bool operator<(const bbf_nn & rhs) const {
+ return dist < rhs.dist;
+ }
+ };
+ typedef std::vector < bbf_nn > bbf_nn_pqueue;
+private:
+ struct bbf_node { // info on branches not taken
+ int node; // corresponding node
+ accum_type dist; // minimum distance from bounds to query point
+ bbf_node(int _node, accum_type _dist)
+ : node(_node), dist(_dist) {
+ }
+ bool operator<(const bbf_node & rhs) const {
+ return dist > rhs.dist;
+ }
+ };
+ typedef std::vector < bbf_node > bbf_pqueue;
+ mutable bbf_pqueue tmp_pq;
+
+ // called for branches not taken, as bbf walks to leaf;
+ // construct bbf_node given minimum distance to bounds of alternate branch
+ void pq_alternate(int alt_n, bbf_pqueue & pq, scalar_type dist) const {
+ if (alt_n == -1)
+ return;
+
+ // add bbf_node for alternate branch in priority queue
+ pq.push_back(bbf_node(alt_n, dist));
+ push_heap(pq.begin(), pq.end());
+ }
+
+ // called by bbf to walk to leaf;
+ // takes one step down the tree towards query point d
+ template < class __desctype >
+ int bbf_branch(int i, const __desctype * d, bbf_pqueue & pq) const {
+ const node & n = nodes[i];
+ // push bbf_node with bounds of alternate branch, then branch
+ if (d[n.dim] <= n.boundary) { // left
+ pq_alternate(n.right, pq, n.boundary - d[n.dim]);
+ return n.left;
+ } else { // right
+ pq_alternate(n.left, pq, d[n.dim] - n.boundary);
+ return n.right;
+ }
+ }
+
+ // compute euclidean distance between two points
+ template < class __desctype >
+ accum_type distance(const __desctype * d, const __valuetype & p) const {
+ accum_type dist = 0;
+ for (int j = 0; j < point_dim; ++j) {
+ accum_type diff = accum_type(d[j]) - accum_type(deref(p, j));
+ dist += diff * diff;
+ } return (accum_type) sqrt(dist);
+ }
+
+ // called per candidate nearest neighbor; constructs new bbf_nn for
+ // candidate and adds it to priority queue of all candidates; if
+ // queue len exceeds k, drops the point furthest from query point d.
+ template < class __desctype >
+ void bbf_new_nn(bbf_nn_pqueue & nn_pq, int k,
+ const __desctype * d, const __valuetype & p) const {
+ bbf_nn nn(p, distance(d, p));
+ if ((int) nn_pq.size() < k) {
+ nn_pq.push_back(nn);
+ push_heap(nn_pq.begin(), nn_pq.end());
+ } else if (nn_pq[0].dist > nn.dist) {
+ pop_heap(nn_pq.begin(), nn_pq.end());
+ nn_pq.end()[-1] = nn;
+ push_heap(nn_pq.begin(), nn_pq.end());
+ }
+ assert(nn_pq.size() < 2 || nn_pq[0].dist >= nn_pq[1].dist);
+ }
+
+public:
+ // finds (with high probability) the k nearest neighbors of d,
+ // searching at most emax leaves/bins.
+ // ret_nn_pq is an array containing the (at most) k nearest neighbors
+ // (see bbf_nn structure def above).
+ template < class __desctype >
+ int find_nn_bbf(const __desctype * d,
+ int k, int emax,
+ bbf_nn_pqueue & ret_nn_pq) const {
+ assert(k > 0);
+ ret_nn_pq.clear();
+
+ if (root_node == -1)
+ return 0;
+
+ // add root_node to bbf_node priority queue;
+ // iterate while queue non-empty and emax>0
+ tmp_pq.clear();
+ tmp_pq.push_back(bbf_node(root_node, 0));
+ while (tmp_pq.size() && emax > 0) {
+
+ // from node nearest query point d, run to leaf
+ pop_heap(tmp_pq.begin(), tmp_pq.end());
+ bbf_node bbf(tmp_pq.end()[-1]);
+ tmp_pq.erase(tmp_pq.end() - 1);
+
+ int i;
+ for (i = bbf.node;
+ i != -1 && nodes[i].dim >= 0;
+ i = bbf_branch(i, d, tmp_pq));
+
+ if (i != -1) {
+
+ // add points in leaf/bin to ret_nn_pq
+ do {
+ bbf_new_nn(ret_nn_pq, k, d, nodes[i].value);
+ } while (-1 != (i = nodes[i].right));
+
+ --emax;
+ }
+ }
+
+ tmp_pq.clear();
+ return ret_nn_pq.size();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////
+ // orthogonal range search
+private:
+ void find_ortho_range(int i, scalar_type * bounds_min,
+ scalar_type * bounds_max,
+ std::vector < __valuetype > &inbounds) const {
+ if (i == -1)
+ return;
+ const node & n = nodes[i];
+ if (n.dim >= 0) { // node
+ if (bounds_min[n.dim] <= n.boundary)
+ find_ortho_range(n.left, bounds_min, bounds_max, inbounds);
+ if (bounds_max[n.dim] > n.boundary)
+ find_ortho_range(n.right, bounds_min, bounds_max, inbounds);
+ } else { // leaf
+ do {
+ inbounds.push_back(nodes[i].value);
+ } while (-1 != (i = nodes[i].right));
+ }
+ }
+public:
+ // return all points that lie within the given bounds; inbounds is cleared
+ int find_ortho_range(scalar_type * bounds_min,
+ scalar_type * bounds_max,
+ std::vector < __valuetype > &inbounds) const {
+ inbounds.clear();
+ find_ortho_range(root_node, bounds_min, bounds_max, inbounds);
+ return inbounds.size();
+ }
+};
+
+#endif // __cv_kdtree_h__
+
+// Local Variables:
+// mode:C++
+// End:
diff --git a/cv/src/_cvlist.h b/cv/src/_cvlist.h
new file mode 100644
index 0000000..b2b63e9
--- /dev/null
+++ b/cv/src/_cvlist.h
@@ -0,0 +1,373 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _CV_LIST_H_
+#define _CV_LIST_H_
+
+#include <stdlib.h>
+#include <assert.h>
+
+#define CV_FORCE_INLINE CV_INLINE
+
+#if !defined(_LIST_INLINE)
+#define _LIST_INLINE CV_FORCE_INLINE
+#endif /*_LIST_INLINE*/
+
+#if defined DECLARE_LIST
+#if defined _MSC_VER && _MSC_VER >= 1200
+ #pragma warning("DECLARE_LIST macro is already defined!")
+#endif
+#endif /*DECLARE_LIST*/
+
+static const long default_size = 10;
+static const long default_inc_size = 10;
+
+struct _pos
+{
+ void* m_pos;
+#ifdef _DEBUG
+ struct _list* m_list;
+#endif /*_DEBUG*/
+};
+typedef struct _pos CVPOS;
+struct _list
+{
+ void* m_buffer;
+ void* m_first_buffer;
+ long m_buf_size; /* The size of the buffer */
+ long m_size; /* The number of elements */
+ CVPOS m_head;
+ CVPOS m_tail;
+ CVPOS m_head_free;
+};
+
+typedef struct _list _CVLIST;
+
+#define DECLARE_LIST(type, prefix)\
+ /* Basic element of a list*/\
+ struct prefix##element_##type\
+ {\
+ struct prefix##element_##type* m_prev;\
+ struct prefix##element_##type* m_next;\
+ type m_data;\
+ };\
+ typedef struct prefix##element_##type ELEMENT_##type;\
+ /* Initialization and destruction*/\
+ _LIST_INLINE _CVLIST* prefix##create_list_##type(long);\
+ _LIST_INLINE void prefix##destroy_list_##type(_CVLIST*);\
+ /* Access functions*/\
+ _LIST_INLINE CVPOS prefix##get_head_pos_##type(_CVLIST*);\
+ _LIST_INLINE CVPOS prefix##get_tail_pos_##type(_CVLIST*);\
+ _LIST_INLINE type* prefix##get_next_##type(CVPOS*);\
+ _LIST_INLINE type* prefix##get_prev_##type(CVPOS*);\
+ /* Modification functions*/\
+ _LIST_INLINE void prefix##clear_list_##type(_CVLIST*);\
+ _LIST_INLINE CVPOS prefix##add_head_##type(_CVLIST*, type*);\
+ _LIST_INLINE CVPOS prefix##add_tail_##type(_CVLIST*, type*);\
+ _LIST_INLINE void prefix##remove_head_##type(_CVLIST*);\
+ _LIST_INLINE void prefix##remove_tail_##type(_CVLIST*);\
+ _LIST_INLINE CVPOS prefix##insert_before_##type(_CVLIST*, CVPOS, type*);\
+ _LIST_INLINE CVPOS prefix##insert_after_##type(_CVLIST*, CVPOS, type*);\
+ _LIST_INLINE void prefix##remove_at_##type(_CVLIST*, CVPOS);\
+ _LIST_INLINE void prefix##set_##type(CVPOS, type*);\
+ _LIST_INLINE type* prefix##get_##type(CVPOS);\
+ /* Statistics functions*/\
+ _LIST_INLINE int prefix##get_count_##type(_CVLIST*);
+
+/* This macro finds a space for a new element and puts in into 'element' pointer */
+#define INSERT_NEW(element_type, l, element)\
+ l->m_size++;\
+ if(l->m_head_free.m_pos != NULL)\
+ {\
+ element = (element_type*)(l->m_head_free.m_pos);\
+ if(element->m_next != NULL)\
+ {\
+ element->m_next->m_prev = NULL;\
+ l->m_head_free.m_pos = element->m_next;\
+ }\
+ else\
+ {\
+ l->m_head_free.m_pos = NULL;\
+ }\
+ }\
+ else\
+ {\
+ if(l->m_buf_size < l->m_size && l->m_head_free.m_pos == NULL)\
+ {\
+ *(void**)l->m_buffer = cvAlloc(l->m_buf_size*sizeof(element_type) + sizeof(void*));\
+ l->m_buffer = *(void**)l->m_buffer;\
+ *(void**)l->m_buffer = NULL;\
+ element = (element_type*)((char*)l->m_buffer + sizeof(void*));\
+ }\
+ else\
+ {\
+ element = (element_type*)((char*)l->m_buffer + sizeof(void*)) + l->m_size - 1;\
+ }\
+ }
+
+/* This macro adds 'element' to the list of free elements*/
+#define INSERT_FREE(element_type, l, element)\
+ if(l->m_head_free.m_pos != NULL)\
+ {\
+ ((element_type*)l->m_head_free.m_pos)->m_prev = element;\
+ }\
+ element->m_next = ((element_type*)l->m_head_free.m_pos);\
+ l->m_head_free.m_pos = element;
+
+
+/*#define GET_FIRST_FREE(l) ((ELEMENT_##type*)(l->m_head_free.m_pos))*/
+
+#define IMPLEMENT_LIST(type, prefix)\
+_CVLIST* prefix##create_list_##type(long size)\
+{\
+ _CVLIST* pl = (_CVLIST*)cvAlloc(sizeof(_CVLIST));\
+ pl->m_buf_size = size > 0 ? size : default_size;\
+ pl->m_first_buffer = cvAlloc(pl->m_buf_size*sizeof(ELEMENT_##type) + sizeof(void*));\
+ pl->m_buffer = pl->m_first_buffer;\
+ *(void**)pl->m_buffer = NULL;\
+ pl->m_size = 0;\
+ pl->m_head.m_pos = NULL;\
+ pl->m_tail.m_pos = NULL;\
+ pl->m_head_free.m_pos = NULL;\
+ return pl;\
+}\
+void prefix##destroy_list_##type(_CVLIST* l)\
+{\
+ void* cur = l->m_first_buffer;\
+ void* next;\
+ while(cur)\
+ {\
+ next = *(void**)cur;\
+ cvFree(&cur);\
+ cur = next;\
+ }\
+ cvFree(&l);\
+}\
+CVPOS prefix##get_head_pos_##type(_CVLIST* l)\
+{\
+ return l->m_head;\
+}\
+CVPOS prefix##get_tail_pos_##type(_CVLIST* l)\
+{\
+ return l->m_tail;\
+}\
+type* prefix##get_next_##type(CVPOS* pos)\
+{\
+ if(pos->m_pos)\
+ {\
+ ELEMENT_##type* element = (ELEMENT_##type*)(pos->m_pos);\
+ pos->m_pos = element->m_next;\
+ return &element->m_data;\
+ }\
+ else\
+ {\
+ return NULL;\
+ }\
+}\
+type* prefix##get_prev_##type(CVPOS* pos)\
+{\
+ if(pos->m_pos)\
+ {\
+ ELEMENT_##type* element = (ELEMENT_##type*)(pos->m_pos);\
+ pos->m_pos = element->m_prev;\
+ return &element->m_data;\
+ }\
+ else\
+ {\
+ return NULL;\
+ }\
+}\
+int prefix##is_pos_##type(CVPOS pos)\
+{\
+ return !!pos.m_pos;\
+}\
+void prefix##clear_list_##type(_CVLIST* l)\
+{\
+ l->m_head.m_pos = NULL;\
+ l->m_tail.m_pos = NULL;\
+ l->m_size = 0;\
+ l->m_head_free.m_pos = NULL;\
+}\
+CVPOS prefix##add_head_##type(_CVLIST* l, type* data)\
+{\
+ ELEMENT_##type* element;\
+ INSERT_NEW(ELEMENT_##type, l, element);\
+ element->m_prev = NULL;\
+ element->m_next = (ELEMENT_##type*)(l->m_head.m_pos);\
+ memcpy(&(element->m_data), data, sizeof(*data));\
+ if(element->m_next)\
+ {\
+ element->m_next->m_prev = element;\
+ }\
+ else\
+ {\
+ l->m_tail.m_pos = element;\
+ }\
+ l->m_head.m_pos = element;\
+ return l->m_head;\
+}\
+CVPOS prefix##add_tail_##type(_CVLIST* l, type* data)\
+{\
+ ELEMENT_##type* element;\
+ INSERT_NEW(ELEMENT_##type, l, element);\
+ element->m_next = NULL;\
+ element->m_prev = (ELEMENT_##type*)(l->m_tail.m_pos);\
+ memcpy(&(element->m_data), data, sizeof(*data));\
+ if(element->m_prev)\
+ {\
+ element->m_prev->m_next = element;\
+ }\
+ else\
+ {\
+ l->m_head.m_pos = element;\
+ }\
+ l->m_tail.m_pos = element;\
+ return l->m_tail;\
+}\
+void prefix##remove_head_##type(_CVLIST* l)\
+{\
+ ELEMENT_##type* element = ((ELEMENT_##type*)(l->m_head.m_pos));\
+ if(element->m_next != NULL)\
+ {\
+ element->m_next->m_prev = NULL;\
+ }\
+ l->m_head.m_pos = element->m_next;\
+ INSERT_FREE(ELEMENT_##type, l, element);\
+ l->m_size--;\
+}\
+void prefix##remove_tail_##type(_CVLIST* l)\
+{\
+ ELEMENT_##type* element = ((ELEMENT_##type*)(l->m_tail.m_pos));\
+ if(element->m_prev != NULL)\
+ {\
+ element->m_prev->m_next = NULL;\
+ }\
+ l->m_tail.m_pos = element->m_prev;\
+ INSERT_FREE(ELEMENT_##type, l, element);\
+ l->m_size--;\
+}\
+CVPOS prefix##insert_after_##type(_CVLIST* l, CVPOS pos, type* data)\
+{\
+ ELEMENT_##type* element;\
+ ELEMENT_##type* before;\
+ CVPOS newpos;\
+ INSERT_NEW(ELEMENT_##type, l, element);\
+ memcpy(&(element->m_data), data, sizeof(*data));\
+ before = (ELEMENT_##type*)pos.m_pos;\
+ element->m_prev = before;\
+ element->m_next = before->m_next;\
+ before->m_next = element;\
+ if(element->m_next != NULL)\
+ element->m_next->m_prev = element;\
+ else\
+ l->m_tail.m_pos = element;\
+ newpos.m_pos = element;\
+ return newpos;\
+}\
+CVPOS prefix##insert_before_##type(_CVLIST* l, CVPOS pos, type* data)\
+{\
+ ELEMENT_##type* element;\
+ ELEMENT_##type* after;\
+ CVPOS newpos;\
+ INSERT_NEW(ELEMENT_##type, l, element);\
+ memcpy(&(element->m_data), data, sizeof(*data));\
+ after = (ELEMENT_##type*)pos.m_pos;\
+ element->m_prev = after->m_prev;\
+ element->m_next = after;\
+ after->m_prev = element;\
+ if(element->m_prev != NULL)\
+ element->m_prev->m_next = element;\
+ else\
+ l->m_head.m_pos = element;\
+ newpos.m_pos = element;\
+ return newpos;\
+}\
+void prefix##remove_at_##type(_CVLIST* l, CVPOS pos)\
+{\
+ ELEMENT_##type* element = ((ELEMENT_##type*)pos.m_pos);\
+ if(element->m_prev != NULL)\
+ {\
+ element->m_prev->m_next = element->m_next;\
+ }\
+ else\
+ {\
+ l->m_head.m_pos = element->m_next;\
+ }\
+ if(element->m_next != NULL)\
+ {\
+ element->m_next->m_prev = element->m_prev;\
+ }\
+ else\
+ {\
+ l->m_tail.m_pos = element->m_prev;\
+ }\
+ INSERT_FREE(ELEMENT_##type, l, element);\
+ l->m_size--;\
+}\
+void prefix##set_##type(CVPOS pos, type* data)\
+{\
+ ELEMENT_##type* element = ((ELEMENT_##type*)(pos.m_pos));\
+ memcpy(&(element->m_data), data, sizeof(data));\
+}\
+type* prefix##get_##type(CVPOS pos)\
+{\
+ ELEMENT_##type* element = ((ELEMENT_##type*)(pos.m_pos));\
+ return &(element->m_data);\
+}\
+int prefix##get_count_##type(_CVLIST* list)\
+{\
+ return list->m_size;\
+}
+
+#define DECLARE_AND_IMPLEMENT_LIST(type, prefix)\
+ DECLARE_LIST(type, prefix)\
+ IMPLEMENT_LIST(type, prefix)
+
+typedef struct __index
+{
+ int value;
+ float rho, theta;
+}
+_index;
+
+DECLARE_LIST( _index, h_ )
+
+#endif/*_CV_LIST_H_*/
diff --git a/cv/src/_cvmatrix.h b/cv/src/_cvmatrix.h
new file mode 100644
index 0000000..af4c591
--- /dev/null
+++ b/cv/src/_cvmatrix.h
@@ -0,0 +1,405 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _CV_MATRIX_H_
+#define _CV_MATRIX_H_
+
+#define icvCopyVector( src, dst, len ) memcpy( (dst), (src), (len)*sizeof((dst)[0]))
+#define icvSetZero( dst, len ) memset( (dst), 0, (len)*sizeof((dst)[0]))
+
+#define icvCopyVector_32f( src, len, dst ) memcpy((dst),(src),(len)*sizeof(float))
+#define icvSetZero_32f( dst, cols, rows ) memset((dst),0,(rows)*(cols)*sizeof(float))
+#define icvCopyVector_64d( src, len, dst ) memcpy((dst),(src),(len)*sizeof(double))
+#define icvSetZero_64d( dst, cols, rows ) memset((dst),0,(rows)*(cols)*sizeof(double))
+#define icvCopyMatrix_32f( src, w, h, dst ) memcpy((dst),(src),(w)*(h)*sizeof(float))
+#define icvCopyMatrix_64d( src, w, h, dst ) memcpy((dst),(src),(w)*(h)*sizeof(double))
+
+#define icvCreateVector_32f( len ) (float*)cvAlloc( (len)*sizeof(float))
+#define icvCreateVector_64d( len ) (double*)cvAlloc( (len)*sizeof(double))
+#define icvCreateMatrix_32f( w, h ) (float*)cvAlloc( (w)*(h)*sizeof(float))
+#define icvCreateMatrix_64d( w, h ) (double*)cvAlloc( (w)*(h)*sizeof(double))
+
+#define icvDeleteVector( vec ) cvFree( &(vec) )
+#define icvDeleteMatrix icvDeleteVector
+
+#define icvAddMatrix_32f( src1, src2, dst, w, h ) \
+ icvAddVector_32f( (src1), (src2), (dst), (w)*(h))
+
+#define icvSubMatrix_32f( src1, src2, dst, w, h ) \
+ icvSubVector_32f( (src1), (src2), (dst), (w)*(h))
+
+#define icvNormVector_32f( src, len ) \
+ sqrt(icvDotProduct_32f( src, src, len ))
+
+#define icvNormVector_64d( src, len ) \
+ sqrt(icvDotProduct_64d( src, src, len ))
+
+
+#define icvDeleteMatrix icvDeleteVector
+
+#define icvCheckVector_64f( ptr, len )
+#define icvCheckVector_32f( ptr, len )
+
+CV_INLINE double icvSum_32f( const float* src, int len )
+{
+ double s = 0;
+ for( int i = 0; i < len; i++ ) s += src[i];
+
+ icvCheckVector_64f( &s, 1 );
+
+ return s;
+}
+
+CV_INLINE double icvDotProduct_32f( const float* src1, const float* src2, int len )
+{
+ double s = 0;
+ for( int i = 0; i < len; i++ ) s += src1[i]*src2[i];
+
+ icvCheckVector_64f( &s, 1 );
+
+ return s;
+}
+
+
+CV_INLINE double icvDotProduct_64f( const double* src1, const double* src2, int len )
+{
+ double s = 0;
+ for( int i = 0; i < len; i++ ) s += src1[i]*src2[i];
+
+ icvCheckVector_64f( &s, 1 );
+
+ return s;
+}
+
+
+CV_INLINE void icvMulVectors_32f( const float* src1, const float* src2,
+ float* dst, int len )
+{
+ int i;
+ for( i = 0; i < len; i++ )
+ dst[i] = src1[i] * src2[i];
+
+ icvCheckVector_32f( dst, len );
+}
+
+CV_INLINE void icvMulVectors_64d( const double* src1, const double* src2,
+ double* dst, int len )
+{
+ int i;
+ for( i = 0; i < len; i++ )
+ dst[i] = src1[i] * src2[i];
+
+ icvCheckVector_64f( dst, len );
+}
+
+
+CV_INLINE void icvAddVector_32f( const float* src1, const float* src2,
+ float* dst, int len )
+{
+ int i;
+ for( i = 0; i < len; i++ )
+ dst[i] = src1[i] + src2[i];
+
+ icvCheckVector_32f( dst, len );
+}
+
+CV_INLINE void icvAddVector_64d( const double* src1, const double* src2,
+ double* dst, int len )
+{
+ int i;
+ for( i = 0; i < len; i++ )
+ dst[i] = src1[i] + src2[i];
+
+ icvCheckVector_64f( dst, len );
+}
+
+
+CV_INLINE void icvSubVector_32f( const float* src1, const float* src2,
+ float* dst, int len )
+{
+ int i;
+ for( i = 0; i < len; i++ )
+ dst[i] = src1[i] - src2[i];
+
+ icvCheckVector_32f( dst, len );
+}
+
+CV_INLINE void icvSubVector_64d( const double* src1, const double* src2,
+ double* dst, int len )
+{
+ int i;
+ for( i = 0; i < len; i++ )
+ dst[i] = src1[i] - src2[i];
+
+ icvCheckVector_64f( dst, len );
+}
+
+
+#define icvAddMatrix_64d( src1, src2, dst, w, h ) \
+ icvAddVector_64d( (src1), (src2), (dst), (w)*(h))
+
+#define icvSubMatrix_64d( src1, src2, dst, w, h ) \
+ icvSubVector_64d( (src1), (src2), (dst), (w)*(h))
+
+
+CV_INLINE void icvSetIdentity_32f( float* dst, int w, int h )
+{
+ int i, len = MIN( w, h );
+ icvSetZero_32f( dst, w, h );
+ for( i = 0; len--; i += w+1 )
+ dst[i] = 1.f;
+}
+
+
+CV_INLINE void icvSetIdentity_64d( double* dst, int w, int h )
+{
+ int i, len = MIN( w, h );
+ icvSetZero_64d( dst, w, h );
+ for( i = 0; len--; i += w+1 )
+ dst[i] = 1.;
+}
+
+
+CV_INLINE void icvTrace_32f( const float* src, int w, int h, float* trace )
+{
+ int i, len = MIN( w, h );
+ double sum = 0;
+ for( i = 0; len--; i += w+1 )
+ sum += src[i];
+ *trace = (float)sum;
+
+ icvCheckVector_64f( &sum, 1 );
+}
+
+
+CV_INLINE void icvTrace_64d( const double* src, int w, int h, double* trace )
+{
+ int i, len = MIN( w, h );
+ double sum = 0;
+ for( i = 0; len--; i += w+1 )
+ sum += src[i];
+ *trace = sum;
+
+ icvCheckVector_64f( &sum, 1 );
+}
+
+
+CV_INLINE void icvScaleVector_32f( const float* src, float* dst,
+ int len, double scale )
+{
+ int i;
+ for( i = 0; i < len; i++ )
+ dst[i] = (float)(src[i]*scale);
+
+ icvCheckVector_32f( dst, len );
+}
+
+
+CV_INLINE void icvScaleVector_64d( const double* src, double* dst,
+ int len, double scale )
+{
+ int i;
+ for( i = 0; i < len; i++ )
+ dst[i] = src[i]*scale;
+
+ icvCheckVector_64f( dst, len );
+}
+
+
+CV_INLINE void icvTransposeMatrix_32f( const float* src, int w, int h, float* dst )
+{
+ int i, j;
+
+ for( i = 0; i < w; i++ )
+ for( j = 0; j < h; j++ )
+ *dst++ = src[j*w + i];
+
+ icvCheckVector_32f( dst, w*h );
+}
+
+CV_INLINE void icvTransposeMatrix_64d( const double* src, int w, int h, double* dst )
+{
+ int i, j;
+
+ for( i = 0; i < w; i++ )
+ for( j = 0; j < h; j++ )
+ *dst++ = src[j*w + i];
+
+ icvCheckVector_64f( dst, w*h );
+}
+
+CV_INLINE void icvDetMatrix3x3_64d( const double* mat, double* det )
+{
+ #define m(y,x) mat[(y)*3 + (x)]
+
+ *det = m(0,0)*(m(1,1)*m(2,2) - m(1,2)*m(2,1)) -
+ m(0,1)*(m(1,0)*m(2,2) - m(1,2)*m(2,0)) +
+ m(0,2)*(m(1,0)*m(2,1) - m(1,1)*m(2,0));
+
+ #undef m
+
+ icvCheckVector_64f( det, 1 );
+}
+
+
+CV_INLINE void icvMulMatrix_32f( const float* src1, int w1, int h1,
+ const float* src2, int w2, int h2,
+ float* dst )
+{
+ int i, j, k;
+
+ if( w1 != h2 )
+ {
+ assert(0);
+ return;
+ }
+
+ for( i = 0; i < h1; i++, src1 += w1, dst += w2 )
+ for( j = 0; j < w2; j++ )
+ {
+ double s = 0;
+ for( k = 0; k < w1; k++ )
+ s += src1[k]*src2[j + k*w2];
+ dst[j] = (float)s;
+ }
+
+ icvCheckVector_32f( dst, h1*w2 );
+}
+
+
+CV_INLINE void icvMulMatrix_64d( const double* src1, int w1, int h1,
+ const double* src2, int w2, int h2,
+ double* dst )
+{
+ int i, j, k;
+
+ if( w1 != h2 )
+ {
+ assert(0);
+ return;
+ }
+
+ for( i = 0; i < h1; i++, src1 += w1, dst += w2 )
+ for( j = 0; j < w2; j++ )
+ {
+ double s = 0;
+ for( k = 0; k < w1; k++ )
+ s += src1[k]*src2[j + k*w2];
+ dst[j] = s;
+ }
+
+ icvCheckVector_64f( dst, h1*w2 );
+}
+
+
+#define icvTransformVector_32f( matr, src, dst, w, h ) \
+ icvMulMatrix_32f( matr, w, h, src, 1, w, dst )
+
+#define icvTransformVector_64d( matr, src, dst, w, h ) \
+ icvMulMatrix_64d( matr, w, h, src, 1, w, dst )
+
+
+#define icvScaleMatrix_32f( src, dst, w, h, scale ) \
+ icvScaleVector_32f( (src), (dst), (w)*(h), (scale) )
+
+#define icvScaleMatrix_64d( src, dst, w, h, scale ) \
+ icvScaleVector_64d( (src), (dst), (w)*(h), (scale) )
+
+#define icvDotProduct_64d icvDotProduct_64f
+
+
+CV_INLINE void icvInvertMatrix_64d( double* A, int n, double* invA )
+{
+ CvMat Am = cvMat( n, n, CV_64F, A );
+ CvMat invAm = cvMat( n, n, CV_64F, invA );
+
+ cvInvert( &Am, &invAm, CV_SVD );
+}
+
+CV_INLINE void icvMulTransMatrixR_64d( double* src, int width, int height, double* dst )
+{
+ CvMat srcMat = cvMat( height, width, CV_64F, src );
+ CvMat dstMat = cvMat( width, width, CV_64F, dst );
+
+ cvMulTransposed( &srcMat, &dstMat, 1 );
+}
+
+CV_INLINE void icvMulTransMatrixL_64d( double* src, int width, int height, double* dst )
+{
+ CvMat srcMat = cvMat( height, width, CV_64F, src );
+ CvMat dstMat = cvMat( height, height, CV_64F, dst );
+
+ cvMulTransposed( &srcMat, &dstMat, 0 );
+}
+
+CV_INLINE void icvMulTransMatrixR_32f( float* src, int width, int height, float* dst )
+{
+ CvMat srcMat = cvMat( height, width, CV_32F, src );
+ CvMat dstMat = cvMat( width, width, CV_32F, dst );
+
+ cvMulTransposed( &srcMat, &dstMat, 1 );
+}
+
+CV_INLINE void icvMulTransMatrixL_32f( float* src, int width, int height, float* dst )
+{
+ CvMat srcMat = cvMat( height, width, CV_32F, src );
+ CvMat dstMat = cvMat( height, height, CV_32F, dst );
+
+ cvMulTransposed( &srcMat, &dstMat, 0 );
+}
+
+CV_INLINE void icvCvt_32f_64d( const float* src, double* dst, int len )
+{
+ int i;
+ for( i = 0; i < len; i++ )
+ dst[i] = src[i];
+}
+
+CV_INLINE void icvCvt_64d_32f( const double* src, float* dst, int len )
+{
+ int i;
+ for( i = 0; i < len; i++ )
+ dst[i] = (float)src[i];
+}
+
+#endif/*_CV_MATRIX_H_*/
+
+/* End of file. */
diff --git a/cv/src/cvaccum.cpp b/cv/src/cvaccum.cpp
new file mode 100644
index 0000000..21b715f
--- /dev/null
+++ b/cv/src/cvaccum.cpp
@@ -0,0 +1,786 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+#define ICV_DEF_ACC_FUNC( name, srctype, dsttype, cvtmacro ) \
+IPCVAPI_IMPL( CvStatus, \
+name,( const srctype *src, int srcstep, dsttype *dst, \
+ int dststep, CvSize size ), (src, srcstep, dst, dststep, size )) \
+ \
+{ \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ int x; \
+ for( x = 0; x <= size.width - 4; x += 4 ) \
+ { \
+ dsttype t0 = dst[x] + cvtmacro(src[x]); \
+ dsttype t1 = dst[x + 1] + cvtmacro(src[x + 1]); \
+ dst[x] = t0; dst[x + 1] = t1; \
+ \
+ t0 = dst[x + 2] + cvtmacro(src[x + 2]); \
+ t1 = dst[x + 3] + cvtmacro(src[x + 3]); \
+ dst[x + 2] = t0; dst[x + 3] = t1; \
+ } \
+ \
+ for( ; x < size.width; x++ ) \
+ dst[x] += cvtmacro(src[x]); \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_ACC_FUNC( icvAdd_8u32f_C1IR, uchar, float, CV_8TO32F )
+ICV_DEF_ACC_FUNC( icvAdd_32f_C1IR, float, float, CV_NOP )
+ICV_DEF_ACC_FUNC( icvAddSquare_8u32f_C1IR, uchar, float, CV_8TO32F_SQR )
+ICV_DEF_ACC_FUNC( icvAddSquare_32f_C1IR, float, float, CV_SQR )
+
+
+#define ICV_DEF_ACCPROD_FUNC( flavor, srctype, dsttype, cvtmacro ) \
+IPCVAPI_IMPL( CvStatus, icvAddProduct_##flavor##_C1IR, \
+( const srctype *src1, int step1, const srctype *src2, int step2, \
+ dsttype *dst, int dststep, CvSize size ), \
+ (src1, step1, src2, step2, dst, dststep, size) ) \
+{ \
+ step1 /= sizeof(src1[0]); \
+ step2 /= sizeof(src2[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2, dst += dststep ) \
+ { \
+ int x; \
+ for( x = 0; x <= size.width - 4; x += 4 ) \
+ { \
+ dsttype t0 = dst[x] + cvtmacro(src1[x])*cvtmacro(src2[x]); \
+ dsttype t1 = dst[x+1] + cvtmacro(src1[x+1])*cvtmacro(src2[x+1]);\
+ dst[x] = t0; dst[x + 1] = t1; \
+ \
+ t0 = dst[x + 2] + cvtmacro(src1[x + 2])*cvtmacro(src2[x + 2]); \
+ t1 = dst[x + 3] + cvtmacro(src1[x + 3])*cvtmacro(src2[x + 3]); \
+ dst[x + 2] = t0; dst[x + 3] = t1; \
+ } \
+ \
+ for( ; x < size.width; x++ ) \
+ dst[x] += cvtmacro(src1[x])*cvtmacro(src2[x]); \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_ACCPROD_FUNC( 8u32f, uchar, float, CV_8TO32F )
+ICV_DEF_ACCPROD_FUNC( 32f, float, float, CV_NOP )
+
+
+#define ICV_DEF_ACCWEIGHT_FUNC( flavor, srctype, dsttype, cvtmacro ) \
+IPCVAPI_IMPL( CvStatus, icvAddWeighted_##flavor##_C1IR, \
+( const srctype *src, int srcstep, dsttype *dst, int dststep, \
+ CvSize size, dsttype alpha ), (src, srcstep, dst, dststep, size, alpha) )\
+{ \
+ dsttype beta = (dsttype)(1 - alpha); \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ int x; \
+ for( x = 0; x <= size.width - 4; x += 4 ) \
+ { \
+ dsttype t0 = dst[x]*beta + cvtmacro(src[x])*alpha; \
+ dsttype t1 = dst[x+1]*beta + cvtmacro(src[x+1])*alpha; \
+ dst[x] = t0; dst[x + 1] = t1; \
+ \
+ t0 = dst[x + 2]*beta + cvtmacro(src[x + 2])*alpha; \
+ t1 = dst[x + 3]*beta + cvtmacro(src[x + 3])*alpha; \
+ dst[x + 2] = t0; dst[x + 3] = t1; \
+ } \
+ \
+ for( ; x < size.width; x++ ) \
+ dst[x] = dst[x]*beta + cvtmacro(src[x])*alpha; \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_ACCWEIGHT_FUNC( 8u32f, uchar, float, CV_8TO32F )
+ICV_DEF_ACCWEIGHT_FUNC( 32f, float, float, CV_NOP )
+
+
+#define ICV_DEF_ACCMASK_FUNC_C1( name, srctype, dsttype, cvtmacro ) \
+IPCVAPI_IMPL( CvStatus, \
+name,( const srctype *src, int srcstep, const uchar* mask, int maskstep,\
+ dsttype *dst, int dststep, CvSize size ), \
+ (src, srcstep, mask, maskstep, dst, dststep, size )) \
+{ \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src += srcstep, \
+ dst += dststep, mask += maskstep ) \
+ { \
+ int x; \
+ for( x = 0; x <= size.width - 2; x += 2 ) \
+ { \
+ if( mask[x] ) \
+ dst[x] += cvtmacro(src[x]); \
+ if( mask[x+1] ) \
+ dst[x+1] += cvtmacro(src[x+1]); \
+ } \
+ \
+ for( ; x < size.width; x++ ) \
+ if( mask[x] ) \
+ dst[x] += cvtmacro(src[x]); \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_ACCMASK_FUNC_C1( icvAdd_8u32f_C1IMR, uchar, float, CV_8TO32F )
+ICV_DEF_ACCMASK_FUNC_C1( icvAdd_32f_C1IMR, float, float, CV_NOP )
+ICV_DEF_ACCMASK_FUNC_C1( icvAddSquare_8u32f_C1IMR, uchar, float, CV_8TO32F_SQR )
+ICV_DEF_ACCMASK_FUNC_C1( icvAddSquare_32f_C1IMR, float, float, CV_SQR )
+
+
+#define ICV_DEF_ACCPRODUCTMASK_FUNC_C1( flavor, srctype, dsttype, cvtmacro ) \
+IPCVAPI_IMPL( CvStatus, icvAddProduct_##flavor##_C1IMR, \
+( const srctype *src1, int step1, const srctype* src2, int step2, \
+ const uchar* mask, int maskstep, dsttype *dst, int dststep, CvSize size ),\
+ (src1, step1, src2, step2, mask, maskstep, dst, dststep, size )) \
+{ \
+ step1 /= sizeof(src1[0]); \
+ step2 /= sizeof(src2[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2, \
+ dst += dststep, mask += maskstep ) \
+ { \
+ int x; \
+ for( x = 0; x <= size.width - 2; x += 2 ) \
+ { \
+ if( mask[x] ) \
+ dst[x] += cvtmacro(src1[x])*cvtmacro(src2[x]); \
+ if( mask[x+1] ) \
+ dst[x+1] += cvtmacro(src1[x+1])*cvtmacro(src2[x+1]); \
+ } \
+ \
+ for( ; x < size.width; x++ ) \
+ if( mask[x] ) \
+ dst[x] += cvtmacro(src1[x])*cvtmacro(src2[x]); \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_ACCPRODUCTMASK_FUNC_C1( 8u32f, uchar, float, CV_8TO32F )
+ICV_DEF_ACCPRODUCTMASK_FUNC_C1( 32f, float, float, CV_NOP )
+
+#define ICV_DEF_ACCWEIGHTMASK_FUNC_C1( flavor, srctype, dsttype, cvtmacro ) \
+IPCVAPI_IMPL( CvStatus, icvAddWeighted_##flavor##_C1IMR, \
+( const srctype *src, int srcstep, const uchar* mask, int maskstep, \
+ dsttype *dst, int dststep, CvSize size, dsttype alpha ), \
+ (src, srcstep, mask, maskstep, dst, dststep, size, alpha )) \
+{ \
+ dsttype beta = (dsttype)(1 - alpha); \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src += srcstep, \
+ dst += dststep, mask += maskstep ) \
+ { \
+ int x; \
+ for( x = 0; x <= size.width - 2; x += 2 ) \
+ { \
+ if( mask[x] ) \
+ dst[x] = dst[x]*beta + cvtmacro(src[x])*alpha; \
+ if( mask[x+1] ) \
+ dst[x+1] = dst[x+1]*beta + cvtmacro(src[x+1])*alpha; \
+ } \
+ \
+ for( ; x < size.width; x++ ) \
+ if( mask[x] ) \
+ dst[x] = dst[x]*beta + cvtmacro(src[x])*alpha; \
+ } \
+ \
+ return CV_OK; \
+}
+
+ICV_DEF_ACCWEIGHTMASK_FUNC_C1( 8u32f, uchar, float, CV_8TO32F )
+ICV_DEF_ACCWEIGHTMASK_FUNC_C1( 32f, float, float, CV_NOP )
+
+
+#define ICV_DEF_ACCMASK_FUNC_C3( name, srctype, dsttype, cvtmacro ) \
+IPCVAPI_IMPL( CvStatus, \
+name,( const srctype *src, int srcstep, const uchar* mask, int maskstep,\
+ dsttype *dst, int dststep, CvSize size ), \
+ (src, srcstep, mask, maskstep, dst, dststep, size )) \
+{ \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src += srcstep, \
+ dst += dststep, mask += maskstep ) \
+ { \
+ int x; \
+ for( x = 0; x < size.width; x++ ) \
+ if( mask[x] ) \
+ { \
+ dsttype t0, t1, t2; \
+ t0 = dst[x*3] + cvtmacro(src[x*3]); \
+ t1 = dst[x*3+1] + cvtmacro(src[x*3+1]); \
+ t2 = dst[x*3+2] + cvtmacro(src[x*3+2]); \
+ dst[x*3] = t0; \
+ dst[x*3+1] = t1; \
+ dst[x*3+2] = t2; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_ACCMASK_FUNC_C3( icvAdd_8u32f_C3IMR, uchar, float, CV_8TO32F )
+ICV_DEF_ACCMASK_FUNC_C3( icvAdd_32f_C3IMR, float, float, CV_NOP )
+ICV_DEF_ACCMASK_FUNC_C3( icvAddSquare_8u32f_C3IMR, uchar, float, CV_8TO32F_SQR )
+ICV_DEF_ACCMASK_FUNC_C3( icvAddSquare_32f_C3IMR, float, float, CV_SQR )
+
+
+#define ICV_DEF_ACCPRODUCTMASK_FUNC_C3( flavor, srctype, dsttype, cvtmacro ) \
+IPCVAPI_IMPL( CvStatus, icvAddProduct_##flavor##_C3IMR, \
+( const srctype *src1, int step1, const srctype* src2, int step2, \
+ const uchar* mask, int maskstep, dsttype *dst, int dststep, CvSize size ),\
+ (src1, step1, src2, step2, mask, maskstep, dst, dststep, size )) \
+{ \
+ step1 /= sizeof(src1[0]); \
+ step2 /= sizeof(src2[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2, \
+ dst += dststep, mask += maskstep ) \
+ { \
+ int x; \
+ for( x = 0; x < size.width; x++ ) \
+ if( mask[x] ) \
+ { \
+ dsttype t0, t1, t2; \
+ t0 = dst[x*3]+cvtmacro(src1[x*3])*cvtmacro(src2[x*3]); \
+ t1 = dst[x*3+1]+cvtmacro(src1[x*3+1])*cvtmacro(src2[x*3+1]);\
+ t2 = dst[x*3+2]+cvtmacro(src1[x*3+2])*cvtmacro(src2[x*3+2]);\
+ dst[x*3] = t0; \
+ dst[x*3+1] = t1; \
+ dst[x*3+2] = t2; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_ACCPRODUCTMASK_FUNC_C3( 8u32f, uchar, float, CV_8TO32F )
+ICV_DEF_ACCPRODUCTMASK_FUNC_C3( 32f, float, float, CV_NOP )
+
+
+#define ICV_DEF_ACCWEIGHTMASK_FUNC_C3( flavor, srctype, dsttype, cvtmacro ) \
+IPCVAPI_IMPL( CvStatus, icvAddWeighted_##flavor##_C3IMR, \
+( const srctype *src, int srcstep, const uchar* mask, int maskstep, \
+ dsttype *dst, int dststep, CvSize size, dsttype alpha ), \
+ (src, srcstep, mask, maskstep, dst, dststep, size, alpha )) \
+{ \
+ dsttype beta = (dsttype)(1 - alpha); \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src += srcstep, \
+ dst += dststep, mask += maskstep ) \
+ { \
+ int x; \
+ for( x = 0; x < size.width; x++ ) \
+ if( mask[x] ) \
+ { \
+ dsttype t0, t1, t2; \
+ t0 = dst[x*3]*beta + cvtmacro(src[x*3])*alpha; \
+ t1 = dst[x*3+1]*beta + cvtmacro(src[x*3+1])*alpha; \
+ t2 = dst[x*3+2]*beta + cvtmacro(src[x*3+2])*alpha; \
+ dst[x*3] = t0; \
+ dst[x*3+1] = t1; \
+ dst[x*3+2] = t2; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+ICV_DEF_ACCWEIGHTMASK_FUNC_C3( 8u32f, uchar, float, CV_8TO32F )
+ICV_DEF_ACCWEIGHTMASK_FUNC_C3( 32f, float, float, CV_NOP )
+
+
+#define ICV_DEF_INIT_ACC_TAB( FUNCNAME ) \
+static void icvInit##FUNCNAME##Table( CvFuncTable* tab, CvBigFuncTable* masktab ) \
+{ \
+ tab->fn_2d[CV_8U] = (void*)icv##FUNCNAME##_8u32f_C1IR; \
+ tab->fn_2d[CV_32F] = (void*)icv##FUNCNAME##_32f_C1IR; \
+ \
+ masktab->fn_2d[CV_8UC1] = (void*)icv##FUNCNAME##_8u32f_C1IMR; \
+ masktab->fn_2d[CV_32FC1] = (void*)icv##FUNCNAME##_32f_C1IMR; \
+ \
+ masktab->fn_2d[CV_8UC3] = (void*)icv##FUNCNAME##_8u32f_C3IMR; \
+ masktab->fn_2d[CV_32FC3] = (void*)icv##FUNCNAME##_32f_C3IMR; \
+}
+
+
+ICV_DEF_INIT_ACC_TAB( Add )
+ICV_DEF_INIT_ACC_TAB( AddSquare )
+ICV_DEF_INIT_ACC_TAB( AddProduct )
+ICV_DEF_INIT_ACC_TAB( AddWeighted )
+
+
+CV_IMPL void
+cvAcc( const void* arr, void* sumarr, const void* maskarr )
+{
+ static CvFuncTable acc_tab;
+ static CvBigFuncTable accmask_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvAcc" );
+
+ __BEGIN__;
+
+ int type, sumdepth;
+ int mat_step, sum_step, mask_step = 0;
+ CvSize size;
+ CvMat stub, *mat = (CvMat*)arr;
+ CvMat sumstub, *sum = (CvMat*)sumarr;
+ CvMat maskstub, *mask = (CvMat*)maskarr;
+
+ if( !inittab )
+ {
+ icvInitAddTable( &acc_tab, &accmask_tab );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT( mat ) || !CV_IS_MAT( sum ))
+ {
+ int coi1 = 0, coi2 = 0;
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi1 ));
+ CV_CALL( sum = cvGetMat( sum, &sumstub, &coi2 ));
+ if( coi1 + coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( CV_MAT_DEPTH( sum->type ) != CV_32F )
+ CV_ERROR( CV_BadDepth, "" );
+
+ if( !CV_ARE_CNS_EQ( mat, sum ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ sumdepth = CV_MAT_DEPTH( sum->type );
+ if( sumdepth != CV_32F && (maskarr != 0 || sumdepth != CV_64F))
+ CV_ERROR( CV_BadDepth, "Bad accumulator type" );
+
+ if( !CV_ARE_SIZES_EQ( mat, sum ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ size = cvGetMatSize( mat );
+ type = CV_MAT_TYPE( mat->type );
+
+ mat_step = mat->step;
+ sum_step = sum->step;
+
+ if( !mask )
+ {
+ CvFunc2D_2A func=(CvFunc2D_2A)acc_tab.fn_2d[CV_MAT_DEPTH(type)];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "Unsupported type combination" );
+
+ size.width *= CV_MAT_CN(type);
+ if( CV_IS_MAT_CONT( mat->type & sum->type ))
+ {
+ size.width *= size.height;
+ mat_step = sum_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, sum->data.ptr, sum_step, size ));
+ }
+ else
+ {
+ CvFunc2D_3A func = (CvFunc2D_3A)accmask_tab.fn_2d[type];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+
+ if( !CV_IS_MASK_ARR( mask ))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !CV_ARE_SIZES_EQ( mat, mask ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ mask_step = mask->step;
+
+ if( CV_IS_MAT_CONT( mat->type & sum->type & mask->type ))
+ {
+ size.width *= size.height;
+ mat_step = sum_step = mask_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, mask->data.ptr, mask_step,
+ sum->data.ptr, sum_step, size ));
+ }
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvSquareAcc( const void* arr, void* sq_sum, const void* maskarr )
+{
+ static CvFuncTable acc_tab;
+ static CvBigFuncTable accmask_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvSquareAcc" );
+
+ __BEGIN__;
+
+ int coi1, coi2;
+ int type;
+ int mat_step, sum_step, mask_step = 0;
+ CvSize size;
+ CvMat stub, *mat = (CvMat*)arr;
+ CvMat sumstub, *sum = (CvMat*)sq_sum;
+ CvMat maskstub, *mask = (CvMat*)maskarr;
+
+ if( !inittab )
+ {
+ icvInitAddSquareTable( &acc_tab, &accmask_tab );
+ inittab = 1;
+ }
+
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi1 ));
+ CV_CALL( sum = cvGetMat( sum, &sumstub, &coi2 ));
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ if( !CV_ARE_CNS_EQ( mat, sum ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( CV_MAT_DEPTH( sum->type ) != CV_32F )
+ CV_ERROR( CV_BadDepth, "" );
+
+ if( !CV_ARE_SIZES_EQ( mat, sum ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ size = cvGetMatSize( mat );
+ type = CV_MAT_TYPE( mat->type );
+
+ mat_step = mat->step;
+ sum_step = sum->step;
+
+ if( !mask )
+ {
+ CvFunc2D_2A func = (CvFunc2D_2A)acc_tab.fn_2d[CV_MAT_DEPTH(type)];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ size.width *= CV_MAT_CN(type);
+
+ if( CV_IS_MAT_CONT( mat->type & sum->type ))
+ {
+ size.width *= size.height;
+ mat_step = sum_step = CV_STUB_STEP;;
+ size.height = 1;
+ }
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, sum->data.ptr, sum_step, size ));
+ }
+ else
+ {
+ CvFunc2D_3A func = (CvFunc2D_3A)accmask_tab.fn_2d[type];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+
+ if( !CV_IS_MASK_ARR( mask ))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !CV_ARE_SIZES_EQ( mat, mask ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ mask_step = mask->step;
+
+ if( CV_IS_MAT_CONT( mat->type & sum->type & mask->type ))
+ {
+ size.width *= size.height;
+ mat_step = sum_step = mask_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, mask->data.ptr, mask_step,
+ sum->data.ptr, sum_step, size ));
+ }
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvMultiplyAcc( const void* arrA, const void* arrB,
+ void* acc, const void* maskarr )
+{
+ static CvFuncTable acc_tab;
+ static CvBigFuncTable accmask_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvMultiplyAcc" );
+
+ __BEGIN__;
+
+ int coi1, coi2, coi3;
+ int type;
+ int mat1_step, mat2_step, sum_step, mask_step = 0;
+ CvSize size;
+ CvMat stub1, *mat1 = (CvMat*)arrA;
+ CvMat stub2, *mat2 = (CvMat*)arrB;
+ CvMat sumstub, *sum = (CvMat*)acc;
+ CvMat maskstub, *mask = (CvMat*)maskarr;
+
+ if( !inittab )
+ {
+ icvInitAddProductTable( &acc_tab, &accmask_tab );
+ inittab = 1;
+ }
+
+ CV_CALL( mat1 = cvGetMat( mat1, &stub1, &coi1 ));
+ CV_CALL( mat2 = cvGetMat( mat2, &stub2, &coi2 ));
+ CV_CALL( sum = cvGetMat( sum, &sumstub, &coi3 ));
+
+ if( coi1 != 0 || coi2 != 0 || coi3 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ if( !CV_ARE_CNS_EQ( mat1, mat2 ) || !CV_ARE_CNS_EQ( mat1, sum ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( CV_MAT_DEPTH( sum->type ) != CV_32F )
+ CV_ERROR( CV_BadDepth, "" );
+
+ if( !CV_ARE_SIZES_EQ( mat1, sum ) || !CV_ARE_SIZES_EQ( mat2, sum ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ size = cvGetMatSize( mat1 );
+ type = CV_MAT_TYPE( mat1->type );
+
+ mat1_step = mat1->step;
+ mat2_step = mat2->step;
+ sum_step = sum->step;
+
+ if( !mask )
+ {
+ CvFunc2D_3A func = (CvFunc2D_3A)acc_tab.fn_2d[CV_MAT_DEPTH(type)];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ size.width *= CV_MAT_CN(type);
+
+ if( CV_IS_MAT_CONT( mat1->type & mat2->type & sum->type ))
+ {
+ size.width *= size.height;
+ mat1_step = mat2_step = sum_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+
+ IPPI_CALL( func( mat1->data.ptr, mat1_step, mat2->data.ptr, mat2_step,
+ sum->data.ptr, sum_step, size ));
+ }
+ else
+ {
+ CvFunc2D_4A func = (CvFunc2D_4A)accmask_tab.fn_2d[type];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+
+ if( !CV_IS_MASK_ARR( mask ))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !CV_ARE_SIZES_EQ( mat1, mask ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ mask_step = mask->step;
+
+ if( CV_IS_MAT_CONT( mat1->type & mat2->type & sum->type & mask->type ))
+ {
+ size.width *= size.height;
+ mat1_step = mat2_step = sum_step = mask_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+
+ IPPI_CALL( func( mat1->data.ptr, mat1_step, mat2->data.ptr, mat2_step,
+ mask->data.ptr, mask_step,
+ sum->data.ptr, sum_step, size ));
+ }
+
+ __END__;
+}
+
+
+typedef CvStatus (CV_STDCALL *CvAddWeightedFunc)( const void* src, int srcstep,
+ void* dst, int dststep,
+ CvSize size, float alpha );
+
+typedef CvStatus (CV_STDCALL *CvAddWeightedMaskFunc)( const void* src, int srcstep,
+ void* dst, int dststep,
+ const void* mask, int maskstep,
+ CvSize size, float alpha );
+
+CV_IMPL void
+cvRunningAvg( const void* arrY, void* arrU,
+ double alpha, const void* maskarr )
+{
+ static CvFuncTable acc_tab;
+ static CvBigFuncTable accmask_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvRunningAvg" );
+
+ __BEGIN__;
+
+ int coi1, coi2;
+ int type;
+ int mat_step, sum_step, mask_step = 0;
+ CvSize size;
+ CvMat stub, *mat = (CvMat*)arrY;
+ CvMat sumstub, *sum = (CvMat*)arrU;
+ CvMat maskstub, *mask = (CvMat*)maskarr;
+
+ if( !inittab )
+ {
+ icvInitAddWeightedTable( &acc_tab, &accmask_tab );
+ inittab = 1;
+ }
+
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi1 ));
+ CV_CALL( sum = cvGetMat( sum, &sumstub, &coi2 ));
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ if( !CV_ARE_CNS_EQ( mat, sum ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( CV_MAT_DEPTH( sum->type ) != CV_32F )
+ CV_ERROR( CV_BadDepth, "" );
+
+ if( !CV_ARE_SIZES_EQ( mat, sum ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ size = cvGetMatSize( mat );
+ type = CV_MAT_TYPE( mat->type );
+
+ mat_step = mat->step;
+ sum_step = sum->step;
+
+ if( !mask )
+ {
+ CvAddWeightedFunc func = (CvAddWeightedFunc)acc_tab.fn_2d[CV_MAT_DEPTH(type)];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ size.width *= CV_MAT_CN(type);
+ if( CV_IS_MAT_CONT( mat->type & sum->type ))
+ {
+ size.width *= size.height;
+ mat_step = sum_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+
+ IPPI_CALL( func( mat->data.ptr, mat_step,
+ sum->data.ptr, sum_step, size, (float)alpha ));
+ }
+ else
+ {
+ CvAddWeightedMaskFunc func = (CvAddWeightedMaskFunc)accmask_tab.fn_2d[type];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+
+ if( !CV_IS_MASK_ARR( mask ))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !CV_ARE_SIZES_EQ( mat, mask ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ mask_step = mask->step;
+
+ if( CV_IS_MAT_CONT( mat->type & sum->type & mask->type ))
+ {
+ size.width *= size.height;
+ mat_step = sum_step = mask_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, mask->data.ptr, mask_step,
+ sum->data.ptr, sum_step, size, (float)alpha ));
+ }
+
+ __END__;
+}
+
+
+/* End of file. */
diff --git a/cv/src/cvadapthresh.cpp b/cv/src/cvadapthresh.cpp
new file mode 100644
index 0000000..30d4733
--- /dev/null
+++ b/cv/src/cvadapthresh.cpp
@@ -0,0 +1,144 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+static void
+icvAdaptiveThreshold_MeanC( const CvMat* src, CvMat* dst, int method,
+ int maxValue, int type, int size, double delta )
+{
+ CvMat* mean = 0;
+ CV_FUNCNAME( "icvAdaptiveThreshold_MeanC" );
+
+ __BEGIN__;
+
+ int i, j, rows, cols;
+ int idelta = type == CV_THRESH_BINARY ? cvCeil(delta) : cvFloor(delta);
+ uchar tab[768];
+
+ if( size <= 1 || (size&1) == 0 )
+ CV_ERROR( CV_StsOutOfRange, "Neighborhood size must be >=3 and odd (3, 5, 7, ...)" );
+
+ if( maxValue < 0 )
+ {
+ CV_CALL( cvSetZero( dst ));
+ EXIT;
+ }
+
+ rows = src->rows;
+ cols = src->cols;
+
+ if( src->data.ptr != dst->data.ptr )
+ mean = dst;
+ else
+ CV_CALL( mean = cvCreateMat( rows, cols, CV_8UC1 ));
+
+ CV_CALL( cvSmooth( src, mean, method == CV_ADAPTIVE_THRESH_MEAN_C ?
+ CV_BLUR : CV_GAUSSIAN, size, size ));
+ if( maxValue > 255 )
+ maxValue = 255;
+
+ if( type == CV_THRESH_BINARY )
+ for( i = 0; i < 768; i++ )
+ tab[i] = (uchar)(i - 255 > -idelta ? maxValue : 0);
+ else
+ for( i = 0; i < 768; i++ )
+ tab[i] = (uchar)(i - 255 <= -idelta ? maxValue : 0);
+
+ for( i = 0; i < rows; i++ )
+ {
+ const uchar* s = src->data.ptr + i*src->step;
+ const uchar* m = mean->data.ptr + i*mean->step;
+ uchar* d = dst->data.ptr + i*dst->step;
+
+ for( j = 0; j < cols; j++ )
+ d[j] = tab[s[j] - m[j] + 255];
+ }
+
+ __END__;
+
+ if( mean != dst )
+ cvReleaseMat( &mean );
+}
+
+
+CV_IMPL void
+cvAdaptiveThreshold( const void *srcIm, void *dstIm, double maxValue,
+ int method, int type, int blockSize, double param1 )
+{
+ CvMat src_stub, dst_stub;
+ CvMat *src = 0, *dst = 0;
+
+ CV_FUNCNAME( "cvAdaptiveThreshold" );
+
+ __BEGIN__;
+
+ if( type != CV_THRESH_BINARY && type != CV_THRESH_BINARY_INV )
+ CV_ERROR( CV_StsBadArg, "Only CV_TRESH_BINARY and CV_THRESH_BINARY_INV "
+ "threshold types are acceptable" );
+
+ CV_CALL( src = cvGetMat( srcIm, &src_stub ));
+ CV_CALL( dst = cvGetMat( dstIm, &dst_stub ));
+
+ if( !CV_ARE_CNS_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( CV_MAT_TYPE(dst->type) != CV_8UC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ) )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ switch( method )
+ {
+ case CV_ADAPTIVE_THRESH_MEAN_C:
+ case CV_ADAPTIVE_THRESH_GAUSSIAN_C:
+ CV_CALL( icvAdaptiveThreshold_MeanC( src, dst, method, cvRound(maxValue),type,
+ blockSize, param1 ));
+ break;
+ default:
+ CV_ERROR( CV_BADCOEF_ERR, "" );
+ }
+
+ __END__;
+}
+
+/* End of file. */
diff --git a/cv/src/cvapprox.cpp b/cv/src/cvapprox.cpp
new file mode 100644
index 0000000..d26ecd4
--- /dev/null
+++ b/cv/src/cvapprox.cpp
@@ -0,0 +1,1064 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+/****************************************************************************************\
+* Chain Approximation *
+\****************************************************************************************/
+
+typedef struct _CvPtInfo
+{
+ CvPoint pt;
+ int k; /* support region */
+ int s; /* curvature value */
+ struct _CvPtInfo *next;
+}
+_CvPtInfo;
+
+
+/* curvature: 0 - 1-curvature, 1 - k-cosine curvature. */
+CvStatus
+icvApproximateChainTC89( CvChain* chain,
+ int header_size,
+ CvMemStorage* storage,
+ CvSeq** contour,
+ int method )
+{
+ static const int abs_diff[] = { 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1 };
+
+ char local_buffer[1 << 16];
+ char* buffer = local_buffer;
+ int buffer_size;
+
+ _CvPtInfo temp;
+ _CvPtInfo *array, *first = 0, *current = 0, *prev_current = 0;
+ int i, j, i1, i2, s, len;
+ int count;
+
+ CvChainPtReader reader;
+ CvSeqWriter writer;
+ CvPoint pt = chain->origin;
+
+ assert( chain && contour && buffer );
+
+ buffer_size = (chain->total + 8) * sizeof( _CvPtInfo );
+
+ *contour = 0;
+
+ if( !CV_IS_SEQ_CHAIN_CONTOUR( chain ))
+ return CV_BADFLAG_ERR;
+
+ if( header_size < (int)sizeof(CvContour) )
+ return CV_BADSIZE_ERR;
+
+ cvStartWriteSeq( (chain->flags & ~CV_SEQ_ELTYPE_MASK) | CV_SEQ_ELTYPE_POINT,
+ header_size, sizeof( CvPoint ), storage, &writer );
+
+ if( chain->total == 0 )
+ {
+ CV_WRITE_SEQ_ELEM( pt, writer );
+ goto exit_function;
+ }
+
+ cvStartReadChainPoints( chain, &reader );
+
+ if( method > CV_CHAIN_APPROX_SIMPLE && buffer_size > (int)sizeof(local_buffer))
+ {
+ buffer = (char *) cvAlloc( buffer_size );
+ if( !buffer )
+ return CV_OUTOFMEM_ERR;
+ }
+
+ array = (_CvPtInfo *) buffer;
+ count = chain->total;
+
+ temp.next = 0;
+ current = &temp;
+
+ /* Pass 0.
+ Restores all the digital curve points from the chain code.
+ Removes the points (from the resultant polygon)
+ that have zero 1-curvature */
+ for( i = 0; i < count; i++ )
+ {
+ int prev_code = *reader.prev_elem;
+
+ reader.prev_elem = reader.ptr;
+ CV_READ_CHAIN_POINT( pt, reader );
+
+ /* calc 1-curvature */
+ s = abs_diff[reader.code - prev_code + 7];
+
+ if( method <= CV_CHAIN_APPROX_SIMPLE )
+ {
+ if( method == CV_CHAIN_APPROX_NONE || s != 0 )
+ {
+ CV_WRITE_SEQ_ELEM( pt, writer );
+ }
+ }
+ else
+ {
+ if( s != 0 )
+ current = current->next = array + i;
+ array[i].s = s;
+ array[i].pt = pt;
+ }
+ }
+
+ //assert( pt.x == chain->origin.x && pt.y == chain->origin.y );
+
+ if( method <= CV_CHAIN_APPROX_SIMPLE )
+ goto exit_function;
+
+ current->next = 0;
+
+ len = i;
+ current = temp.next;
+
+ assert( current );
+
+ /* Pass 1.
+ Determines support region for all the remained points */
+ do
+ {
+ CvPoint pt0;
+ int k, l = 0, d_num = 0;
+
+ i = (int)(current - array);
+ pt0 = array[i].pt;
+
+ /* determine support region */
+ for( k = 1;; k++ )
+ {
+ int lk, dk_num;
+ int dx, dy;
+ Cv32suf d;
+
+ assert( k <= len );
+
+ /* calc indices */
+ i1 = i - k;
+ i1 += i1 < 0 ? len : 0;
+ i2 = i + k;
+ i2 -= i2 >= len ? len : 0;
+
+ dx = array[i2].pt.x - array[i1].pt.x;
+ dy = array[i2].pt.y - array[i1].pt.y;
+
+ /* distance between p_(i - k) and p_(i + k) */
+ lk = dx * dx + dy * dy;
+
+ /* distance between p_i and the line (p_(i-k), p_(i+k)) */
+ dk_num = (pt0.x - array[i1].pt.x) * dy - (pt0.y - array[i1].pt.y) * dx;
+ d.f = (float) (((double) d_num) * lk - ((double) dk_num) * l);
+
+ if( k > 1 && (l >= lk || ((d_num > 0 && d.i <= 0) || (d_num < 0 && d.i >= 0))))
+ break;
+
+ d_num = dk_num;
+ l = lk;
+ }
+
+ current->k = --k;
+
+ /* determine cosine curvature if it should be used */
+ if( method == CV_CHAIN_APPROX_TC89_KCOS )
+ {
+ /* calc k-cosine curvature */
+ for( j = k, s = 0; j > 0; j-- )
+ {
+ double temp_num;
+ int dx1, dy1, dx2, dy2;
+ Cv32suf sk;
+
+ i1 = i - j;
+ i1 += i1 < 0 ? len : 0;
+ i2 = i + j;
+ i2 -= i2 >= len ? len : 0;
+
+ dx1 = array[i1].pt.x - pt0.x;
+ dy1 = array[i1].pt.y - pt0.y;
+ dx2 = array[i2].pt.x - pt0.x;
+ dy2 = array[i2].pt.y - pt0.y;
+
+ if( (dx1 | dy1) == 0 || (dx2 | dy2) == 0 )
+ break;
+
+ temp_num = dx1 * dx2 + dy1 * dy2;
+ temp_num =
+ (float) (temp_num /
+ sqrt( ((double)dx1 * dx1 + (double)dy1 * dy1) *
+ ((double)dx2 * dx2 + (double)dy2 * dy2) ));
+ sk.f = (float) (temp_num + 1.1);
+
+ assert( 0 <= sk.f && sk.f <= 2.2 );
+ if( j < k && sk.i <= s )
+ break;
+
+ s = sk.i;
+ }
+ current->s = s;
+ }
+ current = current->next;
+ }
+ while( current != 0 );
+
+ prev_current = &temp;
+ current = temp.next;
+
+ /* Pass 2.
+ Performs non-maxima supression */
+ do
+ {
+ int k2 = current->k >> 1;
+
+ s = current->s;
+ i = (int)(current - array);
+
+ for( j = 1; j <= k2; j++ )
+ {
+ i2 = i - j;
+ i2 += i2 < 0 ? len : 0;
+
+ if( array[i2].s > s )
+ break;
+
+ i2 = i + j;
+ i2 -= i2 >= len ? len : 0;
+
+ if( array[i2].s > s )
+ break;
+ }
+
+ if( j <= k2 ) /* exclude point */
+ {
+ prev_current->next = current->next;
+ current->s = 0; /* "clear" point */
+ }
+ else
+ prev_current = current;
+ current = current->next;
+ }
+ while( current != 0 );
+
+ /* Pass 3.
+ Removes non-dominant points with 1-length support region */
+ current = temp.next;
+ assert( current );
+ prev_current = &temp;
+
+ do
+ {
+ if( current->k == 1 )
+ {
+ s = current->s;
+ i = (int)(current - array);
+
+ i1 = i - 1;
+ i1 += i1 < 0 ? len : 0;
+
+ i2 = i + 1;
+ i2 -= i2 >= len ? len : 0;
+
+ if( s <= array[i1].s || s <= array[i2].s )
+ {
+ prev_current->next = current->next;
+ current->s = 0;
+ }
+ else
+ prev_current = current;
+ }
+ else
+ prev_current = current;
+ current = current->next;
+ }
+ while( current != 0 );
+
+ if( method == CV_CHAIN_APPROX_TC89_KCOS )
+ goto copy_vect;
+
+ /* Pass 4.
+ Cleans remained couples of points */
+ assert( temp.next );
+
+ if( array[0].s != 0 && array[len - 1].s != 0 ) /* specific case */
+ {
+ for( i1 = 1; i1 < len && array[i1].s != 0; i1++ )
+ {
+ array[i1 - 1].s = 0;
+ }
+ if( i1 == len )
+ goto copy_vect; /* all points survived */
+ i1--;
+
+ for( i2 = len - 2; i2 > 0 && array[i2].s != 0; i2-- )
+ {
+ array[i2].next = 0;
+ array[i2 + 1].s = 0;
+ }
+ i2++;
+
+ if( i1 == 0 && i2 == len - 1 ) /* only two points */
+ {
+ i1 = (int)(array[0].next - array);
+ array[len] = array[0]; /* move to the end */
+ array[len].next = 0;
+ array[len - 1].next = array + len;
+ }
+ temp.next = array + i1;
+ }
+
+ current = temp.next;
+ first = prev_current = &temp;
+ count = 1;
+
+ /* do last pass */
+ do
+ {
+ if( current->next == 0 || current->next - current != 1 )
+ {
+ if( count >= 2 )
+ {
+ if( count == 2 )
+ {
+ int s1 = prev_current->s;
+ int s2 = current->s;
+
+ if( s1 > s2 || (s1 == s2 && prev_current->k <= current->k) )
+ /* remove second */
+ prev_current->next = current->next;
+ else
+ /* remove first */
+ first->next = current;
+ }
+ else
+ first->next->next = current;
+ }
+ first = current;
+ count = 1;
+ }
+ else
+ count++;
+ prev_current = current;
+ current = current->next;
+ }
+ while( current != 0 );
+
+ copy_vect:
+
+ /* gather points */
+ current = temp.next;
+ assert( current );
+
+ do
+ {
+ CV_WRITE_SEQ_ELEM( current->pt, writer );
+ current = current->next;
+ }
+ while( current != 0 );
+
+exit_function:
+
+ *contour = cvEndWriteSeq( &writer );
+
+ assert( writer.seq->total > 0 );
+
+ if( buffer != local_buffer )
+ cvFree( &buffer );
+ return CV_OK;
+}
+
+
+/*Applies some approximation algorithm to chain-coded contour(s) and
+ converts it/them to polygonal representation */
+CV_IMPL CvSeq*
+cvApproxChains( CvSeq* src_seq,
+ CvMemStorage* storage,
+ int method,
+ double /*parameter*/,
+ int minimal_perimeter,
+ int recursive )
+{
+ CvSeq *prev_contour = 0, *parent = 0;
+ CvSeq *dst_seq = 0;
+
+ CV_FUNCNAME( "cvApproxChains" );
+
+ __BEGIN__;
+
+ if( !src_seq || !storage )
+ CV_ERROR( CV_StsNullPtr, "" );
+ if( method > CV_CHAIN_APPROX_TC89_KCOS || method <= 0 || minimal_perimeter < 0 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ while( src_seq != 0 )
+ {
+ int len = src_seq->total;
+
+ if( len >= minimal_perimeter )
+ {
+ CvSeq *contour;
+
+ switch( method )
+ {
+ case CV_CHAIN_APPROX_NONE:
+ case CV_CHAIN_APPROX_SIMPLE:
+ case CV_CHAIN_APPROX_TC89_L1:
+ case CV_CHAIN_APPROX_TC89_KCOS:
+ IPPI_CALL( icvApproximateChainTC89( (CvChain *) src_seq,
+ sizeof( CvContour ), storage,
+ (CvSeq**)&contour, method ));
+ break;
+ default:
+ assert(0);
+ CV_ERROR( CV_StsOutOfRange, "" );
+ }
+
+ assert( contour );
+
+ if( contour->total > 0 )
+ {
+ cvBoundingRect( contour, 1 );
+
+ contour->v_prev = parent;
+ contour->h_prev = prev_contour;
+
+ if( prev_contour )
+ prev_contour->h_next = contour;
+ else if( parent )
+ parent->v_next = contour;
+ prev_contour = contour;
+ if( !dst_seq )
+ dst_seq = prev_contour;
+ }
+ else /* if resultant contour has zero length, skip it */
+ {
+ len = -1;
+ }
+ }
+
+ if( !recursive )
+ break;
+
+ if( src_seq->v_next && len >= minimal_perimeter )
+ {
+ assert( prev_contour != 0 );
+ parent = prev_contour;
+ prev_contour = 0;
+ src_seq = src_seq->v_next;
+ }
+ else
+ {
+ while( src_seq->h_next == 0 )
+ {
+ src_seq = src_seq->v_prev;
+ if( src_seq == 0 )
+ break;
+ prev_contour = parent;
+ if( parent )
+ parent = parent->v_prev;
+ }
+ if( src_seq )
+ src_seq = src_seq->h_next;
+ }
+ }
+
+ __END__;
+
+ return dst_seq;
+}
+
+
+/****************************************************************************************\
+* Polygonal Approximation *
+\****************************************************************************************/
+
+/* Ramer-Douglas-Peucker algorithm for polygon simplification */
+
+/* the version for integer point coordinates */
+static CvStatus
+icvApproxPolyDP_32s( CvSeq* src_contour, int header_size,
+ CvMemStorage* storage,
+ CvSeq** dst_contour, float eps )
+{
+ int init_iters = 3;
+ CvSlice slice = {0, 0}, right_slice = {0, 0};
+ CvSeqReader reader, reader2;
+ CvSeqWriter writer;
+ CvPoint start_pt = {INT_MIN, INT_MIN}, end_pt = {0, 0}, pt = {0,0};
+ int i = 0, j, count = src_contour->total, new_count;
+ int is_closed = CV_IS_SEQ_CLOSED( src_contour );
+ int le_eps = 0;
+ CvMemStorage* temp_storage = 0;
+ CvSeq* stack = 0;
+
+ assert( CV_SEQ_ELTYPE(src_contour) == CV_32SC2 );
+ cvStartWriteSeq( src_contour->flags, header_size, sizeof(pt), storage, &writer );
+
+ if( src_contour->total == 0 )
+ {
+ *dst_contour = cvEndWriteSeq( &writer );
+ return CV_OK;
+ }
+
+ temp_storage = cvCreateChildMemStorage( storage );
+
+ assert( src_contour->first != 0 );
+ stack = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSlice), temp_storage );
+ eps *= eps;
+ cvStartReadSeq( src_contour, &reader, 0 );
+
+ if( !is_closed )
+ {
+ right_slice.start_index = count;
+ end_pt = *(CvPoint*)(reader.ptr);
+ start_pt = *(CvPoint*)cvGetSeqElem( src_contour, -1 );
+
+ if( start_pt.x != end_pt.x || start_pt.y != end_pt.y )
+ {
+ slice.start_index = 0;
+ slice.end_index = count - 1;
+ cvSeqPush( stack, &slice );
+ }
+ else
+ {
+ is_closed = 1;
+ init_iters = 1;
+ }
+ }
+
+ if( is_closed )
+ {
+ /* 1. Find approximately two farthest points of the contour */
+ right_slice.start_index = 0;
+
+ for( i = 0; i < init_iters; i++ )
+ {
+ int max_dist = 0;
+ cvSetSeqReaderPos( &reader, right_slice.start_index, 1 );
+ CV_READ_SEQ_ELEM( start_pt, reader ); /* read the first point */
+
+ for( j = 1; j < count; j++ )
+ {
+ int dx, dy, dist;
+
+ CV_READ_SEQ_ELEM( pt, reader );
+ dx = pt.x - start_pt.x;
+ dy = pt.y - start_pt.y;
+
+ dist = dx * dx + dy * dy;
+
+ if( dist > max_dist )
+ {
+ max_dist = dist;
+ right_slice.start_index = j;
+ }
+ }
+
+ le_eps = max_dist <= eps;
+ }
+
+ /* 2. initialize the stack */
+ if( !le_eps )
+ {
+ slice.start_index = cvGetSeqReaderPos( &reader );
+ slice.end_index = right_slice.start_index += slice.start_index;
+
+ right_slice.start_index -= right_slice.start_index >= count ? count : 0;
+ right_slice.end_index = slice.start_index;
+ if( right_slice.end_index < right_slice.start_index )
+ right_slice.end_index += count;
+
+ cvSeqPush( stack, &right_slice );
+ cvSeqPush( stack, &slice );
+ }
+ else
+ CV_WRITE_SEQ_ELEM( start_pt, writer );
+ }
+
+ /* 3. run recursive process */
+ while( stack->total != 0 )
+ {
+ cvSeqPop( stack, &slice );
+
+ cvSetSeqReaderPos( &reader, slice.end_index );
+ CV_READ_SEQ_ELEM( end_pt, reader );
+
+ cvSetSeqReaderPos( &reader, slice.start_index );
+ CV_READ_SEQ_ELEM( start_pt, reader );
+
+ if( slice.end_index > slice.start_index + 1 )
+ {
+ int dx, dy, dist, max_dist = 0;
+
+ dx = end_pt.x - start_pt.x;
+ dy = end_pt.y - start_pt.y;
+
+ assert( dx != 0 || dy != 0 );
+
+ for( i = slice.start_index + 1; i < slice.end_index; i++ )
+ {
+ CV_READ_SEQ_ELEM( pt, reader );
+ dist = abs((pt.y - start_pt.y) * dx - (pt.x - start_pt.x) * dy);
+
+ if( dist > max_dist )
+ {
+ max_dist = dist;
+ right_slice.start_index = i;
+ }
+ }
+
+ le_eps = (double)max_dist * max_dist <= eps * ((double)dx * dx + (double)dy * dy);
+ }
+ else
+ {
+ assert( slice.end_index > slice.start_index );
+ le_eps = 1;
+ /* read starting point */
+ cvSetSeqReaderPos( &reader, slice.start_index );
+ CV_READ_SEQ_ELEM( start_pt, reader );
+ }
+
+ if( le_eps )
+ {
+ CV_WRITE_SEQ_ELEM( start_pt, writer );
+ }
+ else
+ {
+ right_slice.end_index = slice.end_index;
+ slice.end_index = right_slice.start_index;
+ cvSeqPush( stack, &right_slice );
+ cvSeqPush( stack, &slice );
+ }
+ }
+
+ is_closed = CV_IS_SEQ_CLOSED( src_contour );
+ if( !is_closed )
+ CV_WRITE_SEQ_ELEM( end_pt, writer );
+
+ *dst_contour = cvEndWriteSeq( &writer );
+
+ cvStartReadSeq( *dst_contour, &reader, is_closed );
+ CV_READ_SEQ_ELEM( start_pt, reader );
+
+ reader2 = reader;
+ CV_READ_SEQ_ELEM( pt, reader );
+
+ new_count = count = (*dst_contour)->total;
+ for( i = !is_closed; i < count - !is_closed && new_count > 2; i++ )
+ {
+ int dx, dy, dist;
+ CV_READ_SEQ_ELEM( end_pt, reader );
+
+ dx = end_pt.x - start_pt.x;
+ dy = end_pt.y - start_pt.y;
+ dist = abs((pt.x - start_pt.x)*dy - (pt.y - start_pt.y)*dx);
+ if( (double)dist * dist <= 0.5*eps*((double)dx*dx + (double)dy*dy) && dx != 0 && dy != 0 )
+ {
+ new_count--;
+ *((CvPoint*)reader2.ptr) = start_pt = end_pt;
+ CV_NEXT_SEQ_ELEM( sizeof(pt), reader2 );
+ CV_READ_SEQ_ELEM( pt, reader );
+ i++;
+ continue;
+ }
+ *((CvPoint*)reader2.ptr) = start_pt = pt;
+ CV_NEXT_SEQ_ELEM( sizeof(pt), reader2 );
+ pt = end_pt;
+ }
+
+ if( !is_closed )
+ *((CvPoint*)reader2.ptr) = pt;
+
+ if( new_count < count )
+ cvSeqPopMulti( *dst_contour, 0, count - new_count );
+
+ cvReleaseMemStorage( &temp_storage );
+
+ return CV_OK;
+}
+
+
+/* the version for integer point coordinates */
+static CvStatus
+icvApproxPolyDP_32f( CvSeq* src_contour, int header_size,
+ CvMemStorage* storage,
+ CvSeq** dst_contour, float eps )
+{
+ int init_iters = 3;
+ CvSlice slice = {0, 0}, right_slice = {0, 0};
+ CvSeqReader reader, reader2;
+ CvSeqWriter writer;
+ CvPoint2D32f start_pt = {-1e6f, -1e6f}, end_pt = {0, 0}, pt = {0,0};
+ int i = 0, j, count = src_contour->total, new_count;
+ int is_closed = CV_IS_SEQ_CLOSED( src_contour );
+ int le_eps = 0;
+ CvMemStorage* temp_storage = 0;
+ CvSeq* stack = 0;
+
+ assert( CV_SEQ_ELTYPE(src_contour) == CV_32FC2 );
+ cvStartWriteSeq( src_contour->flags, header_size, sizeof(pt), storage, &writer );
+
+ if( src_contour->total == 0 )
+ {
+ *dst_contour = cvEndWriteSeq( &writer );
+ return CV_OK;
+ }
+
+ temp_storage = cvCreateChildMemStorage( storage );
+
+ assert( src_contour->first != 0 );
+ stack = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSlice), temp_storage );
+ eps *= eps;
+ cvStartReadSeq( src_contour, &reader, 0 );
+
+ if( !is_closed )
+ {
+ right_slice.start_index = count;
+ end_pt = *(CvPoint2D32f*)(reader.ptr);
+ start_pt = *(CvPoint2D32f*)cvGetSeqElem( src_contour, -1 );
+
+ if( fabs(start_pt.x - end_pt.x) > FLT_EPSILON ||
+ fabs(start_pt.y - end_pt.y) > FLT_EPSILON )
+ {
+ slice.start_index = 0;
+ slice.end_index = count - 1;
+ cvSeqPush( stack, &slice );
+ }
+ else
+ {
+ is_closed = 1;
+ init_iters = 1;
+ }
+ }
+
+ if( is_closed )
+ {
+ /* 1. Find approximately two farthest points of the contour */
+ right_slice.start_index = 0;
+
+ for( i = 0; i < init_iters; i++ )
+ {
+ double max_dist = 0;
+ cvSetSeqReaderPos( &reader, right_slice.start_index, 1 );
+ CV_READ_SEQ_ELEM( start_pt, reader ); /* read the first point */
+
+ for( j = 1; j < count; j++ )
+ {
+ double dx, dy, dist;
+
+ CV_READ_SEQ_ELEM( pt, reader );
+ dx = pt.x - start_pt.x;
+ dy = pt.y - start_pt.y;
+
+ dist = dx * dx + dy * dy;
+
+ if( dist > max_dist )
+ {
+ max_dist = dist;
+ right_slice.start_index = j;
+ }
+ }
+
+ le_eps = max_dist <= eps;
+ }
+
+ /* 2. initialize the stack */
+ if( !le_eps )
+ {
+ slice.start_index = cvGetSeqReaderPos( &reader );
+ slice.end_index = right_slice.start_index += slice.start_index;
+
+ right_slice.start_index -= right_slice.start_index >= count ? count : 0;
+ right_slice.end_index = slice.start_index;
+ if( right_slice.end_index < right_slice.start_index )
+ right_slice.end_index += count;
+
+ cvSeqPush( stack, &right_slice );
+ cvSeqPush( stack, &slice );
+ }
+ else
+ CV_WRITE_SEQ_ELEM( start_pt, writer );
+ }
+
+ /* 3. run recursive process */
+ while( stack->total != 0 )
+ {
+ cvSeqPop( stack, &slice );
+
+ cvSetSeqReaderPos( &reader, slice.end_index );
+ CV_READ_SEQ_ELEM( end_pt, reader );
+
+ cvSetSeqReaderPos( &reader, slice.start_index );
+ CV_READ_SEQ_ELEM( start_pt, reader );
+
+ if( slice.end_index > slice.start_index + 1 )
+ {
+ double dx, dy, dist, max_dist = 0;
+
+ dx = end_pt.x - start_pt.x;
+ dy = end_pt.y - start_pt.y;
+
+ assert( dx != 0 || dy != 0 );
+
+ for( i = slice.start_index + 1; i < slice.end_index; i++ )
+ {
+ CV_READ_SEQ_ELEM( pt, reader );
+ dist = fabs((pt.y - start_pt.y) * dx - (pt.x - start_pt.x) * dy);
+
+ if( dist > max_dist )
+ {
+ max_dist = dist;
+ right_slice.start_index = i;
+ }
+ }
+
+ le_eps = (double)max_dist * max_dist <= eps * ((double)dx * dx + (double)dy * dy);
+ }
+ else
+ {
+ assert( slice.end_index > slice.start_index );
+ le_eps = 1;
+ /* read starting point */
+ cvSetSeqReaderPos( &reader, slice.start_index );
+ CV_READ_SEQ_ELEM( start_pt, reader );
+ }
+
+ if( le_eps )
+ {
+ CV_WRITE_SEQ_ELEM( start_pt, writer );
+ }
+ else
+ {
+ right_slice.end_index = slice.end_index;
+ slice.end_index = right_slice.start_index;
+ cvSeqPush( stack, &right_slice );
+ cvSeqPush( stack, &slice );
+ }
+ }
+
+ is_closed = CV_IS_SEQ_CLOSED( src_contour );
+ if( !is_closed )
+ CV_WRITE_SEQ_ELEM( end_pt, writer );
+
+ *dst_contour = cvEndWriteSeq( &writer );
+
+ cvStartReadSeq( *dst_contour, &reader, is_closed );
+ CV_READ_SEQ_ELEM( start_pt, reader );
+
+ reader2 = reader;
+ CV_READ_SEQ_ELEM( pt, reader );
+
+ new_count = count = (*dst_contour)->total;
+ for( i = !is_closed; i < count - !is_closed && new_count > 2; i++ )
+ {
+ double dx, dy, dist;
+ CV_READ_SEQ_ELEM( end_pt, reader );
+
+ dx = end_pt.x - start_pt.x;
+ dy = end_pt.y - start_pt.y;
+ dist = fabs((pt.x - start_pt.x)*dy - (pt.y - start_pt.y)*dx);
+ if( (double)dist * dist <= 0.5*eps*((double)dx*dx + (double)dy*dy) )
+ {
+ new_count--;
+ *((CvPoint2D32f*)reader2.ptr) = start_pt = end_pt;
+ CV_NEXT_SEQ_ELEM( sizeof(pt), reader2 );
+ CV_READ_SEQ_ELEM( pt, reader );
+ i++;
+ continue;
+ }
+ *((CvPoint2D32f*)reader2.ptr) = start_pt = pt;
+ CV_NEXT_SEQ_ELEM( sizeof(pt), reader2 );
+ pt = end_pt;
+ }
+
+ if( !is_closed )
+ *((CvPoint2D32f*)reader2.ptr) = pt;
+
+ if( new_count < count )
+ cvSeqPopMulti( *dst_contour, 0, count - new_count );
+
+ cvReleaseMemStorage( &temp_storage );
+
+ return CV_OK;
+}
+
+
+CV_IMPL CvSeq*
+cvApproxPoly( const void* array, int header_size,
+ CvMemStorage* storage, int method,
+ double parameter, int parameter2 )
+{
+ CvSeq* dst_seq = 0;
+ CvSeq *prev_contour = 0, *parent = 0;
+ CvContour contour_header;
+ CvSeq* src_seq = 0;
+ CvSeqBlock block;
+ int recursive = 0;
+
+ CV_FUNCNAME( "cvApproxPoly" );
+
+ __BEGIN__;
+
+ if( CV_IS_SEQ( array ))
+ {
+ src_seq = (CvSeq*)array;
+ if( !CV_IS_SEQ_POLYLINE( src_seq ))
+ CV_ERROR( CV_StsBadArg, "Unsupported sequence type" );
+
+ recursive = parameter2;
+
+ if( !storage )
+ storage = src_seq->storage;
+ }
+ else
+ {
+ CV_CALL( src_seq = cvPointSeqFromMat(
+ CV_SEQ_KIND_CURVE | (parameter2 ? CV_SEQ_FLAG_CLOSED : 0),
+ array, &contour_header, &block ));
+ }
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "NULL storage pointer " );
+
+ if( header_size < 0 )
+ CV_ERROR( CV_StsOutOfRange, "header_size is negative. "
+ "Pass 0 to make the destination header_size == input header_size" );
+
+ if( header_size == 0 )
+ header_size = src_seq->header_size;
+
+ if( !CV_IS_SEQ_POLYLINE( src_seq ))
+ {
+ if( CV_IS_SEQ_CHAIN( src_seq ))
+ {
+ CV_ERROR( CV_StsBadArg, "Input curves are not polygonal. "
+ "Use cvApproxChains first" );
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg, "Input curves have uknown type" );
+ }
+ }
+
+ if( header_size == 0 )
+ header_size = src_seq->header_size;
+
+ if( header_size < (int)sizeof(CvContour) )
+ CV_ERROR( CV_StsBadSize, "New header size must be non-less than sizeof(CvContour)" );
+
+ if( method != CV_POLY_APPROX_DP )
+ CV_ERROR( CV_StsOutOfRange, "Unknown approximation method" );
+
+ while( src_seq != 0 )
+ {
+ CvSeq *contour = 0;
+
+ switch (method)
+ {
+ case CV_POLY_APPROX_DP:
+ if( parameter < 0 )
+ CV_ERROR( CV_StsOutOfRange, "Accuracy must be non-negative" );
+
+ if( CV_SEQ_ELTYPE(src_seq) == CV_32SC2 )
+ {
+ IPPI_CALL( icvApproxPolyDP_32s( src_seq, header_size, storage,
+ &contour, (float)parameter ));
+ }
+ else
+ {
+ IPPI_CALL( icvApproxPolyDP_32f( src_seq, header_size, storage,
+ &contour, (float)parameter ));
+ }
+ break;
+ default:
+ assert(0);
+ CV_ERROR( CV_StsBadArg, "Invalid approximation method" );
+ }
+
+ assert( contour );
+
+ if( header_size >= (int)sizeof(CvContour))
+ cvBoundingRect( contour, 1 );
+
+ contour->v_prev = parent;
+ contour->h_prev = prev_contour;
+
+ if( prev_contour )
+ prev_contour->h_next = contour;
+ else if( parent )
+ parent->v_next = contour;
+ prev_contour = contour;
+ if( !dst_seq )
+ dst_seq = prev_contour;
+
+ if( !recursive )
+ break;
+
+ if( src_seq->v_next )
+ {
+ assert( prev_contour != 0 );
+ parent = prev_contour;
+ prev_contour = 0;
+ src_seq = src_seq->v_next;
+ }
+ else
+ {
+ while( src_seq->h_next == 0 )
+ {
+ src_seq = src_seq->v_prev;
+ if( src_seq == 0 )
+ break;
+ prev_contour = parent;
+ if( parent )
+ parent = parent->v_prev;
+ }
+ if( src_seq )
+ src_seq = src_seq->h_next;
+ }
+ }
+
+ __END__;
+
+ return dst_seq;
+}
+
+/* End of file. */
diff --git a/cv/src/cvcalccontrasthistogram.cpp b/cv/src/cvcalccontrasthistogram.cpp
new file mode 100644
index 0000000..36a44b3
--- /dev/null
+++ b/cv/src/cvcalccontrasthistogram.cpp
@@ -0,0 +1,385 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+#if 0
+
+IPCVAPI(CvStatus, icvCalcContrastHist8uC1R, ( uchar** img, int step, CvSize size,
+ CvHistogram* hist, int dont_clear ))
+
+IPCVAPI(CvStatus, icvCalcContrastHistMask8uC1R, ( uchar** img, int step,
+ uchar* mask, int mask_step, CvSize size,
+ CvHistogram* hist, int dont_clear ))
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvCalcContrastHist8uC1R
+// Purpose: Calculating the histogram of contrast from one-channel images
+// Context:
+// Parameters:
+// Returns:
+// Notes: if dont_clear parameter is NULL then histogram clearing before
+// calculating (all values sets to NULL)
+//F*/
+static CvStatus CV_STDCALL
+icvCalcContrastHist8uC1R( uchar** img, int step, CvSize size,
+ CvHistogram* hist, int dont_clear )
+{
+ int i, j, t, x = 0, y = 0;
+ int dims;
+
+ if( !hist || !img )
+ return CV_NULLPTR_ERR;
+
+ dims = hist->c_dims;
+ if( dims != 1 )
+ return CV_BADSIZE_ERR;
+
+ if( hist->type != CV_HIST_ARRAY )
+ return CV_BADFLAG_ERR;
+
+ for( i = 0; i < dims; i++ )
+ if( !img[i] )
+ return CV_NULLPTR_ERR;
+
+ for( i = 0; i < hist->c_dims; i++ )
+ {
+ if( !hist->thresh[i] )
+ return CV_NULLPTR_ERR;
+ assert( hist->chdims[i] );
+ }
+
+ j = hist->dims[0] * hist->mdims[0];
+
+ int *n = (int *)cvAlloc( (size_t)hist->dims[0] * sizeof( int ));
+
+ if( hist->type == CV_HIST_ARRAY )
+ {
+ if( !dont_clear )
+ for( i = 0; i < j; i++ )
+ {
+ hist->array[i] = 0;
+ n[i] = 0;
+ }
+
+ switch (hist->c_dims)
+ {
+ case 1:
+ {
+ uchar *data0 = img[0];
+ int *array = (int *) hist->array;
+ int *chdims = hist->chdims[0];
+
+ for( i = 0; i < j; i++ )
+ array[i] = cvRound( hist->array[i] );
+
+ for( y = 0; y < size.height; y++, data0 += step )
+ {
+ for( x = 0; x <= size.width - 1; x += 2 )
+ {
+ int v1_r = MIN( data0[x], data0[x + 1] );
+ int v2_r = MAX( data0[x], data0[x + 1] );
+
+// calculate contrast for the right-left pair
+ for( t = v1_r; t < v2_r; t++ )
+ {
+ int val0 = chdims[t + 128];
+
+ array[val0] += MIN( t - v1_r, v2_r - t );
+ n[val0]++;
+ }
+
+ if( y < size.height - 1 )
+ {
+ int v1_d = MIN( data0[x], data0[x + step] );
+ int v2_d = MAX( data0[x], data0[x + step] );
+
+// calculate contrast for the top-down pair
+ for( t = v1_d; t < v2_d; t++ )
+ {
+ int val0 = chdims[t + 128];
+
+ array[val0] += MIN( t - v1_d, v2_d - t );
+ n[val0]++;
+ }
+ }
+ }
+ }
+
+// convert int to float
+ for( i = 0; i < j; i++ )
+ {
+ if( n[i] != 0 )
+ hist->array[i] = (float) array[i] / n[i];
+ else
+ hist->array[i] = 0;
+ }
+ }
+ break;
+ default:
+ return CV_BADSIZE_ERR;
+ }
+ }
+
+ cvFree( &n );
+ return CV_NO_ERR;
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvCalcContrastHistMask8uC1R
+// Purpose: Calculating the mask histogram of contrast from one-channel images
+// Context:
+// Parameters:
+// Returns:
+// Notes: if dont_clear parameter is NULL then histogram clearing before
+// calculating (all values sets to NULL)
+//F*/
+static CvStatus CV_STDCALL
+icvCalcContrastHistMask8uC1R( uchar** img, int step, uchar* mask, int mask_step,
+ CvSize size, CvHistogram * hist, int dont_clear )
+{
+ int i, j, t, x = 0, y = 0;
+ int dims;
+
+
+ if( !hist || !img || !mask )
+ return CV_NULLPTR_ERR;
+
+ dims = hist->c_dims;
+ if( dims != 1 )
+ return CV_BADSIZE_ERR;
+
+ if( hist->type != CV_HIST_ARRAY )
+ return CV_BADFLAG_ERR;
+
+ for( i = 0; i < dims; i++ )
+ if( !img[i] )
+ return CV_NULLPTR_ERR;
+
+ for( i = 0; i < hist->c_dims; i++ )
+ {
+ if( !hist->thresh[i] )
+ return CV_NULLPTR_ERR;
+ assert( hist->chdims[i] );
+ }
+
+ j = hist->dims[0] * hist->mdims[0];
+
+ int *n = (int *)cvAlloc( (size_t) hist->dims[0] * sizeof( int ));
+
+ if( hist->type == CV_HIST_ARRAY )
+ {
+ if( !dont_clear )
+ for( i = 0; i < j; i++ )
+ {
+ hist->array[i] = 0;
+ n[i] = 0;
+ }
+
+ switch (hist->c_dims)
+ {
+ case 1:
+ {
+ uchar *data0 = img[0];
+ uchar *maskp = mask;
+ int *array = (int *) hist->array;
+ int *chdims = hist->chdims[0];
+
+ for( i = 0; i < j; i++ )
+ array[i] = cvRound( hist->array[i] );
+
+ for( y = 0; y < size.height; y++, data0 += step, maskp += mask_step )
+ {
+ for( x = 0; x <= size.width - 2; x++ )
+ {
+ if( maskp[x] )
+ {
+ if( maskp[x + 1] )
+ {
+ int v1_r = MIN( data0[x], data0[x + 1] );
+ int v2_r = MAX( data0[x], data0[x + 1] );
+
+
+ // calculate contrast for the right-left pair
+ for( t = v1_r; t < v2_r; t++ )
+ {
+ int val0 = chdims[t + 128];
+
+ array[val0] += MIN( t - v1_r, v2_r - t );
+ n[val0]++;
+
+ }
+ }
+
+ if( y < size.height - 1 )
+ {
+ if( maskp[x + mask_step] )
+ {
+ int v1_d = MIN( data0[x], data0[x + step] );
+ int v2_d = MAX( data0[x], data0[x + step] );
+
+ // calculate contrast for the top-down pair
+ for( t = v1_d; t < v2_d; t++ )
+ {
+ int val0 = chdims[t + 128];
+
+ array[val0] += MIN( t - v1_d, v2_d - t );
+ n[val0]++;
+
+ }
+ }
+ }
+ }
+ }
+ }
+
+// convert int to float
+ for( i = 0; i < j; i++ )
+ {
+ if( n[i] != 0 )
+ hist->array[i] = (float) array[i] / n[i];
+ else
+ hist->array[i] = 0;
+ }
+ }
+ break;
+ default:
+ return CV_BADSIZE_ERR;
+ }
+ }
+
+ cvFree( &n );
+ return CV_NO_ERR;
+}
+
+/*
+CV_IMPL void cvCalcContrastHist( IplImage** img, CvHistogram* hist, int dont_clear )
+{
+ CV_FUNCNAME( "cvCalcContrastHist" );
+ uchar* data[CV_HIST_MAX_DIM];
+ int step = 0;
+ CvSize roi = {0,0};
+
+ __BEGIN__;
+
+ {for( int i = 0; i < hist->c_dims; i++ )
+ CV_CALL( CV_CHECK_IMAGE( img[i] ) );}
+
+ {for( int i = 0; i < hist->c_dims; i++ )
+ cvGetImageRawData( img[i], &data[i], &step, &roi );}
+
+ if(img[0]->nChannels != 1)
+ CV_ERROR( IPL_BadNumChannels, "bad channels numbers" );
+
+ if(img[0]->depth != IPL_DEPTH_8U)
+ CV_ERROR( IPL_BadDepth, "bad image depth" );
+
+ switch(img[0]->depth)
+ {
+ case IPL_DEPTH_8U:
+ IPPI_CALL( icvCalcContrastHist8uC1R( data, step, roi, hist, dont_clear ) );
+ break;
+ default: CV_ERROR( IPL_BadDepth, "bad image depth" );
+ }
+
+ __CLEANUP__;
+ __END__;
+}
+*/
+
+CV_IMPL void
+cvCalcContrastHist( IplImage ** img, CvHistogram * hist, int dont_clear, IplImage * mask )
+{
+ CV_FUNCNAME( "cvCalcContrastHist" );
+ uchar *data[CV_HIST_MAX_DIM];
+ uchar *mask_data = 0;
+ int step = 0;
+ int mask_step = 0;
+ CvSize roi = { 0, 0 };
+
+ __BEGIN__;
+
+ {
+ for( int i = 0; i < hist->c_dims; i++ )
+ CV_CALL( CV_CHECK_IMAGE( img[i] ));
+ }
+ if( mask )
+ {
+ CV_CALL( CV_CHECK_IMAGE( mask ));
+ if( mask->depth != IPL_DEPTH_8U )
+ CV_ERROR( CV_BadDepth, "bad mask depth" );
+ cvGetImageRawData( mask, &mask_data, &mask_step, 0 );
+ }
+
+
+ {
+ for( int i = 0; i < hist->c_dims; i++ )
+ cvGetImageRawData( img[i], &data[i], &step, &roi );
+ }
+
+ if( img[0]->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, "bad channels numbers" );
+
+ if( img[0]->depth != IPL_DEPTH_8U )
+ CV_ERROR( CV_BadDepth, "bad image depth" );
+
+
+ switch (img[0]->depth)
+ {
+ case IPL_DEPTH_8U:
+ if( !mask )
+ {
+ IPPI_CALL( icvCalcContrastHist8uC1R( data, step, roi, hist, dont_clear ));
+ }
+ else
+ {
+ IPPI_CALL( icvCalcContrastHistMask8uC1R( data, step, mask_data,
+ mask_step, roi, hist, dont_clear ));
+ }
+ break;
+ default:
+ CV_ERROR( CV_BadDepth, "bad image depth" );
+ }
+
+ __CLEANUP__;
+ __END__;
+}
+
+#endif
diff --git a/cv/src/cvcalcimagehomography.cpp b/cv/src/cvcalcimagehomography.cpp
new file mode 100644
index 0000000..e820dfc
--- /dev/null
+++ b/cv/src/cvcalcimagehomography.cpp
@@ -0,0 +1,120 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+/****************************************************************************************\
+
+ calculate image homography
+
+\****************************************************************************************/
+
+CV_IMPL void
+cvCalcImageHomography( float* line, CvPoint3D32f* _center,
+ float* _intrinsic, float* _homography )
+{
+ CV_FUNCNAME( "cvCalcImageHomography" );
+
+ __BEGIN__;
+
+ double norm_xy, norm_xz, xy_sina, xy_cosa, xz_sina, xz_cosa, nx1, plane_dist;
+ float _ry[3], _rz[3], _r_trans[9];
+ CvMat rx = cvMat( 1, 3, CV_32F, line );
+ CvMat ry = cvMat( 1, 3, CV_32F, _ry );
+ CvMat rz = cvMat( 1, 3, CV_32F, _rz );
+ CvMat r_trans = cvMat( 3, 3, CV_32F, _r_trans );
+ CvMat center = cvMat( 3, 1, CV_32F, _center );
+
+ float _sub[9];
+ CvMat sub = cvMat( 3, 3, CV_32F, _sub );
+ float _t_trans[3];
+ CvMat t_trans = cvMat( 3, 1, CV_32F, _t_trans );
+
+ CvMat intrinsic = cvMat( 3, 3, CV_32F, _intrinsic );
+ CvMat homography = cvMat( 3, 3, CV_32F, _homography );
+
+ if( !line || !_center || !_intrinsic || !_homography )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ norm_xy = cvSqrt( line[0] * line[0] + line[1] * line[1] );
+ xy_cosa = line[0] / norm_xy;
+ xy_sina = line[1] / norm_xy;
+
+ norm_xz = cvSqrt( line[0] * line[0] + line[2] * line[2] );
+ xz_cosa = line[0] / norm_xz;
+ xz_sina = line[2] / norm_xz;
+
+ nx1 = -xz_sina;
+
+ _rz[0] = (float)(xy_cosa * nx1);
+ _rz[1] = (float)(xy_sina * nx1);
+ _rz[2] = (float)xz_cosa;
+ cvScale( &rz, &rz, 1./cvNorm(&rz,0,CV_L2) );
+
+ /* new axe y */
+ cvCrossProduct( &rz, &rx, &ry );
+ cvScale( &ry, &ry, 1./cvNorm( &ry, 0, CV_L2 ) );
+
+ /* transpone rotation matrix */
+ memcpy( &_r_trans[0], line, 3*sizeof(float));
+ memcpy( &_r_trans[3], _ry, 3*sizeof(float));
+ memcpy( &_r_trans[6], _rz, 3*sizeof(float));
+
+ /* calculate center distanse from arm plane */
+ plane_dist = cvDotProduct( &center, &rz );
+
+ /* calculate (I - r_trans)*center */
+ cvSetIdentity( &sub );
+ cvSub( &sub, &r_trans, &sub );
+ cvMatMul( &sub, &center, &t_trans );
+
+ cvMatMul( &t_trans, &rz, &sub );
+ cvScaleAdd( &sub, cvRealScalar(1./plane_dist), &r_trans, &sub ); /* ? */
+
+ cvMatMul( &intrinsic, &sub, &r_trans );
+ cvInvert( &intrinsic, &sub, CV_SVD );
+ cvMatMul( &r_trans, &sub, &homography );
+
+ __END__;
+}
+
+/* End of file. */
+
diff --git a/cv/src/cvcalibinit.cpp b/cv/src/cvcalibinit.cpp
new file mode 100644
index 0000000..bc43238
--- /dev/null
+++ b/cv/src/cvcalibinit.cpp
@@ -0,0 +1,2091 @@
+//M*//////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/************************************************************************************\
+ This is improved variant of chessboard corner detection algorithm that
+ uses a graph of connected quads. It is based on the code contributed
+ by Vladimir Vezhnevets and Philip Gruebele.
+ Here is the copyright notice from the original Vladimir's code:
+ ===============================================================
+
+ The algorithms developed and implemented by Vezhnevets Vldimir
+ aka Dead Moroz (vvp@graphics.cs.msu.ru)
+ See http://graphics.cs.msu.su/en/research/calibration/opencv.html
+ for detailed information.
+
+ Reliability additions and modifications made by Philip Gruebele.
+ <a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
+
+ Some further improvements for detection of partially ocluded boards at non-ideal
+ lighting conditions have been made by Alex Bovyrin and Kurt Kolonige
+
+\************************************************************************************/
+
+#include "_cv.h"
+#include <stdarg.h>
+
+//#define DEBUG_CHESSBOARD
+#ifdef DEBUG_CHESSBOARD
+static int PRINTF( const char* fmt, ... )
+{
+ va_list args;
+ va_start(args, fmt);
+ return vprintf(fmt, args);
+}
+#include "..//..//otherlibs/highgui/highgui.h"
+#else
+static int PRINTF( const char*, ... )
+{
+ return 0;
+}
+#endif
+
+
+//=====================================================================================
+// Implementation for the enhanced calibration object detection
+//=====================================================================================
+
+#define MAX_CONTOUR_APPROX 7
+
+typedef struct CvContourEx
+{
+ CV_CONTOUR_FIELDS()
+ int counter;
+}
+CvContourEx;
+
+//=====================================================================================
+
+/// Corner info structure
+/** This structure stores information about the chessboard corner.*/
+typedef struct CvCBCorner
+{
+ CvPoint2D32f pt; // Coordinates of the corner
+ int row; // Board row index
+ int count; // Number of neighbor corners
+ struct CvCBCorner* neighbors[4]; // Neighbor corners
+}
+CvCBCorner;
+
+//=====================================================================================
+/// Quadrangle contour info structure
+/** This structure stores information about the chessboard quadrange.*/
+typedef struct CvCBQuad
+{
+ int count; // Number of quad neighbors
+ int group_idx; // quad group ID
+ int row, col; // row and column of this quad
+ bool ordered; // true if corners/neighbors are ordered counter-clockwise
+ float edge_len; // quad edge len, in pix^2
+ // neighbors and corners are synced, i.e., neighbor 0 shares corner 0
+ CvCBCorner *corners[4]; // Coordinates of quad corners
+ struct CvCBQuad *neighbors[4]; // Pointers of quad neighbors
+}
+CvCBQuad;
+
+//=====================================================================================
+
+//static CvMat* debug_img = 0;
+
+static int icvGenerateQuads( CvCBQuad **quads, CvCBCorner **corners,
+ CvMemStorage *storage, CvMat *image, int flags );
+
+static int
+icvGenerateQuadsEx( CvCBQuad **out_quads, CvCBCorner **out_corners,
+ CvMemStorage *storage, CvMat *image, CvMat *thresh_img, int dilation, int flags );
+
+static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count );
+
+static int icvFindConnectedQuads( CvCBQuad *quads, int quad_count,
+ CvCBQuad **quad_group, int group_idx,
+ CvMemStorage* storage );
+
+static int icvCheckQuadGroup( CvCBQuad **quad_group, int count,
+ CvCBCorner **out_corners, CvSize pattern_size );
+
+static int icvCleanFoundConnectedQuads( int quad_count,
+ CvCBQuad **quads, CvSize pattern_size );
+
+static int icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
+ int *all_count, CvCBQuad **all_quads, CvCBCorner **corners,
+ CvSize pattern_size, CvMemStorage* storage );
+
+static void icvOrderQuad(CvCBQuad *quad, CvCBCorner *corner, int common);
+
+static int icvTrimCol(CvCBQuad **quads, int count, int col, int dir);
+
+static int icvTrimRow(CvCBQuad **quads, int count, int row, int dir);
+
+static int icvAddOuterQuad(CvCBQuad *quad, CvCBQuad **quads, int quad_count,
+ CvCBQuad **all_quads, int all_count, CvCBCorner **corners);
+
+static void icvRemoveQuadFromGroup(CvCBQuad **quads, int count, CvCBQuad *q0);
+
+static int icvCheckBoardMonotony( CvPoint2D32f* corners, CvSize pattern_size );
+
+#if 0
+static void
+icvCalcAffineTranf2D32f(CvPoint2D32f* pts1, CvPoint2D32f* pts2, int count, CvMat* affine_trans)
+{
+ int i, j;
+ int real_count = 0;
+ for( j = 0; j < count; j++ )
+ {
+ if( pts1[j].x >= 0 ) real_count++;
+ }
+ if(real_count < 3) return;
+ CvMat* xy = cvCreateMat( 2*real_count, 6, CV_32FC1 );
+ CvMat* uv = cvCreateMat( 2*real_count, 1, CV_32FC1 );
+ //estimate affine transfromation
+ for( i = 0, j = 0; j < count; j++ )
+ {
+ if( pts1[j].x >= 0 )
+ {
+ CV_MAT_ELEM( *xy, float, i*2+1, 2 ) = CV_MAT_ELEM( *xy, float, i*2, 0 ) = pts2[j].x;
+ CV_MAT_ELEM( *xy, float, i*2+1, 3 ) = CV_MAT_ELEM( *xy, float, i*2, 1 ) = pts2[j].y;
+ CV_MAT_ELEM( *xy, float, i*2, 2 ) = CV_MAT_ELEM( *xy, float, i*2, 3 ) = CV_MAT_ELEM( *xy, float, i*2, 5 ) = \
+ CV_MAT_ELEM( *xy, float, i*2+1, 0 ) = CV_MAT_ELEM( *xy, float, i*2+1, 1 ) = CV_MAT_ELEM( *xy, float, i*2+1, 4 ) = 0;
+ CV_MAT_ELEM( *xy, float, i*2, 4 ) = CV_MAT_ELEM( *xy, float, i*2+1, 5 ) = 1;
+ CV_MAT_ELEM( *uv, float, i*2, 0 ) = pts1[j].x;
+ CV_MAT_ELEM( *uv, float, i*2+1, 0 ) = pts1[j].y;
+ i++;
+ }
+ }
+
+ cvSolve( xy, uv, affine_trans, CV_SVD );
+ cvReleaseMat(&xy);
+ cvReleaseMat(&uv);
+}
+#endif
+
+CV_IMPL
+int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
+ CvPoint2D32f* out_corners, int* out_corner_count,
+ int flags )
+{
+ int k = 0;
+ const int min_dilations = 0;
+ const int max_dilations = 3;
+ int found = 0;
+ CvMat* norm_img = 0;
+ CvMat* thresh_img = 0;
+#ifdef DEBUG_CHESSBOARD
+ IplImage *dbg_img = 0;
+ IplImage *dbg1_img = 0;
+ IplImage *dbg2_img = 0;
+#endif
+ CvMemStorage* storage = 0;
+
+ CvCBQuad *quads = 0, **quad_group = 0;
+ CvCBCorner *corners = 0, **corner_group = 0;
+
+ int expected_corners_num = (pattern_size.width/2+1)*(pattern_size.height/2+1);
+
+ if( out_corner_count )
+ *out_corner_count = 0;
+
+ CV_FUNCNAME( "cvFindChessBoardCornerGuesses2" );
+
+ __BEGIN__;
+
+ int quad_count = 0, group_idx = 0, i = 0, dilations = 0;
+ CvMat stub, *img = (CvMat*)arr;
+
+ CV_CALL( img = cvGetMat( img, &stub ));
+ //debug_img = img;
+
+ if( CV_MAT_DEPTH( img->type ) != CV_8U || CV_MAT_CN( img->type ) == 2 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Only 8-bit grayscale or color images are supported" );
+
+ if( pattern_size.width <= 2 || pattern_size.height <= 2 )
+ CV_ERROR( CV_StsOutOfRange, "Both width and height of the pattern should have bigger than 2" );
+
+ if( !out_corners )
+ CV_ERROR( CV_StsNullPtr, "Null pointer to corners" );
+
+ CV_CALL( storage = cvCreateMemStorage(0) );
+ CV_CALL( thresh_img = cvCreateMat( img->rows, img->cols, CV_8UC1 ));
+
+#ifdef DEBUG_CHESSBOARD
+ CV_CALL( dbg_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 ));
+ CV_CALL( dbg1_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 ));
+ CV_CALL( dbg2_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 ));
+#endif
+
+ if( CV_MAT_CN(img->type) != 1 || (flags & CV_CALIB_CB_NORMALIZE_IMAGE) )
+ {
+ // equalize the input image histogram -
+ // that should make the contrast between "black" and "white" areas big enough
+ CV_CALL( norm_img = cvCreateMat( img->rows, img->cols, CV_8UC1 ));
+
+ if( CV_MAT_CN(img->type) != 1 )
+ {
+ CV_CALL( cvCvtColor( img, norm_img, CV_BGR2GRAY ));
+ img = norm_img;
+ }
+
+ if( flags & CV_CALIB_CB_NORMALIZE_IMAGE )
+ {
+ cvEqualizeHist( img, norm_img );
+ img = norm_img;
+ }
+ }
+
+ // Try our standard "1" dilation, but if the pattern is not found, iterate the whole procedure with higher dilations.
+ // This is necessary because some squares simply do not separate properly with a single dilation. However,
+ // we want to use the minimum number of dilations possible since dilations cause the squares to become smaller,
+ // making it difficult to detect smaller squares.
+ for( k = 0; k < 2; k++ )
+ {
+ for( dilations = min_dilations; dilations <= max_dilations; dilations++ )
+ {
+ if (found) break; // already found it
+
+ if( k == 1 )
+ {
+ //Pattern was not found using binarization
+ // Run multi-level quads extraction
+ // In case one-level binarization did not give enough number of quads
+ CV_CALL( quad_count = icvGenerateQuadsEx( &quads, &corners, storage, img, thresh_img, dilations, flags ));
+ PRINTF("EX quad count: %d/%d\n", quad_count, expected_corners_num);
+ }
+ else
+ {
+ // convert the input grayscale image to binary (black-n-white)
+ if( flags & CV_CALIB_CB_ADAPTIVE_THRESH )
+ {
+ int block_size = cvRound(MIN(img->cols,img->rows)*0.2)|1;
+
+ // convert to binary
+ cvAdaptiveThreshold( img, thresh_img, 255,
+ CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, block_size, 0 );
+ if (dilations > 0)
+ cvDilate( thresh_img, thresh_img, 0, dilations-1 );
+ }
+ else
+ {
+ // Make dilation before the thresholding.
+ // It splits chessboard corners
+ //cvDilate( img, thresh_img, 0, 1 );
+
+ // empiric threshold level
+ double mean = cvMean( img );
+ int thresh_level = cvRound( mean - 10 );
+ thresh_level = MAX( thresh_level, 10 );
+
+ cvThreshold( img, thresh_img, thresh_level, 255, CV_THRESH_BINARY );
+ cvDilate( thresh_img, thresh_img, 0, dilations );
+ }
+
+
+
+#ifdef DEBUG_CHESSBOARD
+ cvCvtColor(thresh_img,dbg_img,CV_GRAY2BGR);
+#endif
+
+ // So we can find rectangles that go to the edge, we draw a white line around the image edge.
+ // Otherwise FindContours will miss those clipped rectangle contours.
+ // The border color will be the image mean, because otherwise we risk screwing up filters like cvSmooth()...
+ cvRectangle( thresh_img, cvPoint(0,0), cvPoint(thresh_img->cols-1,
+ thresh_img->rows-1), CV_RGB(255,255,255), 3, 8);
+
+ CV_CALL( quad_count = icvGenerateQuads( &quads, &corners, storage, thresh_img, flags ));
+
+
+ PRINTF("Quad count: %d/%d\n", quad_count, expected_corners_num);
+ }
+
+
+#ifdef DEBUG_CHESSBOARD
+ cvCopy(dbg_img, dbg1_img);
+ cvNamedWindow("all_quads", 1);
+ // copy corners to temp array
+ for( i = 0; i < quad_count; i++ )
+ {
+ for (int k=0; k<4; k++)
+ {
+ CvPoint2D32f pt1, pt2;
+ CvScalar color = CV_RGB(30,255,30);
+ pt1 = quads[i].corners[k]->pt;
+ pt2 = quads[i].corners[(k+1)%4]->pt;
+ pt2.x = (pt1.x + pt2.x)/2;
+ pt2.y = (pt1.y + pt2.y)/2;
+ if (k>0)
+ color = CV_RGB(200,200,0);
+ cvLine( dbg1_img, cvPointFrom32f(pt1), cvPointFrom32f(pt2), color, 3, 8);
+ }
+ }
+
+
+// cvShowImage("all_quads", (IplImage*)dbg1_img);
+ cvWaitKey();
+#endif
+
+
+ if( quad_count <= 0 )
+ continue;
+
+ // Find quad's neighbors
+ CV_CALL( icvFindQuadNeighbors( quads, quad_count ));
+
+ // allocate extra for adding in icvOrderFoundQuads
+ CV_CALL( quad_group = (CvCBQuad**)cvAlloc( sizeof(quad_group[0]) * (quad_count+quad_count / 2)));
+ CV_CALL( corner_group = (CvCBCorner**)cvAlloc( sizeof(corner_group[0]) * (quad_count+quad_count / 2)*4 ));
+
+ for( group_idx = 0; ; group_idx++ )
+ {
+ int count = 0;
+ CV_CALL( count = icvFindConnectedQuads( quads, quad_count, quad_group, group_idx, storage ));
+
+ int icount = count;
+ if( count == 0 )
+ break;
+
+ // order the quad corners globally
+ // maybe delete or add some
+ PRINTF("Starting ordering of inner quads\n");
+ count = icvOrderFoundConnectedQuads(count, quad_group, &quad_count, &quads, &corners,
+ pattern_size, storage );
+ PRINTF("Orig count: %d After ordering: %d\n", icount, count);
+
+
+#ifdef DEBUG_CHESSBOARD
+ cvCopy(dbg_img,dbg2_img);
+ cvNamedWindow("connected_group", 1);
+ // copy corners to temp array
+ for( i = 0; i < quad_count; i++ )
+ {
+ if (quads[i].group_idx == group_idx)
+ for (int k=0; k<4; k++)
+ {
+ CvPoint2D32f pt1, pt2;
+ CvScalar color = CV_RGB(30,255,30);
+ if (quads[i].ordered)
+ color = CV_RGB(255,30,30);
+ pt1 = quads[i].corners[k]->pt;
+ pt2 = quads[i].corners[(k+1)%4]->pt;
+ pt2.x = (pt1.x + pt2.x)/2;
+ pt2.y = (pt1.y + pt2.y)/2;
+ if (k>0)
+ color = CV_RGB(200,200,0);
+ cvLine( dbg2_img, cvPointFrom32f(pt1), cvPointFrom32f(pt2), color, 3, 8);
+ }
+ }
+// cvShowImage("connected_group", (IplImage*)dbg2_img);
+ cvWaitKey();
+#endif
+
+ if (count == 0)
+ continue; // haven't found inner quads
+
+
+ // If count is more than it should be, this will remove those quads
+ // which cause maximum deviation from a nice square pattern.
+ CV_CALL( count = icvCleanFoundConnectedQuads( count, quad_group, pattern_size ));
+ PRINTF("Connected group: %d orig count: %d cleaned: %d\n", group_idx, icount, count);
+
+ CV_CALL( count = icvCheckQuadGroup( quad_group, count, corner_group, pattern_size ));
+ PRINTF("Connected group: %d count: %d cleaned: %d\n", group_idx, icount, count);
+
+ if( count > 0 || (out_corner_count && -count > *out_corner_count) )
+ {
+ int n = count > 0 ? pattern_size.width * pattern_size.height : -count;
+ n = MIN( n, pattern_size.width * pattern_size.height );
+
+ // copy corners to output array
+ for( i = 0; i < n; i++ )
+ out_corners[i] = corner_group[i]->pt;
+
+ if( out_corner_count )
+ *out_corner_count = n;
+
+ if( count > 0 )
+ {
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ cvFree( &quads );
+ cvFree( &corners );
+ cvFree( &quad_group );
+ cvFree( &corner_group );
+ }//dilations
+ }//
+
+
+ __END__;
+
+ cvReleaseMemStorage( &storage );
+ cvReleaseMat( &norm_img );
+ cvReleaseMat( &thresh_img );
+ cvFree( &quads );
+ cvFree( &corners );
+
+ if( found )
+ found = icvCheckBoardMonotony( out_corners, pattern_size );
+
+ if( found && pattern_size.height % 2 == 0 && pattern_size.width % 2 == 0 )
+ {
+ int last_row = (pattern_size.height-1)*pattern_size.width;
+ double dy0 = out_corners[last_row].y - out_corners[0].y;
+ if( dy0 < 0 )
+ {
+ int i, n = pattern_size.width*pattern_size.height;
+ for( i = 0; i < n/2; i++ )
+ {
+ CvPoint2D32f temp;
+ CV_SWAP(out_corners[i], out_corners[n-i-1], temp);
+ }
+ }
+ }
+
+ return found;
+}
+
+//
+// Checks that each board row and column is pretty much monotonous curve:
+// It analyzes each row and each column of the chessboard as following:
+// for each corner c lying between end points in the same row/column it checks that
+// the point projection to the line segment (a,b) is lying between projections
+// of the neighbor corners in the same row/column.
+//
+// This function has been created as temporary workaround for the bug in current implementation
+// of cvFindChessboardCornes that produces absolutely unordered sets of corners.
+//
+
+static int
+icvCheckBoardMonotony( CvPoint2D32f* corners, CvSize pattern_size )
+{
+ int i, j, k;
+
+ for( k = 0; k < 2; k++ )
+ {
+ for( i = 0; i < (k == 0 ? pattern_size.height : pattern_size.width); i++ )
+ {
+ CvPoint2D32f a = k == 0 ? corners[i*pattern_size.width] : corners[i];
+ CvPoint2D32f b = k == 0 ? corners[(i+1)*pattern_size.width-1] :
+ corners[(pattern_size.height-1)*pattern_size.width + i];
+ float prevt = 0, dx0 = b.x - a.x, dy0 = b.y - a.y;
+ if( fabs(dx0) + fabs(dy0) < FLT_EPSILON )
+ return 0;
+ for( j = 1; j < (k == 0 ? pattern_size.width : pattern_size.height) - 1; j++ )
+ {
+ CvPoint2D32f c = k == 0 ? corners[i*pattern_size.width + j] :
+ corners[j*pattern_size.width + i];
+ float t = ((c.x - a.x)*dx0 + (c.y - a.y)*dy0)/(dx0*dx0 + dy0*dy0);
+ if( t < prevt || t > 1 )
+ return 0;
+ prevt = t;
+ }
+ }
+ }
+
+ return 1;
+}
+
+//
+// order a group of connected quads
+// order of corners:
+// 0 is top left
+// clockwise from there
+// note: "top left" is nominal, depends on initial ordering of starting quad
+// but all other quads are ordered consistently
+//
+// can change the number of quads in the group
+// can add quads, so we need to have quad/corner arrays passed in
+//
+
+static int
+icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads,
+ int *all_count, CvCBQuad **all_quads, CvCBCorner **corners,
+ CvSize pattern_size, CvMemStorage* storage )
+{
+ CvMemStorage* temp_storage = cvCreateChildMemStorage( storage );
+ CvSeq* stack = cvCreateSeq( 0, sizeof(*stack), sizeof(void*), temp_storage );
+ int i;
+
+ // first find an interior quad
+ CvCBQuad *start = NULL;
+ for (i=0; i<quad_count; i++)
+ {
+ if (quads[i]->count == 4)
+ {
+ start = quads[i];
+ break;
+ }
+ }
+
+ if (start == NULL)
+ {
+ cvReleaseMemStorage( &temp_storage );
+ return 0; // no 4-connected quad
+ }
+
+ // start with first one, assign rows/cols
+ int row_min = 0, col_min = 0, row_max=0, col_max = 0;
+#define HSIZE 20
+ int col_hist[HSIZE*2];
+ int row_hist[HSIZE*2]; // bad programming, should allow variable size
+
+ for (i=0; i<HSIZE*2; i++) // init to zero
+ col_hist[i] = row_hist[i] = 0;
+ cvSeqPush(stack, &start);
+ start->row = 0;
+ start->col = 0;
+ start->ordered = true;
+
+ // Recursively order the quads so that all position numbers (e.g.,
+ // 0,1,2,3) are in the at the same relative corner (e.g., lower right).
+
+ while( stack->total )
+ {
+ CvCBQuad* q;
+ cvSeqPop( stack, &q );
+ int col = q->col;
+ int row = q->row;
+ col_hist[col+HSIZE]++;
+ row_hist[row+HSIZE]++;
+
+ // check min/max
+ if (row > row_max) row_max = row;
+ if (row < row_min) row_min = row;
+ if (col > col_max) col_max = col;
+ if (col < col_min) col_min = col;
+
+ for(int i = 0; i < 4; i++ )
+ {
+ CvCBQuad *neighbor = q->neighbors[i];
+ switch(i) // adjust col, row for this quad
+ { // start at top left, go clockwise
+ case 0:
+ row--; col--; break;
+ case 1:
+ col += 2; break;
+ case 2:
+ row += 2; break;
+ case 3:
+ col -= 2; break;
+ }
+
+ // just do inside quads
+ if (neighbor && neighbor->ordered == false && neighbor->count == 4)
+ {
+ PRINTF("col: %d row: %d\n", col, row);
+ icvOrderQuad(neighbor, q->corners[i], (i+2)%4); // set in order
+ neighbor->ordered = true;
+ neighbor->row = row;
+ neighbor->col = col;
+ cvSeqPush( stack, &neighbor );
+ }
+ }
+ }
+
+ cvReleaseMemStorage( &temp_storage );
+
+ for (i=col_min; i<=col_max; i++)
+ PRINTF("HIST[%d] = %d\n", i, col_hist[i+HSIZE]);
+
+ // analyze inner quad structure
+ int w = pattern_size.width - 1;
+ int h = pattern_size.height - 1;
+ int drow = row_max - row_min + 1;
+ int dcol = col_max - col_min + 1;
+
+ // normalize pattern and found quad indices
+ if ((w > h && dcol < drow) ||
+ (w < h && drow < dcol))
+ {
+ h = pattern_size.width - 1;
+ w = pattern_size.height - 1;
+ }
+
+ PRINTF("Size: %dx%d Pattern: %dx%d\n", dcol, drow, w, h);
+
+ // check if there are enough inner quads
+ if (dcol < w || drow < h) // found enough inner quads?
+ {
+ PRINTF("Too few inner quad rows/cols\n");
+ return 0; // no, return
+ }
+
+ // too many columns, not very common
+ if (dcol == w+1) // too many, trim
+ {
+ PRINTF("Trimming cols\n");
+ if (col_hist[col_max+HSIZE] > col_hist[col_min+HSIZE])
+ {
+ PRINTF("Trimming left col\n");
+ quad_count = icvTrimCol(quads,quad_count,col_min,-1);
+ }
+ else
+ {
+ PRINTF("Trimming right col\n");
+ quad_count = icvTrimCol(quads,quad_count,col_max,+1);
+ }
+ }
+
+ // too many rows, not very common
+ if (drow == h+1) // too many, trim
+ {
+ PRINTF("Trimming rows\n");
+ if (row_hist[row_max+HSIZE] > row_hist[row_min+HSIZE])
+ {
+ PRINTF("Trimming top row\n");
+ quad_count = icvTrimRow(quads,quad_count,row_min,-1);
+ }
+ else
+ {
+ PRINTF("Trimming bottom row\n");
+ quad_count = icvTrimRow(quads,quad_count,row_max,+1);
+ }
+ }
+
+
+ // check edges of inner quads
+ // if there is an outer quad missing, fill it in
+ // first order all inner quads
+ int found = 0;
+ for (i=0; i<quad_count; i++)
+ {
+ if (quads[i]->count == 4)
+ { // ok, look at neighbors
+ int col = quads[i]->col;
+ int row = quads[i]->row;
+ for (int j=0; j<4; j++)
+ {
+ switch(j) // adjust col, row for this quad
+ { // start at top left, go clockwise
+ case 0:
+ row--; col--; break;
+ case 1:
+ col += 2; break;
+ case 2:
+ row += 2; break;
+ case 3:
+ col -= 2; break;
+ }
+ CvCBQuad *neighbor = quads[i]->neighbors[j];
+ if (neighbor && !neighbor->ordered && // is it an inner quad?
+ col <= col_max && col >= col_min &&
+ row <= row_max && row >= row_min)
+ {
+ // if so, set in order
+ PRINTF("Adding inner: col: %d row: %d\n", col, row);
+ found++;
+ icvOrderQuad(neighbor, quads[i]->corners[j], (j+2)%4);
+ neighbor->ordered = true;
+ neighbor->row = row;
+ neighbor->col = col;
+ }
+ }
+ }
+ }
+
+ // if we have found inner quads, add corresponding outer quads,
+ // which are missing
+ if (found > 0)
+ {
+ PRINTF("Found %d inner quads not connected to outer quads, repairing\n", found);
+ for (int i=0; i<quad_count; i++)
+ {
+ if (quads[i]->count < 4 && quads[i]->ordered)
+ {
+ int added = icvAddOuterQuad(quads[i],quads,quad_count,all_quads,*all_count,corners);
+ *all_count += added;
+ quad_count += added;
+ }
+ }
+ }
+
+
+ // final trimming of outer quads
+ if (dcol == w && drow == h) // found correct inner quads
+ {
+ PRINTF("Inner bounds ok, check outer quads\n");
+ int rcount = quad_count;
+ for (int i=quad_count-1; i>=0; i--) // eliminate any quad not connected to
+ // an ordered quad
+ {
+ if (quads[i]->ordered == false)
+ {
+ bool outer = false;
+ for (int j=0; j<4; j++) // any neighbors that are ordered?
+ {
+ if (quads[i]->neighbors[j] && quads[i]->neighbors[j]->ordered)
+ outer = true;
+ }
+ if (!outer) // not an outer quad, eliminate
+ {
+ PRINTF("Removing quad %d\n", i);
+ icvRemoveQuadFromGroup(quads,rcount,quads[i]);
+ rcount--;
+ }
+ }
+
+ }
+ return rcount;
+ }
+
+ return 0;
+}
+
+
+// add an outer quad
+// looks for the neighbor of <quad> that isn't present,
+// tries to add it in.
+// <quad> is ordered
+
+static int
+icvAddOuterQuad( CvCBQuad *quad, CvCBQuad **quads, int quad_count,
+ CvCBQuad **all_quads, int all_count, CvCBCorner **corners )
+
+{
+ int added = 0;
+ for (int i=0; i<4; i++) // find no-neighbor corners
+ {
+ if (!quad->neighbors[i]) // ok, create and add neighbor
+ {
+ int j = (i+2)%4;
+ PRINTF("Adding quad as neighbor 2\n");
+ CvCBQuad *q = &(*all_quads)[all_count];
+ memset( q, 0, sizeof(*q) );
+ added++;
+ quads[quad_count] = q;
+ quad_count++;
+
+ // set neighbor and group id
+ quad->neighbors[i] = q;
+ quad->count += 1;
+ q->neighbors[j] = quad;
+ q->group_idx = quad->group_idx;
+ q->count = 1; // number of neighbors
+ q->ordered = false;
+ q->edge_len = quad->edge_len;
+
+ // make corners of new quad
+ // same as neighbor quad, but offset
+ CvPoint2D32f pt = quad->corners[i]->pt;
+ CvCBCorner* corner;
+ float dx = pt.x - quad->corners[j]->pt.x;
+ float dy = pt.y - quad->corners[j]->pt.y;
+ for (int k=0; k<4; k++)
+ {
+ corner = &(*corners)[all_count*4+k];
+ pt = quad->corners[k]->pt;
+ memset( corner, 0, sizeof(*corner) );
+ corner->pt = pt;
+ q->corners[k] = corner;
+ corner->pt.x += dx;
+ corner->pt.y += dy;
+ }
+ // have to set exact corner
+ q->corners[j] = quad->corners[i];
+
+ // now find other neighbor and add it, if possible
+ if (quad->neighbors[(i+3)%4] &&
+ quad->neighbors[(i+3)%4]->ordered &&
+ quad->neighbors[(i+3)%4]->neighbors[i] &&
+ quad->neighbors[(i+3)%4]->neighbors[i]->ordered )
+ {
+ CvCBQuad *qn = quad->neighbors[(i+3)%4]->neighbors[i];
+ q->count = 2;
+ q->neighbors[(j+1)%4] = qn;
+ qn->neighbors[(i+1)%4] = q;
+ qn->count += 1;
+ // have to set exact corner
+ q->corners[(j+1)%4] = qn->corners[(i+1)%4];
+ }
+
+ all_count++;
+ }
+ }
+ return added;
+}
+
+
+// trimming routines
+
+static int
+icvTrimCol(CvCBQuad **quads, int count, int col, int dir)
+{
+ int rcount = count;
+ // find the right quad(s)
+ for (int i=0; i<count; i++)
+ {
+#ifdef DEBUG_CHESSBOARD
+ if (quads[i]->ordered)
+ PRINTF("index: %d cur: %d\n", col, quads[i]->col);
+#endif
+ if (quads[i]->ordered && quads[i]->col == col)
+ {
+ if (dir == 1)
+ {
+ if (quads[i]->neighbors[1])
+ {
+ icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[1]);
+ rcount--;
+ }
+ if (quads[i]->neighbors[2])
+ {
+ icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[2]);
+ rcount--;
+ }
+ }
+ else
+ {
+ if (quads[i]->neighbors[0])
+ {
+ icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[0]);
+ rcount--;
+ }
+ if (quads[i]->neighbors[3])
+ {
+ icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[3]);
+ rcount--;
+ }
+ }
+
+ }
+ }
+ return rcount;
+}
+
+static int
+icvTrimRow(CvCBQuad **quads, int count, int row, int dir)
+{
+ int i, rcount = count;
+ // find the right quad(s)
+ for (i=0; i<count; i++)
+ {
+#ifdef DEBUG_CHESSBOARD
+ if (quads[i]->ordered)
+ PRINTF("index: %d cur: %d\n", row, quads[i]->row);
+#endif
+ if (quads[i]->ordered && quads[i]->row == row)
+ {
+ if (dir == 1) // remove from bottom
+ {
+ if (quads[i]->neighbors[2])
+ {
+ icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[2]);
+ rcount--;
+ }
+ if (quads[i]->neighbors[3])
+ {
+ icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[3]);
+ rcount--;
+ }
+ }
+ else // remove from top
+ {
+ if (quads[i]->neighbors[0])
+ {
+ icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[0]);
+ rcount--;
+ }
+ if (quads[i]->neighbors[1])
+ {
+ icvRemoveQuadFromGroup(quads,rcount,quads[i]->neighbors[1]);
+ rcount--;
+ }
+ }
+
+ }
+ }
+ return rcount;
+}
+
+
+//
+// remove quad from quad group
+//
+
+static void
+icvRemoveQuadFromGroup(CvCBQuad **quads, int count, CvCBQuad *q0)
+{
+ int i, j;
+ // remove any references to this quad as a neighbor
+ for(i = 0; i < count; i++ )
+ {
+ CvCBQuad *q = quads[i];
+ for(j = 0; j < 4; j++ )
+ {
+ if( q->neighbors[j] == q0 )
+ {
+ q->neighbors[j] = 0;
+ q->count--;
+ for(int k = 0; k < 4; k++ )
+ if( q0->neighbors[k] == q )
+ {
+ q0->neighbors[k] = 0;
+ q0->count--;
+ break;
+ }
+ break;
+ }
+ }
+ }
+
+ // remove the quad
+ for(i = 0; i < count; i++ )
+ {
+ CvCBQuad *q = quads[i];
+ if (q == q0)
+ {
+ quads[i] = quads[count-1];
+ break;
+ }
+ }
+}
+
+//
+// put quad into correct order, where <corner> has value <common>
+//
+
+static void
+icvOrderQuad(CvCBQuad *quad, CvCBCorner *corner, int common)
+{
+ // find the corner
+ int tc;
+ for (tc=0; tc<4; tc++)
+ if (quad->corners[tc]->pt.x == corner->pt.x &&
+ quad->corners[tc]->pt.y == corner->pt.y)
+ break;
+
+ // set corner order
+ // shift
+ while (tc != common)
+ {
+ // shift by one
+ CvCBCorner *tempc;
+ CvCBQuad *tempq;
+ tempc = quad->corners[3];
+ tempq = quad->neighbors[3];
+ for (int i=3; i>0; i--)
+ {
+ quad->corners[i] = quad->corners[i-1];
+ quad->neighbors[i] = quad->neighbors[i-1];
+ }
+ quad->corners[0] = tempc;
+ quad->neighbors[0] = tempq;
+ tc++;
+ tc = tc%4;
+ }
+}
+
+
+// if we found too many connect quads, remove those which probably do not belong.
+static int
+icvCleanFoundConnectedQuads( int quad_count, CvCBQuad **quad_group, CvSize pattern_size )
+{
+ CvMemStorage *temp_storage = 0;
+ CvPoint2D32f *centers = 0;
+
+ CV_FUNCNAME( "icvCleanFoundConnectedQuads" );
+
+ __BEGIN__;
+
+ CvPoint2D32f center = {0,0};
+ int i, j, k;
+ // number of quads this pattern should contain
+ int count = ((pattern_size.width + 1)*(pattern_size.height + 1) + 1)/2;
+
+ // if we have more quadrangles than we should,
+ // try to eliminate duplicates or ones which don't belong to the pattern rectangle...
+ if( quad_count <= count )
+ EXIT;
+
+ // create an array of quadrangle centers
+ CV_CALL( centers = (CvPoint2D32f *)cvAlloc( sizeof(centers[0])*quad_count ));
+ CV_CALL( temp_storage = cvCreateMemStorage(0));
+
+ for( i = 0; i < quad_count; i++ )
+ {
+ CvPoint2D32f ci = {0,0};
+ CvCBQuad* q = quad_group[i];
+
+ for( j = 0; j < 4; j++ )
+ {
+ CvPoint2D32f pt = q->corners[j]->pt;
+ ci.x += pt.x;
+ ci.y += pt.y;
+ }
+
+ ci.x *= 0.25f;
+ ci.y *= 0.25f;
+
+ centers[i] = ci;
+ center.x += ci.x;
+ center.y += ci.y;
+ }
+ center.x /= quad_count;
+ center.y /= quad_count;
+
+ // If we still have more quadrangles than we should,
+ // we try to eliminate bad ones based on minimizing the bounding box.
+ // We iteratively remove the point which reduces the size of
+ // the bounding box of the blobs the most
+ // (since we want the rectangle to be as small as possible)
+ // remove the quadrange that causes the biggest reduction
+ // in pattern size until we have the correct number
+ for( ; quad_count > count; quad_count-- )
+ {
+ double min_box_area = DBL_MAX;
+ int skip, min_box_area_index = -1;
+ CvCBQuad *q0, *q;
+
+ // For each point, calculate box area without that point
+ for( skip = 0; skip < quad_count; skip++ )
+ {
+ // get bounding rectangle
+ CvPoint2D32f temp = centers[skip]; // temporarily make index 'skip' the same as
+ centers[skip] = center; // pattern center (so it is not counted for convex hull)
+ CvMat pointMat = cvMat(1, quad_count, CV_32FC2, centers);
+ CvSeq *hull = cvConvexHull2( &pointMat, temp_storage, CV_CLOCKWISE, 1 );
+ centers[skip] = temp;
+ double hull_area = fabs(cvContourArea(hull, CV_WHOLE_SEQ));
+
+ // remember smallest box area
+ if( hull_area < min_box_area )
+ {
+ min_box_area = hull_area;
+ min_box_area_index = skip;
+ }
+ cvClearMemStorage( temp_storage );
+ }
+
+ q0 = quad_group[min_box_area_index];
+
+ // remove any references to this quad as a neighbor
+ for( i = 0; i < quad_count; i++ )
+ {
+ q = quad_group[i];
+ for( j = 0; j < 4; j++ )
+ {
+ if( q->neighbors[j] == q0 )
+ {
+ q->neighbors[j] = 0;
+ q->count--;
+ for( k = 0; k < 4; k++ )
+ if( q0->neighbors[k] == q )
+ {
+ q0->neighbors[k] = 0;
+ q0->count--;
+ break;
+ }
+ break;
+ }
+ }
+ }
+
+ // remove the quad
+ quad_count--;
+ quad_group[min_box_area_index] = quad_group[quad_count];
+ centers[min_box_area_index] = centers[quad_count];
+ }
+
+ __END__;
+
+ cvReleaseMemStorage( &temp_storage );
+ cvFree( &centers );
+
+ return quad_count;
+}
+
+//=====================================================================================
+
+static int
+icvFindConnectedQuads( CvCBQuad *quad, int quad_count, CvCBQuad **out_group,
+ int group_idx, CvMemStorage* storage )
+{
+ CvMemStorage* temp_storage = cvCreateChildMemStorage( storage );
+ CvSeq* stack = cvCreateSeq( 0, sizeof(*stack), sizeof(void*), temp_storage );
+ int i, count = 0;
+
+ // Scan the array for a first unlabeled quad
+ for( i = 0; i < quad_count; i++ )
+ {
+ if( quad[i].count > 0 && quad[i].group_idx < 0)
+ break;
+ }
+
+ // Recursively find a group of connected quads starting from the seed quad[i]
+ if( i < quad_count )
+ {
+ CvCBQuad* q = &quad[i];
+ cvSeqPush( stack, &q );
+ out_group[count++] = q;
+ q->group_idx = group_idx;
+ q->ordered = false;
+
+ while( stack->total )
+ {
+ cvSeqPop( stack, &q );
+ for( i = 0; i < 4; i++ )
+ {
+ CvCBQuad *neighbor = q->neighbors[i];
+ if( neighbor && neighbor->count > 0 && neighbor->group_idx < 0 )
+ {
+ cvSeqPush( stack, &neighbor );
+ out_group[count++] = neighbor;
+ neighbor->group_idx = group_idx;
+ neighbor->ordered = false;
+ }
+ }
+ }
+ }
+
+ cvReleaseMemStorage( &temp_storage );
+ return count;
+}
+
+
+//=====================================================================================
+
+static int
+icvCheckQuadGroup( CvCBQuad **quad_group, int quad_count,
+ CvCBCorner **out_corners, CvSize pattern_size )
+{
+ const int ROW1 = 1000000;
+ const int ROW2 = 2000000;
+ const int ROW_ = 3000000;
+ int result = 0;
+ int i, out_corner_count = 0, corner_count = 0;
+ CvCBCorner** corners = 0;
+
+ CV_FUNCNAME( "icvCheckQuadGroup" );
+
+ __BEGIN__;
+
+ int j, k, kk;
+ int width = 0, height = 0;
+ int hist[5] = {0,0,0,0,0};
+ CvCBCorner* first = 0, *first2 = 0, *right, *cur, *below, *c;
+ CV_CALL( corners = (CvCBCorner**)cvAlloc( quad_count*4*sizeof(corners[0]) ));
+
+ // build dual graph, which vertices are internal quad corners
+ // and two vertices are connected iff they lie on the same quad edge
+ for( i = 0; i < quad_count; i++ )
+ {
+ CvCBQuad* q = quad_group[i];
+ /*CvScalar color = q->count == 0 ? cvScalar(0,255,255) :
+ q->count == 1 ? cvScalar(0,0,255) :
+ q->count == 2 ? cvScalar(0,255,0) :
+ q->count == 3 ? cvScalar(255,255,0) :
+ cvScalar(255,0,0);*/
+
+ for( j = 0; j < 4; j++ )
+ {
+ //cvLine( debug_img, cvPointFrom32f(q->corners[j]->pt), cvPointFrom32f(q->corners[(j+1)&3]->pt), color, 1, CV_AA, 0 );
+ if( q->neighbors[j] )
+ {
+ CvCBCorner *a = q->corners[j], *b = q->corners[(j+1)&3];
+ // mark internal corners that belong to:
+ // - a quad with a single neighbor - with ROW1,
+ // - a quad with two neighbors - with ROW2
+ // make the rest of internal corners with ROW_
+ int row_flag = q->count == 1 ? ROW1 : q->count == 2 ? ROW2 : ROW_;
+
+ if( a->row == 0 )
+ {
+ corners[corner_count++] = a;
+ a->row = row_flag;
+ }
+ else if( a->row > row_flag )
+ a->row = row_flag;
+
+ if( q->neighbors[(j+1)&3] )
+ {
+ if( a->count >= 4 || b->count >= 4 )
+ EXIT;
+ for( k = 0; k < 4; k++ )
+ {
+ if( a->neighbors[k] == b )
+ EXIT;
+ if( b->neighbors[k] == a )
+ EXIT;
+ }
+ a->neighbors[a->count++] = b;
+ b->neighbors[b->count++] = a;
+ }
+ }
+ }
+ }
+
+ if( corner_count != pattern_size.width*pattern_size.height )
+ EXIT;
+
+ for( i = 0; i < corner_count; i++ )
+ {
+ int n = corners[i]->count;
+ assert( 0 <= n && n <= 4 );
+ hist[n]++;
+ if( !first && n == 2 )
+ {
+ if( corners[i]->row == ROW1 )
+ first = corners[i];
+ else if( !first2 && corners[i]->row == ROW2 )
+ first2 = corners[i];
+ }
+ }
+
+ // start with a corner that belongs to a quad with a signle neighbor.
+ // if we do not have such, start with a corner of a quad with two neighbors.
+ if( !first )
+ first = first2;
+
+ if( !first || hist[0] != 0 || hist[1] != 0 || hist[2] != 4 ||
+ hist[3] != (pattern_size.width + pattern_size.height)*2 - 8 )
+ EXIT;
+
+ cur = first;
+ right = below = 0;
+ out_corners[out_corner_count++] = cur;
+
+ for( k = 0; k < 4; k++ )
+ {
+ c = cur->neighbors[k];
+ if( c )
+ {
+ if( !right )
+ right = c;
+ else if( !below )
+ below = c;
+ }
+ }
+
+ if( !right || (right->count != 2 && right->count != 3) ||
+ !below || (below->count != 2 && below->count != 3) )
+ EXIT;
+
+ cur->row = 0;
+ //cvCircle( debug_img, cvPointFrom32f(cur->pt), 3, cvScalar(0,255,0), -1, 8, 0 );
+
+ first = below; // remember the first corner in the next row
+ // find and store the first row (or column)
+ for(j=1;;j++)
+ {
+ right->row = 0;
+ out_corners[out_corner_count++] = right;
+ //cvCircle( debug_img, cvPointFrom32f(right->pt), 3, cvScalar(0,255-j*10,0), -1, 8, 0 );
+ if( right->count == 2 )
+ break;
+ if( right->count != 3 || out_corner_count >= MAX(pattern_size.width,pattern_size.height) )
+ EXIT;
+ cur = right;
+ for( k = 0; k < 4; k++ )
+ {
+ c = cur->neighbors[k];
+ if( c && c->row > 0 )
+ {
+ for( kk = 0; kk < 4; kk++ )
+ {
+ if( c->neighbors[kk] == below )
+ break;
+ }
+ if( kk < 4 )
+ below = c;
+ else
+ right = c;
+ }
+ }
+ }
+
+ width = out_corner_count;
+ if( width == pattern_size.width )
+ height = pattern_size.height;
+ else if( width == pattern_size.height )
+ height = pattern_size.width;
+ else
+ EXIT;
+
+ // find and store all the other rows
+ for( i = 1; ; i++ )
+ {
+ if( !first )
+ break;
+ cur = first;
+ first = 0;
+ for( j = 0;; j++ )
+ {
+ cur->row = i;
+ out_corners[out_corner_count++] = cur;
+ //cvCircle( debug_img, cvPointFrom32f(cur->pt), 3, cvScalar(0,0,255-j*10), -1, 8, 0 );
+ if( cur->count == 2 + (i < height-1) && j > 0 )
+ break;
+
+ right = 0;
+
+ // find a neighbor that has not been processed yet
+ // and that has a neighbor from the previous row
+ for( k = 0; k < 4; k++ )
+ {
+ c = cur->neighbors[k];
+ if( c && c->row > i )
+ {
+ for( kk = 0; kk < 4; kk++ )
+ {
+ if( c->neighbors[kk] && c->neighbors[kk]->row == i-1 )
+ break;
+ }
+ if( kk < 4 )
+ {
+ right = c;
+ if( j > 0 )
+ break;
+ }
+ else if( j == 0 )
+ first = c;
+ }
+ }
+ if( !right )
+ EXIT;
+ cur = right;
+ }
+
+ if( j != width - 1 )
+ EXIT;
+ }
+
+ if( out_corner_count != corner_count )
+ EXIT;
+
+ // check if we need to transpose the board
+ if( width != pattern_size.width )
+ {
+ CV_SWAP( width, height, k );
+
+ memcpy( corners, out_corners, corner_count*sizeof(corners[0]) );
+ for( i = 0; i < height; i++ )
+ for( j = 0; j < width; j++ )
+ out_corners[i*width + j] = corners[j*height + i];
+ }
+
+ // check if we need to revert the order in each row
+ {
+ CvPoint2D32f p0 = out_corners[0]->pt, p1 = out_corners[pattern_size.width-1]->pt,
+ p2 = out_corners[pattern_size.width]->pt;
+ if( (p1.x - p0.x)*(p2.y - p1.y) - (p1.y - p0.y)*(p2.x - p1.x) < 0 )
+ {
+ if( width % 2 == 0 )
+ {
+ for( i = 0; i < height; i++ )
+ for( j = 0; j < width/2; j++ )
+ CV_SWAP( out_corners[i*width+j], out_corners[i*width+width-j-1], c );
+ }
+ else
+ {
+ for( j = 0; j < width; j++ )
+ for( i = 0; i < height/2; i++ )
+ CV_SWAP( out_corners[i*width+j], out_corners[(height - i - 1)*width+j], c );
+ }
+ }
+ }
+
+ result = corner_count;
+
+ __END__;
+
+ if( result <= 0 && corners )
+ {
+ corner_count = MIN( corner_count, pattern_size.width*pattern_size.height );
+ for( i = 0; i < corner_count; i++ )
+ out_corners[i] = corners[i];
+ result = -corner_count;
+
+ if (result == -pattern_size.width*pattern_size.height)
+ result = -result;
+ }
+
+ cvFree( &corners );
+
+ return result;
+}
+
+
+
+
+//=====================================================================================
+
+static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count )
+{
+ const float thresh_scale = 1.f;
+ int idx, i, k, j;
+ float dx, dy, dist;
+
+ // find quad neighbors
+ for( idx = 0; idx < quad_count; idx++ )
+ {
+ CvCBQuad* cur_quad = &quads[idx];
+
+ // choose the points of the current quadrangle that are close to
+ // some points of the other quadrangles
+ // (it can happen for split corners (due to dilation) of the
+ // checker board). Search only in other quadrangles!
+
+ // for each corner of this quadrangle
+ for( i = 0; i < 4; i++ )
+ {
+ CvPoint2D32f pt;
+ float min_dist = FLT_MAX;
+ int closest_corner_idx = -1;
+ CvCBQuad *closest_quad = 0;
+ CvCBCorner *closest_corner = 0;
+
+ if( cur_quad->neighbors[i] )
+ continue;
+
+ pt = cur_quad->corners[i]->pt;
+
+ // find the closest corner in all other quadrangles
+ for( k = 0; k < quad_count; k++ )
+ {
+ if( k == idx )
+ continue;
+
+ for( j = 0; j < 4; j++ )
+ {
+ if( quads[k].neighbors[j] )
+ continue;
+
+ dx = pt.x - quads[k].corners[j]->pt.x;
+ dy = pt.y - quads[k].corners[j]->pt.y;
+ dist = dx * dx + dy * dy;
+
+ if( dist < min_dist &&
+ dist <= cur_quad->edge_len*thresh_scale &&
+ dist <= quads[k].edge_len*thresh_scale )
+ {
+ // check edge lengths, make sure they're compatible
+ // edges that are different by more than 1:4 are rejected
+ float ediff = cur_quad->edge_len - quads[k].edge_len;
+ if (ediff > 32*cur_quad->edge_len ||
+ ediff > 32*quads[k].edge_len)
+ {
+ PRINTF("Incompatible edge lengths\n");
+ continue;
+ }
+ closest_corner_idx = j;
+ closest_quad = &quads[k];
+ min_dist = dist;
+ }
+ }
+ }
+
+ // we found a matching corner point?
+ if( closest_corner_idx >= 0 && min_dist < FLT_MAX )
+ {
+ // If another point from our current quad is closer to the found corner
+ // than the current one, then we don't count this one after all.
+ // This is necessary to support small squares where otherwise the wrong
+ // corner will get matched to closest_quad;
+ closest_corner = closest_quad->corners[closest_corner_idx];
+
+ for( j = 0; j < 4; j++ )
+ {
+ if( cur_quad->neighbors[j] == closest_quad )
+ break;
+
+ dx = closest_corner->pt.x - cur_quad->corners[j]->pt.x;
+ dy = closest_corner->pt.y - cur_quad->corners[j]->pt.y;
+
+ if( dx * dx + dy * dy < min_dist )
+ break;
+ }
+
+ if( j < 4 || cur_quad->count >= 4 || closest_quad->count >= 4 )
+ continue;
+
+ // Check that each corner is a neighbor of different quads
+ for( j = 0; j < closest_quad->count; j++ )
+ {
+ if( closest_quad->neighbors[j] == cur_quad )
+ break;
+ }
+ if( j < closest_quad->count )
+ continue;
+
+ // check whether the closest corner to closest_corner
+ // is different from cur_quad->corners[i]->pt
+ for( k = 0; k < quad_count; k++ )
+ {
+ CvCBQuad* q = &quads[k];
+ if( k == idx || q == closest_quad )
+ continue;
+
+ for( j = 0; j < 4; j++ )
+ if( !q->neighbors[j] )
+ {
+ dx = closest_corner->pt.x - q->corners[j]->pt.x;
+ dy = closest_corner->pt.y - q->corners[j]->pt.y;
+ dist = dx*dx + dy*dy;
+ if( dist < min_dist )
+ break;
+ }
+ if( j < 4 )
+ break;
+ }
+
+ if( k < quad_count )
+ continue;
+
+ closest_corner->pt.x = (pt.x + closest_corner->pt.x) * 0.5f;
+ closest_corner->pt.y = (pt.y + closest_corner->pt.y) * 0.5f;
+
+ // We've found one more corner - remember it
+ cur_quad->count++;
+ cur_quad->neighbors[i] = closest_quad;
+ cur_quad->corners[i] = closest_corner;
+
+ closest_quad->count++;
+ closest_quad->neighbors[closest_corner_idx] = cur_quad;
+ }
+ }
+ }
+}
+
+//=====================================================================================
+
+// returns corners in clockwise order
+// corners don't necessarily start at same position on quad (e.g.,
+// top left corner)
+
+static int
+icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
+ CvMemStorage *storage, CvMat *image, int flags )
+{
+ int quad_count = 0;
+ CvMemStorage *temp_storage = 0;
+
+ if( out_quads )
+ *out_quads = 0;
+
+ if( out_corners )
+ *out_corners = 0;
+
+ CV_FUNCNAME( "icvGenerateQuads" );
+
+ __BEGIN__;
+
+ CvSeq *src_contour = 0;
+ CvSeq *root;
+ CvContourEx* board = 0;
+ CvContourScanner scanner;
+ int i, idx, min_size;
+
+ CV_ASSERT( out_corners && out_quads );
+
+ // empiric bound for minimal allowed perimeter for squares
+ min_size = cvRound( image->cols * image->rows * .03 * 0.01 * 0.92 );
+
+ // create temporary storage for contours and the sequence of pointers to found quadrangles
+ CV_CALL( temp_storage = cvCreateChildMemStorage( storage ));
+ CV_CALL( root = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSeq*), temp_storage ));
+
+ // initialize contour retrieving routine
+ CV_CALL( scanner = cvStartFindContours( image, temp_storage, sizeof(CvContourEx),
+ CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ));
+
+ // get all the contours one by one
+ while( (src_contour = cvFindNextContour( scanner )) != 0 )
+ {
+ CvSeq *dst_contour = 0;
+ CvRect rect = ((CvContour*)src_contour)->rect;
+
+ // reject contours with too small perimeter
+ if( CV_IS_SEQ_HOLE(src_contour) && rect.width*rect.height >= min_size )
+ {
+ const int min_approx_level = 2, max_approx_level = MAX_CONTOUR_APPROX;
+ int approx_level;
+ for( approx_level = min_approx_level; approx_level <= max_approx_level; approx_level++ )
+ {
+ dst_contour = cvApproxPoly( src_contour, sizeof(CvContour), temp_storage,
+ CV_POLY_APPROX_DP, (float)approx_level );
+ // we call this again on its own output, because sometimes
+ // cvApproxPoly() does not simplify as much as it should.
+ dst_contour = cvApproxPoly( dst_contour, sizeof(CvContour), temp_storage,
+ CV_POLY_APPROX_DP, (float)approx_level );
+
+ if( dst_contour->total == 4 )
+ break;
+ }
+
+ // reject non-quadrangles
+ if( dst_contour->total == 4 && cvCheckContourConvexity(dst_contour) )
+ {
+ CvPoint pt[4];
+ double d1, d2, p = cvContourPerimeter(dst_contour);
+ double area = fabs(cvContourArea(dst_contour, CV_WHOLE_SEQ));
+ double dx, dy;
+
+ for( i = 0; i < 4; i++ )
+ pt[i] = *(CvPoint*)cvGetSeqElem(dst_contour, i);
+
+ dx = pt[0].x - pt[2].x;
+ dy = pt[0].y - pt[2].y;
+ d1 = sqrt(dx*dx + dy*dy);
+
+ dx = pt[1].x - pt[3].x;
+ dy = pt[1].y - pt[3].y;
+ d2 = sqrt(dx*dx + dy*dy);
+
+ // philipg. Only accept those quadrangles which are more square
+ // than rectangular and which are big enough
+ double d3, d4;
+ dx = pt[0].x - pt[1].x;
+ dy = pt[0].y - pt[1].y;
+ d3 = sqrt(dx*dx + dy*dy);
+ dx = pt[1].x - pt[2].x;
+ dy = pt[1].y - pt[2].y;
+ d4 = sqrt(dx*dx + dy*dy);
+ if( !(flags & CV_CALIB_CB_FILTER_QUADS) ||
+ (d3*4 > d4 && d4*4 > d3 && d3*d4 < area*1.5 && area > min_size &&
+ d1 >= 0.15 * p && d2 >= 0.15 * p) )
+ {
+ CvContourEx* parent = (CvContourEx*)(src_contour->v_prev);
+ parent->counter++;
+ if( !board || board->counter < parent->counter )
+ board = parent;
+ dst_contour->v_prev = (CvSeq*)parent;
+ //for( i = 0; i < 4; i++ ) cvLine( debug_img, pt[i], pt[(i+1)&3], cvScalar(200,255,255), 1, CV_AA, 0 );
+ cvSeqPush( root, &dst_contour );
+ }
+ }
+ }
+ }
+
+ // finish contour retrieving
+ cvEndFindContours( &scanner );
+
+ // allocate quad & corner buffers
+ CV_CALL( *out_quads = (CvCBQuad*)cvAlloc((root->total+root->total / 2) * sizeof((*out_quads)[0])));
+ CV_CALL( *out_corners = (CvCBCorner*)cvAlloc((root->total+root->total / 2) * 4 * sizeof((*out_corners)[0])));
+
+ // Create array of quads structures
+ for( idx = 0; idx < root->total; idx++ )
+ {
+ CvCBQuad* q = &(*out_quads)[quad_count];
+ src_contour = *(CvSeq**)cvGetSeqElem( root, idx );
+ if( (flags & CV_CALIB_CB_FILTER_QUADS) && src_contour->v_prev != (CvSeq*)board )
+ continue;
+
+ // reset group ID
+ memset( q, 0, sizeof(*q) );
+ q->group_idx = -1;
+ assert( src_contour->total == 4 );
+ for( i = 0; i < 4; i++ )
+ {
+ CvPoint2D32f pt = cvPointTo32f(*(CvPoint*)cvGetSeqElem(src_contour, i));
+ CvCBCorner* corner = &(*out_corners)[quad_count*4 + i];
+
+ memset( corner, 0, sizeof(*corner) );
+ corner->pt = pt;
+ q->corners[i] = corner;
+ }
+ q->edge_len = FLT_MAX;
+ for( i = 0; i < 4; i++ )
+ {
+ float dx = q->corners[i]->pt.x - q->corners[(i+1)&3]->pt.x;
+ float dy = q->corners[i]->pt.y - q->corners[(i+1)&3]->pt.y;
+ float d = dx*dx + dy*dy;
+ if( q->edge_len > d )
+ q->edge_len = d;
+ }
+ quad_count++;
+ }
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ {
+ if( out_quads )
+ cvFree( out_quads );
+ if( out_corners )
+ cvFree( out_corners );
+ quad_count = 0;
+ }
+
+ cvReleaseMemStorage( &temp_storage );
+ return quad_count;
+}
+
+
+//=====================================================================================
+
+static int is_equal_quad( const void* _a, const void* _b, void* )
+{
+ CvRect a = (*((CvContour**)_a))->rect;
+ CvRect b = (*((CvContour**)_b))->rect;
+
+ int dx = MIN( b.x + b.width - 1, a.x + a.width - 1) - MAX( b.x, a.x);
+ int dy = MIN( b.y + b.height - 1, a.y + a.height - 1) - MAX( b.y, a.y);
+ int w = (a.width + b.width)>>1;
+ int h = (a.height + b.height)>>1;
+
+ if( dx > w*0.75 && dy > h*0.75 && dx < w*1.25 && dy < h*1.25 ) return 1;
+
+ return 0;
+}
+
+static int
+icvGenerateQuadsEx( CvCBQuad **out_quads, CvCBCorner **out_corners,
+ CvMemStorage *storage, CvMat *image, CvMat *thresh_img, int dilations, int flags )
+{
+ int l;
+ int quad_count = 0;
+ CvMemStorage *temp_storage = 0;
+
+ if( out_quads )
+ *out_quads = 0;
+
+ if( out_corners )
+ *out_corners = 0;
+
+ CV_FUNCNAME( "icvGenerateQuads" );
+
+ __BEGIN__;
+
+ CvSeq *src_contour = 0;
+ CvSeq *root, *root_tmp;
+ CvContourEx* board = 0;
+ CvContourScanner scanner;
+ int i, idx, min_size;
+ int step_level = 25;
+
+ CV_ASSERT( out_corners && out_quads );
+
+ // empiric bound for minimal allowed perimeter for squares
+ min_size = cvRound( image->cols * image->rows * .03 * 0.01 * 0.92 );
+
+ // create temporary storage for contours and the sequence of pointers to found quadrangles
+ CV_CALL( temp_storage = cvCreateChildMemStorage( storage ));
+ CV_CALL( root_tmp = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSeq*), temp_storage ));
+ CV_CALL( root = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSeq*), temp_storage ));
+
+ //perform contours slicing
+ cvEqualizeHist(image,image);
+ for(l = step_level; l < 256-step_level; l+= step_level)
+ {
+ cvThreshold( image, thresh_img, l, 255, CV_THRESH_BINARY );
+ cvDilate( thresh_img, thresh_img, 0, dilations );
+
+ //draw frame to extract edge quads
+ cvRectangle( thresh_img, cvPoint(0,0), cvPoint(thresh_img->cols-1,
+ thresh_img->rows-1), CV_RGB(255,255,255), 3, 8);
+
+ // initialize contour retrieving routine
+ CV_CALL( scanner = cvStartFindContours( thresh_img, temp_storage, sizeof(CvContourEx),
+ CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ));
+
+ // get all the contours one by one
+ while( (src_contour = cvFindNextContour( scanner )) != 0 )
+ {
+ CvSeq *dst_contour = 0;
+ CvRect rect = ((CvContour*)src_contour)->rect;
+
+ // reject contours with too small perimeter
+ if( CV_IS_SEQ_HOLE(src_contour) && rect.width*rect.height >= min_size )
+ {
+ const int min_approx_level = 2, max_approx_level = MAX_CONTOUR_APPROX;
+ int approx_level;
+ for( approx_level = min_approx_level; approx_level <= max_approx_level; approx_level++ )
+ {
+ dst_contour = cvApproxPoly( src_contour, sizeof(CvContour), temp_storage,
+ CV_POLY_APPROX_DP, (float)approx_level );
+ // we call this again on its own output, because sometimes
+ // cvApproxPoly() does not simplify as much as it should.
+ dst_contour = cvApproxPoly( dst_contour, sizeof(CvContour), temp_storage,
+ CV_POLY_APPROX_DP, (float)approx_level );
+
+ if( dst_contour->total == 4 )
+ break;
+ }
+
+ // reject non-quadrangles
+ if( dst_contour->total == 4 && cvCheckContourConvexity(dst_contour) )
+ {
+ CvPoint pt[4];
+ double d1, d2, p = cvContourPerimeter(dst_contour);
+ double area = fabs(cvContourArea(dst_contour, CV_WHOLE_SEQ));
+ double dx, dy;
+
+ for( i = 0; i < 4; i++ )
+ pt[i] = *(CvPoint*)cvGetSeqElem(dst_contour, i);
+
+ //check border condition. if this is edge square we will add this as is
+ int edge_flag = 0, eps = 2;
+ for( i = 0; i < 4; i++ )
+ if( pt[i].x <= eps || pt[i].y <= eps ||
+ pt[i].x >= image->width - eps ||
+ pt[i].y >= image->height - eps ) edge_flag = 1;
+
+ dx = pt[0].x - pt[2].x;
+ dy = pt[0].y - pt[2].y;
+ d1 = sqrt(dx*dx + dy*dy);
+
+ dx = pt[1].x - pt[3].x;
+ dy = pt[1].y - pt[3].y;
+ d2 = sqrt(dx*dx + dy*dy);
+
+ // philipg. Only accept those quadrangles which are more square
+ // than rectangular and which are big enough
+ double d3, d4;
+ dx = pt[0].x - pt[1].x;
+ dy = pt[0].y - pt[1].y;
+ d3 = sqrt(dx*dx + dy*dy);
+ dx = pt[1].x - pt[2].x;
+ dy = pt[1].y - pt[2].y;
+ d4 = sqrt(dx*dx + dy*dy);
+ if( edge_flag ||
+ (!(flags & CV_CALIB_CB_FILTER_QUADS) ||
+ (d3*4 > d4 && d4*4 > d3 && d3*d4 < area*1.5 && area > min_size &&
+ d1 >= 0.15 * p && d2 >= 0.15 * p)) )
+ {
+ CvContourEx* parent = (CvContourEx*)(src_contour->v_prev);
+ parent->counter++;
+ if( !board || board->counter < parent->counter )
+ board = parent;
+ dst_contour->v_prev = (CvSeq*)parent;
+ //for( i = 0; i < 4; i++ ) cvLine( debug_img, pt[i], pt[(i+1)&3], cvScalar(200,255,255), 1, CV_AA, 0 );
+ cvSeqPush( root_tmp, &dst_contour );
+ }
+ }
+ }
+ }
+ // finish contour retrieving
+ cvEndFindContours( &scanner );
+ }
+
+
+ // Perform clustering of extracted quads
+ // Same quad can be extracted from different binarization levels
+ if( root_tmp->total )
+ {
+ CvSeq* idx_seq = 0;
+ int n_quads = cvSeqPartition( root_tmp, temp_storage, &idx_seq, is_equal_quad, 0 );
+ for( i = 0; i < n_quads; i++ )
+ {
+ //extract biggest quad in group
+ int max_size = 0;
+ CvSeq* max_seq = 0;
+ for( int j = 0; j < root_tmp->total; j++ )
+ {
+ int index = *(int*)cvGetSeqElem(idx_seq, j);
+ if(index!=i) continue;
+ CvContour* cnt = *(CvContour**)cvGetSeqElem(root_tmp, j);
+ if(cnt->rect.width > max_size)
+ {
+ max_size = cnt->rect.width;
+ max_seq = (CvSeq*)cnt;
+ }
+ }
+ cvSeqPush( root, &max_seq);
+ }
+ }
+
+ // allocate quad & corner buffers
+ CV_CALL( *out_quads = (CvCBQuad*)cvAlloc((root->total+root->total / 2) * sizeof((*out_quads)[0])));
+ CV_CALL( *out_corners = (CvCBCorner*)cvAlloc((root->total+root->total / 2) * 4 * sizeof((*out_corners)[0])));
+
+ // Create array of quads structures
+ for( idx = 0; idx < root->total; idx++ )
+ {
+ CvCBQuad* q = &(*out_quads)[quad_count];
+ src_contour = *(CvSeq**)cvGetSeqElem( root, idx );
+ if( (flags & CV_CALIB_CB_FILTER_QUADS) && src_contour->v_prev != (CvSeq*)board )
+ continue;
+
+ // reset group ID
+ memset( q, 0, sizeof(*q) );
+ q->group_idx = -1;
+ assert( src_contour->total == 4 );
+ for( i = 0; i < 4; i++ )
+ {
+ CvPoint2D32f pt = cvPointTo32f(*(CvPoint*)cvGetSeqElem(src_contour, i));
+ CvCBCorner* corner = &(*out_corners)[quad_count*4 + i];
+
+ memset( corner, 0, sizeof(*corner) );
+ corner->pt = pt;
+ q->corners[i] = corner;
+ }
+ q->edge_len = FLT_MAX;
+ for( i = 0; i < 4; i++ )
+ {
+ float dx = q->corners[i]->pt.x - q->corners[(i+1)&3]->pt.x;
+ float dy = q->corners[i]->pt.y - q->corners[(i+1)&3]->pt.y;
+ float d = dx*dx + dy*dy;
+ if( q->edge_len > d )
+ q->edge_len = d;
+ }
+ quad_count++;
+ }
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ {
+ if( out_quads )
+ cvFree( out_quads );
+ if( out_corners )
+ cvFree( out_corners );
+ quad_count = 0;
+ }
+
+ cvReleaseMemStorage( &temp_storage );
+ return quad_count;
+}
+
+
+CV_IMPL void
+cvDrawChessboardCorners( CvArr* _image, CvSize pattern_size,
+ CvPoint2D32f* corners, int count, int found )
+{
+ CV_FUNCNAME( "cvDrawChessboardCorners" );
+
+ __BEGIN__;
+
+ const int shift = 0;
+ const int radius = 4;
+ const int r = radius*(1 << shift);
+ int i;
+ CvMat stub, *image;
+ double scale = 1;
+ int type, cn, line_type;
+
+ CV_CALL( image = cvGetMat( _image, &stub ));
+
+ type = CV_MAT_TYPE(image->type);
+ cn = CV_MAT_CN(type);
+ if( cn != 1 && cn != 3 && cn != 4 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Number of channels must be 1, 3 or 4" );
+
+ switch( CV_MAT_DEPTH(image->type) )
+ {
+ case CV_8U:
+ scale = 1;
+ break;
+ case CV_16U:
+ scale = 256;
+ break;
+ case CV_32F:
+ scale = 1./255;
+ break;
+ default:
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Only 8-bit, 16-bit or floating-point 32-bit images are supported" );
+ }
+
+ line_type = type == CV_8UC1 || type == CV_8UC3 ? CV_AA : 8;
+
+ if( !found )
+ {
+ CvScalar color = {{0,0,255}};
+ if( cn == 1 )
+ color = cvScalarAll(200);
+ color.val[0] *= scale;
+ color.val[1] *= scale;
+ color.val[2] *= scale;
+ color.val[3] *= scale;
+
+ for( i = 0; i < count; i++ )
+ {
+ CvPoint pt;
+ pt.x = cvRound(corners[i].x*(1 << shift));
+ pt.y = cvRound(corners[i].y*(1 << shift));
+ cvLine( image, cvPoint( pt.x - r, pt.y - r ),
+ cvPoint( pt.x + r, pt.y + r ), color, 1, line_type, shift );
+ cvLine( image, cvPoint( pt.x - r, pt.y + r),
+ cvPoint( pt.x + r, pt.y - r), color, 1, line_type, shift );
+ cvCircle( image, pt, r+(1<<shift), color, 1, line_type, shift );
+ }
+ }
+ else
+ {
+ int x, y;
+ CvPoint prev_pt = {0, 0};
+ const int line_max = 7;
+ static const CvScalar line_colors[line_max] =
+ {
+ {{0,0,255}},
+ {{0,128,255}},
+ {{0,200,200}},
+ {{0,255,0}},
+ {{200,200,0}},
+ {{255,0,0}},
+ {{255,0,255}}
+ };
+
+ for( y = 0, i = 0; y < pattern_size.height; y++ )
+ {
+ CvScalar color = line_colors[y % line_max];
+ if( cn == 1 )
+ color = cvScalarAll(200);
+ color.val[0] *= scale;
+ color.val[1] *= scale;
+ color.val[2] *= scale;
+ color.val[3] *= scale;
+
+ for( x = 0; x < pattern_size.width; x++, i++ )
+ {
+ CvPoint pt;
+ pt.x = cvRound(corners[i].x*(1 << shift));
+ pt.y = cvRound(corners[i].y*(1 << shift));
+
+ if( i != 0 )
+ cvLine( image, prev_pt, pt, color, 1, line_type, shift );
+
+ cvLine( image, cvPoint(pt.x - r, pt.y - r),
+ cvPoint(pt.x + r, pt.y + r), color, 1, line_type, shift );
+ cvLine( image, cvPoint(pt.x - r, pt.y + r),
+ cvPoint(pt.x + r, pt.y - r), color, 1, line_type, shift );
+ cvCircle( image, pt, r+(1<<shift), color, 1, line_type, shift );
+ prev_pt = pt;
+ }
+ }
+ }
+
+ __END__;
+}
+
+
+/* End of file. */
diff --git a/cv/src/cvcalibration.cpp b/cv/src/cvcalibration.cpp
new file mode 100644
index 0000000..202ba32
--- /dev/null
+++ b/cv/src/cvcalibration.cpp
@@ -0,0 +1,2683 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+/*
+ This is stright-forward port v3 of Matlab calibration engine by Jean-Yves Bouguet
+ that is (in a large extent) based on the paper:
+ Z. Zhang. "A flexible new technique for camera calibration".
+ IEEE Transactions on Pattern Analysis and Machine Intelligence, 22(11):1330-1334, 2000.
+
+ The 1st initial port was done by Valery Mosyagin.
+*/
+
+CvLevMarq::CvLevMarq()
+{
+ mask = prevParam = param = J = err = JtJ = JtJN = JtErr = JtJV = JtJW = 0;
+ lambdaLg10 = 0; state = DONE;
+ criteria = cvTermCriteria(0,0,0);
+ iters = 0;
+ completeSymmFlag = false;
+}
+
+CvLevMarq::CvLevMarq( int nparams, int nerrs, CvTermCriteria criteria0, bool _completeSymmFlag )
+{
+ mask = prevParam = param = J = err = JtJ = JtJN = JtErr = JtJV = JtJW = 0;
+ init(nparams, nerrs, criteria0, _completeSymmFlag);
+}
+
+void CvLevMarq::clear()
+{
+ cvReleaseMat(&mask);
+ cvReleaseMat(&prevParam);
+ cvReleaseMat(&param);
+ cvReleaseMat(&J);
+ cvReleaseMat(&err);
+ cvReleaseMat(&JtJ);
+ cvReleaseMat(&JtJN);
+ cvReleaseMat(&JtErr);
+ cvReleaseMat(&JtJV);
+ cvReleaseMat(&JtJW);
+}
+
+CvLevMarq::~CvLevMarq()
+{
+ clear();
+}
+
+void CvLevMarq::init( int nparams, int nerrs, CvTermCriteria criteria0, bool _completeSymmFlag )
+{
+ if( !param || param->rows != nparams || nerrs != (err ? err->rows : 0) )
+ clear();
+ mask = cvCreateMat( nparams, 1, CV_8U );
+ cvSet(mask, cvScalarAll(1));
+ prevParam = cvCreateMat( nparams, 1, CV_64F );
+ param = cvCreateMat( nparams, 1, CV_64F );
+ JtJ = cvCreateMat( nparams, nparams, CV_64F );
+ JtJN = cvCreateMat( nparams, nparams, CV_64F );
+ JtJV = cvCreateMat( nparams, nparams, CV_64F );
+ JtJW = cvCreateMat( nparams, 1, CV_64F );
+ JtErr = cvCreateMat( nparams, 1, CV_64F );
+ if( nerrs > 0 )
+ {
+ J = cvCreateMat( nerrs, nparams, CV_64F );
+ err = cvCreateMat( nerrs, 1, CV_64F );
+ }
+ prevErrNorm = DBL_MAX;
+ lambdaLg10 = -3;
+ criteria = criteria0;
+ if( criteria.type & CV_TERMCRIT_ITER )
+ criteria.max_iter = MIN(MAX(criteria.max_iter,1),1000);
+ else
+ criteria.max_iter = 30;
+ if( criteria.type & CV_TERMCRIT_EPS )
+ criteria.epsilon = MAX(criteria.epsilon, 0);
+ else
+ criteria.epsilon = DBL_EPSILON;
+ state = STARTED;
+ iters = 0;
+ completeSymmFlag = _completeSymmFlag;
+}
+
+bool CvLevMarq::update( const CvMat*& _param, CvMat*& _J, CvMat*& _err )
+{
+ double change;
+
+ assert( err != 0 );
+ if( state == DONE )
+ {
+ _param = param;
+ return false;
+ }
+
+ if( state == STARTED )
+ {
+ _param = param;
+ cvZero( J );
+ cvZero( err );
+ _J = J;
+ _err = err;
+ state = CALC_J;
+ return true;
+ }
+
+ if( state == CALC_J )
+ {
+ cvMulTransposed( J, JtJ, 1 );
+ cvGEMM( J, err, 1, 0, 0, JtErr, CV_GEMM_A_T );
+ cvCopy( param, prevParam );
+ step();
+ if( iters == 0 )
+ prevErrNorm = cvNorm(err, 0, CV_L2);
+ _param = param;
+ cvZero( err );
+ _err = err;
+ state = CHECK_ERR;
+ return true;
+ }
+
+ assert( state == CHECK_ERR );
+ errNorm = cvNorm( err, 0, CV_L2 );
+ if( errNorm > prevErrNorm )
+ {
+ lambdaLg10++;
+ step();
+ _param = param;
+ cvZero( err );
+ _err = err;
+ state = CHECK_ERR;
+ return true;
+ }
+
+ lambdaLg10 = MAX(lambdaLg10-1, -16);
+ if( ++iters >= criteria.max_iter ||
+ (change = cvNorm(param, prevParam, CV_RELATIVE_L2)) < criteria.epsilon )
+ {
+ _param = param;
+ state = DONE;
+ return true;
+ }
+
+ prevErrNorm = errNorm;
+ _param = param;
+ cvZero(J);
+ _J = J;
+ state = CALC_J;
+ return false;
+}
+
+
+bool CvLevMarq::updateAlt( const CvMat*& _param, CvMat*& _JtJ, CvMat*& _JtErr, double*& _errNorm )
+{
+ double change;
+
+ assert( err == 0 );
+ if( state == DONE )
+ {
+ _param = param;
+ return false;
+ }
+
+ if( state == STARTED )
+ {
+ _param = param;
+ cvZero( JtJ );
+ cvZero( JtErr );
+ errNorm = 0;
+ _JtJ = JtJ;
+ _JtErr = JtErr;
+ _errNorm = &errNorm;
+ state = CALC_J;
+ return true;
+ }
+
+ if( state == CALC_J )
+ {
+ cvCopy( param, prevParam );
+ step();
+ _param = param;
+ prevErrNorm = errNorm;
+ errNorm = 0;
+ _errNorm = &errNorm;
+ state = CHECK_ERR;
+ return true;
+ }
+
+ assert( state == CHECK_ERR );
+ if( errNorm > prevErrNorm )
+ {
+ lambdaLg10++;
+ step();
+ _param = param;
+ errNorm = 0;
+ _errNorm = &errNorm;
+ state = CHECK_ERR;
+ return true;
+ }
+
+ lambdaLg10 = MAX(lambdaLg10-1, -16);
+ if( ++iters >= criteria.max_iter ||
+ (change = cvNorm(param, prevParam, CV_RELATIVE_L2)) < criteria.epsilon )
+ {
+ _param = param;
+ state = DONE;
+ return false;
+ }
+
+ prevErrNorm = errNorm;
+ cvZero( JtJ );
+ cvZero( JtErr );
+ _param = param;
+ _JtJ = JtJ;
+ _JtErr = JtErr;
+ state = CALC_J;
+ return true;
+}
+
+void CvLevMarq::step()
+{
+ const double LOG10 = log(10.);
+ double lambda = exp(lambdaLg10*LOG10);
+ int i, j, nparams = param->rows;
+
+ for( i = 0; i < nparams; i++ )
+ if( mask->data.ptr[i] == 0 )
+ {
+ double *row = JtJ->data.db + i*nparams, *col = JtJ->data.db + i;
+ for( j = 0; j < nparams; j++ )
+ row[j] = col[j*nparams] = 0;
+ JtErr->data.db[i] = 0;
+ }
+
+ if( !err )
+ cvCompleteSymm( JtJ, completeSymmFlag );
+ cvSetIdentity( JtJN, cvRealScalar(lambda) );
+ cvAdd( JtJ, JtJN, JtJN );
+ cvSVD( JtJN, JtJW, 0, JtJV, CV_SVD_MODIFY_A + CV_SVD_U_T + CV_SVD_V_T );
+ cvSVBkSb( JtJW, JtJV, JtJV, JtErr, param, CV_SVD_U_T + CV_SVD_V_T );
+ for( i = 0; i < nparams; i++ )
+ param->data.db[i] = prevParam->data.db[i] - (mask->data.ptr[i] ? param->data.db[i] : 0);
+}
+
+// reimplementation of dAB.m
+CV_IMPL void
+cvCalcMatMulDeriv( const CvMat* A, const CvMat* B, CvMat* dABdA, CvMat* dABdB )
+{
+ CV_FUNCNAME( "cvCalcMatMulDeriv" );
+
+ __BEGIN__;
+
+ int i, j, M, N, L;
+ int bstep;
+
+ CV_ASSERT( CV_IS_MAT(A) && CV_IS_MAT(B) );
+ CV_ASSERT( CV_ARE_TYPES_EQ(A, B) &&
+ (CV_MAT_TYPE(A->type) == CV_32F || CV_MAT_TYPE(A->type) == CV_64F) );
+ CV_ASSERT( A->cols == B->rows );
+
+ M = A->rows;
+ L = A->cols;
+ N = B->cols;
+ bstep = B->step/CV_ELEM_SIZE(B->type);
+
+ if( dABdA )
+ {
+ CV_ASSERT( CV_ARE_TYPES_EQ(A, dABdA) &&
+ dABdA->rows == A->rows*B->cols && dABdA->cols == A->rows*A->cols );
+ }
+
+ if( dABdB )
+ {
+ CV_ASSERT( CV_ARE_TYPES_EQ(A, dABdB) &&
+ dABdB->rows == A->rows*B->cols && dABdB->cols == B->rows*B->cols );
+ }
+
+ if( CV_MAT_TYPE(A->type) == CV_32F )
+ {
+ for( i = 0; i < M*N; i++ )
+ {
+ int i1 = i / N, i2 = i % N;
+
+ if( dABdA )
+ {
+ float* dcda = (float*)(dABdA->data.ptr + dABdA->step*i);
+ const float* b = (const float*)B->data.ptr + i2;
+
+ for( j = 0; j < M*L; j++ )
+ dcda[j] = 0;
+ for( j = 0; j < L; j++ )
+ dcda[i1*L + j] = b[j*bstep];
+ }
+
+ if( dABdB )
+ {
+ float* dcdb = (float*)(dABdB->data.ptr + dABdB->step*i);
+ const float* a = (const float*)(A->data.ptr + A->step*i1);
+
+ for( j = 0; j < L*N; j++ )
+ dcdb[j] = 0;
+ for( j = 0; j < L; j++ )
+ dcdb[j*N + i2] = a[j];
+ }
+ }
+ }
+ else
+ {
+ for( i = 0; i < M*N; i++ )
+ {
+ int i1 = i / N, i2 = i % N;
+
+ if( dABdA )
+ {
+ double* dcda = (double*)(dABdA->data.ptr + dABdA->step*i);
+ const double* b = (const double*)B->data.ptr + i2;
+
+ for( j = 0; j < M*L; j++ )
+ dcda[j] = 0;
+ for( j = 0; j < L; j++ )
+ dcda[i1*L + j] = b[j*bstep];
+ }
+
+ if( dABdB )
+ {
+ double* dcdb = (double*)(dABdB->data.ptr + dABdB->step*i);
+ const double* a = (const double*)(A->data.ptr + A->step*i1);
+
+ for( j = 0; j < L*N; j++ )
+ dcdb[j] = 0;
+ for( j = 0; j < L; j++ )
+ dcdb[j*N + i2] = a[j];
+ }
+ }
+ }
+
+ __END__;
+}
+
+// reimplementation of compose_motion.m
+CV_IMPL void
+cvComposeRT( const CvMat* _rvec1, const CvMat* _tvec1,
+ const CvMat* _rvec2, const CvMat* _tvec2,
+ CvMat* _rvec3, CvMat* _tvec3,
+ CvMat* dr3dr1, CvMat* dr3dt1,
+ CvMat* dr3dr2, CvMat* dr3dt2,
+ CvMat* dt3dr1, CvMat* dt3dt1,
+ CvMat* dt3dr2, CvMat* dt3dt2 )
+{
+ CV_FUNCNAME( "cvComposeRT" );
+
+ __BEGIN__;
+
+ double _r1[3], _r2[3];
+ double _R1[9], _d1[9*3], _R2[9], _d2[9*3];
+ CvMat r1 = cvMat(3,1,CV_64F,_r1), r2 = cvMat(3,1,CV_64F,_r2);
+ CvMat R1 = cvMat(3,3,CV_64F,_R1), R2 = cvMat(3,3,CV_64F,_R2);
+ CvMat dR1dr1 = cvMat(9,3,CV_64F,_d1), dR2dr2 = cvMat(9,3,CV_64F,_d2);
+
+ CV_ASSERT( CV_IS_MAT(_rvec1) && CV_IS_MAT(_rvec2) );
+
+ CV_ASSERT( CV_MAT_TYPE(_rvec1->type) == CV_32F ||
+ CV_MAT_TYPE(_rvec1->type) == CV_64F );
+
+ CV_ASSERT( _rvec1->rows == 3 && _rvec1->cols == 1 && CV_ARE_SIZES_EQ(_rvec1, _rvec2) );
+
+ cvConvert( _rvec1, &r1 );
+ cvConvert( _rvec2, &r2 );
+
+ cvRodrigues2( &r1, &R1, &dR1dr1 );
+ cvRodrigues2( &r2, &R2, &dR2dr2 );
+
+ if( _rvec3 || dr3dr1 || dr3dr1 )
+ {
+ double _r3[3], _R3[9], _dR3dR1[9*9], _dR3dR2[9*9], _dr3dR3[9*3];
+ double _W1[9*3], _W2[3*3];
+ CvMat r3 = cvMat(3,1,CV_64F,_r3), R3 = cvMat(3,3,CV_64F,_R3);
+ CvMat dR3dR1 = cvMat(9,9,CV_64F,_dR3dR1), dR3dR2 = cvMat(9,9,CV_64F,_dR3dR2);
+ CvMat dr3dR3 = cvMat(3,9,CV_64F,_dr3dR3);
+ CvMat W1 = cvMat(3,9,CV_64F,_W1), W2 = cvMat(3,3,CV_64F,_W2);
+
+ cvMatMul( &R2, &R1, &R3 );
+ cvCalcMatMulDeriv( &R2, &R1, &dR3dR2, &dR3dR1 );
+
+ cvRodrigues2( &R3, &r3, &dr3dR3 );
+
+ if( _rvec3 )
+ cvConvert( &r3, _rvec3 );
+
+ if( dr3dr1 )
+ {
+ cvMatMul( &dr3dR3, &dR3dR1, &W1 );
+ cvMatMul( &W1, &dR1dr1, &W2 );
+ cvConvert( &W2, dr3dr1 );
+ }
+
+ if( dr3dr2 )
+ {
+ cvMatMul( &dr3dR3, &dR3dR2, &W1 );
+ cvMatMul( &W1, &dR2dr2, &W2 );
+ cvConvert( &W2, dr3dr2 );
+ }
+ }
+
+ if( dr3dt1 )
+ cvZero( dr3dt1 );
+ if( dr3dt2 )
+ cvZero( dr3dt2 );
+
+ if( _tvec3 || dt3dr2 || dt3dt1 )
+ {
+ double _t1[3], _t2[3], _t3[3], _dxdR2[3*9], _dxdt1[3*3], _W3[3*3];
+ CvMat t1 = cvMat(3,1,CV_64F,_t1), t2 = cvMat(3,1,CV_64F,_t2);
+ CvMat t3 = cvMat(3,1,CV_64F,_t3);
+ CvMat dxdR2 = cvMat(3, 9, CV_64F, _dxdR2);
+ CvMat dxdt1 = cvMat(3, 3, CV_64F, _dxdt1);
+ CvMat W3 = cvMat(3, 3, CV_64F, _W3);
+
+ CV_ASSERT( CV_IS_MAT(_tvec1) && CV_IS_MAT(_tvec2) );
+ CV_ASSERT( CV_ARE_SIZES_EQ(_tvec1, _tvec2) && CV_ARE_SIZES_EQ(_tvec1, _rvec1) );
+
+ cvConvert( _tvec1, &t1 );
+ cvConvert( _tvec2, &t2 );
+ cvMatMulAdd( &R2, &t1, &t2, &t3 );
+
+ if( _tvec3 )
+ cvConvert( &t3, _tvec3 );
+
+ if( dt3dr2 || dt3dt1 )
+ {
+ cvCalcMatMulDeriv( &R2, &t1, &dxdR2, &dxdt1 );
+ if( dt3dr2 )
+ {
+ cvMatMul( &dxdR2, &dR2dr2, &W3 );
+ cvConvert( &W3, dt3dr2 );
+ }
+ if( dt3dt1 )
+ cvConvert( &dxdt1, dt3dt1 );
+ }
+ }
+
+ if( dt3dt2 )
+ cvSetIdentity( dt3dt2 );
+ if( dt3dr1 )
+ cvZero( dt3dr1 );
+
+ __END__;
+}
+
+CV_IMPL int
+cvRodrigues2( const CvMat* src, CvMat* dst, CvMat* jacobian )
+{
+ int result = 0;
+
+ CV_FUNCNAME( "cvRogrigues2" );
+
+ __BEGIN__;
+
+ int depth, elem_size;
+ int i, k;
+ double J[27];
+ CvMat _J = cvMat( 3, 9, CV_64F, J );
+
+ if( !CV_IS_MAT(src) )
+ CV_ERROR( !src ? CV_StsNullPtr : CV_StsBadArg, "Input argument is not a valid matrix" );
+
+ if( !CV_IS_MAT(dst) )
+ CV_ERROR( !dst ? CV_StsNullPtr : CV_StsBadArg,
+ "The first output argument is not a valid matrix" );
+
+ depth = CV_MAT_DEPTH(src->type);
+ elem_size = CV_ELEM_SIZE(depth);
+
+ if( depth != CV_32F && depth != CV_64F )
+ CV_ERROR( CV_StsUnsupportedFormat, "The matrices must have 32f or 64f data type" );
+
+ if( !CV_ARE_DEPTHS_EQ(src, dst) )
+ CV_ERROR( CV_StsUnmatchedFormats, "All the matrices must have the same data type" );
+
+ if( jacobian )
+ {
+ if( !CV_IS_MAT(jacobian) )
+ CV_ERROR( CV_StsBadArg, "Jacobian is not a valid matrix" );
+
+ if( !CV_ARE_DEPTHS_EQ(src, jacobian) || CV_MAT_CN(jacobian->type) != 1 )
+ CV_ERROR( CV_StsUnmatchedFormats, "Jacobian must have 32fC1 or 64fC1 datatype" );
+
+ if( (jacobian->rows != 9 || jacobian->cols != 3) &&
+ (jacobian->rows != 3 || jacobian->cols != 9))
+ CV_ERROR( CV_StsBadSize, "Jacobian must be 3x9 or 9x3" );
+ }
+
+ if( src->cols == 1 || src->rows == 1 )
+ {
+ double rx, ry, rz, theta;
+ int step = src->rows > 1 ? src->step / elem_size : 1;
+
+ if( src->rows + src->cols*CV_MAT_CN(src->type) - 1 != 3 )
+ CV_ERROR( CV_StsBadSize, "Input matrix must be 1x3, 3x1 or 3x3" );
+
+ if( dst->rows != 3 || dst->cols != 3 || CV_MAT_CN(dst->type) != 1 )
+ CV_ERROR( CV_StsBadSize, "Output matrix must be 3x3, single-channel floating point matrix" );
+
+ if( depth == CV_32F )
+ {
+ rx = src->data.fl[0];
+ ry = src->data.fl[step];
+ rz = src->data.fl[step*2];
+ }
+ else
+ {
+ rx = src->data.db[0];
+ ry = src->data.db[step];
+ rz = src->data.db[step*2];
+ }
+ theta = sqrt(rx*rx + ry*ry + rz*rz);
+
+ if( theta < DBL_EPSILON )
+ {
+ cvSetIdentity( dst );
+
+ if( jacobian )
+ {
+ memset( J, 0, sizeof(J) );
+ J[5] = J[15] = J[19] = -1;
+ J[7] = J[11] = J[21] = 1;
+ }
+ }
+ else
+ {
+ const double I[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 };
+
+ double c = cos(theta);
+ double s = sin(theta);
+ double c1 = 1. - c;
+ double itheta = theta ? 1./theta : 0.;
+
+ rx *= itheta; ry *= itheta; rz *= itheta;
+
+ double rrt[] = { rx*rx, rx*ry, rx*rz, rx*ry, ry*ry, ry*rz, rx*rz, ry*rz, rz*rz };
+ double _r_x_[] = { 0, -rz, ry, rz, 0, -rx, -ry, rx, 0 };
+ double R[9];
+ CvMat _R = cvMat( 3, 3, CV_64F, R );
+
+ // R = cos(theta)*I + (1 - cos(theta))*r*rT + sin(theta)*[r_x]
+ // where [r_x] is [0 -rz ry; rz 0 -rx; -ry rx 0]
+ for( k = 0; k < 9; k++ )
+ R[k] = c*I[k] + c1*rrt[k] + s*_r_x_[k];
+
+ cvConvert( &_R, dst );
+
+ if( jacobian )
+ {
+ double drrt[] = { rx+rx, ry, rz, ry, 0, 0, rz, 0, 0,
+ 0, rx, 0, rx, ry+ry, rz, 0, rz, 0,
+ 0, 0, rx, 0, 0, ry, rx, ry, rz+rz };
+ double d_r_x_[] = { 0, 0, 0, 0, 0, -1, 0, 1, 0,
+ 0, 0, 1, 0, 0, 0, -1, 0, 0,
+ 0, -1, 0, 1, 0, 0, 0, 0, 0 };
+ for( i = 0; i < 3; i++ )
+ {
+ double ri = i == 0 ? rx : i == 1 ? ry : rz;
+ double a0 = -s*ri, a1 = (s - 2*c1*itheta)*ri, a2 = c1*itheta;
+ double a3 = (c - s*itheta)*ri, a4 = s*itheta;
+ for( k = 0; k < 9; k++ )
+ J[i*9+k] = a0*I[k] + a1*rrt[k] + a2*drrt[i*9+k] +
+ a3*_r_x_[k] + a4*d_r_x_[i*9+k];
+ }
+ }
+ }
+ }
+ else if( src->cols == 3 && src->rows == 3 )
+ {
+ double R[9], U[9], V[9], W[3], rx, ry, rz;
+ CvMat _R = cvMat( 3, 3, CV_64F, R );
+ CvMat _U = cvMat( 3, 3, CV_64F, U );
+ CvMat _V = cvMat( 3, 3, CV_64F, V );
+ CvMat _W = cvMat( 3, 1, CV_64F, W );
+ double theta, s, c;
+ int step = dst->rows > 1 ? dst->step / elem_size : 1;
+
+ if( (dst->rows != 1 || dst->cols*CV_MAT_CN(dst->type) != 3) &&
+ (dst->rows != 3 || dst->cols != 1 || CV_MAT_CN(dst->type) != 1))
+ CV_ERROR( CV_StsBadSize, "Output matrix must be 1x3 or 3x1" );
+
+ cvConvert( src, &_R );
+ if( !cvCheckArr( &_R, CV_CHECK_RANGE+CV_CHECK_QUIET, -100, 100 ) )
+ {
+ cvZero(dst);
+ if( jacobian )
+ cvZero(jacobian);
+ EXIT;
+ }
+
+ cvSVD( &_R, &_W, &_U, &_V, CV_SVD_MODIFY_A + CV_SVD_U_T + CV_SVD_V_T );
+ cvGEMM( &_U, &_V, 1, 0, 0, &_R, CV_GEMM_A_T );
+
+ rx = R[7] - R[5];
+ ry = R[2] - R[6];
+ rz = R[3] - R[1];
+
+ s = sqrt((rx*rx + ry*ry + rz*rz)*0.25);
+ c = (R[0] + R[4] + R[8] - 1)*0.5;
+ c = c > 1. ? 1. : c < -1. ? -1. : c;
+ theta = acos(c);
+
+ if( s < 1e-5 )
+ {
+ double t;
+
+ if( c > 0 )
+ rx = ry = rz = 0;
+ else
+ {
+ t = (R[0] + 1)*0.5;
+ rx = theta*sqrt(MAX(t,0.));
+ t = (R[4] + 1)*0.5;
+ ry = theta*sqrt(MAX(t,0.))*(R[1] < 0 ? -1. : 1.);
+ t = (R[8] + 1)*0.5;
+ rz = theta*sqrt(MAX(t,0.))*(R[2] < 0 ? -1. : 1.);
+ }
+
+ if( jacobian )
+ {
+ memset( J, 0, sizeof(J) );
+ if( c > 0 )
+ {
+ J[5] = J[15] = J[19] = -0.5;
+ J[7] = J[11] = J[21] = 0.5;
+ }
+ }
+ }
+ else
+ {
+ double vth = 1/(2*s);
+
+ if( jacobian )
+ {
+ double t, dtheta_dtr = -1./s;
+ // var1 = [vth;theta]
+ // var = [om1;var1] = [om1;vth;theta]
+ double dvth_dtheta = -vth*c/s;
+ double d1 = 0.5*dvth_dtheta*dtheta_dtr;
+ double d2 = 0.5*dtheta_dtr;
+ // dvar1/dR = dvar1/dtheta*dtheta/dR = [dvth/dtheta; 1] * dtheta/dtr * dtr/dR
+ double dvardR[5*9] =
+ {
+ 0, 0, 0, 0, 0, 1, 0, -1, 0,
+ 0, 0, -1, 0, 0, 0, 1, 0, 0,
+ 0, 1, 0, -1, 0, 0, 0, 0, 0,
+ d1, 0, 0, 0, d1, 0, 0, 0, d1,
+ d2, 0, 0, 0, d2, 0, 0, 0, d2
+ };
+ // var2 = [om;theta]
+ double dvar2dvar[] =
+ {
+ vth, 0, 0, rx, 0,
+ 0, vth, 0, ry, 0,
+ 0, 0, vth, rz, 0,
+ 0, 0, 0, 0, 1
+ };
+ double domegadvar2[] =
+ {
+ theta, 0, 0, rx*vth,
+ 0, theta, 0, ry*vth,
+ 0, 0, theta, rz*vth
+ };
+
+ CvMat _dvardR = cvMat( 5, 9, CV_64FC1, dvardR );
+ CvMat _dvar2dvar = cvMat( 4, 5, CV_64FC1, dvar2dvar );
+ CvMat _domegadvar2 = cvMat( 3, 4, CV_64FC1, domegadvar2 );
+ double t0[3*5];
+ CvMat _t0 = cvMat( 3, 5, CV_64FC1, t0 );
+
+ cvMatMul( &_domegadvar2, &_dvar2dvar, &_t0 );
+ cvMatMul( &_t0, &_dvardR, &_J );
+
+ // transpose every row of _J (treat the rows as 3x3 matrices)
+ CV_SWAP(J[1], J[3], t); CV_SWAP(J[2], J[6], t); CV_SWAP(J[5], J[7], t);
+ CV_SWAP(J[10], J[12], t); CV_SWAP(J[11], J[15], t); CV_SWAP(J[14], J[16], t);
+ CV_SWAP(J[19], J[21], t); CV_SWAP(J[20], J[24], t); CV_SWAP(J[23], J[25], t);
+ }
+
+ vth *= theta;
+ rx *= vth; ry *= vth; rz *= vth;
+ }
+
+ if( depth == CV_32F )
+ {
+ dst->data.fl[0] = (float)rx;
+ dst->data.fl[step] = (float)ry;
+ dst->data.fl[step*2] = (float)rz;
+ }
+ else
+ {
+ dst->data.db[0] = rx;
+ dst->data.db[step] = ry;
+ dst->data.db[step*2] = rz;
+ }
+ }
+
+ if( jacobian )
+ {
+ if( depth == CV_32F )
+ {
+ if( jacobian->rows == _J.rows )
+ cvConvert( &_J, jacobian );
+ else
+ {
+ float Jf[3*9];
+ CvMat _Jf = cvMat( _J.rows, _J.cols, CV_32FC1, Jf );
+ cvConvert( &_J, &_Jf );
+ cvTranspose( &_Jf, jacobian );
+ }
+ }
+ else if( jacobian->rows == _J.rows )
+ cvCopy( &_J, jacobian );
+ else
+ cvTranspose( &_J, jacobian );
+ }
+
+ result = 1;
+
+ __END__;
+
+ return result;
+}
+
+
+CV_IMPL void
+cvProjectPoints2( const CvMat* objectPoints,
+ const CvMat* r_vec,
+ const CvMat* t_vec,
+ const CvMat* A,
+ const CvMat* distCoeffs,
+ CvMat* imagePoints, CvMat* dpdr,
+ CvMat* dpdt, CvMat* dpdf,
+ CvMat* dpdc, CvMat* dpdk,
+ double aspectRatio )
+{
+ CvMat *_M = 0, *_m = 0;
+ CvMat *_dpdr = 0, *_dpdt = 0, *_dpdc = 0, *_dpdf = 0, *_dpdk = 0;
+
+ CV_FUNCNAME( "cvProjectPoints2" );
+
+ __BEGIN__;
+
+ int i, j, count;
+ int calc_derivatives;
+ const CvPoint3D64f* M;
+ CvPoint2D64f* m;
+ double r[3], R[9], dRdr[27], t[3], a[9], k[5] = {0,0,0,0,0}, fx, fy, cx, cy;
+ CvMat _r, _t, _a = cvMat( 3, 3, CV_64F, a ), _k;
+ CvMat _R = cvMat( 3, 3, CV_64F, R ), _dRdr = cvMat( 3, 9, CV_64F, dRdr );
+ double *dpdr_p = 0, *dpdt_p = 0, *dpdk_p = 0, *dpdf_p = 0, *dpdc_p = 0;
+ int dpdr_step = 0, dpdt_step = 0, dpdk_step = 0, dpdf_step = 0, dpdc_step = 0;
+ bool fixedAspectRatio = aspectRatio > FLT_EPSILON;
+
+ if( !CV_IS_MAT(objectPoints) || !CV_IS_MAT(r_vec) ||
+ !CV_IS_MAT(t_vec) || !CV_IS_MAT(A) ||
+ /*!CV_IS_MAT(distCoeffs) ||*/ !CV_IS_MAT(imagePoints) )
+ CV_ERROR( CV_StsBadArg, "One of required arguments is not a valid matrix" );
+
+ count = MAX(objectPoints->rows, objectPoints->cols);
+
+ if( CV_IS_CONT_MAT(objectPoints->type) && CV_MAT_DEPTH(objectPoints->type) == CV_64F &&
+ ((objectPoints->rows == 1 && CV_MAT_CN(objectPoints->type) == 3) ||
+ (objectPoints->rows == count && CV_MAT_CN(objectPoints->type)*objectPoints->cols == 3)))
+ _M = (CvMat*)objectPoints;
+ else
+ {
+ CV_CALL( _M = cvCreateMat( 1, count, CV_64FC3 ));
+ CV_CALL( cvConvertPointsHomogeneous( objectPoints, _M ));
+ }
+
+ if( CV_IS_CONT_MAT(imagePoints->type) && CV_MAT_DEPTH(imagePoints->type) == CV_64F &&
+ ((imagePoints->rows == 1 && CV_MAT_CN(imagePoints->type) == 2) ||
+ (imagePoints->rows == count && CV_MAT_CN(imagePoints->type)*imagePoints->cols == 2)))
+ _m = imagePoints;
+ else
+ CV_CALL( _m = cvCreateMat( 1, count, CV_64FC2 ));
+
+ M = (CvPoint3D64f*)_M->data.db;
+ m = (CvPoint2D64f*)_m->data.db;
+
+ if( (CV_MAT_DEPTH(r_vec->type) != CV_64F && CV_MAT_DEPTH(r_vec->type) != CV_32F) ||
+ (((r_vec->rows != 1 && r_vec->cols != 1) ||
+ r_vec->rows*r_vec->cols*CV_MAT_CN(r_vec->type) != 3) &&
+ ((r_vec->rows != 3 && r_vec->cols != 3) || CV_MAT_CN(r_vec->type) != 1)))
+ CV_ERROR( CV_StsBadArg, "Rotation must be represented by 1x3 or 3x1 "
+ "floating-point rotation vector, or 3x3 rotation matrix" );
+
+ if( r_vec->rows == 3 && r_vec->cols == 3 )
+ {
+ _r = cvMat( 3, 1, CV_64FC1, r );
+ CV_CALL( cvRodrigues2( r_vec, &_r ));
+ CV_CALL( cvRodrigues2( &_r, &_R, &_dRdr ));
+ cvCopy( r_vec, &_R );
+ }
+ else
+ {
+ _r = cvMat( r_vec->rows, r_vec->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(r_vec->type)), r );
+ CV_CALL( cvConvert( r_vec, &_r ));
+ CV_CALL( cvRodrigues2( &_r, &_R, &_dRdr ) );
+ }
+
+ if( (CV_MAT_DEPTH(t_vec->type) != CV_64F && CV_MAT_DEPTH(t_vec->type) != CV_32F) ||
+ (t_vec->rows != 1 && t_vec->cols != 1) ||
+ t_vec->rows*t_vec->cols*CV_MAT_CN(t_vec->type) != 3 )
+ CV_ERROR( CV_StsBadArg,
+ "Translation vector must be 1x3 or 3x1 floating-point vector" );
+
+ _t = cvMat( t_vec->rows, t_vec->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(t_vec->type)), t );
+ CV_CALL( cvConvert( t_vec, &_t ));
+
+ if( (CV_MAT_TYPE(A->type) != CV_64FC1 && CV_MAT_TYPE(A->type) != CV_32FC1) ||
+ A->rows != 3 || A->cols != 3 )
+ CV_ERROR( CV_StsBadArg, "Instrinsic parameters must be 3x3 floating-point matrix" );
+
+ CV_CALL( cvConvert( A, &_a ));
+ fx = a[0]; fy = a[4];
+ cx = a[2]; cy = a[5];
+
+ if( fixedAspectRatio )
+ fx = fy*aspectRatio;
+
+ if( distCoeffs )
+ {
+ if( !CV_IS_MAT(distCoeffs) ||
+ (CV_MAT_DEPTH(distCoeffs->type) != CV_64F &&
+ CV_MAT_DEPTH(distCoeffs->type) != CV_32F) ||
+ (distCoeffs->rows != 1 && distCoeffs->cols != 1) ||
+ (distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 4 &&
+ distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 5) )
+ CV_ERROR( CV_StsBadArg,
+ "Distortion coefficients must be 1x4, 4x1, 1x5 or 5x1 floating-point vector" );
+
+ _k = cvMat( distCoeffs->rows, distCoeffs->cols,
+ CV_MAKETYPE(CV_64F,CV_MAT_CN(distCoeffs->type)), k );
+ CV_CALL( cvConvert( distCoeffs, &_k ));
+ }
+
+ if( dpdr )
+ {
+ if( !CV_IS_MAT(dpdr) ||
+ (CV_MAT_TYPE(dpdr->type) != CV_32FC1 &&
+ CV_MAT_TYPE(dpdr->type) != CV_64FC1) ||
+ dpdr->rows != count*2 || dpdr->cols != 3 )
+ CV_ERROR( CV_StsBadArg, "dp/drot must be 2Nx3 floating-point matrix" );
+
+ if( CV_MAT_TYPE(dpdr->type) == CV_64FC1 )
+ _dpdr = dpdr;
+ else
+ CV_CALL( _dpdr = cvCreateMat( 2*count, 3, CV_64FC1 ));
+ dpdr_p = _dpdr->data.db;
+ dpdr_step = _dpdr->step/sizeof(dpdr_p[0]);
+ }
+
+ if( dpdt )
+ {
+ if( !CV_IS_MAT(dpdt) ||
+ (CV_MAT_TYPE(dpdt->type) != CV_32FC1 &&
+ CV_MAT_TYPE(dpdt->type) != CV_64FC1) ||
+ dpdt->rows != count*2 || dpdt->cols != 3 )
+ CV_ERROR( CV_StsBadArg, "dp/dT must be 2Nx3 floating-point matrix" );
+
+ if( CV_MAT_TYPE(dpdt->type) == CV_64FC1 )
+ _dpdt = dpdt;
+ else
+ CV_CALL( _dpdt = cvCreateMat( 2*count, 3, CV_64FC1 ));
+ dpdt_p = _dpdt->data.db;
+ dpdt_step = _dpdt->step/sizeof(dpdt_p[0]);
+ }
+
+ if( dpdf )
+ {
+ if( !CV_IS_MAT(dpdf) ||
+ (CV_MAT_TYPE(dpdf->type) != CV_32FC1 && CV_MAT_TYPE(dpdf->type) != CV_64FC1) ||
+ dpdf->rows != count*2 || dpdf->cols != 2 )
+ CV_ERROR( CV_StsBadArg, "dp/df must be 2Nx2 floating-point matrix" );
+
+ if( CV_MAT_TYPE(dpdf->type) == CV_64FC1 )
+ _dpdf = dpdf;
+ else
+ CV_CALL( _dpdf = cvCreateMat( 2*count, 2, CV_64FC1 ));
+ dpdf_p = _dpdf->data.db;
+ dpdf_step = _dpdf->step/sizeof(dpdf_p[0]);
+ }
+
+ if( dpdc )
+ {
+ if( !CV_IS_MAT(dpdc) ||
+ (CV_MAT_TYPE(dpdc->type) != CV_32FC1 && CV_MAT_TYPE(dpdc->type) != CV_64FC1) ||
+ dpdc->rows != count*2 || dpdc->cols != 2 )
+ CV_ERROR( CV_StsBadArg, "dp/dc must be 2Nx2 floating-point matrix" );
+
+ if( CV_MAT_TYPE(dpdc->type) == CV_64FC1 )
+ _dpdc = dpdc;
+ else
+ CV_CALL( _dpdc = cvCreateMat( 2*count, 2, CV_64FC1 ));
+ dpdc_p = _dpdc->data.db;
+ dpdc_step = _dpdc->step/sizeof(dpdc_p[0]);
+ }
+
+ if( dpdk )
+ {
+ if( !CV_IS_MAT(dpdk) ||
+ (CV_MAT_TYPE(dpdk->type) != CV_32FC1 && CV_MAT_TYPE(dpdk->type) != CV_64FC1) ||
+ dpdk->rows != count*2 || (dpdk->cols != 5 && dpdk->cols != 4 && dpdk->cols != 2) )
+ CV_ERROR( CV_StsBadArg, "dp/df must be 2Nx5, 2Nx4 or 2Nx2 floating-point matrix" );
+
+ if( !distCoeffs )
+ CV_ERROR( CV_StsNullPtr, "distCoeffs is NULL while dpdk is not" );
+
+ if( CV_MAT_TYPE(dpdk->type) == CV_64FC1 )
+ _dpdk = dpdk;
+ else
+ CV_CALL( _dpdk = cvCreateMat( dpdk->rows, dpdk->cols, CV_64FC1 ));
+ dpdk_p = _dpdk->data.db;
+ dpdk_step = _dpdk->step/sizeof(dpdk_p[0]);
+ }
+
+ calc_derivatives = dpdr || dpdt || dpdf || dpdc || dpdk;
+
+ for( i = 0; i < count; i++ )
+ {
+ double X = M[i].x, Y = M[i].y, Z = M[i].z;
+ double x = R[0]*X + R[1]*Y + R[2]*Z + t[0];
+ double y = R[3]*X + R[4]*Y + R[5]*Z + t[1];
+ double z = R[6]*X + R[7]*Y + R[8]*Z + t[2];
+ double r2, r4, r6, a1, a2, a3, cdist;
+ double xd, yd;
+
+ z = z ? 1./z : 1;
+ x *= z; y *= z;
+
+ r2 = x*x + y*y;
+ r4 = r2*r2;
+ r6 = r4*r2;
+ a1 = 2*x*y;
+ a2 = r2 + 2*x*x;
+ a3 = r2 + 2*y*y;
+ cdist = 1 + k[0]*r2 + k[1]*r4 + k[4]*r6;
+ xd = x*cdist + k[2]*a1 + k[3]*a2;
+ yd = y*cdist + k[2]*a3 + k[3]*a1;
+
+ m[i].x = xd*fx + cx;
+ m[i].y = yd*fy + cy;
+
+ if( calc_derivatives )
+ {
+ if( dpdc_p )
+ {
+ dpdc_p[0] = 1; dpdc_p[1] = 0;
+ dpdc_p[dpdc_step] = 0;
+ dpdc_p[dpdc_step+1] = 1;
+ dpdc_p += dpdc_step*2;
+ }
+
+ if( dpdf_p )
+ {
+ if( fixedAspectRatio )
+ {
+ dpdf_p[0] = 0; dpdf_p[1] = xd*aspectRatio;
+ dpdf_p[dpdf_step] = 0;
+ dpdf_p[dpdf_step+1] = yd;
+ }
+ else
+ {
+ dpdf_p[0] = xd; dpdf_p[1] = 0;
+ dpdf_p[dpdf_step] = 0;
+ dpdf_p[dpdf_step+1] = yd;
+ }
+ dpdf_p += dpdf_step*2;
+ }
+
+ if( dpdk_p )
+ {
+ dpdk_p[0] = fx*x*r2;
+ dpdk_p[1] = fx*x*r4;
+ dpdk_p[dpdk_step] = fy*y*r2;
+ dpdk_p[dpdk_step+1] = fy*y*r4;
+ if( _dpdk->cols > 2 )
+ {
+ dpdk_p[2] = fx*a1;
+ dpdk_p[3] = fx*a2;
+ dpdk_p[dpdk_step+2] = fy*a3;
+ dpdk_p[dpdk_step+3] = fy*a1;
+ if( _dpdk->cols > 4 )
+ {
+ dpdk_p[4] = fx*x*r6;
+ dpdk_p[dpdk_step+4] = fy*y*r6;
+ }
+ }
+ dpdk_p += dpdk_step*2;
+ }
+
+ if( dpdt_p )
+ {
+ double dxdt[] = { z, 0, -x*z }, dydt[] = { 0, z, -y*z };
+ for( j = 0; j < 3; j++ )
+ {
+ double dr2dt = 2*x*dxdt[j] + 2*y*dydt[j];
+ double dcdist_dt = k[0]*dr2dt + 2*k[1]*r2*dr2dt + 3*k[4]*r4*dr2dt;
+ double da1dt = 2*(x*dydt[j] + y*dxdt[j]);
+ double dmxdt = fx*(dxdt[j]*cdist + x*dcdist_dt +
+ k[2]*da1dt + k[3]*(dr2dt + 2*x*dxdt[j]));
+ double dmydt = fy*(dydt[j]*cdist + y*dcdist_dt +
+ k[2]*(dr2dt + 2*y*dydt[j]) + k[3]*da1dt);
+ dpdt_p[j] = dmxdt;
+ dpdt_p[dpdt_step+j] = dmydt;
+ }
+ dpdt_p += dpdt_step*2;
+ }
+
+ if( dpdr_p )
+ {
+ double dx0dr[] =
+ {
+ X*dRdr[0] + Y*dRdr[1] + Z*dRdr[2],
+ X*dRdr[9] + Y*dRdr[10] + Z*dRdr[11],
+ X*dRdr[18] + Y*dRdr[19] + Z*dRdr[20]
+ };
+ double dy0dr[] =
+ {
+ X*dRdr[3] + Y*dRdr[4] + Z*dRdr[5],
+ X*dRdr[12] + Y*dRdr[13] + Z*dRdr[14],
+ X*dRdr[21] + Y*dRdr[22] + Z*dRdr[23]
+ };
+ double dz0dr[] =
+ {
+ X*dRdr[6] + Y*dRdr[7] + Z*dRdr[8],
+ X*dRdr[15] + Y*dRdr[16] + Z*dRdr[17],
+ X*dRdr[24] + Y*dRdr[25] + Z*dRdr[26]
+ };
+ for( j = 0; j < 3; j++ )
+ {
+ double dxdr = z*(dx0dr[j] - x*dz0dr[j]);
+ double dydr = z*(dy0dr[j] - y*dz0dr[j]);
+ double dr2dr = 2*x*dxdr + 2*y*dydr;
+ double dcdist_dr = k[0]*dr2dr + 2*k[1]*r2*dr2dr + 3*k[4]*r4*dr2dr;
+ double da1dr = 2*(x*dydr + y*dxdr);
+ double dmxdr = fx*(dxdr*cdist + x*dcdist_dr +
+ k[2]*da1dr + k[3]*(dr2dr + 2*x*dxdr));
+ double dmydr = fy*(dydr*cdist + y*dcdist_dr +
+ k[2]*(dr2dr + 2*y*dydr) + k[3]*da1dr);
+ dpdr_p[j] = dmxdr;
+ dpdr_p[dpdr_step+j] = dmydr;
+ }
+ dpdr_p += dpdr_step*2;
+ }
+ }
+ }
+
+ if( _m != imagePoints )
+ cvConvertPointsHomogeneous( _m, imagePoints );
+ if( _dpdr != dpdr )
+ cvConvert( _dpdr, dpdr );
+ if( _dpdt != dpdt )
+ cvConvert( _dpdt, dpdt );
+ if( _dpdf != dpdf )
+ cvConvert( _dpdf, dpdf );
+ if( _dpdc != dpdc )
+ cvConvert( _dpdc, dpdc );
+ if( _dpdk != dpdk )
+ cvConvert( _dpdk, dpdk );
+
+ __END__;
+
+ if( _M != objectPoints )
+ cvReleaseMat( &_M );
+ if( _m != imagePoints )
+ cvReleaseMat( &_m );
+ if( _dpdr != dpdr )
+ cvReleaseMat( &_dpdr );
+ if( _dpdt != dpdt )
+ cvReleaseMat( &_dpdt );
+ if( _dpdf != dpdf )
+ cvReleaseMat( &_dpdf );
+ if( _dpdc != dpdc )
+ cvReleaseMat( &_dpdc );
+ if( _dpdk != dpdk )
+ cvReleaseMat( &_dpdk );
+}
+
+
+CV_IMPL void
+cvFindExtrinsicCameraParams2( const CvMat* objectPoints,
+ const CvMat* imagePoints, const CvMat* A,
+ const CvMat* distCoeffs,
+ CvMat* rvec, CvMat* tvec )
+{
+ const int max_iter = 20;
+ CvMat *_M = 0, *_Mxy = 0, *_m = 0, *_mn = 0, *_L = 0, *_J = 0;
+
+ CV_FUNCNAME( "cvFindExtrinsicCameraParams2" );
+
+ __BEGIN__;
+
+ int i, count;
+ double a[9], ar[9]={1,0,0,0,1,0,0,0,1}, R[9];
+ double MM[9], U[9], V[9], W[3];
+ CvScalar Mc;
+ double JtJ[6*6], JtErr[6], JtJW[6], JtJV[6*6], delta[6], param[6];
+ CvMat _A = cvMat( 3, 3, CV_64F, a );
+ CvMat _Ar = cvMat( 3, 3, CV_64F, ar );
+ CvMat _R = cvMat( 3, 3, CV_64F, R );
+ CvMat _r = cvMat( 3, 1, CV_64F, param );
+ CvMat _t = cvMat( 3, 1, CV_64F, param + 3 );
+ CvMat _Mc = cvMat( 1, 3, CV_64F, Mc.val );
+ CvMat _MM = cvMat( 3, 3, CV_64F, MM );
+ CvMat _U = cvMat( 3, 3, CV_64F, U );
+ CvMat _V = cvMat( 3, 3, CV_64F, V );
+ CvMat _W = cvMat( 3, 1, CV_64F, W );
+ CvMat _JtJ = cvMat( 6, 6, CV_64F, JtJ );
+ CvMat _JtErr = cvMat( 6, 1, CV_64F, JtErr );
+ CvMat _JtJW = cvMat( 6, 1, CV_64F, JtJW );
+ CvMat _JtJV = cvMat( 6, 6, CV_64F, JtJV );
+ CvMat _delta = cvMat( 6, 1, CV_64F, delta );
+ CvMat _param = cvMat( 6, 1, CV_64F, param );
+ CvMat _dpdr, _dpdt;
+
+ CV_ASSERT( CV_IS_MAT(objectPoints) && CV_IS_MAT(imagePoints) &&
+ CV_IS_MAT(A) && CV_IS_MAT(rvec) && CV_IS_MAT(tvec) );
+
+ count = MAX(objectPoints->cols, objectPoints->rows);
+ CV_CALL( _M = cvCreateMat( 1, count, CV_64FC3 ));
+ CV_CALL( _m = cvCreateMat( 1, count, CV_64FC2 ));
+
+ CV_CALL( cvConvertPointsHomogeneous( objectPoints, _M ));
+ CV_CALL( cvConvertPointsHomogeneous( imagePoints, _m ));
+ CV_CALL( cvConvert( A, &_A ));
+
+ CV_ASSERT( (CV_MAT_DEPTH(rvec->type) == CV_64F || CV_MAT_DEPTH(rvec->type) == CV_32F) &&
+ (rvec->rows == 1 || rvec->cols == 1) && rvec->rows*rvec->cols*CV_MAT_CN(rvec->type) == 3 );
+
+ CV_ASSERT( (CV_MAT_DEPTH(tvec->type) == CV_64F || CV_MAT_DEPTH(tvec->type) == CV_32F) &&
+ (tvec->rows == 1 || tvec->cols == 1) && tvec->rows*tvec->cols*CV_MAT_CN(tvec->type) == 3 );
+
+ CV_CALL( _mn = cvCreateMat( 1, count, CV_64FC2 ));
+ CV_CALL( _Mxy = cvCreateMat( 1, count, CV_64FC2 ));
+
+ // normalize image points
+ // (unapply the intrinsic matrix transformation and distortion)
+ cvUndistortPoints( _m, _mn, &_A, distCoeffs, 0, &_Ar );
+
+ Mc = cvAvg(_M);
+ cvReshape( _M, _M, 1, count );
+ cvMulTransposed( _M, &_MM, 1, &_Mc );
+ cvSVD( &_MM, &_W, 0, &_V, CV_SVD_MODIFY_A + CV_SVD_V_T );
+
+ // initialize extrinsic parameters
+ if( W[2]/W[1] < 1e-3 || count < 4 )
+ {
+ // a planar structure case (all M's lie in the same plane)
+ double tt[3], h[9], h1_norm, h2_norm;
+ CvMat* R_transform = &_V;
+ CvMat T_transform = cvMat( 3, 1, CV_64F, tt );
+ CvMat _H = cvMat( 3, 3, CV_64F, h );
+ CvMat _h1, _h2, _h3;
+
+ if( V[2]*V[2] + V[5]*V[5] < 1e-10 )
+ cvSetIdentity( R_transform );
+
+ if( cvDet(R_transform) < 0 )
+ cvScale( R_transform, R_transform, -1 );
+
+ cvGEMM( R_transform, &_Mc, -1, 0, 0, &T_transform, CV_GEMM_B_T );
+
+ for( i = 0; i < count; i++ )
+ {
+ const double* Rp = R_transform->data.db;
+ const double* Tp = T_transform.data.db;
+ const double* src = _M->data.db + i*3;
+ double* dst = _Mxy->data.db + i*2;
+
+ dst[0] = Rp[0]*src[0] + Rp[1]*src[1] + Rp[2]*src[2] + Tp[0];
+ dst[1] = Rp[3]*src[0] + Rp[4]*src[1] + Rp[5]*src[2] + Tp[1];
+ }
+
+ cvFindHomography( _Mxy, _mn, &_H );
+
+ cvGetCol( &_H, &_h1, 0 );
+ _h2 = _h1; _h2.data.db++;
+ _h3 = _h2; _h3.data.db++;
+ h1_norm = sqrt(h[0]*h[0] + h[3]*h[3] + h[6]*h[6]);
+ h2_norm = sqrt(h[1]*h[1] + h[4]*h[4] + h[7]*h[7]);
+
+ cvScale( &_h1, &_h1, 1./h1_norm );
+ cvScale( &_h2, &_h2, 1./h2_norm );
+ cvScale( &_h3, &_t, 2./(h1_norm + h2_norm));
+ cvCrossProduct( &_h1, &_h2, &_h3 );
+
+ cvRodrigues2( &_H, &_r );
+ cvRodrigues2( &_r, &_H );
+ cvMatMulAdd( &_H, &T_transform, &_t, &_t );
+ cvMatMul( &_H, R_transform, &_R );
+ cvRodrigues2( &_R, &_r );
+ }
+ else
+ {
+ // non-planar structure. Use DLT method
+ double* L;
+ double LL[12*12], LW[12], LV[12*12], sc;
+ CvMat _LL = cvMat( 12, 12, CV_64F, LL );
+ CvMat _LW = cvMat( 12, 1, CV_64F, LW );
+ CvMat _LV = cvMat( 12, 12, CV_64F, LV );
+ CvMat _RRt, _RR, _tt;
+ CvPoint3D64f* M = (CvPoint3D64f*)_M->data.db;
+ CvPoint2D64f* mn = (CvPoint2D64f*)_mn->data.db;
+
+ CV_CALL( _L = cvCreateMat( 2*count, 12, CV_64F ));
+ L = _L->data.db;
+
+ for( i = 0; i < count; i++, L += 24 )
+ {
+ double x = -mn[i].x, y = -mn[i].y;
+ L[0] = L[16] = M[i].x;
+ L[1] = L[17] = M[i].y;
+ L[2] = L[18] = M[i].z;
+ L[3] = L[19] = 1.;
+ L[4] = L[5] = L[6] = L[7] = 0.;
+ L[12] = L[13] = L[14] = L[15] = 0.;
+ L[8] = x*M[i].x;
+ L[9] = x*M[i].y;
+ L[10] = x*M[i].z;
+ L[11] = x;
+ L[20] = y*M[i].x;
+ L[21] = y*M[i].y;
+ L[22] = y*M[i].z;
+ L[23] = y;
+ }
+
+ cvMulTransposed( _L, &_LL, 1 );
+ cvSVD( &_LL, &_LW, 0, &_LV, CV_SVD_MODIFY_A + CV_SVD_V_T );
+ _RRt = cvMat( 3, 4, CV_64F, LV + 11*12 );
+ cvGetCols( &_RRt, &_RR, 0, 3 );
+ cvGetCol( &_RRt, &_tt, 3 );
+ if( cvDet(&_RR) < 0 )
+ cvScale( &_RRt, &_RRt, -1 );
+ sc = cvNorm(&_RR);
+ cvSVD( &_RR, &_W, &_U, &_V, CV_SVD_MODIFY_A + CV_SVD_U_T + CV_SVD_V_T );
+ cvGEMM( &_U, &_V, 1, 0, 0, &_R, CV_GEMM_A_T );
+ cvScale( &_tt, &_t, cvNorm(&_R)/sc );
+ cvRodrigues2( &_R, &_r );
+ cvReleaseMat( &_L );
+ }
+
+ cvReshape( _M, _M, 3, 1 );
+ cvReshape( _mn, _mn, 2, 1 );
+
+ CV_CALL( _J = cvCreateMat( 2*count, 6, CV_64FC1 ));
+ cvGetCols( _J, &_dpdr, 0, 3 );
+ cvGetCols( _J, &_dpdt, 3, 6 );
+
+ // refine extrinsic parameters using iterative algorithm
+ for( i = 0; i < max_iter; i++ )
+ {
+ double n1, n2;
+ cvReshape( _mn, _mn, 2, 1 );
+ cvProjectPoints2( _M, &_r, &_t, &_A, distCoeffs,
+ _mn, &_dpdr, &_dpdt, 0, 0, 0 );
+ cvSub( _m, _mn, _mn );
+ cvReshape( _mn, _mn, 1, 2*count );
+
+ cvMulTransposed( _J, &_JtJ, 1 );
+ cvGEMM( _J, _mn, 1, 0, 0, &_JtErr, CV_GEMM_A_T );
+ cvSVD( &_JtJ, &_JtJW, 0, &_JtJV, CV_SVD_MODIFY_A + CV_SVD_V_T );
+ if( JtJW[5]/JtJW[0] < 1e-12 )
+ break;
+ cvSVBkSb( &_JtJW, &_JtJV, &_JtJV, &_JtErr,
+ &_delta, CV_SVD_U_T + CV_SVD_V_T );
+ cvAdd( &_delta, &_param, &_param );
+ n1 = cvNorm( &_delta );
+ n2 = cvNorm( &_param );
+ if( n1/n2 < 1e-10 )
+ break;
+ }
+
+ _r = cvMat( rvec->rows, rvec->cols,
+ CV_MAKETYPE(CV_64F,CV_MAT_CN(rvec->type)), param );
+ _t = cvMat( tvec->rows, tvec->cols,
+ CV_MAKETYPE(CV_64F,CV_MAT_CN(tvec->type)), param + 3 );
+
+ cvConvert( &_r, rvec );
+ cvConvert( &_t, tvec );
+
+ __END__;
+
+ cvReleaseMat( &_M );
+ cvReleaseMat( &_Mxy );
+ cvReleaseMat( &_m );
+ cvReleaseMat( &_mn );
+ cvReleaseMat( &_L );
+ cvReleaseMat( &_J );
+}
+
+
+CV_IMPL void
+cvInitIntrinsicParams2D( const CvMat* objectPoints,
+ const CvMat* imagePoints,
+ const CvMat* npoints,
+ CvSize imageSize,
+ CvMat* cameraMatrix,
+ double aspectRatio )
+{
+ CvMat *_A = 0, *_b = 0, *_allH = 0, *_allK = 0;
+
+ CV_FUNCNAME( "cvInitIntrinsicParams2D" );
+
+ __BEGIN__;
+
+ int i, j, pos, nimages, total, ni = 0;
+ double a[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 1 };
+ double H[9], f[2];
+ CvMat _a = cvMat( 3, 3, CV_64F, a );
+ CvMat _H = cvMat( 3, 3, CV_64F, H );
+ CvMat _f = cvMat( 2, 1, CV_64F, f );
+
+ assert( CV_MAT_TYPE(npoints->type) == CV_32SC1 &&
+ CV_IS_MAT_CONT(npoints->type) );
+ nimages = npoints->rows + npoints->cols - 1;
+
+ if( (CV_MAT_TYPE(objectPoints->type) != CV_32FC3 &&
+ CV_MAT_TYPE(objectPoints->type) != CV_64FC3) ||
+ (CV_MAT_TYPE(imagePoints->type) != CV_32FC2 &&
+ CV_MAT_TYPE(imagePoints->type) != CV_64FC2) )
+ CV_ERROR( CV_StsUnsupportedFormat, "Both object points and image points must be 2D" );
+
+ if( objectPoints->rows != 1 || imagePoints->rows != 1 )
+ CV_ERROR( CV_StsBadSize, "object points and image points must be a single-row matrices" );
+
+ _A = cvCreateMat( 2*nimages, 2, CV_64F );
+ _b = cvCreateMat( 2*nimages, 1, CV_64F );
+ a[2] = (imageSize.width - 1)*0.5;
+ a[5] = (imageSize.height - 1)*0.5;
+ _allH = cvCreateMat( nimages, 9, CV_64F );
+
+ total = cvRound(cvSum(npoints).val[0]);
+
+ // extract vanishing points in order to obtain initial value for the focal length
+ for( i = 0, pos = 0; i < nimages; i++, pos += ni )
+ {
+ double* Ap = _A->data.db + i*4;
+ double* bp = _b->data.db + i*2;
+ ni = npoints->data.i[i];
+ double h[3], v[3], d1[3], d2[3];
+ double n[4] = {0,0,0,0};
+ CvMat _m, _M;
+ cvGetCols( objectPoints, &_M, pos, pos + ni );
+ cvGetCols( imagePoints, &_m, pos, pos + ni );
+
+ cvFindHomography( &_M, &_m, &_H );
+ memcpy( _allH->data.db + i*9, H, sizeof(H) );
+
+ H[0] -= H[6]*a[2]; H[1] -= H[7]*a[2]; H[2] -= H[8]*a[2];
+ H[3] -= H[6]*a[5]; H[4] -= H[7]*a[5]; H[5] -= H[8]*a[5];
+
+ for( j = 0; j < 3; j++ )
+ {
+ double t0 = H[j*3], t1 = H[j*3+1];
+ h[j] = t0; v[j] = t1;
+ d1[j] = (t0 + t1)*0.5;
+ d2[j] = (t0 - t1)*0.5;
+ n[0] += t0*t0; n[1] += t1*t1;
+ n[2] += d1[j]*d1[j]; n[3] += d2[j]*d2[j];
+ }
+
+ for( j = 0; j < 4; j++ )
+ n[j] = 1./sqrt(n[j]);
+
+ for( j = 0; j < 3; j++ )
+ {
+ h[j] *= n[0]; v[j] *= n[1];
+ d1[j] *= n[2]; d2[j] *= n[3];
+ }
+
+ Ap[0] = h[0]*v[0]; Ap[1] = h[1]*v[1];
+ Ap[2] = d1[0]*d2[0]; Ap[3] = d1[1]*d2[1];
+ bp[0] = -h[2]*v[2]; bp[1] = -d1[2]*d2[2];
+ }
+
+ cvSolve( _A, _b, &_f, CV_LSQ | CV_SVD );
+ a[0] = sqrt(fabs(1./f[0]));
+ a[4] = sqrt(fabs(1./f[1]));
+ if( aspectRatio != 0 )
+ {
+ double tf = (a[0] + a[4])/(aspectRatio + 1.);
+ a[0] = aspectRatio*tf;
+ a[4] = tf;
+ }
+
+ cvConvert( &_a, cameraMatrix );
+
+ __END__;
+
+ cvReleaseMat( &_A );
+ cvReleaseMat( &_b );
+ cvReleaseMat( &_allH );
+ cvReleaseMat( &_allK );
+}
+
+
+/* finds intrinsic and extrinsic camera parameters
+ from a few views of known calibration pattern */
+CV_IMPL void
+cvCalibrateCamera2( const CvMat* objectPoints,
+ const CvMat* imagePoints,
+ const CvMat* npoints,
+ CvSize imageSize,
+ CvMat* cameraMatrix, CvMat* distCoeffs,
+ CvMat* rvecs, CvMat* tvecs,
+ int flags )
+{
+ const int NINTRINSIC = 9;
+ CvMat *_M = 0, *_m = 0, *_Ji = 0, *_Je = 0, *_err = 0;
+ CvLevMarq solver;
+
+ CV_FUNCNAME( "cvCalibrateCamera2" );
+
+ __BEGIN__;
+
+ double A[9], k[5] = {0,0,0,0,0};
+ CvMat _A = cvMat(3, 3, CV_64F, A), _k;
+ int i, nimages, maxPoints = 0, ni = 0, pos, total = 0, nparams, npstep, cn;
+ double aspectRatio = 0.;
+
+ // 0. check the parameters & allocate buffers
+ if( !CV_IS_MAT(objectPoints) || !CV_IS_MAT(imagePoints) ||
+ !CV_IS_MAT(npoints) || !CV_IS_MAT(cameraMatrix) || !CV_IS_MAT(distCoeffs) )
+ CV_ERROR( CV_StsBadArg, "One of required vector arguments is not a valid matrix" );
+
+ if( imageSize.width <= 0 || imageSize.height <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "image width and height must be positive" );
+
+ if( CV_MAT_TYPE(npoints->type) != CV_32SC1 ||
+ (npoints->rows != 1 && npoints->cols != 1) )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "the array of point counters must be 1-dimensional integer vector" );
+
+ nimages = npoints->rows*npoints->cols;
+ npstep = npoints->rows == 1 ? 1 : npoints->step/CV_ELEM_SIZE(npoints->type);
+
+ if( rvecs )
+ {
+ cn = CV_MAT_CN(rvecs->type);
+ if( !CV_IS_MAT(rvecs) ||
+ (CV_MAT_DEPTH(rvecs->type) != CV_32F && CV_MAT_DEPTH(rvecs->type) != CV_64F) ||
+ ((rvecs->rows != nimages || (rvecs->cols*cn != 3 && rvecs->cols*cn != 9)) &&
+ (rvecs->rows != 1 || rvecs->cols != nimages || cn != 3)) )
+ CV_ERROR( CV_StsBadArg, "the output array of rotation vectors must be 3-channel "
+ "1xn or nx1 array or 1-channel nx3 or nx9 array, where n is the number of views" );
+ }
+
+ if( tvecs )
+ {
+ cn = CV_MAT_CN(tvecs->type);
+ if( !CV_IS_MAT(tvecs) ||
+ (CV_MAT_DEPTH(tvecs->type) != CV_32F && CV_MAT_DEPTH(tvecs->type) != CV_64F) ||
+ ((tvecs->rows != nimages || tvecs->cols*cn != 3) &&
+ (tvecs->rows != 1 || tvecs->cols != nimages || cn != 3)) )
+ CV_ERROR( CV_StsBadArg, "the output array of translation vectors must be 3-channel "
+ "1xn or nx1 array or 1-channel nx3 array, where n is the number of views" );
+ }
+
+ if( (CV_MAT_TYPE(cameraMatrix->type) != CV_32FC1 &&
+ CV_MAT_TYPE(cameraMatrix->type) != CV_64FC1) ||
+ cameraMatrix->rows != 3 || cameraMatrix->cols != 3 )
+ CV_ERROR( CV_StsBadArg,
+ "Intrinsic parameters must be 3x3 floating-point matrix" );
+
+ if( (CV_MAT_TYPE(distCoeffs->type) != CV_32FC1 &&
+ CV_MAT_TYPE(distCoeffs->type) != CV_64FC1) ||
+ (distCoeffs->cols != 1 && distCoeffs->rows != 1) ||
+ (distCoeffs->cols*distCoeffs->rows != 4 &&
+ distCoeffs->cols*distCoeffs->rows != 5) )
+ CV_ERROR( CV_StsBadArg,
+ "Distortion coefficients must be 4x1, 1x4, 5x1 or 1x5 floating-point matrix" );
+
+ for( i = 0; i < nimages; i++ )
+ {
+ ni = npoints->data.i[i*npstep];
+ if( ni < 4 )
+ {
+ char buf[100];
+ sprintf( buf, "The number of points in the view #%d is < 4", i );
+ CV_ERROR( CV_StsOutOfRange, buf );
+ }
+ maxPoints = MAX( maxPoints, ni );
+ total += ni;
+ }
+
+ CV_CALL( _M = cvCreateMat( 1, total, CV_64FC3 ));
+ CV_CALL( _m = cvCreateMat( 1, total, CV_64FC2 ));
+
+ CV_CALL( cvConvertPointsHomogeneous( objectPoints, _M ));
+ CV_CALL( cvConvertPointsHomogeneous( imagePoints, _m ));
+
+ nparams = NINTRINSIC + nimages*6;
+ CV_CALL( _Ji = cvCreateMat( maxPoints*2, NINTRINSIC, CV_64FC1 ));
+ CV_CALL( _Je = cvCreateMat( maxPoints*2, 6, CV_64FC1 ));
+ CV_CALL( _err = cvCreateMat( maxPoints*2, 1, CV_64FC1 ));
+ cvZero( _Ji );
+
+ _k = cvMat( distCoeffs->rows, distCoeffs->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(distCoeffs->type)), k);
+ if( distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) == 4 )
+ flags |= CV_CALIB_FIX_K3;
+
+ // 1. initialize intrinsic parameters & LM solver
+ if( flags & CV_CALIB_USE_INTRINSIC_GUESS )
+ {
+ cvConvert( cameraMatrix, &_A );
+ if( A[0] <= 0 || A[4] <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "Focal length (fx and fy) must be positive" );
+ if( A[2] < 0 || A[2] >= imageSize.width ||
+ A[5] < 0 || A[5] >= imageSize.height )
+ CV_ERROR( CV_StsOutOfRange, "Principal point must be within the image" );
+ if( fabs(A[1]) > 1e-5 )
+ CV_ERROR( CV_StsOutOfRange, "Non-zero skew is not supported by the function" );
+ if( fabs(A[3]) > 1e-5 || fabs(A[6]) > 1e-5 ||
+ fabs(A[7]) > 1e-5 || fabs(A[8]-1) > 1e-5 )
+ CV_ERROR( CV_StsOutOfRange,
+ "The intrinsic matrix must have [fx 0 cx; 0 fy cy; 0 0 1] shape" );
+ A[1] = A[3] = A[6] = A[7] = 0.;
+ A[8] = 1.;
+
+ if( flags & CV_CALIB_FIX_ASPECT_RATIO )
+ aspectRatio = A[0]/A[4];
+ cvConvert( distCoeffs, &_k );
+ }
+ else
+ {
+ CvScalar mean, sdv;
+ cvAvgSdv( _M, &mean, &sdv );
+ if( (fabs(mean.val[2]) > 1e-5 && fabs(mean.val[2] - 1) > 1e-5) || fabs(sdv.val[2]) > 1e-5 )
+ CV_ERROR( CV_StsBadArg,
+ "For non-planar calibration rigs the initial intrinsic matrix must be specified" );
+ for( i = 0; i < total; i++ )
+ ((CvPoint3D64f*)_M->data.db)[i].z = 0.;
+
+ if( flags & CV_CALIB_FIX_ASPECT_RATIO )
+ {
+ aspectRatio = cvmGet(cameraMatrix,0,0);
+ aspectRatio /= cvmGet(cameraMatrix,1,1);
+ if( aspectRatio < 0.01 || aspectRatio > 100 )
+ CV_ERROR( CV_StsOutOfRange,
+ "The specified aspect ratio (=A[0][0]/A[1][1]) is incorrect" );
+ }
+ cvInitIntrinsicParams2D( _M, _m, npoints, imageSize, &_A, aspectRatio );
+ }
+
+ solver.init( nparams, 0, cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS,30,DBL_EPSILON) );
+
+ {
+ double* param = solver.param->data.db;
+ uchar* mask = solver.mask->data.ptr;
+
+ param[0] = A[0]; param[1] = A[4]; param[2] = A[2]; param[3] = A[5];
+ param[4] = k[0]; param[5] = k[1]; param[6] = k[2]; param[7] = k[3];
+ param[8] = k[4];
+
+ if( flags & CV_CALIB_FIX_FOCAL_LENGTH )
+ mask[0] = mask[1] = 0;
+ if( flags & CV_CALIB_FIX_PRINCIPAL_POINT )
+ mask[2] = mask[3] = 0;
+ if( flags & CV_CALIB_ZERO_TANGENT_DIST )
+ {
+ param[6] = param[7] = 0;
+ mask[6] = mask[7] = 0;
+ }
+ if( flags & CV_CALIB_FIX_K1 )
+ mask[4] = 0;
+ if( flags & CV_CALIB_FIX_K2 )
+ mask[5] = 0;
+ if( flags & CV_CALIB_FIX_K3 )
+ mask[8] = 0;
+ }
+
+ // 2. initialize extrinsic parameters
+ for( i = 0, pos = 0; i < nimages; i++, pos += ni )
+ {
+ CvMat _Mi, _mi, _ri, _ti;
+ ni = npoints->data.i[i*npstep];
+
+ cvGetRows( solver.param, &_ri, NINTRINSIC + i*6, NINTRINSIC + i*6 + 3 );
+ cvGetRows( solver.param, &_ti, NINTRINSIC + i*6 + 3, NINTRINSIC + i*6 + 6 );
+
+ cvGetCols( _M, &_Mi, pos, pos + ni );
+ cvGetCols( _m, &_mi, pos, pos + ni );
+
+ cvFindExtrinsicCameraParams2( &_Mi, &_mi, &_A, &_k, &_ri, &_ti );
+ }
+
+ // 3. run the optimization
+ for(;;)
+ {
+ const CvMat* _param = 0;
+ CvMat *_JtJ = 0, *_JtErr = 0;
+ double* _errNorm = 0;
+ bool proceed = solver.updateAlt( _param, _JtJ, _JtErr, _errNorm );
+ double *param = solver.param->data.db, *pparam = solver.prevParam->data.db;
+
+ if( flags & CV_CALIB_FIX_ASPECT_RATIO )
+ {
+ param[0] = param[1]*aspectRatio;
+ pparam[0] = pparam[1]*aspectRatio;
+ }
+
+ A[0] = param[0]; A[4] = param[1];
+ A[2] = param[2]; A[5] = param[3];
+ k[0] = param[4]; k[1] = param[5]; k[2] = param[6];
+ k[3] = param[7];
+ k[4] = param[8];
+
+ if( !proceed )
+ break;
+
+ for( i = 0, pos = 0; i < nimages; i++, pos += ni )
+ {
+ CvMat _Mi, _mi, _ri, _ti, _dpdr, _dpdt, _dpdf, _dpdc, _dpdk, _mp, _part;
+ ni = npoints->data.i[i*npstep];
+
+ cvGetRows( solver.param, &_ri, NINTRINSIC + i*6, NINTRINSIC + i*6 + 3 );
+ cvGetRows( solver.param, &_ti, NINTRINSIC + i*6 + 3, NINTRINSIC + i*6 + 6 );
+
+ cvGetCols( _M, &_Mi, pos, pos + ni );
+ cvGetCols( _m, &_mi, pos, pos + ni );
+
+ _Je->rows = _Ji->rows = _err->rows = ni*2;
+ cvGetCols( _Je, &_dpdr, 0, 3 );
+ cvGetCols( _Je, &_dpdt, 3, 6 );
+ cvGetCols( _Ji, &_dpdf, 0, 2 );
+ cvGetCols( _Ji, &_dpdc, 2, 4 );
+ cvGetCols( _Ji, &_dpdk, 4, NINTRINSIC );
+ cvReshape( _err, &_mp, 2, 1 );
+
+ if( _JtJ || _JtErr )
+ {
+ cvProjectPoints2( &_Mi, &_ri, &_ti, &_A, &_k, &_mp, &_dpdr, &_dpdt,
+ (flags & CV_CALIB_FIX_FOCAL_LENGTH) ? 0 : &_dpdf,
+ (flags & CV_CALIB_FIX_PRINCIPAL_POINT) ? 0 : &_dpdc, &_dpdk,
+ (flags & CV_CALIB_FIX_ASPECT_RATIO) ? aspectRatio : 0);
+ }
+ else
+ cvProjectPoints2( &_Mi, &_ri, &_ti, &_A, &_k, &_mp );
+
+ cvSub( &_mp, &_mi, &_mp );
+
+ if( _JtJ || _JtErr )
+ {
+ cvGetSubRect( _JtJ, &_part, cvRect(0,0,NINTRINSIC,NINTRINSIC) );
+ cvGEMM( _Ji, _Ji, 1, &_part, 1, &_part, CV_GEMM_A_T );
+
+ cvGetSubRect( _JtJ, &_part, cvRect(NINTRINSIC+i*6,NINTRINSIC+i*6,6,6) );
+ cvGEMM( _Je, _Je, 1, 0, 0, &_part, CV_GEMM_A_T );
+
+ cvGetSubRect( _JtJ, &_part, cvRect(NINTRINSIC+i*6,0,6,NINTRINSIC) );
+ cvGEMM( _Ji, _Je, 1, 0, 0, &_part, CV_GEMM_A_T );
+
+ cvGetRows( _JtErr, &_part, 0, NINTRINSIC );
+ cvGEMM( _Ji, _err, 1, &_part, 1, &_part, CV_GEMM_A_T );
+
+ cvGetRows( _JtErr, &_part, NINTRINSIC + i*6, NINTRINSIC + (i+1)*6 );
+ cvGEMM( _Je, _err, 1, 0, 0, &_part, CV_GEMM_A_T );
+ }
+
+ if( _errNorm )
+ {
+ double errNorm = cvNorm( &_mp, 0, CV_L2 );
+ *_errNorm += errNorm*errNorm;
+ }
+ }
+ }
+
+ // 4. store the results
+ cvConvert( &_A, cameraMatrix );
+ cvConvert( &_k, distCoeffs );
+
+ for( i = 0; i < nimages; i++ )
+ {
+ CvMat src, dst;
+ if( rvecs )
+ {
+ src = cvMat( 3, 1, CV_64F, solver.param->data.db + NINTRINSIC + i*6 );
+ if( rvecs->rows == nimages && rvecs->cols*CV_MAT_CN(rvecs->type) == 9 )
+ {
+ dst = cvMat( 3, 3, CV_MAT_DEPTH(rvecs->type),
+ rvecs->data.ptr + rvecs->step*i );
+ cvRodrigues2( &src, &_A );
+ cvConvert( &_A, &dst );
+ }
+ else
+ {
+ dst = cvMat( 3, 1, CV_MAT_DEPTH(rvecs->type), rvecs->rows == 1 ?
+ rvecs->data.ptr + i*CV_ELEM_SIZE(rvecs->type) :
+ rvecs->data.ptr + rvecs->step*i );
+ cvConvert( &src, &dst );
+ }
+ }
+ if( tvecs )
+ {
+ src = cvMat( 3, 1, CV_64F, solver.param->data.db + NINTRINSIC + i*6 + 3 );
+ dst = cvMat( 3, 1, CV_MAT_TYPE(tvecs->type), tvecs->rows == 1 ?
+ tvecs->data.ptr + i*CV_ELEM_SIZE(tvecs->type) :
+ tvecs->data.ptr + tvecs->step*i );
+ cvConvert( &src, &dst );
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &_M );
+ cvReleaseMat( &_m );
+ cvReleaseMat( &_Ji );
+ cvReleaseMat( &_Je );
+ cvReleaseMat( &_err );
+}
+
+
+void cvCalibrationMatrixValues( const CvMat *calibMatr, CvSize imgSize,
+ double apertureWidth, double apertureHeight, double *fovx, double *fovy,
+ double *focalLength, CvPoint2D64f *principalPoint, double *pasp )
+{
+ double alphax, alphay, mx, my;
+ int imgWidth = imgSize.width, imgHeight = imgSize.height;
+
+ CV_FUNCNAME("cvCalibrationMatrixValues");
+ __BEGIN__;
+
+ /* Validate parameters. */
+
+ if(calibMatr == 0)
+ CV_ERROR(CV_StsNullPtr, "Some of parameters is a NULL pointer!");
+
+ if(!CV_IS_MAT(calibMatr))
+ CV_ERROR(CV_StsUnsupportedFormat, "Input parameters must be a matrices!");
+
+ if(calibMatr->cols != 3 || calibMatr->rows != 3)
+ CV_ERROR(CV_StsUnmatchedSizes, "Size of matrices must be 3x3!");
+
+ alphax = cvmGet(calibMatr, 0, 0);
+ alphay = cvmGet(calibMatr, 1, 1);
+ assert(imgWidth != 0 && imgHeight != 0 && alphax != 0.0 && alphay != 0.0);
+
+ /* Calculate pixel aspect ratio. */
+ if(pasp)
+ *pasp = alphay / alphax;
+
+ /* Calculate number of pixel per realworld unit. */
+
+ if(apertureWidth != 0.0 && apertureHeight != 0.0) {
+ mx = imgWidth / apertureWidth;
+ my = imgHeight / apertureHeight;
+ } else {
+ mx = 1.0;
+ my = *pasp;
+ }
+
+ /* Calculate fovx and fovy. */
+
+ if(fovx)
+ *fovx = 2 * atan(imgWidth / (2 * alphax)) * 180.0 / CV_PI;
+
+ if(fovy)
+ *fovy = 2 * atan(imgHeight / (2 * alphay)) * 180.0 / CV_PI;
+
+ /* Calculate focal length. */
+
+ if(focalLength)
+ *focalLength = alphax / mx;
+
+ /* Calculate principle point. */
+
+ if(principalPoint)
+ *principalPoint = cvPoint2D64f(cvmGet(calibMatr, 0, 2) / mx, cvmGet(calibMatr, 1, 2) / my);
+
+ __END__;
+}
+
+
+//////////////////////////////// Stereo Calibration ///////////////////////////////////
+
+static int dbCmp( const void* _a, const void* _b )
+{
+ double a = *(const double*)_a;
+ double b = *(const double*)_b;
+
+ return (a > b) - (a < b);
+}
+
+
+void cvStereoCalibrate( const CvMat* _objectPoints, const CvMat* _imagePoints1,
+ const CvMat* _imagePoints2, const CvMat* _npoints,
+ CvMat* _cameraMatrix1, CvMat* _distCoeffs1,
+ CvMat* _cameraMatrix2, CvMat* _distCoeffs2,
+ CvSize imageSize, CvMat* _R, CvMat* _T,
+ CvMat* _E, CvMat* _F,
+ CvTermCriteria termCrit, int flags )
+{
+ const int NINTRINSIC = 9;
+ CvMat* npoints = 0;
+ CvMat* err = 0;
+ CvMat* J_LR = 0;
+ CvMat* Je = 0;
+ CvMat* Ji = 0;
+ CvMat* imagePoints[2] = {0,0};
+ CvMat* objectPoints = 0;
+ CvMat* RT0 = 0;
+ CvLevMarq solver;
+
+ CV_FUNCNAME( "cvStereoCalibrate" );
+
+ __BEGIN__;
+
+ double A[2][9], dk[2][5]={{0,0,0,0,0},{0,0,0,0,0}}, rlr[9];
+ CvMat K[2], Dist[2], om_LR, T_LR;
+ CvMat R_LR = cvMat(3, 3, CV_64F, rlr);
+ int i, k, p, ni = 0, ofs, nimages, pointsTotal, maxPoints = 0;
+ int nparams;
+ bool recomputeIntrinsics = false;
+ double aspectRatio[2] = {0,0};
+
+ CV_ASSERT( CV_IS_MAT(_imagePoints1) && CV_IS_MAT(_imagePoints2) &&
+ CV_IS_MAT(_objectPoints) && CV_IS_MAT(_npoints) &&
+ CV_IS_MAT(_R) && CV_IS_MAT(_T) );
+
+ CV_ASSERT( CV_ARE_TYPES_EQ(_imagePoints1, _imagePoints2) &&
+ CV_ARE_DEPTHS_EQ(_imagePoints1, _objectPoints) );
+
+ CV_ASSERT( (_npoints->cols == 1 || _npoints->rows == 1) &&
+ CV_MAT_TYPE(_npoints->type) == CV_32SC1 );
+
+ nimages = _npoints->cols + _npoints->rows - 1;
+ npoints = cvCreateMat( _npoints->rows, _npoints->cols, _npoints->type );
+ cvCopy( _npoints, npoints );
+
+ for( i = 0, pointsTotal = 0; i < nimages; i++ )
+ {
+ maxPoints = MAX(maxPoints, npoints->data.i[i]);
+ pointsTotal += npoints->data.i[i];
+ }
+
+ objectPoints = cvCreateMat( _objectPoints->rows, _objectPoints->cols,
+ CV_64FC(CV_MAT_CN(_objectPoints->type)));
+ cvConvert( _objectPoints, objectPoints );
+ cvReshape( objectPoints, objectPoints, 3, 1 );
+
+ for( k = 0; k < 2; k++ )
+ {
+ const CvMat* points = k == 0 ? _imagePoints1 : _imagePoints2;
+ const CvMat* cameraMatrix = k == 0 ? _cameraMatrix1 : _cameraMatrix2;
+ const CvMat* distCoeffs = k == 0 ? _distCoeffs1 : _distCoeffs2;
+
+ int cn = CV_MAT_CN(_imagePoints1->type);
+ CV_ASSERT( (CV_MAT_DEPTH(_imagePoints1->type) == CV_32F ||
+ CV_MAT_DEPTH(_imagePoints1->type) == CV_64F) &&
+ ((_imagePoints1->rows == pointsTotal && _imagePoints1->cols*cn == 2) ||
+ (_imagePoints1->rows == 1 && _imagePoints1->cols == pointsTotal && cn == 2)) );
+
+ K[k] = cvMat(3,3,CV_64F,A[k]);
+ Dist[k] = cvMat(1,5,CV_64F,dk[k]);
+
+ imagePoints[k] = cvCreateMat( points->rows, points->cols, CV_64FC(CV_MAT_CN(points->type)));
+ cvConvert( points, imagePoints[k] );
+ cvReshape( imagePoints[k], imagePoints[k], 2, 1 );
+
+ if( flags & (CV_CALIB_FIX_INTRINSIC|CV_CALIB_USE_INTRINSIC_GUESS|
+ CV_CALIB_FIX_ASPECT_RATIO|CV_CALIB_FIX_FOCAL_LENGTH) )
+ cvConvert( cameraMatrix, &K[k] );
+
+ if( flags & (CV_CALIB_FIX_INTRINSIC|CV_CALIB_USE_INTRINSIC_GUESS|
+ CV_CALIB_FIX_K1|CV_CALIB_FIX_K2|CV_CALIB_FIX_K3) )
+ {
+ CvMat tdist = cvMat( distCoeffs->rows, distCoeffs->cols,
+ CV_MAKETYPE(CV_64F,CV_MAT_CN(distCoeffs->type)), Dist[k].data.db );
+ cvConvert( distCoeffs, &tdist );
+ }
+
+ if( !(flags & (CV_CALIB_FIX_INTRINSIC|CV_CALIB_USE_INTRINSIC_GUESS)))
+ {
+ cvCalibrateCamera2( objectPoints, imagePoints[k],
+ npoints, imageSize, &K[k], &Dist[k], 0, 0, flags );
+ }
+ }
+
+ if( flags & CV_CALIB_SAME_FOCAL_LENGTH )
+ {
+ static const int avg_idx[] = { 0, 4, 2, 5, -1 };
+ for( k = 0; avg_idx[k] >= 0; k++ )
+ A[0][avg_idx[k]] = A[1][avg_idx[k]] = (A[0][avg_idx[k]] + A[1][avg_idx[k]])*0.5;
+ }
+
+ if( flags & CV_CALIB_FIX_ASPECT_RATIO )
+ {
+ for( k = 0; k < 2; k++ )
+ aspectRatio[k] = A[k][0]/A[k][4];
+ }
+
+ recomputeIntrinsics = (flags & CV_CALIB_FIX_INTRINSIC) == 0;
+
+ err = cvCreateMat( maxPoints*2, 1, CV_64F );
+ Je = cvCreateMat( maxPoints*2, 6, CV_64F );
+ J_LR = cvCreateMat( maxPoints*2, 6, CV_64F );
+ Ji = cvCreateMat( maxPoints*2, NINTRINSIC, CV_64F );
+ cvZero( Ji );
+
+ // we optimize for the inter-camera R(3),t(3), then, optionally,
+ // for intrinisic parameters of each camera ((fx,fy,cx,cy,k1,k2,p1,p2) ~ 8 parameters).
+ nparams = 6*(nimages+1) + (recomputeIntrinsics ? NINTRINSIC*2 : 0);
+
+ // storage for initial [om(R){i}|t{i}] (in order to compute the median for each component)
+ RT0 = cvCreateMat( 6, nimages, CV_64F );
+
+ solver.init( nparams, 0, termCrit );
+ if( recomputeIntrinsics )
+ {
+ uchar* imask = solver.mask->data.ptr + nparams - NINTRINSIC*2;
+ if( flags & CV_CALIB_FIX_ASPECT_RATIO )
+ imask[0] = imask[NINTRINSIC] = 0;
+ if( flags & CV_CALIB_FIX_FOCAL_LENGTH )
+ imask[0] = imask[1] = imask[NINTRINSIC] = imask[NINTRINSIC+1] = 0;
+ if( flags & CV_CALIB_FIX_PRINCIPAL_POINT )
+ imask[2] = imask[3] = imask[NINTRINSIC+2] = imask[NINTRINSIC+3] = 0;
+ if( flags & CV_CALIB_ZERO_TANGENT_DIST )
+ imask[6] = imask[7] = imask[NINTRINSIC+6] = imask[NINTRINSIC+7] = 0;
+ if( flags & CV_CALIB_FIX_K1 )
+ imask[4] = imask[NINTRINSIC+4] = 0;
+ if( flags & CV_CALIB_FIX_K2 )
+ imask[5] = imask[NINTRINSIC+5] = 0;
+ if( flags & CV_CALIB_FIX_K3 )
+ imask[8] = imask[NINTRINSIC+8] = 0;
+ }
+
+ /*
+ Compute initial estimate of pose
+
+ For each image, compute:
+ R(om) is the rotation matrix of om
+ om(R) is the rotation vector of R
+ R_ref = R(om_right) * R(om_left)'
+ T_ref_list = [T_ref_list; T_right - R_ref * T_left]
+ om_ref_list = {om_ref_list; om(R_ref)]
+
+ om = median(om_ref_list)
+ T = median(T_ref_list)
+ */
+ for( i = ofs = 0; i < nimages; ofs += ni, i++ )
+ {
+ ni = npoints->data.i[i];
+ CvMat objpt_i;
+ double _om[2][3], r[2][9], t[2][3];
+ CvMat om[2], R[2], T[2], imgpt_i[2];
+
+ objpt_i = cvMat(1, ni, CV_64FC3, objectPoints->data.db + ofs*3);
+ for( k = 0; k < 2; k++ )
+ {
+ imgpt_i[k] = cvMat(1, ni, CV_64FC2, imagePoints[k]->data.db + ofs*2);
+ om[k] = cvMat(3, 1, CV_64F, _om[k]);
+ R[k] = cvMat(3, 3, CV_64F, r[k]);
+ T[k] = cvMat(3, 1, CV_64F, t[k]);
+
+ // FIXME: here we ignore activePoints[k] because of
+ // the limited API of cvFindExtrnisicCameraParams2
+ cvFindExtrinsicCameraParams2( &objpt_i, &imgpt_i[k], &K[k], &Dist[k], &om[k], &T[k] );
+ cvRodrigues2( &om[k], &R[k] );
+ if( k == 0 )
+ {
+ // save initial om_left and T_left
+ solver.param->data.db[(i+1)*6] = _om[0][0];
+ solver.param->data.db[(i+1)*6 + 1] = _om[0][1];
+ solver.param->data.db[(i+1)*6 + 2] = _om[0][2];
+ solver.param->data.db[(i+1)*6 + 3] = t[0][0];
+ solver.param->data.db[(i+1)*6 + 4] = t[0][1];
+ solver.param->data.db[(i+1)*6 + 5] = t[0][2];
+ }
+ }
+ cvGEMM( &R[1], &R[0], 1, 0, 0, &R[0], CV_GEMM_B_T );
+ cvGEMM( &R[0], &T[0], -1, &T[1], 1, &T[1] );
+ cvRodrigues2( &R[0], &T[0] );
+ RT0->data.db[i] = t[0][0];
+ RT0->data.db[i + nimages] = t[0][1];
+ RT0->data.db[i + nimages*2] = t[0][2];
+ RT0->data.db[i + nimages*3] = t[1][0];
+ RT0->data.db[i + nimages*4] = t[1][1];
+ RT0->data.db[i + nimages*5] = t[1][2];
+ }
+
+ // find the medians and save the first 6 parameters
+ for( i = 0; i < 6; i++ )
+ {
+ qsort( RT0->data.db + i*nimages, nimages, CV_ELEM_SIZE(RT0->type), dbCmp );
+ solver.param->data.db[i] = nimages % 2 != 0 ? RT0->data.db[i*nimages + nimages/2] :
+ (RT0->data.db[i*nimages + nimages/2 - 1] + RT0->data.db[i*nimages + nimages/2])*0.5;
+ }
+
+ if( recomputeIntrinsics )
+ for( k = 0; k < 2; k++ )
+ {
+ double* iparam = solver.param->data.db + (nimages+1)*6 + k*NINTRINSIC;
+ if( flags & CV_CALIB_ZERO_TANGENT_DIST )
+ dk[k][2] = dk[k][3] = 0;
+ iparam[0] = A[k][0]; iparam[1] = A[k][4]; iparam[2] = A[k][2]; iparam[3] = A[k][5];
+ iparam[4] = dk[k][0]; iparam[5] = dk[k][1]; iparam[6] = dk[k][2];
+ iparam[7] = dk[k][3]; iparam[8] = dk[k][4];
+ }
+
+ om_LR = cvMat(3, 1, CV_64F, solver.param->data.db);
+ T_LR = cvMat(3, 1, CV_64F, solver.param->data.db + 3);
+
+ for(;;)
+ {
+ const CvMat* param = 0;
+ CvMat tmpimagePoints;
+ CvMat *JtJ = 0, *JtErr = 0;
+ double* errNorm = 0;
+ double _omR[3], _tR[3];
+ double _dr3dr1[9], _dr3dr2[9], /*_dt3dr1[9],*/ _dt3dr2[9], _dt3dt1[9], _dt3dt2[9];
+ CvMat dr3dr1 = cvMat(3, 3, CV_64F, _dr3dr1);
+ CvMat dr3dr2 = cvMat(3, 3, CV_64F, _dr3dr2);
+ //CvMat dt3dr1 = cvMat(3, 3, CV_64F, _dt3dr1);
+ CvMat dt3dr2 = cvMat(3, 3, CV_64F, _dt3dr2);
+ CvMat dt3dt1 = cvMat(3, 3, CV_64F, _dt3dt1);
+ CvMat dt3dt2 = cvMat(3, 3, CV_64F, _dt3dt2);
+ CvMat om[2], T[2], imgpt_i[2];
+ CvMat dpdrot_hdr, dpdt_hdr, dpdf_hdr, dpdc_hdr, dpdk_hdr;
+ CvMat *dpdrot = &dpdrot_hdr, *dpdt = &dpdt_hdr, *dpdf = 0, *dpdc = 0, *dpdk = 0;
+
+ if( !solver.updateAlt( param, JtJ, JtErr, errNorm ))
+ break;
+
+ cvRodrigues2( &om_LR, &R_LR );
+ om[1] = cvMat(3,1,CV_64F,_omR);
+ T[1] = cvMat(3,1,CV_64F,_tR);
+
+ if( recomputeIntrinsics )
+ {
+ double* iparam = solver.param->data.db + (nimages+1)*6;
+ double* ipparam = solver.prevParam->data.db + (nimages+1)*6;
+ dpdf = &dpdf_hdr;
+ dpdc = &dpdc_hdr;
+ dpdk = &dpdk_hdr;
+ if( flags & CV_CALIB_SAME_FOCAL_LENGTH )
+ {
+ iparam[NINTRINSIC] = iparam[0];
+ iparam[NINTRINSIC+1] = iparam[1];
+ ipparam[NINTRINSIC] = ipparam[0];
+ ipparam[NINTRINSIC+1] = ipparam[1];
+ }
+ if( flags & CV_CALIB_FIX_ASPECT_RATIO )
+ {
+ iparam[0] = iparam[1]*aspectRatio[0];
+ iparam[NINTRINSIC] = iparam[NINTRINSIC+1]*aspectRatio[1];
+ ipparam[0] = ipparam[1]*aspectRatio[0];
+ ipparam[NINTRINSIC] = ipparam[NINTRINSIC+1]*aspectRatio[1];
+ }
+ for( k = 0; k < 2; k++ )
+ {
+ A[k][0] = iparam[k*NINTRINSIC+0];
+ A[k][4] = iparam[k*NINTRINSIC+1];
+ A[k][2] = iparam[k*NINTRINSIC+2];
+ A[k][5] = iparam[k*NINTRINSIC+3];
+ dk[k][0] = iparam[k*NINTRINSIC+4];
+ dk[k][1] = iparam[k*NINTRINSIC+5];
+ dk[k][2] = iparam[k*NINTRINSIC+6];
+ dk[k][3] = iparam[k*NINTRINSIC+7];
+ dk[k][4] = iparam[k*NINTRINSIC+8];
+ }
+ }
+
+ for( i = ofs = 0; i < nimages; ofs += ni, i++ )
+ {
+ ni = npoints->data.i[i];
+ CvMat objpt_i, _part;
+
+ om[0] = cvMat(3,1,CV_64F,solver.param->data.db+(i+1)*6);
+ T[0] = cvMat(3,1,CV_64F,solver.param->data.db+(i+1)*6+3);
+
+ if( JtJ || JtErr )
+ cvComposeRT( &om[0], &T[0], &om_LR, &T_LR, &om[1], &T[1], &dr3dr1, 0,
+ &dr3dr2, 0, 0, &dt3dt1, &dt3dr2, &dt3dt2 );
+ else
+ cvComposeRT( &om[0], &T[0], &om_LR, &T_LR, &om[1], &T[1] );
+
+ objpt_i = cvMat(1, ni, CV_64FC3, objectPoints->data.db + ofs*3);
+ err->rows = Je->rows = J_LR->rows = Ji->rows = ni*2;
+ cvReshape( err, &tmpimagePoints, 2, 1 );
+
+ cvGetCols( Ji, &dpdf_hdr, 0, 2 );
+ cvGetCols( Ji, &dpdc_hdr, 2, 4 );
+ cvGetCols( Ji, &dpdk_hdr, 4, NINTRINSIC );
+ cvGetCols( Je, &dpdrot_hdr, 0, 3 );
+ cvGetCols( Je, &dpdt_hdr, 3, 6 );
+
+ for( k = 0; k < 2; k++ )
+ {
+ double maxErr, l2err;
+ imgpt_i[k] = cvMat(1, ni, CV_64FC2, imagePoints[k]->data.db + ofs*2);
+
+ if( JtJ || JtErr )
+ cvProjectPoints2( &objpt_i, &om[k], &T[k], &K[k], &Dist[k],
+ &tmpimagePoints, dpdrot, dpdt, dpdf, dpdc, dpdk,
+ (flags & CV_CALIB_FIX_ASPECT_RATIO) ? aspectRatio[k] : 0);
+ else
+ cvProjectPoints2( &objpt_i, &om[k], &T[k], &K[k], &Dist[k], &tmpimagePoints );
+ cvSub( &tmpimagePoints, &imgpt_i[k], &tmpimagePoints );
+
+ l2err = cvNorm( &tmpimagePoints, 0, CV_L2 );
+ maxErr = cvNorm( &tmpimagePoints, 0, CV_C );
+
+ if( JtJ || JtErr )
+ {
+ int iofs = (nimages+1)*6 + k*NINTRINSIC, eofs = (i+1)*6;
+ assert( JtJ && JtErr );
+
+ if( k == 1 )
+ {
+ // d(err_{x|y}R) ~ de3
+ // convert de3/{dr3,dt3} => de3{dr1,dt1} & de3{dr2,dt2}
+ for( p = 0; p < ni*2; p++ )
+ {
+ CvMat de3dr3 = cvMat( 1, 3, CV_64F, Je->data.ptr + Je->step*p );
+ CvMat de3dt3 = cvMat( 1, 3, CV_64F, de3dr3.data.db + 3 );
+ CvMat de3dr2 = cvMat( 1, 3, CV_64F, J_LR->data.ptr + J_LR->step*p );
+ CvMat de3dt2 = cvMat( 1, 3, CV_64F, de3dr2.data.db + 3 );
+ double _de3dr1[3], _de3dt1[3];
+ CvMat de3dr1 = cvMat( 1, 3, CV_64F, _de3dr1 );
+ CvMat de3dt1 = cvMat( 1, 3, CV_64F, _de3dt1 );
+
+ cvMatMul( &de3dr3, &dr3dr1, &de3dr1 );
+ cvMatMul( &de3dt3, &dt3dt1, &de3dt1 );
+
+ cvMatMul( &de3dr3, &dr3dr2, &de3dr2 );
+ cvMatMulAdd( &de3dt3, &dt3dr2, &de3dr2, &de3dr2 );
+
+ cvMatMul( &de3dt3, &dt3dt2, &de3dt2 );
+
+ cvCopy( &de3dr1, &de3dr3 );
+ cvCopy( &de3dt1, &de3dt3 );
+ }
+
+ cvGetSubRect( JtJ, &_part, cvRect(0, 0, 6, 6) );
+ cvGEMM( J_LR, J_LR, 1, &_part, 1, &_part, CV_GEMM_A_T );
+
+ cvGetSubRect( JtJ, &_part, cvRect(eofs, 0, 6, 6) );
+ cvGEMM( J_LR, Je, 1, 0, 0, &_part, CV_GEMM_A_T );
+
+ cvGetRows( JtErr, &_part, 0, 6 );
+ cvGEMM( J_LR, err, 1, &_part, 1, &_part, CV_GEMM_A_T );
+ }
+
+ cvGetSubRect( JtJ, &_part, cvRect(eofs, eofs, 6, 6) );
+ cvGEMM( Je, Je, 1, &_part, 1, &_part, CV_GEMM_A_T );
+
+ cvGetRows( JtErr, &_part, eofs, eofs + 6 );
+ cvGEMM( Je, err, 1, &_part, 1, &_part, CV_GEMM_A_T );
+
+ if( recomputeIntrinsics )
+ {
+ cvGetSubRect( JtJ, &_part, cvRect(iofs, iofs, NINTRINSIC, NINTRINSIC) );
+ cvGEMM( Ji, Ji, 1, &_part, 1, &_part, CV_GEMM_A_T );
+ cvGetSubRect( JtJ, &_part, cvRect(iofs, eofs, NINTRINSIC, 6) );
+ cvGEMM( Je, Ji, 1, &_part, 1, &_part, CV_GEMM_A_T );
+ if( k == 1 )
+ {
+ cvGetSubRect( JtJ, &_part, cvRect(iofs, 0, NINTRINSIC, 6) );
+ cvGEMM( J_LR, Ji, 1, &_part, 1, &_part, CV_GEMM_A_T );
+ }
+ cvGetRows( JtErr, &_part, iofs, iofs + NINTRINSIC );
+ cvGEMM( Ji, err, 1, &_part, 1, &_part, CV_GEMM_A_T );
+ }
+ }
+
+ if( errNorm )
+ *errNorm += l2err*l2err;
+ }
+ }
+ }
+
+ cvRodrigues2( &om_LR, &R_LR );
+ if( _R->rows == 1 || _R->cols == 1 )
+ cvConvert( &om_LR, _R );
+ else
+ cvConvert( &R_LR, _R );
+ cvConvert( &T_LR, _T );
+
+ if( recomputeIntrinsics )
+ {
+ cvConvert( &K[0], _cameraMatrix1 );
+ cvConvert( &K[1], _cameraMatrix2 );
+
+ for( k = 0; k < 2; k++ )
+ {
+ CvMat* distCoeffs = k == 0 ? _distCoeffs1 : _distCoeffs2;
+ CvMat tdist = cvMat( distCoeffs->rows, distCoeffs->cols,
+ CV_MAKETYPE(CV_64F,CV_MAT_CN(distCoeffs->type)), Dist[k].data.db );
+ cvConvert( &tdist, distCoeffs );
+ }
+ }
+
+ if( _E || _F )
+ {
+ double* t = T_LR.data.db;
+ double tx[] =
+ {
+ 0, -t[2], t[1],
+ t[2], 0, -t[0],
+ -t[1], t[0], 0
+ };
+ CvMat Tx = cvMat(3, 3, CV_64F, tx);
+ double e[9], f[9];
+ CvMat E = cvMat(3, 3, CV_64F, e);
+ CvMat F = cvMat(3, 3, CV_64F, f);
+ cvMatMul( &Tx, &R_LR, &E );
+ if( _E )
+ cvConvert( &E, _E );
+ if( _F )
+ {
+ double ik[9];
+ CvMat iK = cvMat(3, 3, CV_64F, ik);
+ cvInvert(&K[1], &iK);
+ cvGEMM( &iK, &E, 1, 0, 0, &E, CV_GEMM_A_T );
+ cvInvert(&K[0], &iK);
+ cvMatMul(&E, &iK, &F);
+ cvConvertScale( &F, _F, fabs(f[8]) > 0 ? 1./f[8] : 1 );
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &npoints );
+ cvReleaseMat( &err );
+ cvReleaseMat( &J_LR );
+ cvReleaseMat( &Je );
+ cvReleaseMat( &Ji );
+ cvReleaseMat( &RT0 );
+ cvReleaseMat( &objectPoints );
+ cvReleaseMat( &imagePoints[0] );
+ cvReleaseMat( &imagePoints[1] );
+}
+
+
+void cvStereoRectify( const CvMat* _cameraMatrix1, const CvMat* _cameraMatrix2,
+ const CvMat* _distCoeffs1, const CvMat* _distCoeffs2,
+ CvSize imageSize, const CvMat* _R, const CvMat* _T,
+ CvMat* _R1, CvMat* _R2, CvMat* _P1, CvMat* _P2,
+ CvMat* _Q, int flags )
+{
+ double _om[3], _t[3], _uu[3]={0,0,0}, _r_r[3][3], _pp[3][4];
+ double _ww[3], _wr[3][3], _z[3] = {0,0,0}, _ri[3][3];
+ CvMat om = cvMat(3, 1, CV_64F, _om);
+ CvMat t = cvMat(3, 1, CV_64F, _t);
+ CvMat uu = cvMat(3, 1, CV_64F, _uu);
+ CvMat r_r = cvMat(3, 3, CV_64F, _r_r);
+ CvMat pp = cvMat(3, 4, CV_64F, _pp);
+ CvMat ww = cvMat(3, 1, CV_64F, _ww); // temps
+ CvMat wR = cvMat(3, 3, CV_64F, _wr);
+ CvMat Z = cvMat(3, 1, CV_64F, _z);
+ CvMat Ri = cvMat(3, 3, CV_64F, _ri);
+ double nx = imageSize.width, ny = imageSize.height;
+ int i, k;
+
+ if( _R->rows == 3 && _R->cols == 3 )
+ cvRodrigues2(_R, &om); // get vector rotation
+ else
+ cvConvert(_R, &om); // it's already a rotation vector
+ cvConvertScale(&om, &om, -0.5); // get average rotation
+ cvRodrigues2(&om, &r_r); // rotate cameras to same orientation by averaging
+ cvMatMul(&r_r, _T, &t);
+
+ int idx = fabs(_t[0]) > fabs(_t[1]) ? 0 : 1;
+ double c = _t[idx], nt = cvNorm(&t, 0, CV_L2);
+ _uu[idx] = c > 0 ? 1 : -1;
+
+ // calculate global Z rotation
+ cvCrossProduct(&t,&uu,&ww);
+ double nw = cvNorm(&ww, 0, CV_L2);
+ cvConvertScale(&ww, &ww, acos(fabs(c)/nt)/nw);
+ cvRodrigues2(&ww, &wR);
+
+ // apply to both views
+ cvGEMM(&wR, &r_r, 1, 0, 0, &Ri, CV_GEMM_B_T);
+ cvConvert( &Ri, _R1 );
+ cvGEMM(&wR, &r_r, 1, 0, 0, &Ri, 0);
+ cvConvert( &Ri, _R2 );
+ cvMatMul(&r_r, _T, &t);
+
+ // calculate projection/camera matrices
+ // these contain the relevant rectified image internal params (fx, fy=fx, cx, cy)
+ double fc_new = DBL_MAX;
+ CvPoint2D64f cc_new[2] = {{0,0}, {0,0}};
+
+ for( k = 0; k < 2; k++ )
+ {
+ const CvMat* A = k == 0 ? _cameraMatrix1 : _cameraMatrix2;
+ const CvMat* Dk = k == 0 ? _distCoeffs1 : _distCoeffs2;
+ CvPoint2D32f _pts[4];
+ CvPoint3D32f _pts_3[4];
+ CvMat pts = cvMat(1, 4, CV_32FC2, _pts);
+ CvMat pts_3 = cvMat(1, 4, CV_32FC3, _pts_3);
+ double fc, dk1 = Dk ? cvmGet(Dk, 0, 0) : 0;
+
+ fc = cvmGet(A,idx^1,idx^1);
+ if( dk1 < 0 )
+ fc *= 1 + 0.2*dk1*(nx*nx + ny*ny)/(8*fc*fc);
+ fc_new = MIN(fc_new, fc);
+
+ for( i = 0; i < 4; i++ )
+ {
+ _pts[i].x = (float)(((i % 2) + 0.5)*nx*0.5);
+ _pts[i].y = (float)(((i / 2) + 0.5)*ny*0.5);
+ }
+ cvUndistortPoints( &pts, &pts, A, Dk, 0, 0 );
+ cvConvertPointsHomogeneous( &pts, &pts_3 );
+ cvProjectPoints2( &pts_3, k == 0 ? _R1 : _R2, &Z, A, 0, &pts );
+ CvScalar avg = cvAvg(&pts);
+ cc_new[k].x = avg.val[0];
+ cc_new[k].y = avg.val[1];
+ }
+
+ // vertical focal length must be the same for both images to keep the epipolar constraint
+ // (for horizontal epipolar lines -- TBD: check for vertical epipolar lines)
+ // use fy for fx also, for simplicity
+
+ // For simplicity, set the principal points for both cameras to be the average
+ // of the two principal points (either one of or both x- and y- coordinates)
+ if( flags & CV_CALIB_ZERO_DISPARITY )
+ {
+ cc_new[0].x = cc_new[1].x = (cc_new[0].x + cc_new[1].x)*0.5;
+ cc_new[0].y = cc_new[1].y = (cc_new[0].y + cc_new[1].y)*0.5;
+ }
+ else if( idx == 0 ) // horizontal stereo
+ cc_new[0].y = cc_new[1].y = (cc_new[0].y + cc_new[1].y)*0.5;
+ else // vertical stereo
+ cc_new[0].x = cc_new[1].x = (cc_new[0].x + cc_new[1].x)*0.5;
+
+ cvZero( &pp );
+ _pp[0][0] = _pp[1][1] = fc_new;
+ _pp[0][2] = cc_new[0].x;
+ _pp[1][2] = cc_new[0].y;
+ _pp[2][2] = 1;
+ cvConvert(&pp, _P1);
+
+ _pp[0][2] = cc_new[1].x;
+ _pp[1][2] = cc_new[1].y;
+ _pp[idx][3] = _t[idx]*fc_new; // baseline * focal length
+ cvConvert(&pp, _P2);
+
+ if( _Q )
+ {
+ double q[] =
+ {
+ 1, 0, 0, -cc_new[0].x,
+ 0, 1, 0, -cc_new[0].y,
+ 0, 0, 0, fc_new,
+ 0, 0, 1./_t[idx],
+ (idx == 0 ? cc_new[0].x - cc_new[1].x : cc_new[0].y - cc_new[1].y)/_t[idx]
+ };
+ CvMat Q = cvMat(4, 4, CV_64F, q);
+ cvConvert( &Q, _Q );
+ }
+}
+
+
+CV_IMPL int
+cvStereoRectifyUncalibrated(
+ const CvMat* _points1, const CvMat* _points2,
+ const CvMat* F0, CvSize imgSize, CvMat* _H1, CvMat* _H2, double threshold )
+{
+ int result = 0;
+ CvMat* _m1 = 0;
+ CvMat* _m2 = 0;
+ CvMat* _lines1 = 0;
+ CvMat* _lines2 = 0;
+
+ CV_FUNCNAME( "cvStereoCalcHomographiesFromF" );
+
+ __BEGIN__;
+
+ int i, j, npoints;
+ double cx, cy;
+ double u[9], v[9], w[9], f[9], h1[9], h2[9], h0[9], e2[3];
+ CvMat E2 = cvMat( 3, 1, CV_64F, e2 );
+ CvMat U = cvMat( 3, 3, CV_64F, u );
+ CvMat V = cvMat( 3, 3, CV_64F, v );
+ CvMat W = cvMat( 3, 3, CV_64F, w );
+ CvMat F = cvMat( 3, 3, CV_64F, f );
+ CvMat H1 = cvMat( 3, 3, CV_64F, h1 );
+ CvMat H2 = cvMat( 3, 3, CV_64F, h2 );
+ CvMat H0 = cvMat( 3, 3, CV_64F, h0 );
+
+ CvPoint2D64f* m1;
+ CvPoint2D64f* m2;
+ CvPoint3D64f* lines1;
+ CvPoint3D64f* lines2;
+
+ CV_ASSERT( CV_IS_MAT(_points1) && CV_IS_MAT(_points2) &&
+ (_points1->rows == 1 || _points1->cols == 1) &&
+ (_points2->rows == 1 || _points2->cols == 1) &&
+ CV_ARE_SIZES_EQ(_points1, _points2) );
+
+ npoints = _points1->rows * _points1->cols * CV_MAT_CN(_points1->type) / 2;
+
+ _m1 = cvCreateMat( _points1->rows, _points1->cols, CV_64FC(CV_MAT_CN(_points1->type)) );
+ _m2 = cvCreateMat( _points2->rows, _points2->cols, CV_64FC(CV_MAT_CN(_points2->type)) );
+ _lines1 = cvCreateMat( 1, npoints, CV_64FC3 );
+ _lines2 = cvCreateMat( 1, npoints, CV_64FC3 );
+
+ cvConvert( F0, &F );
+
+ cvSVD( (CvMat*)&F, &W, &U, &V, CV_SVD_U_T + CV_SVD_V_T );
+ W.data.db[8] = 0.;
+ cvGEMM( &U, &W, 1, 0, 0, &W, CV_GEMM_A_T );
+ cvMatMul( &W, &V, &F );
+
+ cx = cvRound( (imgSize.width-1)*0.5 );
+ cy = cvRound( (imgSize.height-1)*0.5 );
+
+ cvZero( _H1 );
+ cvZero( _H2 );
+
+ cvConvert( _points1, _m1 );
+ cvConvert( _points2, _m2 );
+ cvReshape( _m1, _m1, 2, 1 );
+ cvReshape( _m1, _m1, 2, 1 );
+
+ m1 = (CvPoint2D64f*)_m1->data.ptr;
+ m2 = (CvPoint2D64f*)_m2->data.ptr;
+ lines1 = (CvPoint3D64f*)_lines1->data.ptr;
+ lines2 = (CvPoint3D64f*)_lines2->data.ptr;
+
+ if( threshold > 0 )
+ {
+ cvComputeCorrespondEpilines( _m1, 1, &F, _lines1 );
+ cvComputeCorrespondEpilines( _m2, 2, &F, _lines2 );
+
+ // measure distance from points to the corresponding epilines, mark outliers
+ for( i = j = 0; i < npoints; i++ )
+ {
+ if( fabs(m1[i].x*lines2[i].x +
+ m1[i].y*lines2[i].y +
+ lines2[i].z) <= threshold &&
+ fabs(m2[i].x*lines1[i].x +
+ m2[i].y*lines1[i].y +
+ lines1[i].z) <= threshold )
+ {
+ if( j > i )
+ {
+ m1[j] = m1[i];
+ m2[j] = m2[i];
+ }
+ j++;
+ }
+ }
+
+ npoints = j;
+ if( npoints == 0 )
+ EXIT;
+ }
+
+ {
+ _m1->cols = _m2->cols = npoints;
+ memcpy( E2.data.db, U.data.db + 6, sizeof(e2));
+ cvScale( &E2, &E2, e2[2] > 0 ? 1 : -1 );
+
+ double t[] =
+ {
+ 1, 0, -cx,
+ 0, 1, -cy,
+ 0, 0, 1
+ };
+ CvMat T = cvMat(3, 3, CV_64F, t);
+ cvMatMul( &T, &E2, &E2 );
+
+ int mirror = e2[0] < 0;
+ double d = MAX(sqrt(e2[0]*e2[0] + e2[1]*e2[1]),DBL_EPSILON);
+ double alpha = e2[0]/d;
+ double beta = e2[1]/d;
+ double r[] =
+ {
+ alpha, beta, 0,
+ -beta, alpha, 0,
+ 0, 0, 1
+ };
+ CvMat R = cvMat(3, 3, CV_64F, r);
+ cvMatMul( &R, &T, &T );
+ cvMatMul( &R, &E2, &E2 );
+ double invf = fabs(e2[2]) < 1e-6*fabs(e2[0]) ? 0 : -e2[2]/e2[0];
+ double k[] =
+ {
+ 1, 0, 0,
+ 0, 1, 0,
+ invf, 0, 1
+ };
+ CvMat K = cvMat(3, 3, CV_64F, k);
+ cvMatMul( &K, &T, &H2 );
+ cvMatMul( &K, &E2, &E2 );
+
+ double it[] =
+ {
+ 1, 0, cx,
+ 0, 1, cy,
+ 0, 0, 1
+ };
+ CvMat iT = cvMat( 3, 3, CV_64F, it );
+ cvMatMul( &iT, &H2, &H2 );
+
+ memcpy( E2.data.db, U.data.db + 6, sizeof(e2));
+ cvScale( &E2, &E2, e2[2] > 0 ? 1 : -1 );
+
+ double e2_x[] =
+ {
+ 0, -e2[2], e2[1],
+ e2[2], 0, -e2[0],
+ -e2[1], e2[0], 0
+ };
+ double e2_111[] =
+ {
+ e2[0], e2[0], e2[0],
+ e2[1], e2[1], e2[1],
+ e2[2], e2[2], e2[2],
+ };
+ CvMat E2_x = cvMat(3, 3, CV_64F, e2_x);
+ CvMat E2_111 = cvMat(3, 3, CV_64F, e2_111);
+ cvMatMulAdd(&E2_x, &F, &E2_111, &H0 );
+ cvMatMul(&H2, &H0, &H0);
+ CvMat E1=cvMat(3, 1, CV_64F, V.data.db+6);
+ cvMatMul(&H0, &E1, &E1);
+
+ cvPerspectiveTransform( _m1, _m1, &H0 );
+ cvPerspectiveTransform( _m2, _m2, &H2 );
+ CvMat A = cvMat( 1, npoints, CV_64FC3, lines1 ), BxBy, B;
+ double a[9], atb[3], x[3];
+ CvMat AtA = cvMat( 3, 3, CV_64F, a );
+ CvMat AtB = cvMat( 3, 1, CV_64F, atb );
+ CvMat X = cvMat( 3, 1, CV_64F, x );
+ cvConvertPointsHomogeneous( _m1, &A );
+ cvReshape( &A, &A, 1, npoints );
+ cvReshape( _m2, &BxBy, 1, npoints );
+ cvGetCol( &BxBy, &B, 0 );
+ cvGEMM( &A, &A, 1, 0, 0, &AtA, CV_GEMM_A_T );
+ cvGEMM( &A, &B, 1, 0, 0, &AtB, CV_GEMM_A_T );
+ cvSolve( &AtA, &AtB, &X, CV_SVD_SYM );
+
+ double ha[] =
+ {
+ x[0], x[1], x[2],
+ 0, 1, 0,
+ 0, 0, 1
+ };
+ CvMat Ha = cvMat(3, 3, CV_64F, ha);
+ cvMatMul( &Ha, &H0, &H1 );
+ cvPerspectiveTransform( _m1, _m1, &Ha );
+
+ if( mirror )
+ {
+ double mm[] = { -1, 0, cx*2, 0, -1, cy*2, 0, 0, 1 };
+ CvMat MM = cvMat(3, 3, CV_64F, mm);
+ cvMatMul( &MM, &H1, &H1 );
+ cvMatMul( &MM, &H2, &H2 );
+ }
+
+ cvConvert( &H1, _H1 );
+ cvConvert( &H2, _H2 );
+
+ result = 1;
+ }
+
+ __END__;
+
+ cvReleaseMat( &_m1 );
+ cvReleaseMat( &_m2 );
+ cvReleaseMat( &_lines1 );
+ cvReleaseMat( &_lines2 );
+
+ return result;
+}
+
+
+CV_IMPL void
+cvReprojectImageTo3D(
+ const CvArr* disparityImage,
+ CvArr* _3dImage, const CvMat* _Q )
+{
+ CV_FUNCNAME( "cvReprojectImageTo3D" );
+
+ __BEGIN__;
+
+ double q[4][4];
+ CvMat Q = cvMat(4, 4, CV_64F, q);
+ CvMat sstub, *src = cvGetMat( disparityImage, &sstub );
+ CvMat dstub, *dst = cvGetMat( _3dImage, &dstub );
+ int stype = CV_MAT_TYPE(src->type), dtype = CV_MAT_TYPE(dst->type);
+ int x, y, rows = src->rows, cols = src->cols;
+ float* sbuf = (float*)cvStackAlloc( cols*sizeof(sbuf[0]) );
+ float* dbuf = (float*)cvStackAlloc( cols*3*sizeof(dbuf[0]) );
+
+ CV_ASSERT( CV_ARE_SIZES_EQ(src, dst) &&
+ (CV_MAT_TYPE(stype) == CV_16SC1 || CV_MAT_TYPE(stype) == CV_32FC1) &&
+ (CV_MAT_TYPE(dtype) == CV_16SC3 || CV_MAT_TYPE(dtype) == CV_32FC3) );
+
+ cvConvert( _Q, &Q );
+
+ for( y = 0; y < rows; y++ )
+ {
+ const float* sptr = (const float*)(src->data.ptr + src->step*y);
+ float* dptr0 = (float*)(dst->data.ptr + dst->step*y), *dptr = dptr0;
+ double qx = q[0][1]*y + q[0][3], qy = q[1][1]*y + q[1][3];
+ double qz = q[2][1]*y + q[2][3], qw = q[3][1]*y + q[3][3];
+
+ if( stype == CV_16SC1 )
+ {
+ const short* sptr0 = (const short*)sptr;
+ for( x = 0; x < cols; x++ )
+ sbuf[x] = (float)sptr0[x];
+ sptr = sbuf;
+ }
+ if( dtype != CV_32FC3 )
+ dptr = dbuf;
+
+ for( x = 0; x < cols; x++, qx += q[0][0], qy += q[1][0], qz += q[2][0], qw += q[3][0] )
+ {
+ double d = sptr[x];
+ double iW = 1./(qw + q[3][2]*d);
+ double X = (qx + q[0][2]*d)*iW;
+ double Y = (qy + q[1][2]*d)*iW;
+ double Z = (qz + q[2][2]*d)*iW;
+
+ dptr[x*3] = (float)X;
+ dptr[x*3+1] = (float)Y;
+ dptr[x*3+2] = (float)Z;
+ }
+
+ if( dtype == CV_16SC3 )
+ {
+ for( x = 0; x < cols*3; x++ )
+ {
+ int ival = cvRound(dptr[x]);
+ ((short*)dptr0)[x] = CV_CAST_16S(ival);
+ }
+ }
+ }
+
+ __END__;
+}
+
+
+/* End of file. */
diff --git a/cv/src/cvcamshift.cpp b/cv/src/cvcamshift.cpp
new file mode 100644
index 0000000..41fbebd
--- /dev/null
+++ b/cv/src/cvcamshift.cpp
@@ -0,0 +1,300 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvMeanShift
+// Purpose: MeanShift algorithm
+// Context:
+// Parameters:
+// imgProb - 2D object probability distribution
+// windowIn - CvRect of CAMSHIFT Window intial size
+// numIters - If CAMSHIFT iterates this many times, stop
+// windowOut - Location, height and width of converged CAMSHIFT window
+// len - If != NULL, return equivalent len
+// width - If != NULL, return equivalent width
+// itersUsed - Returns number of iterations CAMSHIFT took to converge
+// Returns:
+// The function itself returns the area found
+// Notes:
+//F*/
+CV_IMPL int
+cvMeanShift( const void* imgProb, CvRect windowIn,
+ CvTermCriteria criteria, CvConnectedComp* comp )
+{
+ CvMoments moments;
+ int i = 0, eps;
+ CvMat stub, *mat = (CvMat*)imgProb;
+ CvMat cur_win;
+ CvRect cur_rect = windowIn;
+
+ CV_FUNCNAME( "cvMeanShift" );
+
+ if( comp )
+ comp->rect = windowIn;
+
+ moments.m00 = moments.m10 = moments.m01 = 0;
+
+ __BEGIN__;
+
+ CV_CALL( mat = cvGetMat( mat, &stub ));
+
+ if( CV_MAT_CN( mat->type ) > 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+
+ if( windowIn.height <= 0 || windowIn.width <= 0 )
+ CV_ERROR( CV_StsBadArg, "Input window has non-positive sizes" );
+
+ if( windowIn.x < 0 || windowIn.x + windowIn.width > mat->cols ||
+ windowIn.y < 0 || windowIn.y + windowIn.height > mat->rows )
+ CV_ERROR( CV_StsBadArg, "Initial window is not inside the image ROI" );
+
+ CV_CALL( criteria = cvCheckTermCriteria( criteria, 1., 100 ));
+
+ eps = cvRound( criteria.epsilon * criteria.epsilon );
+
+ for( i = 0; i < criteria.max_iter; i++ )
+ {
+ int dx, dy, nx, ny;
+ double inv_m00;
+
+ CV_CALL( cvGetSubRect( mat, &cur_win, cur_rect ));
+ CV_CALL( cvMoments( &cur_win, &moments ));
+
+ /* Calculating center of mass */
+ if( fabs(moments.m00) < DBL_EPSILON )
+ break;
+
+ inv_m00 = moments.inv_sqrt_m00*moments.inv_sqrt_m00;
+ dx = cvRound( moments.m10 * inv_m00 - windowIn.width*0.5 );
+ dy = cvRound( moments.m01 * inv_m00 - windowIn.height*0.5 );
+
+ nx = cur_rect.x + dx;
+ ny = cur_rect.y + dy;
+
+ if( nx < 0 )
+ nx = 0;
+ else if( nx + cur_rect.width > mat->cols )
+ nx = mat->cols - cur_rect.width;
+
+ if( ny < 0 )
+ ny = 0;
+ else if( ny + cur_rect.height > mat->rows )
+ ny = mat->rows - cur_rect.height;
+
+ dx = nx - cur_rect.x;
+ dy = ny - cur_rect.y;
+ cur_rect.x = nx;
+ cur_rect.y = ny;
+
+ /* Check for coverage centers mass & window */
+ if( dx*dx + dy*dy < eps )
+ break;
+ }
+
+ __END__;
+
+ if( comp )
+ {
+ comp->rect = cur_rect;
+ comp->area = (float)moments.m00;
+ }
+
+ return i;
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvCamShift
+// Purpose: CAMSHIFT algorithm
+// Context:
+// Parameters:
+// imgProb - 2D object probability distribution
+// windowIn - CvRect of CAMSHIFT Window intial size
+// criteria - criteria of stop finding window
+// windowOut - Location, height and width of converged CAMSHIFT window
+// orientation - If != NULL, return distribution orientation
+// len - If != NULL, return equivalent len
+// width - If != NULL, return equivalent width
+// area - sum of all elements in result window
+// itersUsed - Returns number of iterations CAMSHIFT took to converge
+// Returns:
+// The function itself returns the area found
+// Notes:
+//F*/
+CV_IMPL int
+cvCamShift( const void* imgProb, CvRect windowIn,
+ CvTermCriteria criteria,
+ CvConnectedComp* _comp,
+ CvBox2D* box )
+{
+ const int TOLERANCE = 10;
+ CvMoments moments;
+ double m00 = 0, m10, m01, mu20, mu11, mu02, inv_m00;
+ double a, b, c, xc, yc;
+ double rotate_a, rotate_c;
+ double theta = 0, square;
+ double cs, sn;
+ double length = 0, width = 0;
+ int itersUsed = 0;
+ CvConnectedComp comp;
+ CvMat cur_win, stub, *mat = (CvMat*)imgProb;
+
+ CV_FUNCNAME( "cvCamShift" );
+
+ comp.rect = windowIn;
+
+ __BEGIN__;
+
+ CV_CALL( mat = cvGetMat( mat, &stub ));
+
+ CV_CALL( itersUsed = cvMeanShift( mat, windowIn, criteria, &comp ));
+ windowIn = comp.rect;
+
+ windowIn.x -= TOLERANCE;
+ if( windowIn.x < 0 )
+ windowIn.x = 0;
+
+ windowIn.y -= TOLERANCE;
+ if( windowIn.y < 0 )
+ windowIn.y = 0;
+
+ windowIn.width += 2 * TOLERANCE;
+ if( windowIn.x + windowIn.width > mat->width )
+ windowIn.width = mat->width - windowIn.x;
+
+ windowIn.height += 2 * TOLERANCE;
+ if( windowIn.y + windowIn.height > mat->height )
+ windowIn.height = mat->height - windowIn.y;
+
+ CV_CALL( cvGetSubRect( mat, &cur_win, windowIn ));
+
+ /* Calculating moments in new center mass */
+ CV_CALL( cvMoments( &cur_win, &moments ));
+
+ m00 = moments.m00;
+ m10 = moments.m10;
+ m01 = moments.m01;
+ mu11 = moments.mu11;
+ mu20 = moments.mu20;
+ mu02 = moments.mu02;
+
+ if( fabs(m00) < DBL_EPSILON )
+ EXIT;
+
+ inv_m00 = 1. / m00;
+ xc = cvRound( m10 * inv_m00 + windowIn.x );
+ yc = cvRound( m01 * inv_m00 + windowIn.y );
+ a = mu20 * inv_m00;
+ b = mu11 * inv_m00;
+ c = mu02 * inv_m00;
+
+ /* Calculating width & height */
+ square = sqrt( 4 * b * b + (a - c) * (a - c) );
+
+ /* Calculating orientation */
+ theta = atan2( 2 * b, a - c + square );
+
+ /* Calculating width & length of figure */
+ cs = cos( theta );
+ sn = sin( theta );
+
+ rotate_a = cs * cs * mu20 + 2 * cs * sn * mu11 + sn * sn * mu02;
+ rotate_c = sn * sn * mu20 - 2 * cs * sn * mu11 + cs * cs * mu02;
+ length = sqrt( rotate_a * inv_m00 ) * 4;
+ width = sqrt( rotate_c * inv_m00 ) * 4;
+
+ /* In case, when tetta is 0 or 1.57... the Length & Width may be exchanged */
+ if( length < width )
+ {
+ double t;
+
+ CV_SWAP( length, width, t );
+ CV_SWAP( cs, sn, t );
+ theta = CV_PI*0.5 - theta;
+ }
+
+ /* Saving results */
+ if( _comp || box )
+ {
+ int t0, t1;
+ int _xc = cvRound( xc );
+ int _yc = cvRound( yc );
+
+ t0 = cvRound( fabs( length * cs ));
+ t1 = cvRound( fabs( width * sn ));
+
+ t0 = MAX( t0, t1 ) + 2;
+ comp.rect.width = MIN( t0, (mat->width - _xc) * 2 );
+
+ t0 = cvRound( fabs( length * sn ));
+ t1 = cvRound( fabs( width * cs ));
+
+ t0 = MAX( t0, t1 ) + 2;
+ comp.rect.height = MIN( t0, (mat->height - _yc) * 2 );
+
+ comp.rect.x = MAX( 0, _xc - comp.rect.width / 2 );
+ comp.rect.y = MAX( 0, _yc - comp.rect.height / 2 );
+
+ comp.rect.width = MIN( mat->width - comp.rect.x, comp.rect.width );
+ comp.rect.height = MIN( mat->height - comp.rect.y, comp.rect.height );
+ comp.area = (float) m00;
+ }
+
+ __END__;
+
+ if( _comp )
+ *_comp = comp;
+
+ if( box )
+ {
+ box->size.height = (float)length;
+ box->size.width = (float)width;
+ box->angle = (float)(theta*180./CV_PI);
+ box->center = cvPoint2D32f( comp.rect.x + comp.rect.width*0.5f,
+ comp.rect.y + comp.rect.height*0.5f);
+ }
+
+ return itersUsed;
+}
+
+/* End of file. */
diff --git a/cv/src/cvcanny.cpp b/cv/src/cvcanny.cpp
new file mode 100644
index 0000000..92b6dc3
--- /dev/null
+++ b/cv/src/cvcanny.cpp
@@ -0,0 +1,357 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+icvCannyGetSize_t icvCannyGetSize_p = 0;
+icvCanny_16s8u_C1R_t icvCanny_16s8u_C1R_p = 0;
+
+CV_IMPL void
+cvCanny( const void* srcarr, void* dstarr,
+ double low_thresh, double high_thresh, int aperture_size )
+{
+ CvMat *dx = 0, *dy = 0;
+ void *buffer = 0;
+ uchar **stack_top, **stack_bottom = 0;
+
+ CV_FUNCNAME( "cvCanny" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize size;
+ int flags = aperture_size;
+ int low, high;
+ int* mag_buf[3];
+ uchar* map;
+ int mapstep, maxsize;
+ int i, j;
+ CvMat mag_row;
+
+ CV_CALL( src = cvGetMat( src, &srcstub ));
+ CV_CALL( dst = cvGetMat( dst, &dststub ));
+
+ if( CV_MAT_TYPE( src->type ) != CV_8UC1 ||
+ CV_MAT_TYPE( dst->type ) != CV_8UC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( low_thresh > high_thresh )
+ {
+ double t;
+ CV_SWAP( low_thresh, high_thresh, t );
+ }
+
+ aperture_size &= INT_MAX;
+ if( (aperture_size & 1) == 0 || aperture_size < 3 || aperture_size > 7 )
+ CV_ERROR( CV_StsBadFlag, "" );
+
+ size = cvGetMatSize( src );
+
+ dx = cvCreateMat( size.height, size.width, CV_16SC1 );
+ dy = cvCreateMat( size.height, size.width, CV_16SC1 );
+ cvSobel( src, dx, 1, 0, aperture_size );
+ cvSobel( src, dy, 0, 1, aperture_size );
+
+ if( icvCannyGetSize_p && icvCanny_16s8u_C1R_p && !(flags & CV_CANNY_L2_GRADIENT) )
+ {
+ int buf_size= 0;
+ IPPI_CALL( icvCannyGetSize_p( size, &buf_size ));
+ CV_CALL( buffer = cvAlloc( buf_size ));
+ IPPI_CALL( icvCanny_16s8u_C1R_p( (short*)dx->data.ptr, dx->step,
+ (short*)dy->data.ptr, dy->step,
+ dst->data.ptr, dst->step,
+ size, (float)low_thresh,
+ (float)high_thresh, buffer ));
+ EXIT;
+ }
+
+ if( flags & CV_CANNY_L2_GRADIENT )
+ {
+ Cv32suf ul, uh;
+ ul.f = (float)low_thresh;
+ uh.f = (float)high_thresh;
+
+ low = ul.i;
+ high = uh.i;
+ }
+ else
+ {
+ low = cvFloor( low_thresh );
+ high = cvFloor( high_thresh );
+ }
+
+ CV_CALL( buffer = cvAlloc( (size.width+2)*(size.height+2) +
+ (size.width+2)*3*sizeof(int)) );
+
+ mag_buf[0] = (int*)buffer;
+ mag_buf[1] = mag_buf[0] + size.width + 2;
+ mag_buf[2] = mag_buf[1] + size.width + 2;
+ map = (uchar*)(mag_buf[2] + size.width + 2);
+ mapstep = size.width + 2;
+
+ maxsize = MAX( 1 << 10, size.width*size.height/10 );
+ CV_CALL( stack_top = stack_bottom = (uchar**)cvAlloc( maxsize*sizeof(stack_top[0]) ));
+
+ memset( mag_buf[0], 0, (size.width+2)*sizeof(int) );
+ memset( map, 1, mapstep );
+ memset( map + mapstep*(size.height + 1), 1, mapstep );
+
+ /* sector numbers
+ (Top-Left Origin)
+
+ 1 2 3
+ * * *
+ * * *
+ 0*******0
+ * * *
+ * * *
+ 3 2 1
+ */
+
+ #define CANNY_PUSH(d) *(d) = (uchar)2, *stack_top++ = (d)
+ #define CANNY_POP(d) (d) = *--stack_top
+
+ mag_row = cvMat( 1, size.width, CV_32F );
+
+ // calculate magnitude and angle of gradient, perform non-maxima supression.
+ // fill the map with one of the following values:
+ // 0 - the pixel might belong to an edge
+ // 1 - the pixel can not belong to an edge
+ // 2 - the pixel does belong to an edge
+ for( i = 0; i <= size.height; i++ )
+ {
+ int* _mag = mag_buf[(i > 0) + 1] + 1;
+ float* _magf = (float*)_mag;
+ const short* _dx = (short*)(dx->data.ptr + dx->step*i);
+ const short* _dy = (short*)(dy->data.ptr + dy->step*i);
+ uchar* _map;
+ int x, y;
+ int magstep1, magstep2;
+ int prev_flag = 0;
+
+ if( i < size.height )
+ {
+ _mag[-1] = _mag[size.width] = 0;
+
+ if( !(flags & CV_CANNY_L2_GRADIENT) )
+ for( j = 0; j < size.width; j++ )
+ _mag[j] = abs(_dx[j]) + abs(_dy[j]);
+ else if( icvFilterSobelVert_8u16s_C1R_p != 0 ) // check for IPP
+ {
+ // use vectorized sqrt
+ mag_row.data.fl = _magf;
+ for( j = 0; j < size.width; j++ )
+ {
+ x = _dx[j]; y = _dy[j];
+ _magf[j] = (float)((double)x*x + (double)y*y);
+ }
+ cvPow( &mag_row, &mag_row, 0.5 );
+ }
+ else
+ {
+ for( j = 0; j < size.width; j++ )
+ {
+ x = _dx[j]; y = _dy[j];
+ _magf[j] = (float)sqrt((double)x*x + (double)y*y);
+ }
+ }
+ }
+ else
+ memset( _mag-1, 0, (size.width + 2)*sizeof(int) );
+
+ // at the very beginning we do not have a complete ring
+ // buffer of 3 magnitude rows for non-maxima suppression
+ if( i == 0 )
+ continue;
+
+ _map = map + mapstep*i + 1;
+ _map[-1] = _map[size.width] = 1;
+
+ _mag = mag_buf[1] + 1; // take the central row
+ _dx = (short*)(dx->data.ptr + dx->step*(i-1));
+ _dy = (short*)(dy->data.ptr + dy->step*(i-1));
+
+ magstep1 = (int)(mag_buf[2] - mag_buf[1]);
+ magstep2 = (int)(mag_buf[0] - mag_buf[1]);
+
+ if( (stack_top - stack_bottom) + size.width > maxsize )
+ {
+ uchar** new_stack_bottom;
+ maxsize = MAX( maxsize * 3/2, maxsize + size.width );
+ CV_CALL( new_stack_bottom = (uchar**)cvAlloc( maxsize * sizeof(stack_top[0])) );
+ memcpy( new_stack_bottom, stack_bottom, (stack_top - stack_bottom)*sizeof(stack_top[0]) );
+ stack_top = new_stack_bottom + (stack_top - stack_bottom);
+ cvFree( &stack_bottom );
+ stack_bottom = new_stack_bottom;
+ }
+
+ for( j = 0; j < size.width; j++ )
+ {
+ #define CANNY_SHIFT 15
+ #define TG22 (int)(0.4142135623730950488016887242097*(1<<CANNY_SHIFT) + 0.5)
+
+ x = _dx[j];
+ y = _dy[j];
+ int s = x ^ y;
+ int m = _mag[j];
+
+ x = abs(x);
+ y = abs(y);
+ if( m > low )
+ {
+ int tg22x = x * TG22;
+ int tg67x = tg22x + ((x + x) << CANNY_SHIFT);
+
+ y <<= CANNY_SHIFT;
+
+ if( y < tg22x )
+ {
+ if( m > _mag[j-1] && m >= _mag[j+1] )
+ {
+ if( m > high && !prev_flag && _map[j-mapstep] != 2 )
+ {
+ CANNY_PUSH( _map + j );
+ prev_flag = 1;
+ }
+ else
+ _map[j] = (uchar)0;
+ continue;
+ }
+ }
+ else if( y > tg67x )
+ {
+ if( m > _mag[j+magstep2] && m >= _mag[j+magstep1] )
+ {
+ if( m > high && !prev_flag && _map[j-mapstep] != 2 )
+ {
+ CANNY_PUSH( _map + j );
+ prev_flag = 1;
+ }
+ else
+ _map[j] = (uchar)0;
+ continue;
+ }
+ }
+ else
+ {
+ s = s < 0 ? -1 : 1;
+ if( m > _mag[j+magstep2-s] && m > _mag[j+magstep1+s] )
+ {
+ if( m > high && !prev_flag && _map[j-mapstep] != 2 )
+ {
+ CANNY_PUSH( _map + j );
+ prev_flag = 1;
+ }
+ else
+ _map[j] = (uchar)0;
+ continue;
+ }
+ }
+ }
+ prev_flag = 0;
+ _map[j] = (uchar)1;
+ }
+
+ // scroll the ring buffer
+ _mag = mag_buf[0];
+ mag_buf[0] = mag_buf[1];
+ mag_buf[1] = mag_buf[2];
+ mag_buf[2] = _mag;
+ }
+
+ // now track the edges (hysteresis thresholding)
+ while( stack_top > stack_bottom )
+ {
+ uchar* m;
+ if( (stack_top - stack_bottom) + 8 > maxsize )
+ {
+ uchar** new_stack_bottom;
+ maxsize = MAX( maxsize * 3/2, maxsize + 8 );
+ CV_CALL( new_stack_bottom = (uchar**)cvAlloc( maxsize * sizeof(stack_top[0])) );
+ memcpy( new_stack_bottom, stack_bottom, (stack_top - stack_bottom)*sizeof(stack_top[0]) );
+ stack_top = new_stack_bottom + (stack_top - stack_bottom);
+ cvFree( &stack_bottom );
+ stack_bottom = new_stack_bottom;
+ }
+
+ CANNY_POP(m);
+
+ if( !m[-1] )
+ CANNY_PUSH( m - 1 );
+ if( !m[1] )
+ CANNY_PUSH( m + 1 );
+ if( !m[-mapstep-1] )
+ CANNY_PUSH( m - mapstep - 1 );
+ if( !m[-mapstep] )
+ CANNY_PUSH( m - mapstep );
+ if( !m[-mapstep+1] )
+ CANNY_PUSH( m - mapstep + 1 );
+ if( !m[mapstep-1] )
+ CANNY_PUSH( m + mapstep - 1 );
+ if( !m[mapstep] )
+ CANNY_PUSH( m + mapstep );
+ if( !m[mapstep+1] )
+ CANNY_PUSH( m + mapstep + 1 );
+ }
+
+ // the final pass, form the final image
+ for( i = 0; i < size.height; i++ )
+ {
+ const uchar* _map = map + mapstep*(i+1) + 1;
+ uchar* _dst = dst->data.ptr + dst->step*i;
+
+ for( j = 0; j < size.width; j++ )
+ _dst[j] = (uchar)-(_map[j] >> 1);
+ }
+
+ __END__;
+
+ cvReleaseMat( &dx );
+ cvReleaseMat( &dy );
+ cvFree( &buffer );
+ cvFree( &stack_bottom );
+}
+
+/* End of file. */
diff --git a/cv/src/cvcolor.cpp b/cv/src/cvcolor.cpp
new file mode 100644
index 0000000..87baa1c
--- /dev/null
+++ b/cv/src/cvcolor.cpp
@@ -0,0 +1,2551 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/********************************* COPYRIGHT NOTICE *******************************\
+ The function for RGB to Lab conversion is based on the MATLAB script
+ RGB2Lab.m translated by Mark Ruzon from C code by Yossi Rubner, 23 September 1997.
+ See the page [http://vision.stanford.edu/~ruzon/software/rgblab.html]
+\**********************************************************************************/
+
+/********************************* COPYRIGHT NOTICE *******************************\
+ Original code for Bayer->BGR/RGB conversion is provided by Dirk Schaefer
+ from MD-Mathematische Dienste GmbH. Below is the copyright notice:
+
+ IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ By downloading, copying, installing or using the software you agree
+ to this license. If you do not agree to this license, do not download,
+ install, copy or use the software.
+
+ Contributors License Agreement:
+
+ Copyright (c) 2002,
+ MD-Mathematische Dienste GmbH
+ Im Defdahl 5-10
+ 44141 Dortmund
+ Germany
+ www.md-it.de
+
+ Redistribution and use in source and binary forms,
+ with or without modification, are permitted provided
+ that the following conditions are met:
+
+ Redistributions of source code must retain
+ the above copyright notice, this list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ The name of Contributor may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ THE POSSIBILITY OF SUCH DAMAGE.
+\**********************************************************************************/
+
+#include "_cv.h"
+
+typedef CvStatus (CV_STDCALL * CvColorCvtFunc0)(
+ const void* src, int srcstep, void* dst, int dststep, CvSize size );
+
+typedef CvStatus (CV_STDCALL * CvColorCvtFunc1)(
+ const void* src, int srcstep, void* dst, int dststep,
+ CvSize size, int param0 );
+
+typedef CvStatus (CV_STDCALL * CvColorCvtFunc2)(
+ const void* src, int srcstep, void* dst, int dststep,
+ CvSize size, int param0, int param1 );
+
+typedef CvStatus (CV_STDCALL * CvColorCvtFunc3)(
+ const void* src, int srcstep, void* dst, int dststep,
+ CvSize size, int param0, int param1, int param2 );
+
+/****************************************************************************************\
+* Various 3/4-channel to 3/4-channel RGB transformations *
+\****************************************************************************************/
+
+#define CV_IMPL_BGRX2BGR( flavor, arrtype ) \
+static CvStatus CV_STDCALL \
+icvBGRx2BGR_##flavor##_CnC3R( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, \
+ CvSize size, int src_cn, int blue_idx ) \
+{ \
+ int i; \
+ \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ srcstep -= size.width*src_cn; \
+ size.width *= 3; \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ for( i = 0; i < size.width; i += 3, src += src_cn ) \
+ { \
+ arrtype t0=src[blue_idx], t1=src[1], t2=src[blue_idx^2]; \
+ dst[i] = t0; \
+ dst[i+1] = t1; \
+ dst[i+2] = t2; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define CV_IMPL_BGR2BGRX( flavor, arrtype ) \
+static CvStatus CV_STDCALL \
+icvBGR2BGRx_##flavor##_C3C4R( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, \
+ CvSize size, int blue_idx ) \
+{ \
+ int i; \
+ \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ srcstep -= size.width*3; \
+ size.width *= 4; \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ for( i = 0; i < size.width; i += 4, src += 3 ) \
+ { \
+ arrtype t0=src[blue_idx], t1=src[1], t2=src[blue_idx^2]; \
+ dst[i] = t0; \
+ dst[i+1] = t1; \
+ dst[i+2] = t2; \
+ dst[i+3] = 0; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define CV_IMPL_BGRA2RGBA( flavor, arrtype ) \
+static CvStatus CV_STDCALL \
+icvBGRA2RGBA_##flavor##_C4R( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, CvSize size ) \
+{ \
+ int i; \
+ \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ size.width *= 4; \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ for( i = 0; i < size.width; i += 4 ) \
+ { \
+ arrtype t0 = src[2], t1 = src[1], t2 = src[0], t3 = src[3]; \
+ dst[i] = t0; \
+ dst[i+1] = t1; \
+ dst[i+2] = t2; \
+ dst[i+3] = t3; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+CV_IMPL_BGRX2BGR( 8u, uchar )
+CV_IMPL_BGRX2BGR( 16u, ushort )
+CV_IMPL_BGRX2BGR( 32f, int )
+CV_IMPL_BGR2BGRX( 8u, uchar )
+CV_IMPL_BGR2BGRX( 16u, ushort )
+CV_IMPL_BGR2BGRX( 32f, int )
+CV_IMPL_BGRA2RGBA( 8u, uchar )
+CV_IMPL_BGRA2RGBA( 16u, ushort )
+CV_IMPL_BGRA2RGBA( 32f, int )
+
+
+/****************************************************************************************\
+* Transforming 16-bit (565 or 555) RGB to/from 24/32-bit (888[8]) RGB *
+\****************************************************************************************/
+
+static CvStatus CV_STDCALL
+icvBGR5x52BGRx_8u_C2CnR( const uchar* src, int srcstep,
+ uchar* dst, int dststep,
+ CvSize size, int dst_cn,
+ int blue_idx, int green_bits )
+{
+ int i;
+ assert( green_bits == 5 || green_bits == 6 );
+ dststep -= size.width*dst_cn;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ if( green_bits == 6 )
+ for( i = 0; i < size.width; i++, dst += dst_cn )
+ {
+ unsigned t = ((const ushort*)src)[i];
+ dst[blue_idx] = (uchar)(t << 3);
+ dst[1] = (uchar)((t >> 3) & ~3);
+ dst[blue_idx ^ 2] = (uchar)((t >> 8) & ~7);
+ if( dst_cn == 4 )
+ dst[3] = 0;
+ }
+ else
+ for( i = 0; i < size.width; i++, dst += dst_cn )
+ {
+ unsigned t = ((const ushort*)src)[i];
+ dst[blue_idx] = (uchar)(t << 3);
+ dst[1] = (uchar)((t >> 2) & ~7);
+ dst[blue_idx ^ 2] = (uchar)((t >> 7) & ~7);
+ if( dst_cn == 4 )
+ dst[3] = 0;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvBGRx2BGR5x5_8u_CnC2R( const uchar* src, int srcstep,
+ uchar* dst, int dststep,
+ CvSize size, int src_cn,
+ int blue_idx, int green_bits )
+{
+ int i;
+ srcstep -= size.width*src_cn;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ if( green_bits == 6 )
+ for( i = 0; i < size.width; i++, src += src_cn )
+ {
+ int t = (src[blue_idx] >> 3)|((src[1]&~3) << 3)|((src[blue_idx^2]&~7) << 8);
+ ((ushort*)dst)[i] = (ushort)t;
+ }
+ else
+ for( i = 0; i < size.width; i++, src += src_cn )
+ {
+ int t = (src[blue_idx] >> 3)|((src[1]&~7) << 2)|((src[blue_idx^2]&~7) << 7);
+ ((ushort*)dst)[i] = (ushort)t;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+
+/////////////////////////// IPP Color Conversion Functions //////////////////////////////
+
+icvRGB2XYZ_8u_C3R_t icvRGB2XYZ_8u_C3R_p = 0;
+icvRGB2XYZ_16u_C3R_t icvRGB2XYZ_16u_C3R_p = 0;
+icvRGB2XYZ_32f_C3R_t icvRGB2XYZ_32f_C3R_p = 0;
+icvXYZ2RGB_8u_C3R_t icvXYZ2RGB_8u_C3R_p = 0;
+icvXYZ2RGB_16u_C3R_t icvXYZ2RGB_16u_C3R_p = 0;
+icvXYZ2RGB_32f_C3R_t icvXYZ2RGB_32f_C3R_p = 0;
+
+icvRGB2HSV_8u_C3R_t icvRGB2HSV_8u_C3R_p = 0;
+icvHSV2RGB_8u_C3R_t icvHSV2RGB_8u_C3R_p = 0;
+
+icvBGR2Lab_8u_C3R_t icvBGR2Lab_8u_C3R_p = 0;
+icvLab2BGR_8u_C3R_t icvLab2BGR_8u_C3R_p = 0;
+
+icvRGB2HLS_8u_C3R_t icvRGB2HLS_8u_C3R_p = 0;
+icvRGB2HLS_32f_C3R_t icvRGB2HLS_32f_C3R_p = 0;
+icvHLS2RGB_8u_C3R_t icvHLS2RGB_8u_C3R_p = 0;
+icvHLS2RGB_32f_C3R_t icvHLS2RGB_32f_C3R_p = 0;
+
+icvRGB2Luv_8u_C3R_t icvRGB2Luv_8u_C3R_p = 0;
+icvLuv2RGB_8u_C3R_t icvLuv2RGB_8u_C3R_p = 0;
+
+//icvRGB2Luv_32f_C3R_t icvRGB2Luv_32f_C3R_p = 0;
+//icvLuv2RGB_32f_C3R_t icvLuv2RGB_32f_C3R_p = 0;
+//icvRGB2Luv_32f_C3R_t icvRGB2Luv_32f_C3R_p = 0;
+//icvLuv2RGB_32f_C3R_t icvLuv2RGB_32f_C3R_p = 0;
+
+
+#define CV_IMPL_BGRx2ABC_IPP( flavor, arrtype ) \
+static CvStatus CV_STDCALL \
+icvBGRx2ABC_IPP_##flavor##_CnC3R( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, CvSize size, int src_cn, \
+ int blue_idx, CvColorCvtFunc0 ipp_func ) \
+{ \
+ int block_size = MIN(1 << 14, size.width); \
+ arrtype* buffer; \
+ int i, di, k; \
+ int do_copy = src_cn > 3 || blue_idx != 2 || src == dst; \
+ CvStatus status = CV_OK; \
+ \
+ if( !do_copy ) \
+ return ipp_func( src, srcstep, dst, dststep, size ); \
+ \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ buffer = (arrtype*)cvStackAlloc( block_size*3*sizeof(buffer[0]) ); \
+ srcstep -= size.width*src_cn; \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ for( i = 0; i < size.width; i += block_size ) \
+ { \
+ arrtype* dst1 = dst + i*3; \
+ di = MIN(block_size, size.width - i); \
+ \
+ for( k = 0; k < di*3; k += 3, src += src_cn ) \
+ { \
+ arrtype b = src[blue_idx]; \
+ arrtype g = src[1]; \
+ arrtype r = src[blue_idx^2]; \
+ buffer[k] = r; \
+ buffer[k+1] = g; \
+ buffer[k+2] = b; \
+ } \
+ \
+ status = ipp_func( buffer, CV_STUB_STEP, \
+ dst1, CV_STUB_STEP, cvSize(di,1) ); \
+ if( status < 0 ) \
+ return status; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+static CvStatus CV_STDCALL
+icvBGRx2ABC_IPP_8u_CnC3R( const uchar* src, int srcstep,
+ uchar* dst, int dststep, CvSize size, int src_cn,
+ int blue_idx, CvColorCvtFunc0 ipp_func )
+{
+ int block_size = MIN(1 << 14, size.width);
+ uchar* buffer;
+ int i, di, k;
+ int do_copy = src_cn > 3 || blue_idx != 2 || src == dst;
+ CvStatus status = CV_OK;
+
+ if( !do_copy )
+ return ipp_func( src, srcstep, dst, dststep, size );
+
+ srcstep /= sizeof(src[0]);
+ dststep /= sizeof(dst[0]);
+
+ buffer = (uchar*)cvStackAlloc( block_size*3*sizeof(buffer[0]) );
+ srcstep -= size.width*src_cn;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i += block_size )
+ {
+ uchar* dst1 = dst + i*3;
+ di = MIN(block_size, size.width - i);
+
+ for( k = 0; k < di*3; k += 3, src += src_cn )
+ {
+ uchar b = src[blue_idx];
+ uchar g = src[1];
+ uchar r = src[blue_idx^2];
+ buffer[k] = r;
+ buffer[k+1] = g;
+ buffer[k+2] = b;
+ }
+
+ status = ipp_func( buffer, CV_STUB_STEP,
+ dst1, CV_STUB_STEP, cvSize(di,1) );
+ if( status < 0 )
+ return status;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+
+//CV_IMPL_BGRx2ABC_IPP( 8u, uchar )
+CV_IMPL_BGRx2ABC_IPP( 16u, ushort )
+CV_IMPL_BGRx2ABC_IPP( 32f, float )
+
+#define CV_IMPL_ABC2BGRx_IPP( flavor, arrtype ) \
+static CvStatus CV_STDCALL \
+icvABC2BGRx_IPP_##flavor##_C3CnR( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, CvSize size, int dst_cn, \
+ int blue_idx, CvColorCvtFunc0 ipp_func ) \
+{ \
+ int block_size = MIN(1 << 10, size.width); \
+ arrtype* buffer; \
+ int i, di, k; \
+ int do_copy = dst_cn > 3 || blue_idx != 2 || src == dst; \
+ CvStatus status = CV_OK; \
+ \
+ if( !do_copy ) \
+ return ipp_func( src, srcstep, dst, dststep, size ); \
+ \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ buffer = (arrtype*)cvStackAlloc( block_size*3*sizeof(buffer[0]) ); \
+ dststep -= size.width*dst_cn; \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ for( i = 0; i < size.width; i += block_size ) \
+ { \
+ const arrtype* src1 = src + i*3; \
+ di = MIN(block_size, size.width - i); \
+ \
+ status = ipp_func( src1, CV_STUB_STEP, \
+ buffer, CV_STUB_STEP, cvSize(di,1) ); \
+ if( status < 0 ) \
+ return status; \
+ \
+ for( k = 0; k < di*3; k += 3, dst += dst_cn ) \
+ { \
+ arrtype r = buffer[k]; \
+ arrtype g = buffer[k+1]; \
+ arrtype b = buffer[k+2]; \
+ dst[blue_idx] = b; \
+ dst[1] = g; \
+ dst[blue_idx^2] = r; \
+ if( dst_cn == 4 ) \
+ dst[3] = 0; \
+ } \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+CV_IMPL_ABC2BGRx_IPP( 8u, uchar )
+CV_IMPL_ABC2BGRx_IPP( 16u, ushort )
+CV_IMPL_ABC2BGRx_IPP( 32f, float )
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+
+/****************************************************************************************\
+* Color to/from Grayscale *
+\****************************************************************************************/
+
+#define fix(x,n) (int)((x)*(1 << (n)) + 0.5)
+#define descale CV_DESCALE
+
+#define cscGr_32f 0.299f
+#define cscGg_32f 0.587f
+#define cscGb_32f 0.114f
+
+/* BGR/RGB -> Gray */
+#define csc_shift 14
+#define cscGr fix(cscGr_32f,csc_shift)
+#define cscGg fix(cscGg_32f,csc_shift)
+#define cscGb /*fix(cscGb_32f,csc_shift)*/ ((1 << csc_shift) - cscGr - cscGg)
+
+#define CV_IMPL_GRAY2BGRX( flavor, arrtype ) \
+static CvStatus CV_STDCALL \
+icvGray2BGRx_##flavor##_C1CnR( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, CvSize size, \
+ int dst_cn ) \
+{ \
+ int i; \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(src[0]); \
+ dststep -= size.width*dst_cn; \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ if( dst_cn == 3 ) \
+ for( i = 0; i < size.width; i++, dst += 3 ) \
+ dst[0] = dst[1] = dst[2] = src[i]; \
+ else \
+ for( i = 0; i < size.width; i++, dst += 4 ) \
+ { \
+ dst[0] = dst[1] = dst[2] = src[i]; \
+ dst[3] = 0; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+CV_IMPL_GRAY2BGRX( 8u, uchar )
+CV_IMPL_GRAY2BGRX( 16u, ushort )
+CV_IMPL_GRAY2BGRX( 32f, float )
+
+
+static CvStatus CV_STDCALL
+icvBGR5x52Gray_8u_C2C1R( const uchar* src, int srcstep,
+ uchar* dst, int dststep,
+ CvSize size, int green_bits )
+{
+ int i;
+ assert( green_bits == 5 || green_bits == 6 );
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ if( green_bits == 6 )
+ for( i = 0; i < size.width; i++ )
+ {
+ int t = ((ushort*)src)[i];
+ t = ((t << 3) & 0xf8)*cscGb + ((t >> 3) & 0xfc)*cscGg +
+ ((t >> 8) & 0xf8)*cscGr;
+ dst[i] = (uchar)CV_DESCALE(t,csc_shift);
+ }
+ else
+ for( i = 0; i < size.width; i++ )
+ {
+ int t = ((ushort*)src)[i];
+ t = ((t << 3) & 0xf8)*cscGb + ((t >> 2) & 0xf8)*cscGg +
+ ((t >> 7) & 0xf8)*cscGr;
+ dst[i] = (uchar)CV_DESCALE(t,csc_shift);
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvGray2BGR5x5_8u_C1C2R( const uchar* src, int srcstep,
+ uchar* dst, int dststep,
+ CvSize size, int green_bits )
+{
+ int i;
+ assert( green_bits == 5 || green_bits == 6 );
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ if( green_bits == 6 )
+ for( i = 0; i < size.width; i++ )
+ {
+ int t = src[i];
+ ((ushort*)dst)[i] = (ushort)((t >> 3)|((t & ~3) << 3)|((t & ~7) << 8));
+ }
+ else
+ for( i = 0; i < size.width; i++ )
+ {
+ int t = src[i] >> 3;
+ ((ushort*)dst)[i] = (ushort)(t|(t << 5)|(t << 10));
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvBGRx2Gray_8u_CnC1R( const uchar* src, int srcstep,
+ uchar* dst, int dststep, CvSize size,
+ int src_cn, int blue_idx )
+{
+ int i;
+ srcstep -= size.width*src_cn;
+
+ if( size.width*size.height >= 1024 )
+ {
+ int* tab = (int*)cvStackAlloc( 256*3*sizeof(tab[0]) );
+ int r = 0, g = 0, b = (1 << (csc_shift-1));
+
+ for( i = 0; i < 256; i++ )
+ {
+ tab[i] = b;
+ tab[i+256] = g;
+ tab[i+512] = r;
+ g += cscGg;
+ if( !blue_idx )
+ b += cscGb, r += cscGr;
+ else
+ b += cscGr, r += cscGb;
+ }
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i++, src += src_cn )
+ {
+ int t0 = tab[src[0]] + tab[src[1] + 256] + tab[src[2] + 512];
+ dst[i] = (uchar)(t0 >> csc_shift);
+ }
+ }
+ }
+ else
+ {
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i++, src += src_cn )
+ {
+ int t0 = src[blue_idx]*cscGb + src[1]*cscGg + src[blue_idx^2]*cscGr;
+ dst[i] = (uchar)CV_DESCALE(t0, csc_shift);
+ }
+ }
+ }
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvBGRx2Gray_16u_CnC1R( const ushort* src, int srcstep,
+ ushort* dst, int dststep, CvSize size,
+ int src_cn, int blue_idx )
+{
+ int i;
+ int cb = cscGb, cr = cscGr;
+ srcstep /= sizeof(src[0]);
+ dststep /= sizeof(dst[0]);
+ srcstep -= size.width*src_cn;
+
+ if( blue_idx )
+ cb = cscGr, cr = cscGb;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ for( i = 0; i < size.width; i++, src += src_cn )
+ dst[i] = (ushort)CV_DESCALE((unsigned)(src[0]*cb +
+ src[1]*cscGg + src[2]*cr), csc_shift);
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvBGRx2Gray_32f_CnC1R( const float* src, int srcstep,
+ float* dst, int dststep, CvSize size,
+ int src_cn, int blue_idx )
+{
+ int i;
+ float cb = cscGb_32f, cr = cscGr_32f;
+ if( blue_idx )
+ cb = cscGr_32f, cr = cscGb_32f;
+
+ srcstep /= sizeof(src[0]);
+ dststep /= sizeof(dst[0]);
+ srcstep -= size.width*src_cn;
+ for( ; size.height--; src += srcstep, dst += dststep )
+ for( i = 0; i < size.width; i++, src += src_cn )
+ dst[i] = src[0]*cb + src[1]*cscGg_32f + src[2]*cr;
+
+ return CV_OK;
+}
+
+
+/****************************************************************************************\
+* RGB <-> YCrCb *
+\****************************************************************************************/
+
+/* BGR/RGB -> YCrCb */
+#define yuvYr_32f cscGr_32f
+#define yuvYg_32f cscGg_32f
+#define yuvYb_32f cscGb_32f
+#define yuvCr_32f 0.713f
+#define yuvCb_32f 0.564f
+
+#define yuv_shift 14
+#define yuvYr fix(yuvYr_32f,yuv_shift)
+#define yuvYg fix(yuvYg_32f,yuv_shift)
+#define yuvYb fix(yuvYb_32f,yuv_shift)
+#define yuvCr fix(yuvCr_32f,yuv_shift)
+#define yuvCb fix(yuvCb_32f,yuv_shift)
+
+#define yuv_descale(x) CV_DESCALE((x), yuv_shift)
+#define yuv_prescale(x) ((x) << yuv_shift)
+
+#define yuvRCr_32f 1.403f
+#define yuvGCr_32f (-0.714f)
+#define yuvGCb_32f (-0.344f)
+#define yuvBCb_32f 1.773f
+
+#define yuvRCr fix(yuvRCr_32f,yuv_shift)
+#define yuvGCr (-fix(-yuvGCr_32f,yuv_shift))
+#define yuvGCb (-fix(-yuvGCb_32f,yuv_shift))
+#define yuvBCb fix(yuvBCb_32f,yuv_shift)
+
+#define CV_IMPL_BGRx2YCrCb( flavor, arrtype, worktype, scale_macro, cast_macro, \
+ YUV_YB, YUV_YG, YUV_YR, YUV_CR, YUV_CB, YUV_Cx_BIAS ) \
+static CvStatus CV_STDCALL \
+icvBGRx2YCrCb_##flavor##_CnC3R( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, CvSize size, int src_cn, int blue_idx ) \
+{ \
+ int i; \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(src[0]); \
+ srcstep -= size.width*src_cn; \
+ size.width *= 3; \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ for( i = 0; i < size.width; i += 3, src += src_cn ) \
+ { \
+ worktype b = src[blue_idx], r = src[2^blue_idx], y; \
+ y = scale_macro(b*YUV_YB + src[1]*YUV_YG + r*YUV_YR); \
+ r = scale_macro((r - y)*YUV_CR) + YUV_Cx_BIAS; \
+ b = scale_macro((b - y)*YUV_CB) + YUV_Cx_BIAS; \
+ dst[i] = cast_macro(y); \
+ dst[i+1] = cast_macro(r); \
+ dst[i+2] = cast_macro(b); \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+CV_IMPL_BGRx2YCrCb( 8u, uchar, int, yuv_descale, CV_CAST_8U,
+ yuvYb, yuvYg, yuvYr, yuvCr, yuvCb, 128 )
+
+CV_IMPL_BGRx2YCrCb( 16u, ushort, int, yuv_descale, CV_CAST_16U,
+ yuvYb, yuvYg, yuvYr, yuvCr, yuvCb, 32768 )
+
+CV_IMPL_BGRx2YCrCb( 32f, float, float, CV_NOP, CV_NOP,
+ yuvYb_32f, yuvYg_32f, yuvYr_32f, yuvCr_32f, yuvCb_32f, 0.5f )
+
+
+#define CV_IMPL_YCrCb2BGRx( flavor, arrtype, worktype, prescale_macro, \
+ scale_macro, cast_macro, YUV_BCb, YUV_GCr, YUV_GCb, YUV_RCr, YUV_Cx_BIAS)\
+static CvStatus CV_STDCALL \
+icvYCrCb2BGRx_##flavor##_C3CnR( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, CvSize size, \
+ int dst_cn, int blue_idx ) \
+{ \
+ int i; \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(src[0]); \
+ dststep -= size.width*dst_cn; \
+ size.width *= 3; \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ for( i = 0; i < size.width; i += 3, dst += dst_cn ) \
+ { \
+ worktype Y = prescale_macro(src[i]), \
+ Cr = src[i+1] - YUV_Cx_BIAS, \
+ Cb = src[i+2] - YUV_Cx_BIAS; \
+ worktype b, g, r; \
+ b = scale_macro( Y + YUV_BCb*Cb ); \
+ g = scale_macro( Y + YUV_GCr*Cr + YUV_GCb*Cb ); \
+ r = scale_macro( Y + YUV_RCr*Cr ); \
+ \
+ dst[blue_idx] = cast_macro(b); \
+ dst[1] = cast_macro(g); \
+ dst[blue_idx^2] = cast_macro(r); \
+ if( dst_cn == 4 ) \
+ dst[3] = 0; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+CV_IMPL_YCrCb2BGRx( 8u, uchar, int, yuv_prescale, yuv_descale, CV_CAST_8U,
+ yuvBCb, yuvGCr, yuvGCb, yuvRCr, 128 )
+
+CV_IMPL_YCrCb2BGRx( 16u, ushort, int, yuv_prescale, yuv_descale, CV_CAST_16U,
+ yuvBCb, yuvGCr, yuvGCb, yuvRCr, 32768 )
+
+CV_IMPL_YCrCb2BGRx( 32f, float, float, CV_NOP, CV_NOP, CV_NOP,
+ yuvBCb_32f, yuvGCr_32f, yuvGCb_32f, yuvRCr_32f, 0.5f )
+
+
+/****************************************************************************************\
+* RGB <-> XYZ *
+\****************************************************************************************/
+
+#define xyzXr_32f 0.412453f
+#define xyzXg_32f 0.357580f
+#define xyzXb_32f 0.180423f
+
+#define xyzYr_32f 0.212671f
+#define xyzYg_32f 0.715160f
+#define xyzYb_32f 0.072169f
+
+#define xyzZr_32f 0.019334f
+#define xyzZg_32f 0.119193f
+#define xyzZb_32f 0.950227f
+
+#define xyzRx_32f 3.240479f
+#define xyzRy_32f (-1.53715f)
+#define xyzRz_32f (-0.498535f)
+
+#define xyzGx_32f (-0.969256f)
+#define xyzGy_32f 1.875991f
+#define xyzGz_32f 0.041556f
+
+#define xyzBx_32f 0.055648f
+#define xyzBy_32f (-0.204043f)
+#define xyzBz_32f 1.057311f
+
+#define xyz_shift 10
+#define xyzXr_32s fix(xyzXr_32f, xyz_shift )
+#define xyzXg_32s fix(xyzXg_32f, xyz_shift )
+#define xyzXb_32s fix(xyzXb_32f, xyz_shift )
+
+#define xyzYr_32s fix(xyzYr_32f, xyz_shift )
+#define xyzYg_32s fix(xyzYg_32f, xyz_shift )
+#define xyzYb_32s fix(xyzYb_32f, xyz_shift )
+
+#define xyzZr_32s fix(xyzZr_32f, xyz_shift )
+#define xyzZg_32s fix(xyzZg_32f, xyz_shift )
+#define xyzZb_32s fix(xyzZb_32f, xyz_shift )
+
+#define xyzRx_32s fix(3.240479f, xyz_shift )
+#define xyzRy_32s -fix(1.53715f, xyz_shift )
+#define xyzRz_32s -fix(0.498535f, xyz_shift )
+
+#define xyzGx_32s -fix(0.969256f, xyz_shift )
+#define xyzGy_32s fix(1.875991f, xyz_shift )
+#define xyzGz_32s fix(0.041556f, xyz_shift )
+
+#define xyzBx_32s fix(0.055648f, xyz_shift )
+#define xyzBy_32s -fix(0.204043f, xyz_shift )
+#define xyzBz_32s fix(1.057311f, xyz_shift )
+
+#define xyz_descale(x) CV_DESCALE((x),xyz_shift)
+
+#define CV_IMPL_BGRx2XYZ( flavor, arrtype, worktype, \
+ scale_macro, cast_macro, suffix ) \
+static CvStatus CV_STDCALL \
+icvBGRx2XYZ_##flavor##_CnC3R( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, CvSize size, \
+ int src_cn, int blue_idx ) \
+{ \
+ int i; \
+ worktype t, matrix[] = \
+ { \
+ xyzXb##suffix, xyzXg##suffix, xyzXr##suffix, \
+ xyzYb##suffix, xyzYg##suffix, xyzYr##suffix, \
+ xyzZb##suffix, xyzZg##suffix, xyzZr##suffix \
+ }; \
+ \
+ if( icvRGB2XYZ_##flavor##_C3R_p ) \
+ return icvBGRx2ABC_IPP_##flavor##_CnC3R( src, srcstep, \
+ dst, dststep, size, src_cn, blue_idx, \
+ icvRGB2XYZ_##flavor##_C3R_p ); \
+ \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ srcstep -= size.width*src_cn; \
+ size.width *= 3; \
+ \
+ if( blue_idx ) \
+ { \
+ CV_SWAP( matrix[0], matrix[2], t ); \
+ CV_SWAP( matrix[3], matrix[5], t ); \
+ CV_SWAP( matrix[6], matrix[8], t ); \
+ } \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ for( i = 0; i < size.width; i += 3, src += src_cn ) \
+ { \
+ worktype x = scale_macro(src[0]*matrix[0] + \
+ src[1]*matrix[1] + src[2]*matrix[2]); \
+ worktype y = scale_macro(src[0]*matrix[3] + \
+ src[1]*matrix[4] + src[2]*matrix[5]); \
+ worktype z = scale_macro(src[0]*matrix[6] + \
+ src[1]*matrix[7] + src[2]*matrix[8]); \
+ \
+ dst[i] = (arrtype)(x); \
+ dst[i+1] = (arrtype)(y); \
+ dst[i+2] = cast_macro(z); /*sum of weights for z > 1*/ \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+CV_IMPL_BGRx2XYZ( 8u, uchar, int, xyz_descale, CV_CAST_8U, _32s )
+CV_IMPL_BGRx2XYZ( 16u, ushort, int, xyz_descale, CV_CAST_16U, _32s )
+CV_IMPL_BGRx2XYZ( 32f, float, float, CV_NOP, CV_NOP, _32f )
+
+
+#define CV_IMPL_XYZ2BGRx( flavor, arrtype, worktype, scale_macro, \
+ cast_macro, suffix ) \
+static CvStatus CV_STDCALL \
+icvXYZ2BGRx_##flavor##_C3CnR( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, CvSize size, \
+ int dst_cn, int blue_idx ) \
+{ \
+ int i; \
+ worktype t, matrix[] = \
+ { \
+ xyzBx##suffix, xyzBy##suffix, xyzBz##suffix, \
+ xyzGx##suffix, xyzGy##suffix, xyzGz##suffix, \
+ xyzRx##suffix, xyzRy##suffix, xyzRz##suffix \
+ }; \
+ \
+ if( icvXYZ2RGB_##flavor##_C3R_p ) \
+ return icvABC2BGRx_IPP_##flavor##_C3CnR( src, srcstep, \
+ dst, dststep, size, dst_cn, blue_idx, \
+ icvXYZ2RGB_##flavor##_C3R_p ); \
+ \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ dststep -= size.width*dst_cn; \
+ size.width *= 3; \
+ \
+ if( blue_idx ) \
+ { \
+ CV_SWAP( matrix[0], matrix[6], t ); \
+ CV_SWAP( matrix[1], matrix[7], t ); \
+ CV_SWAP( matrix[2], matrix[8], t ); \
+ } \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ for( i = 0; i < size.width; i += 3, dst += dst_cn ) \
+ { \
+ worktype b = scale_macro(src[i]*matrix[0] + \
+ src[i+1]*matrix[1] + src[i+2]*matrix[2]); \
+ worktype g = scale_macro(src[i]*matrix[3] + \
+ src[i+1]*matrix[4] + src[i+2]*matrix[5]); \
+ worktype r = scale_macro(src[i]*matrix[6] + \
+ src[i+1]*matrix[7] + src[i+2]*matrix[8]); \
+ \
+ dst[0] = cast_macro(b); \
+ dst[1] = cast_macro(g); \
+ dst[2] = cast_macro(r); \
+ \
+ if( dst_cn == 4 ) \
+ dst[3] = 0; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+CV_IMPL_XYZ2BGRx( 8u, uchar, int, xyz_descale, CV_CAST_8U, _32s )
+CV_IMPL_XYZ2BGRx( 16u, ushort, int, xyz_descale, CV_CAST_16U, _32s )
+CV_IMPL_XYZ2BGRx( 32f, float, float, CV_NOP, CV_NOP, _32f )
+
+
+/****************************************************************************************\
+* Non-linear Color Space Transformations *
+\****************************************************************************************/
+
+// driver color space conversion function for 8u arrays that uses 32f function
+// with appropriate pre- and post-scaling.
+static CvStatus CV_STDCALL
+icvABC2BGRx_8u_C3CnR( const uchar* src, int srcstep, uchar* dst, int dststep,
+ CvSize size, int dst_cn, int blue_idx, CvColorCvtFunc2 cvtfunc_32f,
+ const float* pre_coeffs, int postscale )
+{
+ int block_size = MIN(1 << 8, size.width);
+ float* buffer = (float*)cvStackAlloc( block_size*3*sizeof(buffer[0]) );
+ int i, di, k;
+ CvStatus status = CV_OK;
+
+ dststep -= size.width*dst_cn;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i += block_size )
+ {
+ const uchar* src1 = src + i*3;
+ di = MIN(block_size, size.width - i);
+
+ for( k = 0; k < di*3; k += 3 )
+ {
+ float a = CV_8TO32F(src1[k])*pre_coeffs[0] + pre_coeffs[1];
+ float b = CV_8TO32F(src1[k+1])*pre_coeffs[2] + pre_coeffs[3];
+ float c = CV_8TO32F(src1[k+2])*pre_coeffs[4] + pre_coeffs[5];
+ buffer[k] = a;
+ buffer[k+1] = b;
+ buffer[k+2] = c;
+ }
+
+ status = cvtfunc_32f( buffer, 0, buffer, 0, cvSize(di,1), 3, blue_idx );
+ if( status < 0 )
+ return status;
+
+ if( postscale )
+ {
+ for( k = 0; k < di*3; k += 3, dst += dst_cn )
+ {
+ int b = cvRound(buffer[k]*255.);
+ int g = cvRound(buffer[k+1]*255.);
+ int r = cvRound(buffer[k+2]*255.);
+
+ dst[0] = CV_CAST_8U(b);
+ dst[1] = CV_CAST_8U(g);
+ dst[2] = CV_CAST_8U(r);
+ if( dst_cn == 4 )
+ dst[3] = 0;
+ }
+ }
+ else
+ {
+ for( k = 0; k < di*3; k += 3, dst += dst_cn )
+ {
+ int b = cvRound(buffer[k]);
+ int g = cvRound(buffer[k+1]);
+ int r = cvRound(buffer[k+2]);
+
+ dst[0] = CV_CAST_8U(b);
+ dst[1] = CV_CAST_8U(g);
+ dst[2] = CV_CAST_8U(r);
+ if( dst_cn == 4 )
+ dst[3] = 0;
+ }
+ }
+ }
+ }
+
+ return CV_OK;
+}
+
+
+// driver color space conversion function for 8u arrays that uses 32f function
+// with appropriate pre- and post-scaling.
+static CvStatus CV_STDCALL
+icvBGRx2ABC_8u_CnC3R( const uchar* src, int srcstep, uchar* dst, int dststep,
+ CvSize size, int src_cn, int blue_idx, CvColorCvtFunc2 cvtfunc_32f,
+ int prescale, const float* post_coeffs )
+{
+ int block_size = MIN(1 << 8, size.width);
+ float* buffer = (float*)cvStackAlloc( block_size*3*sizeof(buffer[0]) );
+ int i, di, k;
+ CvStatus status = CV_OK;
+
+ srcstep -= size.width*src_cn;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i += block_size )
+ {
+ uchar* dst1 = dst + i*3;
+ di = MIN(block_size, size.width - i);
+
+ if( prescale )
+ {
+ for( k = 0; k < di*3; k += 3, src += src_cn )
+ {
+ float b = CV_8TO32F(src[0])*0.0039215686274509803f;
+ float g = CV_8TO32F(src[1])*0.0039215686274509803f;
+ float r = CV_8TO32F(src[2])*0.0039215686274509803f;
+
+ buffer[k] = b;
+ buffer[k+1] = g;
+ buffer[k+2] = r;
+ }
+ }
+ else
+ {
+ for( k = 0; k < di*3; k += 3, src += src_cn )
+ {
+ float b = CV_8TO32F(src[0]);
+ float g = CV_8TO32F(src[1]);
+ float r = CV_8TO32F(src[2]);
+
+ buffer[k] = b;
+ buffer[k+1] = g;
+ buffer[k+2] = r;
+ }
+ }
+
+ status = cvtfunc_32f( buffer, 0, buffer, 0, cvSize(di,1), 3, blue_idx );
+ if( status < 0 )
+ return status;
+
+ for( k = 0; k < di*3; k += 3 )
+ {
+ int a = cvRound( buffer[k]*post_coeffs[0] + post_coeffs[1] );
+ int b = cvRound( buffer[k+1]*post_coeffs[2] + post_coeffs[3] );
+ int c = cvRound( buffer[k+2]*post_coeffs[4] + post_coeffs[5] );
+ dst1[k] = CV_CAST_8U(a);
+ dst1[k+1] = CV_CAST_8U(b);
+ dst1[k+2] = CV_CAST_8U(c);
+ }
+ }
+ }
+
+ return CV_OK;
+}
+
+
+/****************************************************************************************\
+* RGB <-> HSV *
+\****************************************************************************************/
+
+static const uchar icvHue255To180[] =
+{
+ 0, 1, 1, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11,
+ 11, 12, 13, 13, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22,
+ 23, 23, 24, 25, 25, 26, 27, 28, 28, 29, 30, 30, 31, 32, 32, 33,
+ 34, 35, 35, 36, 37, 37, 38, 39, 40, 40, 41, 42, 42, 43, 44, 44,
+ 45, 46, 47, 47, 48, 49, 49, 50, 51, 52, 52, 53, 54, 54, 55, 56,
+ 56, 57, 58, 59, 59, 60, 61, 61, 62, 63, 64, 64, 65, 66, 66, 67,
+ 68, 68, 69, 70, 71, 71, 72, 73, 73, 74, 75, 76, 76, 77, 78, 78,
+ 79, 80, 80, 81, 82, 83, 83, 84, 85, 85, 86, 87, 88, 88, 89, 90,
+ 90, 91, 92, 92, 93, 94, 95, 95, 96, 97, 97, 98, 99, 100, 100, 101,
+ 102, 102, 103, 104, 104, 105, 106, 107, 107, 108, 109, 109, 110, 111, 112, 112,
+ 113, 114, 114, 115, 116, 116, 117, 118, 119, 119, 120, 121, 121, 122, 123, 124,
+ 124, 125, 126, 126, 127, 128, 128, 129, 130, 131, 131, 132, 133, 133, 134, 135,
+ 136, 136, 137, 138, 138, 139, 140, 140, 141, 142, 143, 143, 144, 145, 145, 146,
+ 147, 148, 148, 149, 150, 150, 151, 152, 152, 153, 154, 155, 155, 156, 157, 157,
+ 158, 159, 160, 160, 161, 162, 162, 163, 164, 164, 165, 166, 167, 167, 168, 169,
+ 169, 170, 171, 172, 172, 173, 174, 174, 175, 176, 176, 177, 178, 179, 179, 180
+};
+
+
+static const uchar icvHue180To255[] =
+{
+ 0, 1, 3, 4, 6, 7, 9, 10, 11, 13, 14, 16, 17, 18, 20, 21,
+ 23, 24, 26, 27, 28, 30, 31, 33, 34, 35, 37, 38, 40, 41, 43, 44,
+ 45, 47, 48, 50, 51, 52, 54, 55, 57, 58, 60, 61, 62, 64, 65, 67,
+ 68, 69, 71, 72, 74, 75, 77, 78, 79, 81, 82, 84, 85, 86, 88, 89,
+ 91, 92, 94, 95, 96, 98, 99, 101, 102, 103, 105, 106, 108, 109, 111, 112,
+ 113, 115, 116, 118, 119, 120, 122, 123, 125, 126, 128, 129, 130, 132, 133, 135,
+ 136, 137, 139, 140, 142, 143, 145, 146, 147, 149, 150, 152, 153, 154, 156, 157,
+ 159, 160, 162, 163, 164, 166, 167, 169, 170, 171, 173, 174, 176, 177, 179, 180,
+ 181, 183, 184, 186, 187, 188, 190, 191, 193, 194, 196, 197, 198, 200, 201, 203,
+ 204, 205, 207, 208, 210, 211, 213, 214, 215, 217, 218, 220, 221, 222, 224, 225,
+ 227, 228, 230, 231, 232, 234, 235, 237, 238, 239, 241, 242, 244, 245, 247, 248,
+ 249, 251, 252, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+};
+
+
+static CvStatus CV_STDCALL
+icvBGRx2HSV_8u_CnC3R( const uchar* src, int srcstep, uchar* dst, int dststep,
+ CvSize size, int src_cn, int blue_idx )
+{
+ const int hsv_shift = 12;
+
+ static const int div_table[] = {
+ 0, 1044480, 522240, 348160, 261120, 208896, 174080, 149211,
+ 130560, 116053, 104448, 94953, 87040, 80345, 74606, 69632,
+ 65280, 61440, 58027, 54973, 52224, 49737, 47476, 45412,
+ 43520, 41779, 40172, 38684, 37303, 36017, 34816, 33693,
+ 32640, 31651, 30720, 29842, 29013, 28229, 27486, 26782,
+ 26112, 25475, 24869, 24290, 23738, 23211, 22706, 22223,
+ 21760, 21316, 20890, 20480, 20086, 19707, 19342, 18991,
+ 18651, 18324, 18008, 17703, 17408, 17123, 16846, 16579,
+ 16320, 16069, 15825, 15589, 15360, 15137, 14921, 14711,
+ 14507, 14308, 14115, 13926, 13743, 13565, 13391, 13221,
+ 13056, 12895, 12738, 12584, 12434, 12288, 12145, 12006,
+ 11869, 11736, 11605, 11478, 11353, 11231, 11111, 10995,
+ 10880, 10768, 10658, 10550, 10445, 10341, 10240, 10141,
+ 10043, 9947, 9854, 9761, 9671, 9582, 9495, 9410,
+ 9326, 9243, 9162, 9082, 9004, 8927, 8852, 8777,
+ 8704, 8632, 8561, 8492, 8423, 8356, 8290, 8224,
+ 8160, 8097, 8034, 7973, 7913, 7853, 7795, 7737,
+ 7680, 7624, 7569, 7514, 7461, 7408, 7355, 7304,
+ 7253, 7203, 7154, 7105, 7057, 7010, 6963, 6917,
+ 6872, 6827, 6782, 6739, 6695, 6653, 6611, 6569,
+ 6528, 6487, 6447, 6408, 6369, 6330, 6292, 6254,
+ 6217, 6180, 6144, 6108, 6073, 6037, 6003, 5968,
+ 5935, 5901, 5868, 5835, 5803, 5771, 5739, 5708,
+ 5677, 5646, 5615, 5585, 5556, 5526, 5497, 5468,
+ 5440, 5412, 5384, 5356, 5329, 5302, 5275, 5249,
+ 5222, 5196, 5171, 5145, 5120, 5095, 5070, 5046,
+ 5022, 4998, 4974, 4950, 4927, 4904, 4881, 4858,
+ 4836, 4813, 4791, 4769, 4748, 4726, 4705, 4684,
+ 4663, 4642, 4622, 4601, 4581, 4561, 4541, 4522,
+ 4502, 4483, 4464, 4445, 4426, 4407, 4389, 4370,
+ 4352, 4334, 4316, 4298, 4281, 4263, 4246, 4229,
+ 4212, 4195, 4178, 4161, 4145, 4128, 4112, 4096
+ };
+
+ int i;
+ if( icvRGB2HSV_8u_C3R_p )
+ {
+ CvStatus status = icvBGRx2ABC_IPP_8u_CnC3R( src, srcstep, dst, dststep, size,
+ src_cn, blue_idx, icvRGB2HSV_8u_C3R_p );
+ if( status >= 0 )
+ {
+ size.width *= 3;
+ for( ; size.height--; dst += dststep )
+ {
+ for( i = 0; i <= size.width - 12; i += 12 )
+ {
+ uchar t0 = icvHue255To180[dst[i]], t1 = icvHue255To180[dst[i+3]];
+ dst[i] = t0; dst[i+3] = t1;
+ t0 = icvHue255To180[dst[i+6]]; t1 = icvHue255To180[dst[i+9]];
+ dst[i+6] = t0; dst[i+9] = t1;
+ }
+ for( ; i < size.width; i += 3 )
+ dst[i] = icvHue255To180[dst[i]];
+ }
+ }
+ return status;
+ }
+
+ srcstep -= size.width*src_cn;
+ size.width *= 3;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i += 3, src += src_cn )
+ {
+ int b = (src)[blue_idx], g = (src)[1], r = (src)[2^blue_idx];
+ int h, s, v = b;
+ int vmin = b, diff;
+ int vr, vg;
+
+ CV_CALC_MAX_8U( v, g );
+ CV_CALC_MAX_8U( v, r );
+ CV_CALC_MIN_8U( vmin, g );
+ CV_CALC_MIN_8U( vmin, r );
+
+ diff = v - vmin;
+ vr = v == r ? -1 : 0;
+ vg = v == g ? -1 : 0;
+
+ s = diff * div_table[v] >> hsv_shift;
+ h = (vr & (g - b)) +
+ (~vr & ((vg & (b - r + 2 * diff)) + ((~vg) & (r - g + 4 * diff))));
+ h = ((h * div_table[diff] * 15 + (1 << (hsv_shift + 6))) >> (7 + hsv_shift))\
+ + (h < 0 ? 30*6 : 0);
+
+ dst[i] = (uchar)h;
+ dst[i+1] = (uchar)s;
+ dst[i+2] = (uchar)v;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvBGRx2HSV_32f_CnC3R( const float* src, int srcstep,
+ float* dst, int dststep,
+ CvSize size, int src_cn, int blue_idx )
+{
+ int i;
+ srcstep /= sizeof(src[0]);
+ dststep /= sizeof(dst[0]);
+ srcstep -= size.width*src_cn;
+ size.width *= 3;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i += 3, src += src_cn )
+ {
+ float b = src[blue_idx], g = src[1], r = src[2^blue_idx];
+ float h, s, v;
+
+ float vmin, diff;
+
+ v = vmin = r;
+ if( v < g ) v = g;
+ if( v < b ) v = b;
+ if( vmin > g ) vmin = g;
+ if( vmin > b ) vmin = b;
+
+ diff = v - vmin;
+ s = diff/(float)(fabs(v) + FLT_EPSILON);
+ diff = (float)(60./(diff + FLT_EPSILON));
+ if( v == r )
+ h = (g - b)*diff;
+ else if( v == g )
+ h = (b - r)*diff + 120.f;
+ else
+ h = (r - g)*diff + 240.f;
+
+ if( h < 0 ) h += 360.f;
+
+ dst[i] = h;
+ dst[i+1] = s;
+ dst[i+2] = v;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvHSV2BGRx_32f_C3CnR( const float* src, int srcstep, float* dst,
+ int dststep, CvSize size, int dst_cn, int blue_idx )
+{
+ int i;
+ srcstep /= sizeof(src[0]);
+ dststep /= sizeof(dst[0]);
+ dststep -= size.width*dst_cn;
+ size.width *= 3;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i += 3, dst += dst_cn )
+ {
+ float h = src[i], s = src[i+1], v = src[i+2];
+ float b, g, r;
+
+ if( s == 0 )
+ b = g = r = v;
+ else
+ {
+ static const int sector_data[][3]=
+ {{1,3,0}, {1,0,2}, {3,0,1}, {0,2,1}, {0,1,3}, {2,1,0}};
+ float tab[4];
+ int sector;
+ h *= 0.016666666666666666f; // h /= 60;
+ if( h < 0 )
+ do h += 6; while( h < 0 );
+ else if( h >= 6 )
+ do h -= 6; while( h >= 6 );
+ sector = cvFloor(h);
+ h -= sector;
+
+ tab[0] = v;
+ tab[1] = v*(1.f - s);
+ tab[2] = v*(1.f - s*h);
+ tab[3] = v*(1.f - s*(1.f - h));
+
+ b = tab[sector_data[sector][0]];
+ g = tab[sector_data[sector][1]];
+ r = tab[sector_data[sector][2]];
+ }
+
+ dst[blue_idx] = b;
+ dst[1] = g;
+ dst[blue_idx^2] = r;
+ if( dst_cn == 4 )
+ dst[3] = 0;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvHSV2BGRx_8u_C3CnR( const uchar* src, int srcstep, uchar* dst, int dststep,
+ CvSize size, int dst_cn, int blue_idx )
+{
+ static const float pre_coeffs[] = { 2.f, 0.f, 0.0039215686274509803f, 0.f, 1.f, 0.f };
+
+ if( icvHSV2RGB_8u_C3R_p )
+ {
+ int block_size = MIN(1 << 14, size.width);
+ uchar* buffer;
+ int i, di, k;
+ CvStatus status = CV_OK;
+
+ buffer = (uchar*)cvStackAlloc( block_size*3*sizeof(buffer[0]) );
+ dststep -= size.width*dst_cn;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i += block_size )
+ {
+ const uchar* src1 = src + i*3;
+ di = MIN(block_size, size.width - i);
+ for( k = 0; k < di*3; k += 3 )
+ {
+ uchar h = icvHue180To255[src1[k]];
+ uchar s = src1[k+1];
+ uchar v = src1[k+2];
+ buffer[k] = h;
+ buffer[k+1] = s;
+ buffer[k+2] = v;
+ }
+
+ status = icvHSV2RGB_8u_C3R_p( buffer, di*3,
+ buffer, di*3, cvSize(di,1) );
+ if( status < 0 )
+ return status;
+
+ for( k = 0; k < di*3; k += 3, dst += dst_cn )
+ {
+ uchar r = buffer[k];
+ uchar g = buffer[k+1];
+ uchar b = buffer[k+2];
+ dst[blue_idx] = b;
+ dst[1] = g;
+ dst[blue_idx^2] = r;
+ if( dst_cn == 4 )
+ dst[3] = 0;
+ }
+ }
+ }
+
+ return CV_OK;
+ }
+
+ return icvABC2BGRx_8u_C3CnR( src, srcstep, dst, dststep, size, dst_cn, blue_idx,
+ (CvColorCvtFunc2)icvHSV2BGRx_32f_C3CnR, pre_coeffs, 0 );
+}
+
+
+/****************************************************************************************\
+* RGB <-> HLS *
+\****************************************************************************************/
+
+static CvStatus CV_STDCALL
+icvBGRx2HLS_32f_CnC3R( const float* src, int srcstep, float* dst, int dststep,
+ CvSize size, int src_cn, int blue_idx )
+{
+ int i;
+
+ if( icvRGB2HLS_32f_C3R_p )
+ {
+ CvStatus status = icvBGRx2ABC_IPP_32f_CnC3R( src, srcstep, dst, dststep, size,
+ src_cn, blue_idx, icvRGB2HLS_32f_C3R_p );
+ if( status >= 0 )
+ {
+ size.width *= 3;
+ dststep /= sizeof(dst[0]);
+
+ for( ; size.height--; dst += dststep )
+ {
+ for( i = 0; i <= size.width - 12; i += 12 )
+ {
+ float t0 = dst[i]*360.f, t1 = dst[i+3]*360.f;
+ dst[i] = t0; dst[i+3] = t1;
+ t0 = dst[i+6]*360.f; t1 = dst[i+9]*360.f;
+ dst[i+6] = t0; dst[i+9] = t1;
+ }
+ for( ; i < size.width; i += 3 )
+ dst[i] = dst[i]*360.f;
+ }
+ }
+ return status;
+ }
+
+ srcstep /= sizeof(src[0]);
+ dststep /= sizeof(dst[0]);
+ srcstep -= size.width*src_cn;
+ size.width *= 3;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i += 3, src += src_cn )
+ {
+ float b = src[blue_idx], g = src[1], r = src[2^blue_idx];
+ float h = 0.f, s = 0.f, l;
+ float vmin, vmax, diff;
+
+ vmax = vmin = r;
+ if( vmax < g ) vmax = g;
+ if( vmax < b ) vmax = b;
+ if( vmin > g ) vmin = g;
+ if( vmin > b ) vmin = b;
+
+ diff = vmax - vmin;
+ l = (vmax + vmin)*0.5f;
+
+ if( diff > FLT_EPSILON )
+ {
+ s = l < 0.5f ? diff/(vmax + vmin) : diff/(2 - vmax - vmin);
+ diff = 60.f/diff;
+
+ if( vmax == r )
+ h = (g - b)*diff;
+ else if( vmax == g )
+ h = (b - r)*diff + 120.f;
+ else
+ h = (r - g)*diff + 240.f;
+
+ if( h < 0.f ) h += 360.f;
+ }
+
+ dst[i] = h;
+ dst[i+1] = l;
+ dst[i+2] = s;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvHLS2BGRx_32f_C3CnR( const float* src, int srcstep, float* dst, int dststep,
+ CvSize size, int dst_cn, int blue_idx )
+{
+ int i;
+ srcstep /= sizeof(src[0]);
+ dststep /= sizeof(dst[0]);
+
+ if( icvHLS2RGB_32f_C3R_p )
+ {
+ int block_size = MIN(1 << 10, size.width);
+ float* buffer;
+ int di, k;
+ CvStatus status = CV_OK;
+
+ buffer = (float*)cvStackAlloc( block_size*3*sizeof(buffer[0]) );
+ dststep -= size.width*dst_cn;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i += block_size )
+ {
+ const float* src1 = src + i*3;
+ di = MIN(block_size, size.width - i);
+ for( k = 0; k < di*3; k += 3 )
+ {
+ float h = src1[k]*0.0027777777777777779f; // /360.
+ float s = src1[k+1], v = src1[k+2];
+ buffer[k] = h; buffer[k+1] = s; buffer[k+2] = v;
+ }
+
+ status = icvHLS2RGB_32f_C3R_p( buffer, di*3*sizeof(dst[0]),
+ buffer, di*3*sizeof(dst[0]), cvSize(di,1) );
+ if( status < 0 )
+ return status;
+
+ for( k = 0; k < di*3; k += 3, dst += dst_cn )
+ {
+ float r = buffer[k], g = buffer[k+1], b = buffer[k+2];
+ dst[blue_idx] = b; dst[1] = g; dst[blue_idx^2] = r;
+ if( dst_cn == 4 )
+ dst[3] = 0;
+ }
+ }
+ }
+
+ return CV_OK;
+ }
+
+ dststep -= size.width*dst_cn;
+ size.width *= 3;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i += 3, dst += dst_cn )
+ {
+ float h = src[i], l = src[i+1], s = src[i+2];
+ float b, g, r;
+
+ if( s == 0 )
+ b = g = r = l;
+ else
+ {
+ static const int sector_data[][3]=
+ {{1,3,0}, {1,0,2}, {3,0,1}, {0,2,1}, {0,1,3}, {2,1,0}};
+ float tab[4];
+ int sector;
+
+ float p2 = l <= 0.5f ? l*(1 + s) : l + s - l*s;
+ float p1 = 2*l - p2;
+
+ h *= 0.016666666666666666f; // h /= 60;
+ if( h < 0 )
+ do h += 6; while( h < 0 );
+ else if( h >= 6 )
+ do h -= 6; while( h >= 6 );
+
+ assert( 0 <= h && h < 6 );
+ sector = cvFloor(h);
+ h -= sector;
+
+ tab[0] = p2;
+ tab[1] = p1;
+ tab[2] = p1 + (p2 - p1)*(1-h);
+ tab[3] = p1 + (p2 - p1)*h;
+
+ b = tab[sector_data[sector][0]];
+ g = tab[sector_data[sector][1]];
+ r = tab[sector_data[sector][2]];
+ }
+
+ dst[blue_idx] = b;
+ dst[1] = g;
+ dst[blue_idx^2] = r;
+ if( dst_cn == 4 )
+ dst[3] = 0;
+ }
+ }
+
+ return CV_OK;
+}
+
+static CvStatus CV_STDCALL
+icvBGRx2HLS_8u_CnC3R( const uchar* src, int srcstep, uchar* dst, int dststep,
+ CvSize size, int src_cn, int blue_idx )
+{
+ static const float post_coeffs[] = { 0.5f, 0.f, 255.f, 0.f, 255.f, 0.f };
+
+ if( icvRGB2HLS_8u_C3R_p )
+ {
+ CvStatus status = icvBGRx2ABC_IPP_8u_CnC3R( src, srcstep, dst, dststep, size,
+ src_cn, blue_idx, icvRGB2HLS_8u_C3R_p );
+ if( status >= 0 )
+ {
+ size.width *= 3;
+ for( ; size.height--; dst += dststep )
+ {
+ int i;
+ for( i = 0; i <= size.width - 12; i += 12 )
+ {
+ uchar t0 = icvHue255To180[dst[i]], t1 = icvHue255To180[dst[i+3]];
+ dst[i] = t0; dst[i+3] = t1;
+ t0 = icvHue255To180[dst[i+6]]; t1 = icvHue255To180[dst[i+9]];
+ dst[i+6] = t0; dst[i+9] = t1;
+ }
+ for( ; i < size.width; i += 3 )
+ dst[i] = icvHue255To180[dst[i]];
+ }
+ }
+ return status;
+ }
+
+ return icvBGRx2ABC_8u_CnC3R( src, srcstep, dst, dststep, size, src_cn, blue_idx,
+ (CvColorCvtFunc2)icvBGRx2HLS_32f_CnC3R, 1, post_coeffs );
+}
+
+
+static CvStatus CV_STDCALL
+icvHLS2BGRx_8u_C3CnR( const uchar* src, int srcstep, uchar* dst, int dststep,
+ CvSize size, int dst_cn, int blue_idx )
+{
+ static const float pre_coeffs[] = { 2.f, 0.f, 0.0039215686274509803f, 0.f,
+ 0.0039215686274509803f, 0.f };
+
+ if( icvHLS2RGB_8u_C3R_p )
+ {
+ int block_size = MIN(1 << 14, size.width);
+ uchar* buffer;
+ int i, di, k;
+ CvStatus status = CV_OK;
+
+ buffer = (uchar*)cvStackAlloc( block_size*3*sizeof(buffer[0]) );
+ dststep -= size.width*dst_cn;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i += block_size )
+ {
+ const uchar* src1 = src + i*3;
+ di = MIN(block_size, size.width - i);
+ for( k = 0; k < di*3; k += 3 )
+ {
+ uchar h = icvHue180To255[src1[k]];
+ uchar l = src1[k+1];
+ uchar s = src1[k+2];
+ buffer[k] = h;
+ buffer[k+1] = l;
+ buffer[k+2] = s;
+ }
+
+ status = icvHLS2RGB_8u_C3R_p( buffer, di*3,
+ buffer, di*3, cvSize(di,1) );
+ if( status < 0 )
+ return status;
+
+ for( k = 0; k < di*3; k += 3, dst += dst_cn )
+ {
+ uchar r = buffer[k];
+ uchar g = buffer[k+1];
+ uchar b = buffer[k+2];
+ dst[blue_idx] = b;
+ dst[1] = g;
+ dst[blue_idx^2] = r;
+ if( dst_cn == 4 )
+ dst[3] = 0;
+ }
+ }
+ }
+
+ return CV_OK;
+ }
+
+ return icvABC2BGRx_8u_C3CnR( src, srcstep, dst, dststep, size, dst_cn, blue_idx,
+ (CvColorCvtFunc2)icvHLS2BGRx_32f_C3CnR, pre_coeffs, 1 );
+}
+
+
+/****************************************************************************************\
+* RGB <-> L*a*b* *
+\****************************************************************************************/
+
+#define labXr_32f 0.433953f /* = xyzXr_32f / 0.950456 */
+#define labXg_32f 0.376219f /* = xyzXg_32f / 0.950456 */
+#define labXb_32f 0.189828f /* = xyzXb_32f / 0.950456 */
+
+#define labYr_32f 0.212671f /* = xyzYr_32f */
+#define labYg_32f 0.715160f /* = xyzYg_32f */
+#define labYb_32f 0.072169f /* = xyzYb_32f */
+
+#define labZr_32f 0.017758f /* = xyzZr_32f / 1.088754 */
+#define labZg_32f 0.109477f /* = xyzZg_32f / 1.088754 */
+#define labZb_32f 0.872766f /* = xyzZb_32f / 1.088754 */
+
+#define labRx_32f 3.0799327f /* = xyzRx_32f * 0.950456 */
+#define labRy_32f (-1.53715f) /* = xyzRy_32f */
+#define labRz_32f (-0.542782f)/* = xyzRz_32f * 1.088754 */
+
+#define labGx_32f (-0.921235f)/* = xyzGx_32f * 0.950456 */
+#define labGy_32f 1.875991f /* = xyzGy_32f */
+#define labGz_32f 0.04524426f /* = xyzGz_32f * 1.088754 */
+
+#define labBx_32f 0.0528909755f /* = xyzBx_32f * 0.950456 */
+#define labBy_32f (-0.204043f) /* = xyzBy_32f */
+#define labBz_32f 1.15115158f /* = xyzBz_32f * 1.088754 */
+
+#define labT_32f 0.008856f
+
+#define labT fix(labT_32f*255,lab_shift)
+
+#undef lab_shift
+#define lab_shift 10
+#define labXr fix(labXr_32f,lab_shift)
+#define labXg fix(labXg_32f,lab_shift)
+#define labXb fix(labXb_32f,lab_shift)
+
+#define labYr fix(labYr_32f,lab_shift)
+#define labYg fix(labYg_32f,lab_shift)
+#define labYb fix(labYb_32f,lab_shift)
+
+#define labZr fix(labZr_32f,lab_shift)
+#define labZg fix(labZg_32f,lab_shift)
+#define labZb fix(labZb_32f,lab_shift)
+
+#define labSmallScale_32f 7.787f
+#define labSmallShift_32f 0.13793103448275862f /* 16/116 */
+#define labLScale_32f 116.f
+#define labLShift_32f 16.f
+#define labLScale2_32f 903.3f
+
+#define labSmallScale fix(31.27 /* labSmallScale_32f*(1<<lab_shift)/255 */,lab_shift)
+#define labSmallShift fix(141.24138 /* labSmallScale_32f*(1<<lab) */,lab_shift)
+#define labLScale fix(295.8 /* labLScale_32f*255/100 */,lab_shift)
+#define labLShift fix(41779.2 /* labLShift_32f*1024*255/100 */,lab_shift)
+#define labLScale2 fix(labLScale2_32f*0.01,lab_shift)
+
+/* 1024*(([0..511]./255)**(1./3)) */
+static ushort icvLabCubeRootTab[] = {
+ 0, 161, 203, 232, 256, 276, 293, 308, 322, 335, 347, 359, 369, 379, 389, 398,
+ 406, 415, 423, 430, 438, 445, 452, 459, 465, 472, 478, 484, 490, 496, 501, 507,
+ 512, 517, 523, 528, 533, 538, 542, 547, 552, 556, 561, 565, 570, 574, 578, 582,
+ 586, 590, 594, 598, 602, 606, 610, 614, 617, 621, 625, 628, 632, 635, 639, 642,
+ 645, 649, 652, 655, 659, 662, 665, 668, 671, 674, 677, 680, 684, 686, 689, 692,
+ 695, 698, 701, 704, 707, 710, 712, 715, 718, 720, 723, 726, 728, 731, 734, 736,
+ 739, 741, 744, 747, 749, 752, 754, 756, 759, 761, 764, 766, 769, 771, 773, 776,
+ 778, 780, 782, 785, 787, 789, 792, 794, 796, 798, 800, 803, 805, 807, 809, 811,
+ 813, 815, 818, 820, 822, 824, 826, 828, 830, 832, 834, 836, 838, 840, 842, 844,
+ 846, 848, 850, 852, 854, 856, 857, 859, 861, 863, 865, 867, 869, 871, 872, 874,
+ 876, 878, 880, 882, 883, 885, 887, 889, 891, 892, 894, 896, 898, 899, 901, 903,
+ 904, 906, 908, 910, 911, 913, 915, 916, 918, 920, 921, 923, 925, 926, 928, 929,
+ 931, 933, 934, 936, 938, 939, 941, 942, 944, 945, 947, 949, 950, 952, 953, 955,
+ 956, 958, 959, 961, 962, 964, 965, 967, 968, 970, 971, 973, 974, 976, 977, 979,
+ 980, 982, 983, 985, 986, 987, 989, 990, 992, 993, 995, 996, 997, 999, 1000, 1002,
+ 1003, 1004, 1006, 1007, 1009, 1010, 1011, 1013, 1014, 1015, 1017, 1018, 1019, 1021, 1022, 1024,
+ 1025, 1026, 1028, 1029, 1030, 1031, 1033, 1034, 1035, 1037, 1038, 1039, 1041, 1042, 1043, 1044,
+ 1046, 1047, 1048, 1050, 1051, 1052, 1053, 1055, 1056, 1057, 1058, 1060, 1061, 1062, 1063, 1065,
+ 1066, 1067, 1068, 1070, 1071, 1072, 1073, 1074, 1076, 1077, 1078, 1079, 1081, 1082, 1083, 1084,
+ 1085, 1086, 1088, 1089, 1090, 1091, 1092, 1094, 1095, 1096, 1097, 1098, 1099, 1101, 1102, 1103,
+ 1104, 1105, 1106, 1107, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1117, 1118, 1119, 1120, 1121,
+ 1122, 1123, 1124, 1125, 1127, 1128, 1129, 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1138, 1139,
+ 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1154, 1155, 1156,
+ 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172,
+ 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188,
+ 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204,
+ 1205, 1206, 1207, 1208, 1209, 1210, 1211, 1212, 1213, 1214, 1215, 1215, 1216, 1217, 1218, 1219,
+ 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1230, 1231, 1232, 1233, 1234,
+ 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249,
+ 1250, 1251, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259, 1259, 1260, 1261, 1262, 1263,
+ 1264, 1265, 1266, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1273, 1274, 1275, 1276, 1277,
+ 1278, 1279, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1285, 1286, 1287, 1288, 1289, 1290, 1291
+};
+
+
+static CvStatus CV_STDCALL
+icvBGRx2Lab_8u_CnC3R( const uchar* src, int srcstep, uchar* dst, int dststep,
+ CvSize size, int src_cn, int blue_idx )
+{
+ int i;
+
+ /*if( icvBGR2Lab_8u_C3R_p )
+ return icvBGRx2ABC_IPP_8u_CnC3R( src, srcstep, dst, dststep, size,
+ src_cn, blue_idx^2, icvBGR2Lab_8u_C3R_p );*/
+
+ srcstep -= size.width*src_cn;
+ size.width *= 3;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i += 3, src += src_cn )
+ {
+ int b = src[blue_idx], g = src[1], r = src[2^blue_idx];
+ int x, y, z, f;
+ int L, a;
+
+ x = b*labXb + g*labXg + r*labXr;
+ y = b*labYb + g*labYg + r*labYr;
+ z = b*labZb + g*labZg + r*labZr;
+
+ f = x > labT;
+ x = CV_DESCALE( x, lab_shift );
+
+ if( f )
+ assert( (unsigned)x < 512 ), x = icvLabCubeRootTab[x];
+ else
+ x = CV_DESCALE(x*labSmallScale + labSmallShift,lab_shift);
+
+ f = z > labT;
+ z = CV_DESCALE( z, lab_shift );
+
+ if( f )
+ assert( (unsigned)z < 512 ), z = icvLabCubeRootTab[z];
+ else
+ z = CV_DESCALE(z*labSmallScale + labSmallShift,lab_shift);
+
+ f = y > labT;
+ y = CV_DESCALE( y, lab_shift );
+
+ if( f )
+ {
+ assert( (unsigned)y < 512 ), y = icvLabCubeRootTab[y];
+ L = CV_DESCALE(y*labLScale - labLShift, 2*lab_shift );
+ }
+ else
+ {
+ L = CV_DESCALE(y*labLScale2,lab_shift);
+ y = CV_DESCALE(y*labSmallScale + labSmallShift,lab_shift);
+ }
+
+ a = CV_DESCALE( 500*(x - y), lab_shift ) + 128;
+ b = CV_DESCALE( 200*(y - z), lab_shift ) + 128;
+
+ dst[i] = CV_CAST_8U(L);
+ dst[i+1] = CV_CAST_8U(a);
+ dst[i+2] = CV_CAST_8U(b);
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvBGRx2Lab_32f_CnC3R( const float* src, int srcstep, float* dst, int dststep,
+ CvSize size, int src_cn, int blue_idx )
+{
+ int i;
+ srcstep /= sizeof(src[0]);
+ dststep /= sizeof(dst[0]);
+ srcstep -= size.width*src_cn;
+ size.width *= 3;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i += 3, src += src_cn )
+ {
+ float b = src[blue_idx], g = src[1], r = src[2^blue_idx];
+ float x, y, z;
+ float L, a;
+
+ x = b*labXb_32f + g*labXg_32f + r*labXr_32f;
+ y = b*labYb_32f + g*labYg_32f + r*labYr_32f;
+ z = b*labZb_32f + g*labZg_32f + r*labZr_32f;
+
+ if( x > labT_32f )
+ x = cvCbrt(x);
+ else
+ x = x*labSmallScale_32f + labSmallShift_32f;
+
+ if( z > labT_32f )
+ z = cvCbrt(z);
+ else
+ z = z*labSmallScale_32f + labSmallShift_32f;
+
+ if( y > labT_32f )
+ {
+ y = cvCbrt(y);
+ L = y*labLScale_32f - labLShift_32f;
+ }
+ else
+ {
+ L = y*labLScale2_32f;
+ y = y*labSmallScale_32f + labSmallShift_32f;
+ }
+
+ a = 500.f*(x - y);
+ b = 200.f*(y - z);
+
+ dst[i] = L;
+ dst[i+1] = a;
+ dst[i+2] = b;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvLab2BGRx_32f_C3CnR( const float* src, int srcstep, float* dst, int dststep,
+ CvSize size, int dst_cn, int blue_idx )
+{
+ int i;
+ srcstep /= sizeof(src[0]);
+ dststep /= sizeof(dst[0]);
+ dststep -= size.width*dst_cn;
+ size.width *= 3;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i += 3, dst += dst_cn )
+ {
+ float L = src[i], a = src[i+1], b = src[i+2];
+ float x, y, z;
+ float g, r;
+
+ L = (L + labLShift_32f)*(1.f/labLScale_32f);
+ x = (L + a*0.002f);
+ z = (L - b*0.005f);
+ y = L*L*L;
+ x = x*x*x;
+ z = z*z*z;
+
+ b = x*labBx_32f + y*labBy_32f + z*labBz_32f;
+ g = x*labGx_32f + y*labGy_32f + z*labGz_32f;
+ r = x*labRx_32f + y*labRy_32f + z*labRz_32f;
+
+ dst[blue_idx] = b;
+ dst[1] = g;
+ dst[blue_idx^2] = r;
+ if( dst_cn == 4 )
+ dst[3] = 0;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvLab2BGRx_8u_C3CnR( const uchar* src, int srcstep, uchar* dst, int dststep,
+ CvSize size, int dst_cn, int blue_idx )
+{
+ // L: [0..255] -> [0..100]
+ // a: [0..255] -> [-128..127]
+ // b: [0..255] -> [-128..127]
+ static const float pre_coeffs[] = { 0.39215686274509809f, 0.f, 1.f, -128.f, 1.f, -128.f };
+
+ if( icvLab2BGR_8u_C3R_p )
+ return icvABC2BGRx_IPP_8u_C3CnR( src, srcstep, dst, dststep, size,
+ dst_cn, blue_idx^2, icvLab2BGR_8u_C3R_p );
+
+ return icvABC2BGRx_8u_C3CnR( src, srcstep, dst, dststep, size, dst_cn, blue_idx,
+ (CvColorCvtFunc2)icvLab2BGRx_32f_C3CnR, pre_coeffs, 1 );
+}
+
+
+/****************************************************************************************\
+* RGB <-> L*u*v* *
+\****************************************************************************************/
+
+#define luvUn_32f 0.19793943f
+#define luvVn_32f 0.46831096f
+#define luvYmin_32f 0.05882353f /* 15/255 */
+
+static CvStatus CV_STDCALL
+icvBGRx2Luv_32f_CnC3R( const float* src, int srcstep, float* dst, int dststep,
+ CvSize size, int src_cn, int blue_idx )
+{
+ int i;
+
+ /*if( icvRGB2Luv_32f_C3R_p )
+ return icvBGRx2ABC_IPP_32f_CnC3R( src, srcstep, dst, dststep, size,
+ src_cn, blue_idx, icvRGB2Luv_32f_C3R_p );*/
+
+ srcstep /= sizeof(src[0]);
+ dststep /= sizeof(dst[0]);
+ srcstep -= size.width*src_cn;
+ size.width *= 3;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i += 3, src += src_cn )
+ {
+ float b = src[blue_idx], g = src[1], r = src[2^blue_idx];
+ float x, y, z;
+ float L, u, v, t;
+
+ x = b*xyzXb_32f + g*xyzXg_32f + r*xyzXr_32f;
+ y = b*xyzYb_32f + g*xyzYg_32f + r*xyzYr_32f;
+ z = b*xyzZb_32f + g*xyzZg_32f + r*xyzZr_32f;
+
+ if( !x && !y && !z )
+ L = u = v = 0.f;
+ else
+ {
+ if( y > labT_32f )
+ L = labLScale_32f * cvCbrt(y) - labLShift_32f;
+ else
+ L = labLScale2_32f * y;
+
+ t = 1.f / (x + 15 * y + 3 * z);
+ u = 4.0f * x * t;
+ v = 9.0f * y * t;
+
+ u = 13*L*(u - luvUn_32f);
+ v = 13*L*(v - luvVn_32f);
+ }
+
+ dst[i] = L;
+ dst[i+1] = u;
+ dst[i+2] = v;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvLuv2BGRx_32f_C3CnR( const float* src, int srcstep, float* dst, int dststep,
+ CvSize size, int dst_cn, int blue_idx )
+{
+ int i;
+
+ /*if( icvLuv2RGB_32f_C3R_p )
+ return icvABC2BGRx_IPP_32f_C3CnR( src, srcstep, dst, dststep, size,
+ dst_cn, blue_idx, icvLuv2RGB_32f_C3R_p );*/
+
+ srcstep /= sizeof(src[0]);
+ dststep /= sizeof(dst[0]);
+ dststep -= size.width*dst_cn;
+ size.width *= 3;
+
+ for( ; size.height--; src += srcstep, dst += dststep )
+ {
+ for( i = 0; i < size.width; i += 3, dst += dst_cn )
+ {
+ float L = src[i], u = src[i+1], v = src[i+2];
+ float x, y, z, t, u1, v1, b, g, r;
+
+ if( L >= 8 )
+ {
+ t = (L + labLShift_32f) * (1.f/labLScale_32f);
+ y = t*t*t;
+ }
+ else
+ {
+ y = L * (1.f/labLScale2_32f);
+ L = MAX( L, 0.001f );
+ }
+
+ t = 1.f/(13.f * L);
+ u1 = u*t + luvUn_32f;
+ v1 = v*t + luvVn_32f;
+ x = 2.25f * u1 * y / v1 ;
+ z = (12 - 3 * u1 - 20 * v1) * y / (4 * v1);
+
+ b = xyzBx_32f*x + xyzBy_32f*y + xyzBz_32f*z;
+ g = xyzGx_32f*x + xyzGy_32f*y + xyzGz_32f*z;
+ r = xyzRx_32f*x + xyzRy_32f*y + xyzRz_32f*z;
+
+ dst[blue_idx] = b;
+ dst[1] = g;
+ dst[blue_idx^2] = r;
+ if( dst_cn == 4 )
+ dst[3] = 0.f;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvBGRx2Luv_8u_CnC3R( const uchar* src, int srcstep, uchar* dst, int dststep,
+ CvSize size, int src_cn, int blue_idx )
+{
+ // L: [0..100] -> [0..255]
+ // u: [-134..220] -> [0..255]
+ // v: [-140..122] -> [0..255]
+ //static const float post_coeffs[] = { 2.55f, 0.f, 1.f, 83.f, 1.f, 140.f };
+ static const float post_coeffs[] = { 2.55f, 0.f, 0.72033898305084743f, 96.525423728813564f,
+ 0.99609375f, 139.453125f };
+
+ if( icvRGB2Luv_8u_C3R_p )
+ return icvBGRx2ABC_IPP_8u_CnC3R( src, srcstep, dst, dststep, size,
+ src_cn, blue_idx, icvRGB2Luv_8u_C3R_p );
+
+ return icvBGRx2ABC_8u_CnC3R( src, srcstep, dst, dststep, size, src_cn, blue_idx,
+ (CvColorCvtFunc2)icvBGRx2Luv_32f_CnC3R, 1, post_coeffs );
+}
+
+
+static CvStatus CV_STDCALL
+icvLuv2BGRx_8u_C3CnR( const uchar* src, int srcstep, uchar* dst, int dststep,
+ CvSize size, int dst_cn, int blue_idx )
+{
+ // L: [0..255] -> [0..100]
+ // u: [0..255] -> [-134..220]
+ // v: [0..255] -> [-140..122]
+ static const float pre_coeffs[] = { 0.39215686274509809f, 0.f, 1.388235294117647f, -134.f,
+ 1.003921568627451f, -140.f };
+
+ if( icvLuv2RGB_8u_C3R_p )
+ return icvABC2BGRx_IPP_8u_C3CnR( src, srcstep, dst, dststep, size,
+ dst_cn, blue_idx, icvLuv2RGB_8u_C3R_p );
+
+ return icvABC2BGRx_8u_C3CnR( src, srcstep, dst, dststep, size, dst_cn, blue_idx,
+ (CvColorCvtFunc2)icvLuv2BGRx_32f_C3CnR, pre_coeffs, 1 );
+}
+
+/****************************************************************************************\
+* Bayer Pattern -> RGB conversion *
+\****************************************************************************************/
+
+static CvStatus CV_STDCALL
+icvBayer2BGR_8u_C1C3R( const uchar* bayer0, int bayer_step,
+ uchar *dst0, int dst_step,
+ CvSize size, int code )
+{
+ int blue = code == CV_BayerBG2BGR || code == CV_BayerGB2BGR ? -1 : 1;
+ int start_with_green = code == CV_BayerGB2BGR || code == CV_BayerGR2BGR;
+
+ memset( dst0, 0, size.width*3*sizeof(dst0[0]) );
+ memset( dst0 + (size.height - 1)*dst_step, 0, size.width*3*sizeof(dst0[0]) );
+ dst0 += dst_step + 3 + 1;
+ size.height -= 2;
+ size.width -= 2;
+
+ for( ; size.height-- > 0; bayer0 += bayer_step, dst0 += dst_step )
+ {
+ int t0, t1;
+ const uchar* bayer = bayer0;
+ uchar* dst = dst0;
+ const uchar* bayer_end = bayer + size.width;
+
+ dst[-4] = dst[-3] = dst[-2] = dst[size.width*3-1] =
+ dst[size.width*3] = dst[size.width*3+1] = 0;
+
+ if( size.width <= 0 )
+ continue;
+
+ if( start_with_green )
+ {
+ t0 = (bayer[1] + bayer[bayer_step*2+1] + 1) >> 1;
+ t1 = (bayer[bayer_step] + bayer[bayer_step+2] + 1) >> 1;
+ dst[-blue] = (uchar)t0;
+ dst[0] = bayer[bayer_step+1];
+ dst[blue] = (uchar)t1;
+ bayer++;
+ dst += 3;
+ }
+
+ if( blue > 0 )
+ {
+ for( ; bayer <= bayer_end - 2; bayer += 2, dst += 6 )
+ {
+ t0 = (bayer[0] + bayer[2] + bayer[bayer_step*2] +
+ bayer[bayer_step*2+2] + 2) >> 2;
+ t1 = (bayer[1] + bayer[bayer_step] +
+ bayer[bayer_step+2] + bayer[bayer_step*2+1]+2) >> 2;
+ dst[-1] = (uchar)t0;
+ dst[0] = (uchar)t1;
+ dst[1] = bayer[bayer_step+1];
+
+ t0 = (bayer[2] + bayer[bayer_step*2+2] + 1) >> 1;
+ t1 = (bayer[bayer_step+1] + bayer[bayer_step+3] + 1) >> 1;
+ dst[2] = (uchar)t0;
+ dst[3] = bayer[bayer_step+2];
+ dst[4] = (uchar)t1;
+ }
+ }
+ else
+ {
+ for( ; bayer <= bayer_end - 2; bayer += 2, dst += 6 )
+ {
+ t0 = (bayer[0] + bayer[2] + bayer[bayer_step*2] +
+ bayer[bayer_step*2+2] + 2) >> 2;
+ t1 = (bayer[1] + bayer[bayer_step] +
+ bayer[bayer_step+2] + bayer[bayer_step*2+1]+2) >> 2;
+ dst[1] = (uchar)t0;
+ dst[0] = (uchar)t1;
+ dst[-1] = bayer[bayer_step+1];
+
+ t0 = (bayer[2] + bayer[bayer_step*2+2] + 1) >> 1;
+ t1 = (bayer[bayer_step+1] + bayer[bayer_step+3] + 1) >> 1;
+ dst[4] = (uchar)t0;
+ dst[3] = bayer[bayer_step+2];
+ dst[2] = (uchar)t1;
+ }
+ }
+
+ if( bayer < bayer_end )
+ {
+ t0 = (bayer[0] + bayer[2] + bayer[bayer_step*2] +
+ bayer[bayer_step*2+2] + 2) >> 2;
+ t1 = (bayer[1] + bayer[bayer_step] +
+ bayer[bayer_step+2] + bayer[bayer_step*2+1]+2) >> 2;
+ dst[-blue] = (uchar)t0;
+ dst[0] = (uchar)t1;
+ dst[blue] = bayer[bayer_step+1];
+ bayer++;
+ dst += 3;
+ }
+
+ blue = -blue;
+ start_with_green = !start_with_green;
+ }
+
+ return CV_OK;
+}
+
+
+/****************************************************************************************\
+* The main function *
+\****************************************************************************************/
+
+CV_IMPL void
+cvCvtColor( const CvArr* srcarr, CvArr* dstarr, int code )
+{
+ CV_FUNCNAME( "cvCvtColor" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize size;
+ int src_step, dst_step;
+ int src_cn, dst_cn, depth;
+ CvColorCvtFunc0 func0 = 0;
+ CvColorCvtFunc1 func1 = 0;
+ CvColorCvtFunc2 func2 = 0;
+ CvColorCvtFunc3 func3 = 0;
+ int param[] = { 0, 0, 0, 0 };
+
+ CV_CALL( src = cvGetMat( srcarr, &srcstub ));
+ CV_CALL( dst = cvGetMat( dstarr, &dststub ));
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( !CV_ARE_DEPTHS_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ depth = CV_MAT_DEPTH(src->type);
+ if( depth != CV_8U && depth != CV_16U && depth != CV_32F )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ src_cn = CV_MAT_CN( src->type );
+ dst_cn = CV_MAT_CN( dst->type );
+ size = cvGetMatSize( src );
+ src_step = src->step;
+ dst_step = dst->step;
+
+ if( CV_IS_MAT_CONT(src->type & dst->type) &&
+ code != CV_BayerBG2BGR && code != CV_BayerGB2BGR &&
+ code != CV_BayerRG2BGR && code != CV_BayerGR2BGR )
+ {
+ size.width *= size.height;
+ size.height = 1;
+ src_step = dst_step = CV_STUB_STEP;
+ }
+
+ switch( code )
+ {
+ case CV_BGR2BGRA:
+ case CV_RGB2BGRA:
+ if( src_cn != 3 || dst_cn != 4 )
+ CV_ERROR( CV_BadNumChannels,
+ "Incorrect number of channels for this conversion code" );
+
+ func1 = depth == CV_8U ? (CvColorCvtFunc1)icvBGR2BGRx_8u_C3C4R :
+ depth == CV_16U ? (CvColorCvtFunc1)icvBGR2BGRx_16u_C3C4R :
+ depth == CV_32F ? (CvColorCvtFunc1)icvBGR2BGRx_32f_C3C4R : 0;
+ param[0] = code == CV_BGR2BGRA ? 0 : 2; // blue_idx
+ break;
+
+ case CV_BGRA2BGR:
+ case CV_RGBA2BGR:
+ case CV_RGB2BGR:
+ if( (src_cn != 3 && src_cn != 4) || dst_cn != 3 )
+ CV_ERROR( CV_BadNumChannels,
+ "Incorrect number of channels for this conversion code" );
+
+ func2 = depth == CV_8U ? (CvColorCvtFunc2)icvBGRx2BGR_8u_CnC3R :
+ depth == CV_16U ? (CvColorCvtFunc2)icvBGRx2BGR_16u_CnC3R :
+ depth == CV_32F ? (CvColorCvtFunc2)icvBGRx2BGR_32f_CnC3R : 0;
+ param[0] = src_cn;
+ param[1] = code == CV_BGRA2BGR ? 0 : 2; // blue_idx
+ break;
+
+ case CV_BGRA2RGBA:
+ if( src_cn != 4 || dst_cn != 4 )
+ CV_ERROR( CV_BadNumChannels,
+ "Incorrect number of channels for this conversion code" );
+
+ func0 = depth == CV_8U ? (CvColorCvtFunc0)icvBGRA2RGBA_8u_C4R :
+ depth == CV_16U ? (CvColorCvtFunc0)icvBGRA2RGBA_16u_C4R :
+ depth == CV_32F ? (CvColorCvtFunc0)icvBGRA2RGBA_32f_C4R : 0;
+ break;
+
+ case CV_BGR2BGR565:
+ case CV_BGR2BGR555:
+ case CV_RGB2BGR565:
+ case CV_RGB2BGR555:
+ case CV_BGRA2BGR565:
+ case CV_BGRA2BGR555:
+ case CV_RGBA2BGR565:
+ case CV_RGBA2BGR555:
+ if( (src_cn != 3 && src_cn != 4) || dst_cn != 2 )
+ CV_ERROR( CV_BadNumChannels,
+ "Incorrect number of channels for this conversion code" );
+
+ if( depth != CV_8U )
+ CV_ERROR( CV_BadDepth,
+ "Conversion to/from 16-bit packed RGB format "
+ "is only possible for 8-bit images (8-bit grayscale, 888 BGR/RGB or 8888 BGRA/RGBA)" );
+
+ func3 = (CvColorCvtFunc3)icvBGRx2BGR5x5_8u_CnC2R;
+ param[0] = src_cn;
+ param[1] = code == CV_BGR2BGR565 || code == CV_BGR2BGR555 ||
+ code == CV_BGRA2BGR565 || code == CV_BGRA2BGR555 ? 0 : 2; // blue_idx
+ param[2] = code == CV_BGR2BGR565 || code == CV_RGB2BGR565 ||
+ code == CV_BGRA2BGR565 || code == CV_RGBA2BGR565 ? 6 : 5; // green_bits
+ break;
+
+ case CV_BGR5652BGR:
+ case CV_BGR5552BGR:
+ case CV_BGR5652RGB:
+ case CV_BGR5552RGB:
+ case CV_BGR5652BGRA:
+ case CV_BGR5552BGRA:
+ case CV_BGR5652RGBA:
+ case CV_BGR5552RGBA:
+ if( src_cn != 2 || (dst_cn != 3 && dst_cn != 4))
+ CV_ERROR( CV_BadNumChannels,
+ "Incorrect number of channels for this conversion code" );
+
+ if( depth != CV_8U )
+ CV_ERROR( CV_BadDepth,
+ "Conversion to/from 16-bit packed BGR format "
+ "is only possible for 8-bit images (8-bit grayscale, 888 BGR/BGR or 8888 BGRA/BGRA)" );
+
+ func3 = (CvColorCvtFunc3)icvBGR5x52BGRx_8u_C2CnR;
+ param[0] = dst_cn;
+ param[1] = code == CV_BGR5652BGR || code == CV_BGR5552BGR ||
+ code == CV_BGR5652BGRA || code == CV_BGR5552BGRA ? 0 : 2; // blue_idx
+ param[2] = code == CV_BGR5652BGR || code == CV_BGR5652RGB ||
+ code == CV_BGR5652BGRA || code == CV_BGR5652RGBA ? 6 : 5; // green_bits
+ break;
+
+ case CV_BGR2GRAY:
+ case CV_BGRA2GRAY:
+ case CV_RGB2GRAY:
+ case CV_RGBA2GRAY:
+ if( (src_cn != 3 && src_cn != 4) || dst_cn != 1 )
+ CV_ERROR( CV_BadNumChannels,
+ "Incorrect number of channels for this conversion code" );
+
+ func2 = depth == CV_8U ? (CvColorCvtFunc2)icvBGRx2Gray_8u_CnC1R :
+ depth == CV_16U ? (CvColorCvtFunc2)icvBGRx2Gray_16u_CnC1R :
+ depth == CV_32F ? (CvColorCvtFunc2)icvBGRx2Gray_32f_CnC1R : 0;
+
+ param[0] = src_cn;
+ param[1] = code == CV_BGR2GRAY || code == CV_BGRA2GRAY ? 0 : 2;
+ break;
+
+ case CV_BGR5652GRAY:
+ case CV_BGR5552GRAY:
+ if( src_cn != 2 || dst_cn != 1 )
+ CV_ERROR( CV_BadNumChannels,
+ "Incorrect number of channels for this conversion code" );
+
+ if( depth != CV_8U )
+ CV_ERROR( CV_BadDepth,
+ "Conversion to/from 16-bit packed BGR format "
+ "is only possible for 8-bit images (888 BGR/BGR or 8888 BGRA/BGRA)" );
+
+ func2 = (CvColorCvtFunc2)icvBGR5x52Gray_8u_C2C1R;
+
+ param[0] = code == CV_BGR5652GRAY ? 6 : 5; // green_bits
+ break;
+
+ case CV_GRAY2BGR:
+ case CV_GRAY2BGRA:
+ if( src_cn != 1 || (dst_cn != 3 && dst_cn != 4))
+ CV_ERROR( CV_BadNumChannels,
+ "Incorrect number of channels for this conversion code" );
+
+ func1 = depth == CV_8U ? (CvColorCvtFunc1)icvGray2BGRx_8u_C1CnR :
+ depth == CV_16U ? (CvColorCvtFunc1)icvGray2BGRx_16u_C1CnR :
+ depth == CV_32F ? (CvColorCvtFunc1)icvGray2BGRx_32f_C1CnR : 0;
+
+ param[0] = dst_cn;
+ break;
+
+ case CV_GRAY2BGR565:
+ case CV_GRAY2BGR555:
+ if( src_cn != 1 || dst_cn != 2 )
+ CV_ERROR( CV_BadNumChannels,
+ "Incorrect number of channels for this conversion code" );
+
+ if( depth != CV_8U )
+ CV_ERROR( CV_BadDepth,
+ "Conversion to/from 16-bit packed BGR format "
+ "is only possible for 8-bit images (888 BGR/BGR or 8888 BGRA/BGRA)" );
+
+ func2 = (CvColorCvtFunc2)icvGray2BGR5x5_8u_C1C2R;
+ param[0] = code == CV_GRAY2BGR565 ? 6 : 5; // green_bits
+ break;
+
+ case CV_BGR2YCrCb:
+ case CV_RGB2YCrCb:
+ case CV_BGR2XYZ:
+ case CV_RGB2XYZ:
+ case CV_BGR2HSV:
+ case CV_RGB2HSV:
+ case CV_BGR2Lab:
+ case CV_RGB2Lab:
+ case CV_BGR2Luv:
+ case CV_RGB2Luv:
+ case CV_BGR2HLS:
+ case CV_RGB2HLS:
+ if( (src_cn != 3 && src_cn != 4) || dst_cn != 3 )
+ CV_ERROR( CV_BadNumChannels,
+ "Incorrect number of channels for this conversion code" );
+
+ if( depth == CV_8U )
+ func2 = code == CV_BGR2YCrCb || code == CV_RGB2YCrCb ? (CvColorCvtFunc2)icvBGRx2YCrCb_8u_CnC3R :
+ code == CV_BGR2XYZ || code == CV_RGB2XYZ ? (CvColorCvtFunc2)icvBGRx2XYZ_8u_CnC3R :
+ code == CV_BGR2HSV || code == CV_RGB2HSV ? (CvColorCvtFunc2)icvBGRx2HSV_8u_CnC3R :
+ code == CV_BGR2Lab || code == CV_RGB2Lab ? (CvColorCvtFunc2)icvBGRx2Lab_8u_CnC3R :
+ code == CV_BGR2Luv || code == CV_RGB2Luv ? (CvColorCvtFunc2)icvBGRx2Luv_8u_CnC3R :
+ code == CV_BGR2HLS || code == CV_RGB2HLS ? (CvColorCvtFunc2)icvBGRx2HLS_8u_CnC3R : 0;
+ else if( depth == CV_16U )
+ func2 = code == CV_BGR2YCrCb || code == CV_RGB2YCrCb ? (CvColorCvtFunc2)icvBGRx2YCrCb_16u_CnC3R :
+ code == CV_BGR2XYZ || code == CV_RGB2XYZ ? (CvColorCvtFunc2)icvBGRx2XYZ_16u_CnC3R : 0;
+ else if( depth == CV_32F )
+ func2 = code == CV_BGR2YCrCb || code == CV_RGB2YCrCb ? (CvColorCvtFunc2)icvBGRx2YCrCb_32f_CnC3R :
+ code == CV_BGR2XYZ || code == CV_RGB2XYZ ? (CvColorCvtFunc2)icvBGRx2XYZ_32f_CnC3R :
+ code == CV_BGR2HSV || code == CV_RGB2HSV ? (CvColorCvtFunc2)icvBGRx2HSV_32f_CnC3R :
+ code == CV_BGR2Lab || code == CV_RGB2Lab ? (CvColorCvtFunc2)icvBGRx2Lab_32f_CnC3R :
+ code == CV_BGR2Luv || code == CV_RGB2Luv ? (CvColorCvtFunc2)icvBGRx2Luv_32f_CnC3R :
+ code == CV_BGR2HLS || code == CV_RGB2HLS ? (CvColorCvtFunc2)icvBGRx2HLS_32f_CnC3R : 0;
+
+ param[0] = src_cn;
+ param[1] = code == CV_BGR2XYZ || code == CV_BGR2YCrCb || code == CV_BGR2HSV ||
+ code == CV_BGR2Lab || code == CV_BGR2Luv || code == CV_BGR2HLS ? 0 : 2;
+ break;
+
+ case CV_YCrCb2BGR:
+ case CV_YCrCb2RGB:
+ case CV_XYZ2BGR:
+ case CV_XYZ2RGB:
+ case CV_HSV2BGR:
+ case CV_HSV2RGB:
+ case CV_Lab2BGR:
+ case CV_Lab2RGB:
+ case CV_Luv2BGR:
+ case CV_Luv2RGB:
+ case CV_HLS2BGR:
+ case CV_HLS2RGB:
+ if( src_cn != 3 || (dst_cn != 3 && dst_cn != 4) )
+ CV_ERROR( CV_BadNumChannels,
+ "Incorrect number of channels for this conversion code" );
+
+ if( depth == CV_8U )
+ func2 = code == CV_YCrCb2BGR || code == CV_YCrCb2RGB ? (CvColorCvtFunc2)icvYCrCb2BGRx_8u_C3CnR :
+ code == CV_XYZ2BGR || code == CV_XYZ2RGB ? (CvColorCvtFunc2)icvXYZ2BGRx_8u_C3CnR :
+ code == CV_HSV2BGR || code == CV_HSV2RGB ? (CvColorCvtFunc2)icvHSV2BGRx_8u_C3CnR :
+ code == CV_HLS2BGR || code == CV_HLS2RGB ? (CvColorCvtFunc2)icvHLS2BGRx_8u_C3CnR :
+ code == CV_Lab2BGR || code == CV_Lab2RGB ? (CvColorCvtFunc2)icvLab2BGRx_8u_C3CnR :
+ code == CV_Luv2BGR || code == CV_Luv2RGB ? (CvColorCvtFunc2)icvLuv2BGRx_8u_C3CnR : 0;
+ else if( depth == CV_16U )
+ func2 = code == CV_YCrCb2BGR || code == CV_YCrCb2RGB ? (CvColorCvtFunc2)icvYCrCb2BGRx_16u_C3CnR :
+ code == CV_XYZ2BGR || code == CV_XYZ2RGB ? (CvColorCvtFunc2)icvXYZ2BGRx_16u_C3CnR : 0;
+ else if( depth == CV_32F )
+ func2 = code == CV_YCrCb2BGR || code == CV_YCrCb2RGB ? (CvColorCvtFunc2)icvYCrCb2BGRx_32f_C3CnR :
+ code == CV_XYZ2BGR || code == CV_XYZ2RGB ? (CvColorCvtFunc2)icvXYZ2BGRx_32f_C3CnR :
+ code == CV_HSV2BGR || code == CV_HSV2RGB ? (CvColorCvtFunc2)icvHSV2BGRx_32f_C3CnR :
+ code == CV_HLS2BGR || code == CV_HLS2RGB ? (CvColorCvtFunc2)icvHLS2BGRx_32f_C3CnR :
+ code == CV_Lab2BGR || code == CV_Lab2RGB ? (CvColorCvtFunc2)icvLab2BGRx_32f_C3CnR :
+ code == CV_Luv2BGR || code == CV_Luv2RGB ? (CvColorCvtFunc2)icvLuv2BGRx_32f_C3CnR : 0;
+
+ param[0] = dst_cn;
+ param[1] = code == CV_XYZ2BGR || code == CV_YCrCb2BGR || code == CV_HSV2BGR ||
+ code == CV_Lab2BGR || code == CV_Luv2BGR || code == CV_HLS2BGR ? 0 : 2;
+ break;
+
+ case CV_BayerBG2BGR:
+ case CV_BayerGB2BGR:
+ case CV_BayerRG2BGR:
+ case CV_BayerGR2BGR:
+ if( src_cn != 1 || dst_cn != 3 )
+ CV_ERROR( CV_BadNumChannels,
+ "Incorrect number of channels for this conversion code" );
+
+ if( depth != CV_8U )
+ CV_ERROR( CV_BadDepth,
+ "Bayer pattern can be converted only to 8-bit 3-channel BGR/RGB image" );
+
+ func1 = (CvColorCvtFunc1)icvBayer2BGR_8u_C1C3R;
+ param[0] = code; // conversion code
+ break;
+ default:
+ CV_ERROR( CV_StsBadFlag, "Unknown/unsupported color conversion code" );
+ }
+
+ if( func0 )
+ {
+ IPPI_CALL( func0( src->data.ptr, src_step, dst->data.ptr, dst_step, size ));
+ }
+ else if( func1 )
+ {
+ IPPI_CALL( func1( src->data.ptr, src_step,
+ dst->data.ptr, dst_step, size, param[0] ));
+ }
+ else if( func2 )
+ {
+ IPPI_CALL( func2( src->data.ptr, src_step,
+ dst->data.ptr, dst_step, size, param[0], param[1] ));
+ }
+ else if( func3 )
+ {
+ IPPI_CALL( func3( src->data.ptr, src_step,
+ dst->data.ptr, dst_step, size, param[0], param[1], param[2] ));
+ }
+ else
+ CV_ERROR( CV_StsUnsupportedFormat, "The image format is not supported" );
+
+ __END__;
+}
+
+/* End of file. */
+
+
diff --git a/cv/src/cvcondens.cpp b/cv/src/cvcondens.cpp
new file mode 100644
index 0000000..cf0d2a8
--- /dev/null
+++ b/cv/src/cvcondens.cpp
@@ -0,0 +1,284 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvCreateConDensation
+// Purpose: Creating CvConDensation structure and allocating memory for it
+// Context:
+// Parameters:
+// Kalman - double pointer to CvConDensation structure
+// DP - dimension of the dynamical vector
+// MP - dimension of the measurement vector
+// SamplesNum - number of samples in sample set used in algorithm
+// Returns:
+// Notes:
+//
+//F*/
+
+CV_IMPL CvConDensation* cvCreateConDensation( int DP, int MP, int SamplesNum )
+{
+ int i;
+ CvConDensation *CD = 0;
+
+ CV_FUNCNAME( "cvCreateConDensation" );
+ __BEGIN__;
+
+ if( DP < 0 || MP < 0 || SamplesNum < 0 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ /* allocating memory for the structure */
+ CV_CALL( CD = (CvConDensation *) cvAlloc( sizeof( CvConDensation )));
+ /* setting structure params */
+ CD->SamplesNum = SamplesNum;
+ CD->DP = DP;
+ CD->MP = MP;
+ /* allocating memory for structure fields */
+ CV_CALL( CD->flSamples = (float **) cvAlloc( sizeof( float * ) * SamplesNum ));
+ CV_CALL( CD->flNewSamples = (float **) cvAlloc( sizeof( float * ) * SamplesNum ));
+ CV_CALL( CD->flSamples[0] = (float *) cvAlloc( sizeof( float ) * SamplesNum * DP ));
+ CV_CALL( CD->flNewSamples[0] = (float *) cvAlloc( sizeof( float ) * SamplesNum * DP ));
+
+ /* setting pointers in pointer's arrays */
+ for( i = 1; i < SamplesNum; i++ )
+ {
+ CD->flSamples[i] = CD->flSamples[i - 1] + DP;
+ CD->flNewSamples[i] = CD->flNewSamples[i - 1] + DP;
+ }
+
+ CV_CALL( CD->State = (float *) cvAlloc( sizeof( float ) * DP ));
+ CV_CALL( CD->DynamMatr = (float *) cvAlloc( sizeof( float ) * DP * DP ));
+ CV_CALL( CD->flConfidence = (float *) cvAlloc( sizeof( float ) * SamplesNum ));
+ CV_CALL( CD->flCumulative = (float *) cvAlloc( sizeof( float ) * SamplesNum ));
+
+ CV_CALL( CD->RandS = (CvRandState *) cvAlloc( sizeof( CvRandState ) * DP ));
+ CV_CALL( CD->Temp = (float *) cvAlloc( sizeof( float ) * DP ));
+ CV_CALL( CD->RandomSample = (float *) cvAlloc( sizeof( float ) * DP ));
+
+ /* Returning created structure */
+ __END__;
+
+ return CD;
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvReleaseConDensation
+// Purpose: Releases CvConDensation structure and frees memory allocated for it
+// Context:
+// Parameters:
+// Kalman - double pointer to CvConDensation structure
+// DP - dimension of the dynamical vector
+// MP - dimension of the measurement vector
+// SamplesNum - number of samples in sample set used in algorithm
+// Returns:
+// Notes:
+//
+//F*/
+CV_IMPL void
+cvReleaseConDensation( CvConDensation ** ConDensation )
+{
+ CV_FUNCNAME( "cvReleaseConDensation" );
+ __BEGIN__;
+
+ CvConDensation *CD = *ConDensation;
+
+ if( !ConDensation )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !CD )
+ EXIT;
+
+ /* freeing the memory */
+ cvFree( &CD->State );
+ cvFree( &CD->DynamMatr);
+ cvFree( &CD->flConfidence );
+ cvFree( &CD->flCumulative );
+ cvFree( &CD->flSamples[0] );
+ cvFree( &CD->flNewSamples[0] );
+ cvFree( &CD->flSamples );
+ cvFree( &CD->flNewSamples );
+ cvFree( &CD->Temp );
+ cvFree( &CD->RandS );
+ cvFree( &CD->RandomSample );
+ /* release structure */
+ cvFree( ConDensation );
+
+ __END__;
+
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvConDensUpdateByTime
+// Purpose: Performing Time Update routine for ConDensation algorithm
+// Context:
+// Parameters:
+// Kalman - pointer to CvConDensation structure
+// Returns:
+// Notes:
+//
+//F*/
+CV_IMPL void
+cvConDensUpdateByTime( CvConDensation * ConDens )
+{
+ int i, j;
+ float Sum = 0;
+
+ CV_FUNCNAME( "cvConDensUpdateByTime" );
+ __BEGIN__;
+
+ if( !ConDens )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ /* Sets Temp to Zero */
+ icvSetZero_32f( ConDens->Temp, ConDens->DP, 1 );
+
+ /* Calculating the Mean */
+ for( i = 0; i < ConDens->SamplesNum; i++ )
+ {
+ icvScaleVector_32f( ConDens->flSamples[i], ConDens->State, ConDens->DP,
+ ConDens->flConfidence[i] );
+ icvAddVector_32f( ConDens->Temp, ConDens->State, ConDens->Temp, ConDens->DP );
+ Sum += ConDens->flConfidence[i];
+ ConDens->flCumulative[i] = Sum;
+ }
+
+ /* Taking the new vector from transformation of mean by dynamics matrix */
+
+ icvScaleVector_32f( ConDens->Temp, ConDens->Temp, ConDens->DP, 1.f / Sum );
+ icvTransformVector_32f( ConDens->DynamMatr, ConDens->Temp, ConDens->State, ConDens->DP,
+ ConDens->DP );
+ Sum = Sum / ConDens->SamplesNum;
+
+ /* Updating the set of random samples */
+ for( i = 0; i < ConDens->SamplesNum; i++ )
+ {
+ j = 0;
+ while( (ConDens->flCumulative[j] <= (float) i * Sum)&&(j<ConDens->SamplesNum-1))
+ {
+ j++;
+ }
+ icvCopyVector_32f( ConDens->flSamples[j], ConDens->DP, ConDens->flNewSamples[i] );
+ }
+
+ /* Adding the random-generated vector to every vector in sample set */
+ for( i = 0; i < ConDens->SamplesNum; i++ )
+ {
+ for( j = 0; j < ConDens->DP; j++ )
+ {
+ cvbRand( ConDens->RandS + j, ConDens->RandomSample + j, 1 );
+ }
+
+ icvTransformVector_32f( ConDens->DynamMatr, ConDens->flNewSamples[i],
+ ConDens->flSamples[i], ConDens->DP, ConDens->DP );
+ icvAddVector_32f( ConDens->flSamples[i], ConDens->RandomSample, ConDens->flSamples[i],
+ ConDens->DP );
+ }
+
+ __END__;
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvConDensInitSamplSet
+// Purpose: Performing Time Update routine for ConDensation algorithm
+// Context:
+// Parameters:
+// conDens - pointer to CvConDensation structure
+// lowerBound - vector of lower bounds used to random update of sample set
+// lowerBound - vector of upper bounds used to random update of sample set
+// Returns:
+// Notes:
+//
+//F*/
+
+CV_IMPL void
+cvConDensInitSampleSet( CvConDensation * conDens, CvMat * lowerBound, CvMat * upperBound )
+{
+ int i, j;
+ float *LBound;
+ float *UBound;
+ float Prob = 1.f / conDens->SamplesNum;
+
+ CV_FUNCNAME( "cvConDensInitSampleSet" );
+ __BEGIN__;
+
+ if( !conDens || !lowerBound || !upperBound )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( CV_MAT_TYPE(lowerBound->type) != CV_32FC1 ||
+ !CV_ARE_TYPES_EQ(lowerBound,upperBound) )
+ CV_ERROR( CV_StsBadArg, "source has not appropriate format" );
+
+ if( (lowerBound->cols != 1) || (upperBound->cols != 1) )
+ CV_ERROR( CV_StsBadArg, "source has not appropriate size" );
+
+ if( (lowerBound->rows != conDens->DP) || (upperBound->rows != conDens->DP) )
+ CV_ERROR( CV_StsBadArg, "source has not appropriate size" );
+
+ LBound = lowerBound->data.fl;
+ UBound = upperBound->data.fl;
+ /* Initializing the structures to create initial Sample set */
+ for( i = 0; i < conDens->DP; i++ )
+ {
+ cvRandInit( &(conDens->RandS[i]),
+ LBound[i],
+ UBound[i],
+ i );
+ }
+ /* Generating the samples */
+ for( j = 0; j < conDens->SamplesNum; j++ )
+ {
+ for( i = 0; i < conDens->DP; i++ )
+ {
+ cvbRand( conDens->RandS + i, conDens->flSamples[j] + i, 1 );
+ }
+ conDens->flConfidence[j] = Prob;
+ }
+ /* Reinitializes the structures to update samples randomly */
+ for( i = 0; i < conDens->DP; i++ )
+ {
+ cvRandInit( &(conDens->RandS[i]),
+ (LBound[i] - UBound[i]) / 5,
+ (UBound[i] - LBound[i]) / 5,
+ i);
+ }
+
+ __END__;
+}
diff --git a/cv/src/cvcontours.cpp b/cv/src/cvcontours.cpp
new file mode 100644
index 0000000..63652b9
--- /dev/null
+++ b/cv/src/cvcontours.cpp
@@ -0,0 +1,1557 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+/* initializes 8-element array for fast access to 3x3 neighborhood of a pixel */
+#define CV_INIT_3X3_DELTAS( deltas, step, nch ) \
+ ((deltas)[0] = (nch), (deltas)[1] = -(step) + (nch), \
+ (deltas)[2] = -(step), (deltas)[3] = -(step) - (nch), \
+ (deltas)[4] = -(nch), (deltas)[5] = (step) - (nch), \
+ (deltas)[6] = (step), (deltas)[7] = (step) + (nch))
+
+static const CvPoint icvCodeDeltas[8] =
+ { {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} };
+
+CV_IMPL void
+cvStartReadChainPoints( CvChain * chain, CvChainPtReader * reader )
+{
+ int i;
+
+ CV_FUNCNAME( "cvStartReadChainPoints" );
+
+ __BEGIN__;
+
+ if( !chain || !reader )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( chain->elem_size != 1 || chain->header_size < (int)sizeof(CvChain))
+ CV_ERROR_FROM_STATUS( CV_BADSIZE_ERR );
+
+ cvStartReadSeq( (CvSeq *) chain, (CvSeqReader *) reader, 0 );
+ CV_CHECK();
+
+ reader->pt = chain->origin;
+
+ for( i = 0; i < 8; i++ )
+ {
+ reader->deltas[i][0] = (schar) icvCodeDeltas[i].x;
+ reader->deltas[i][1] = (schar) icvCodeDeltas[i].y;
+ }
+
+ __END__;
+}
+
+
+/* retrieves next point of the chain curve and updates reader */
+CV_IMPL CvPoint
+cvReadChainPoint( CvChainPtReader * reader )
+{
+ schar *ptr;
+ int code;
+ CvPoint pt = { 0, 0 };
+
+ CV_FUNCNAME( "cvReadChainPoint" );
+
+ __BEGIN__;
+
+ if( !reader )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ pt = reader->pt;
+
+ ptr = reader->ptr;
+ if( ptr )
+ {
+ code = *ptr++;
+
+ if( ptr >= reader->block_max )
+ {
+ cvChangeSeqBlock( (CvSeqReader *) reader, 1 );
+ ptr = reader->ptr;
+ }
+
+ reader->ptr = ptr;
+ reader->code = (schar)code;
+ assert( (code & ~7) == 0 );
+ reader->pt.x = pt.x + icvCodeDeltas[code].x;
+ reader->pt.y = pt.y + icvCodeDeltas[code].y;
+ }
+
+ __END__;
+
+ return pt;
+}
+
+
+/****************************************************************************************\
+* Raster->Chain Tree (Suzuki algorithms) *
+\****************************************************************************************/
+
+typedef struct _CvContourInfo
+{
+ int flags;
+ struct _CvContourInfo *next; /* next contour with the same mark value */
+ struct _CvContourInfo *parent; /* information about parent contour */
+ CvSeq *contour; /* corresponding contour (may be 0, if rejected) */
+ CvRect rect; /* bounding rectangle */
+ CvPoint origin; /* origin point (where the contour was traced from) */
+ int is_hole; /* hole flag */
+}
+_CvContourInfo;
+
+
+/*
+ Structure that is used for sequental retrieving contours from the image.
+ It supports both hierarchical and plane variants of Suzuki algorithm.
+*/
+typedef struct _CvContourScanner
+{
+ CvMemStorage *storage1; /* contains fetched contours */
+ CvMemStorage *storage2; /* contains approximated contours
+ (!=storage1 if approx_method2 != approx_method1) */
+ CvMemStorage *cinfo_storage; /* contains _CvContourInfo nodes */
+ CvSet *cinfo_set; /* set of _CvContourInfo nodes */
+ CvMemStoragePos initial_pos; /* starting storage pos */
+ CvMemStoragePos backup_pos; /* beginning of the latest approx. contour */
+ CvMemStoragePos backup_pos2; /* ending of the latest approx. contour */
+ schar *img0; /* image origin */
+ schar *img; /* current image row */
+ int img_step; /* image step */
+ CvSize img_size; /* ROI size */
+ CvPoint offset; /* ROI offset: coordinates, added to each contour point */
+ CvPoint pt; /* current scanner position */
+ CvPoint lnbd; /* position of the last met contour */
+ int nbd; /* current mark val */
+ _CvContourInfo *l_cinfo; /* information about latest approx. contour */
+ _CvContourInfo cinfo_temp; /* temporary var which is used in simple modes */
+ _CvContourInfo frame_info; /* information about frame */
+ CvSeq frame; /* frame itself */
+ int approx_method1; /* approx method when tracing */
+ int approx_method2; /* final approx method */
+ int mode; /* contour scanning mode:
+ 0 - external only
+ 1 - all the contours w/o any hierarchy
+ 2 - connected components (i.e. two-level structure -
+ external contours and holes) */
+ int subst_flag;
+ int seq_type1; /* type of fetched contours */
+ int header_size1; /* hdr size of fetched contours */
+ int elem_size1; /* elem size of fetched contours */
+ int seq_type2; /* */
+ int header_size2; /* the same for approx. contours */
+ int elem_size2; /* */
+ _CvContourInfo *cinfo_table[126];
+}
+_CvContourScanner;
+
+#define _CV_FIND_CONTOURS_FLAGS_EXTERNAL_ONLY 1
+#define _CV_FIND_CONTOURS_FLAGS_HIERARCHIC 2
+
+/*
+ Initializes scanner structure.
+ Prepare image for scanning ( clear borders and convert all pixels to 0-1.
+*/
+CV_IMPL CvContourScanner
+cvStartFindContours( void* _img, CvMemStorage* storage,
+ int header_size, int mode,
+ int method, CvPoint offset )
+{
+ int y;
+ int step;
+ CvSize size;
+ uchar *img = 0;
+ CvContourScanner scanner = 0;
+ CvMat stub, *mat = (CvMat*)_img;
+
+ CV_FUNCNAME( "cvStartFindContours" );
+
+ __BEGIN__;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ CV_CALL( mat = cvGetMat( mat, &stub ));
+
+ if( !CV_IS_MASK_ARR( mat ))
+ CV_ERROR( CV_StsUnsupportedFormat, "[Start]FindContours support only 8uC1 images" );
+
+ size = cvSize( mat->width, mat->height );
+ step = mat->step;
+ img = (uchar*)(mat->data.ptr);
+
+ if( method < 0 || method > CV_CHAIN_APPROX_TC89_KCOS )
+ CV_ERROR_FROM_STATUS( CV_BADRANGE_ERR );
+
+ if( header_size < (int) (method == CV_CHAIN_CODE ? sizeof( CvChain ) : sizeof( CvContour )))
+ CV_ERROR_FROM_STATUS( CV_BADSIZE_ERR );
+
+ scanner = (CvContourScanner)cvAlloc( sizeof( *scanner ));
+ if( !scanner )
+ CV_ERROR_FROM_STATUS( CV_OUTOFMEM_ERR );
+
+ memset( scanner, 0, sizeof( *scanner ));
+
+ scanner->storage1 = scanner->storage2 = storage;
+ scanner->img0 = (schar *) img;
+ scanner->img = (schar *) (img + step);
+ scanner->img_step = step;
+ scanner->img_size.width = size.width - 1; /* exclude rightest column */
+ scanner->img_size.height = size.height - 1; /* exclude bottomost row */
+ scanner->mode = mode;
+ scanner->offset = offset;
+ scanner->pt.x = scanner->pt.y = 1;
+ scanner->lnbd.x = 0;
+ scanner->lnbd.y = 1;
+ scanner->nbd = 2;
+ scanner->mode = (int) mode;
+ scanner->frame_info.contour = &(scanner->frame);
+ scanner->frame_info.is_hole = 1;
+ scanner->frame_info.next = 0;
+ scanner->frame_info.parent = 0;
+ scanner->frame_info.rect = cvRect( 0, 0, size.width, size.height );
+ scanner->l_cinfo = 0;
+ scanner->subst_flag = 0;
+
+ scanner->frame.flags = CV_SEQ_FLAG_HOLE;
+
+ scanner->approx_method2 = scanner->approx_method1 = method;
+
+ if( method == CV_CHAIN_APPROX_TC89_L1 || method == CV_CHAIN_APPROX_TC89_KCOS )
+ scanner->approx_method1 = CV_CHAIN_CODE;
+
+ if( scanner->approx_method1 == CV_CHAIN_CODE )
+ {
+ scanner->seq_type1 = CV_SEQ_CHAIN_CONTOUR;
+ scanner->header_size1 = scanner->approx_method1 == scanner->approx_method2 ?
+ header_size : sizeof( CvChain );
+ scanner->elem_size1 = sizeof( char );
+ }
+ else
+ {
+ scanner->seq_type1 = CV_SEQ_POLYGON;
+ scanner->header_size1 = scanner->approx_method1 == scanner->approx_method2 ?
+ header_size : sizeof( CvContour );
+ scanner->elem_size1 = sizeof( CvPoint );
+ }
+
+ scanner->header_size2 = header_size;
+
+ if( scanner->approx_method2 == CV_CHAIN_CODE )
+ {
+ scanner->seq_type2 = scanner->seq_type1;
+ scanner->elem_size2 = scanner->elem_size1;
+ }
+ else
+ {
+ scanner->seq_type2 = CV_SEQ_POLYGON;
+ scanner->elem_size2 = sizeof( CvPoint );
+ }
+
+ scanner->seq_type1 = scanner->approx_method1 == CV_CHAIN_CODE ?
+ CV_SEQ_CHAIN_CONTOUR : CV_SEQ_POLYGON;
+
+ scanner->seq_type2 = scanner->approx_method2 == CV_CHAIN_CODE ?
+ CV_SEQ_CHAIN_CONTOUR : CV_SEQ_POLYGON;
+
+ cvSaveMemStoragePos( storage, &(scanner->initial_pos) );
+
+ if( method > CV_CHAIN_APPROX_SIMPLE )
+ {
+ scanner->storage1 = cvCreateChildMemStorage( scanner->storage2 );
+ }
+
+ if( mode > CV_RETR_LIST )
+ {
+ scanner->cinfo_storage = cvCreateChildMemStorage( scanner->storage2 );
+ scanner->cinfo_set = cvCreateSet( 0, sizeof( CvSet ), sizeof( _CvContourInfo ),
+ scanner->cinfo_storage );
+ if( scanner->cinfo_storage == 0 || scanner->cinfo_set == 0 )
+ CV_ERROR_FROM_STATUS( CV_OUTOFMEM_ERR );
+ }
+
+ /* make zero borders */
+ memset( img, 0, size.width );
+ memset( img + step * (size.height - 1), 0, size.width );
+
+ for( y = 1, img += step; y < size.height - 1; y++, img += step )
+ {
+ img[0] = img[size.width - 1] = 0;
+ }
+
+ /* converts all pixels to 0 or 1 */
+ cvThreshold( mat, mat, 0, 1, CV_THRESH_BINARY );
+ CV_CHECK();
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvFree( &scanner );
+
+ return scanner;
+}
+
+/*
+ Final stage of contour processing.
+ Three variants possible:
+ 1. Contour, which was retrieved using border following, is added to
+ the contour tree. It is the case when the icvSubstituteContour function
+ was not called after retrieving the contour.
+
+ 2. New contour, assigned by icvSubstituteContour function, is added to the
+ tree. The retrieved contour itself is removed from the storage.
+ Here two cases are possible:
+ 2a. If one deals with plane variant of algorithm
+ (hierarchical strucutre is not reconstructed),
+ the contour is removed completely.
+ 2b. In hierarchical case, the header of the contour is not removed.
+ It's marked as "link to contour" and h_next pointer of it is set to
+ new, substituting contour.
+
+ 3. The similar to 2, but when NULL pointer was assigned by
+ icvSubstituteContour function. In this case, the function removes
+ retrieved contour completely if plane case and
+ leaves header if hierarchical (but doesn't mark header as "link").
+ ------------------------------------------------------------------------
+ The 1st variant can be used to retrieve and store all the contours from the image
+ (with optional convertion from chains to contours using some approximation from
+ restriced set of methods). Some characteristics of contour can be computed in the
+ same pass.
+
+ The usage scheme can look like:
+
+ icvContourScanner scanner;
+ CvMemStorage* contour_storage;
+ CvSeq* first_contour;
+ CvStatus result;
+
+ ...
+
+ icvCreateMemStorage( &contour_storage, block_size/0 );
+
+ ...
+
+ cvStartFindContours
+ ( img, contour_storage,
+ header_size, approx_method,
+ [external_only,]
+ &scanner );
+
+ for(;;)
+ {
+ [CvSeq* contour;]
+ result = icvFindNextContour( &scanner, &contour/0 );
+
+ if( result != CV_OK ) break;
+
+ // calculate some characteristics
+ ...
+ }
+
+ if( result < 0 ) goto error_processing;
+
+ cvEndFindContours( &scanner, &first_contour );
+ ...
+
+ -----------------------------------------------------------------
+
+ Second variant is more complex and can be used when someone wants store not
+ the retrieved contours but transformed ones. (e.g. approximated with some
+ non-default algorithm ).
+
+ The scheme can be the as following:
+
+ icvContourScanner scanner;
+ CvMemStorage* contour_storage;
+ CvMemStorage* temp_storage;
+ CvSeq* first_contour;
+ CvStatus result;
+
+ ...
+
+ icvCreateMemStorage( &contour_storage, block_size/0 );
+ icvCreateMemStorage( &temp_storage, block_size/0 );
+
+ ...
+
+ icvStartFindContours8uC1R
+ ( <img_params>, temp_storage,
+ header_size, approx_method,
+ [retrival_mode],
+ &scanner );
+
+ for(;;)
+ {
+ CvSeq* temp_contour;
+ CvSeq* new_contour;
+ result = icvFindNextContour( scanner, &temp_contour );
+
+ if( result != CV_OK ) break;
+
+ <approximation_function>( temp_contour, contour_storage,
+ &new_contour, <parameters...> );
+
+ icvSubstituteContour( scanner, new_contour );
+ ...
+ }
+
+ if( result < 0 ) goto error_processing;
+
+ cvEndFindContours( &scanner, &first_contour );
+ ...
+
+ ----------------------------------------------------------------------------
+ Third method to retrieve contours may be applied if contours are irrelevant
+ themselves but some characteristics of them are used only.
+ The usage is similar to second except slightly different internal loop
+
+ for(;;)
+ {
+ CvSeq* temp_contour;
+ result = icvFindNextContour( &scanner, &temp_contour );
+
+ if( result != CV_OK ) break;
+
+ // calculate some characteristics of temp_contour
+
+ icvSubstituteContour( scanner, 0 );
+ ...
+ }
+
+ new_storage variable is not needed here.
+
+ Two notes.
+ 1. Second and third method can interleave. I.e. it is possible to
+ remain contours that satisfy with some criteria and reject others.
+ In hierarchic case the resulting tree is the part of original tree with
+ some nodes absent. But in the resulting tree the contour1 is a child
+ (may be indirect) of contour2 iff in the original tree the contour1
+ is a child (may be indirect) of contour2.
+*/
+static void
+icvEndProcessContour( CvContourScanner scanner )
+{
+ _CvContourInfo *l_cinfo = scanner->l_cinfo;
+
+ if( l_cinfo )
+ {
+ if( scanner->subst_flag )
+ {
+ CvMemStoragePos temp;
+
+ cvSaveMemStoragePos( scanner->storage2, &temp );
+
+ if( temp.top == scanner->backup_pos2.top &&
+ temp.free_space == scanner->backup_pos2.free_space )
+ {
+ cvRestoreMemStoragePos( scanner->storage2, &scanner->backup_pos );
+ }
+ scanner->subst_flag = 0;
+ }
+
+ if( l_cinfo->contour )
+ {
+ cvInsertNodeIntoTree( l_cinfo->contour, l_cinfo->parent->contour,
+ &(scanner->frame) );
+ }
+ scanner->l_cinfo = 0;
+ }
+}
+
+/* replaces one contour with another */
+CV_IMPL void
+cvSubstituteContour( CvContourScanner scanner, CvSeq * new_contour )
+{
+ _CvContourInfo *l_cinfo;
+
+ CV_FUNCNAME( "cvSubstituteContour" );
+
+ __BEGIN__;
+
+ if( !scanner )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ l_cinfo = scanner->l_cinfo;
+ if( l_cinfo && l_cinfo->contour && l_cinfo->contour != new_contour )
+ {
+ l_cinfo->contour = new_contour;
+ scanner->subst_flag = 1;
+ }
+
+ __END__;
+}
+
+
+/*
+ marks domain border with +/-<constant> and stores the contour into CvSeq.
+ method:
+ <0 - chain
+ ==0 - direct
+ >0 - simple approximation
+*/
+static CvStatus
+icvFetchContour( schar *ptr,
+ int step,
+ CvPoint pt,
+ CvSeq* contour,
+ int _method )
+{
+ const schar nbd = 2;
+ int deltas[16];
+ CvSeqWriter writer;
+ schar *i0 = ptr, *i1, *i3, *i4 = 0;
+ int prev_s = -1, s, s_end;
+ int method = _method - 1;
+
+ assert( (unsigned) _method <= CV_CHAIN_APPROX_SIMPLE );
+
+ /* initialize local state */
+ CV_INIT_3X3_DELTAS( deltas, step, 1 );
+ memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
+
+ /* initialize writer */
+ cvStartAppendToSeq( contour, &writer );
+
+ if( method < 0 )
+ ((CvChain *) contour)->origin = pt;
+
+ s_end = s = CV_IS_SEQ_HOLE( contour ) ? 0 : 4;
+
+ do
+ {
+ s = (s - 1) & 7;
+ i1 = i0 + deltas[s];
+ if( *i1 != 0 )
+ break;
+ }
+ while( s != s_end );
+
+ if( s == s_end ) /* single pixel domain */
+ {
+ *i0 = (schar) (nbd | -128);
+ if( method >= 0 )
+ {
+ CV_WRITE_SEQ_ELEM( pt, writer );
+ }
+ }
+ else
+ {
+ i3 = i0;
+ prev_s = s ^ 4;
+
+ /* follow border */
+ for( ;; )
+ {
+ s_end = s;
+
+ for( ;; )
+ {
+ i4 = i3 + deltas[++s];
+ if( *i4 != 0 )
+ break;
+ }
+ s &= 7;
+
+ /* check "right" bound */
+ if( (unsigned) (s - 1) < (unsigned) s_end )
+ {
+ *i3 = (schar) (nbd | -128);
+ }
+ else if( *i3 == 1 )
+ {
+ *i3 = nbd;
+ }
+
+ if( method < 0 )
+ {
+ schar _s = (schar) s;
+
+ CV_WRITE_SEQ_ELEM( _s, writer );
+ }
+ else
+ {
+ if( s != prev_s || method == 0 )
+ {
+ CV_WRITE_SEQ_ELEM( pt, writer );
+ prev_s = s;
+ }
+
+ pt.x += icvCodeDeltas[s].x;
+ pt.y += icvCodeDeltas[s].y;
+
+ }
+
+ if( i4 == i0 && i3 == i1 )
+ break;
+
+ i3 = i4;
+ s = (s + 4) & 7;
+ } /* end of border following loop */
+ }
+
+ cvEndWriteSeq( &writer );
+
+ if( _method != CV_CHAIN_CODE )
+ cvBoundingRect( contour, 1 );
+
+ assert( writer.seq->total == 0 && writer.seq->first == 0 ||
+ writer.seq->total > writer.seq->first->count ||
+ (writer.seq->first->prev == writer.seq->first &&
+ writer.seq->first->next == writer.seq->first) );
+
+ return CV_OK;
+}
+
+
+
+/*
+ trace contour until certain point is met.
+ returns 1 if met, 0 else.
+*/
+static int
+icvTraceContour( schar *ptr, int step, schar *stop_ptr, int is_hole )
+{
+ int deltas[16];
+ schar *i0 = ptr, *i1, *i3, *i4;
+ int s, s_end;
+
+ /* initialize local state */
+ CV_INIT_3X3_DELTAS( deltas, step, 1 );
+ memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
+
+ assert( (*i0 & -2) != 0 );
+
+ s_end = s = is_hole ? 0 : 4;
+
+ do
+ {
+ s = (s - 1) & 7;
+ i1 = i0 + deltas[s];
+ if( *i1 != 0 )
+ break;
+ }
+ while( s != s_end );
+
+ i3 = i0;
+
+ /* check single pixel domain */
+ if( s != s_end )
+ {
+ /* follow border */
+ for( ;; )
+ {
+ s_end = s;
+
+ for( ;; )
+ {
+ i4 = i3 + deltas[++s];
+ if( *i4 != 0 )
+ break;
+ }
+
+ if( i3 == stop_ptr || (i4 == i0 && i3 == i1) )
+ break;
+
+ i3 = i4;
+ s = (s + 4) & 7;
+ } /* end of border following loop */
+ }
+ return i3 == stop_ptr;
+}
+
+
+static CvStatus
+icvFetchContourEx( schar* ptr,
+ int step,
+ CvPoint pt,
+ CvSeq* contour,
+ int _method,
+ int nbd,
+ CvRect* _rect )
+{
+ int deltas[16];
+ CvSeqWriter writer;
+ schar *i0 = ptr, *i1, *i3, *i4;
+ CvRect rect;
+ int prev_s = -1, s, s_end;
+ int method = _method - 1;
+
+ assert( (unsigned) _method <= CV_CHAIN_APPROX_SIMPLE );
+ assert( 1 < nbd && nbd < 128 );
+
+ /* initialize local state */
+ CV_INIT_3X3_DELTAS( deltas, step, 1 );
+ memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
+
+ /* initialize writer */
+ cvStartAppendToSeq( contour, &writer );
+
+ if( method < 0 )
+ ((CvChain *)contour)->origin = pt;
+
+ rect.x = rect.width = pt.x;
+ rect.y = rect.height = pt.y;
+
+ s_end = s = CV_IS_SEQ_HOLE( contour ) ? 0 : 4;
+
+ do
+ {
+ s = (s - 1) & 7;
+ i1 = i0 + deltas[s];
+ if( *i1 != 0 )
+ break;
+ }
+ while( s != s_end );
+
+ if( s == s_end ) /* single pixel domain */
+ {
+ *i0 = (schar) (nbd | 0x80);
+ if( method >= 0 )
+ {
+ CV_WRITE_SEQ_ELEM( pt, writer );
+ }
+ }
+ else
+ {
+ i3 = i0;
+
+ prev_s = s ^ 4;
+
+ /* follow border */
+ for( ;; )
+ {
+ s_end = s;
+
+ for( ;; )
+ {
+ i4 = i3 + deltas[++s];
+ if( *i4 != 0 )
+ break;
+ }
+ s &= 7;
+
+ /* check "right" bound */
+ if( (unsigned) (s - 1) < (unsigned) s_end )
+ {
+ *i3 = (schar) (nbd | 0x80);
+ }
+ else if( *i3 == 1 )
+ {
+ *i3 = (schar) nbd;
+ }
+
+ if( method < 0 )
+ {
+ schar _s = (schar) s;
+ CV_WRITE_SEQ_ELEM( _s, writer );
+ }
+ else if( s != prev_s || method == 0 )
+ {
+ CV_WRITE_SEQ_ELEM( pt, writer );
+ }
+
+ if( s != prev_s )
+ {
+ /* update bounds */
+ if( pt.x < rect.x )
+ rect.x = pt.x;
+ else if( pt.x > rect.width )
+ rect.width = pt.x;
+
+ if( pt.y < rect.y )
+ rect.y = pt.y;
+ else if( pt.y > rect.height )
+ rect.height = pt.y;
+ }
+
+ prev_s = s;
+ pt.x += icvCodeDeltas[s].x;
+ pt.y += icvCodeDeltas[s].y;
+
+ if( i4 == i0 && i3 == i1 ) break;
+
+ i3 = i4;
+ s = (s + 4) & 7;
+ } /* end of border following loop */
+ }
+
+ rect.width -= rect.x - 1;
+ rect.height -= rect.y - 1;
+
+ cvEndWriteSeq( &writer );
+
+ if( _method != CV_CHAIN_CODE )
+ ((CvContour*)contour)->rect = rect;
+
+ assert( writer.seq->total == 0 && writer.seq->first == 0 ||
+ writer.seq->total > writer.seq->first->count ||
+ (writer.seq->first->prev == writer.seq->first &&
+ writer.seq->first->next == writer.seq->first) );
+
+ if( _rect ) *_rect = rect;
+
+ return CV_OK;
+}
+
+
+CvSeq *
+cvFindNextContour( CvContourScanner scanner )
+{
+ schar *img0;
+ schar *img;
+ int step;
+ int width, height;
+ int x, y;
+ int prev;
+ CvPoint lnbd;
+ CvSeq *contour = 0;
+ int nbd;
+ int mode;
+ CvStatus result = (CvStatus) 1;
+
+ CV_FUNCNAME( "cvFindNextContour" );
+
+ __BEGIN__;
+
+ if( !scanner )
+ CV_ERROR( CV_StsNullPtr, "" );
+ icvEndProcessContour( scanner );
+
+ /* initialize local state */
+ img0 = scanner->img0;
+ img = scanner->img;
+ step = scanner->img_step;
+ x = scanner->pt.x;
+ y = scanner->pt.y;
+ width = scanner->img_size.width;
+ height = scanner->img_size.height;
+ mode = scanner->mode;
+ lnbd = scanner->lnbd;
+ nbd = scanner->nbd;
+
+ prev = img[x - 1];
+
+ for( ; y < height; y++, img += step )
+ {
+ for( ; x < width; x++ )
+ {
+ int p = img[x];
+
+ if( p != prev )
+ {
+ _CvContourInfo *par_info = 0;
+ _CvContourInfo *l_cinfo = 0;
+ CvSeq *seq = 0;
+ int is_hole = 0;
+ CvPoint origin;
+
+ if( !(prev == 0 && p == 1) ) /* if not external contour */
+ {
+ /* check hole */
+ if( p != 0 || prev < 1 )
+ goto resume_scan;
+
+ if( prev & -2 )
+ {
+ lnbd.x = x - 1;
+ }
+ is_hole = 1;
+ }
+
+ if( mode == 0 && (is_hole || img0[lnbd.y * step + lnbd.x] > 0) )
+ goto resume_scan;
+
+ origin.y = y;
+ origin.x = x - is_hole;
+
+ /* find contour parent */
+ if( mode <= 1 || (!is_hole && mode == 2) || lnbd.x <= 0 )
+ {
+ par_info = &(scanner->frame_info);
+ }
+ else
+ {
+ int lval = img0[lnbd.y * step + lnbd.x] & 0x7f;
+ _CvContourInfo *cur = scanner->cinfo_table[lval - 2];
+
+ assert( lval >= 2 );
+
+ /* find the first bounding contour */
+ while( cur )
+ {
+ if( (unsigned) (lnbd.x - cur->rect.x) < (unsigned) cur->rect.width &&
+ (unsigned) (lnbd.y - cur->rect.y) < (unsigned) cur->rect.height )
+ {
+ if( par_info )
+ {
+ if( icvTraceContour( scanner->img0 +
+ par_info->origin.y * step +
+ par_info->origin.x, step, img + lnbd.x,
+ par_info->is_hole ) > 0 )
+ break;
+ }
+ par_info = cur;
+ }
+ cur = cur->next;
+ }
+
+ assert( par_info != 0 );
+
+ /* if current contour is a hole and previous contour is a hole or
+ current contour is external and previous contour is external then
+ the parent of the contour is the parent of the previous contour else
+ the parent is the previous contour itself. */
+ if( par_info->is_hole == is_hole )
+ {
+ par_info = par_info->parent;
+ /* every contour must have a parent
+ (at least, the frame of the image) */
+ if( !par_info )
+ par_info = &(scanner->frame_info);
+ }
+
+ /* hole flag of the parent must differ from the flag of the contour */
+ assert( par_info->is_hole != is_hole );
+ if( par_info->contour == 0 ) /* removed contour */
+ goto resume_scan;
+ }
+
+ lnbd.x = x - is_hole;
+
+ cvSaveMemStoragePos( scanner->storage2, &(scanner->backup_pos) );
+
+ seq = cvCreateSeq( scanner->seq_type1, scanner->header_size1,
+ scanner->elem_size1, scanner->storage1 );
+ if( !seq )
+ {
+ result = CV_OUTOFMEM_ERR;
+ goto exit_func;
+ }
+ seq->flags |= is_hole ? CV_SEQ_FLAG_HOLE : 0;
+
+ /* initialize header */
+ if( mode <= 1 )
+ {
+ l_cinfo = &(scanner->cinfo_temp);
+ result = icvFetchContour( img + x - is_hole, step,
+ cvPoint( origin.x + scanner->offset.x,
+ origin.y + scanner->offset.y),
+ seq, scanner->approx_method1 );
+ if( result < 0 )
+ goto exit_func;
+ }
+ else
+ {
+ union { _CvContourInfo* ci; CvSetElem* se; } v;
+ v.ci = l_cinfo;
+ cvSetAdd( scanner->cinfo_set, 0, &v.se );
+ l_cinfo = v.ci;
+
+ result = icvFetchContourEx( img + x - is_hole, step,
+ cvPoint( origin.x + scanner->offset.x,
+ origin.y + scanner->offset.y),
+ seq, scanner->approx_method1,
+ nbd, &(l_cinfo->rect) );
+ if( result < 0 )
+ goto exit_func;
+ l_cinfo->rect.x -= scanner->offset.x;
+ l_cinfo->rect.y -= scanner->offset.y;
+
+ l_cinfo->next = scanner->cinfo_table[nbd - 2];
+ scanner->cinfo_table[nbd - 2] = l_cinfo;
+
+ /* change nbd */
+ nbd = (nbd + 1) & 127;
+ nbd += nbd == 0 ? 3 : 0;
+ }
+
+ l_cinfo->is_hole = is_hole;
+ l_cinfo->contour = seq;
+ l_cinfo->origin = origin;
+ l_cinfo->parent = par_info;
+
+ if( scanner->approx_method1 != scanner->approx_method2 )
+ {
+ result = icvApproximateChainTC89( (CvChain *) seq,
+ scanner->header_size2,
+ scanner->storage2,
+ &(l_cinfo->contour),
+ scanner->approx_method2 );
+ if( result < 0 )
+ goto exit_func;
+ cvClearMemStorage( scanner->storage1 );
+ }
+
+ l_cinfo->contour->v_prev = l_cinfo->parent->contour;
+
+ if( par_info->contour == 0 )
+ {
+ l_cinfo->contour = 0;
+ if( scanner->storage1 == scanner->storage2 )
+ {
+ cvRestoreMemStoragePos( scanner->storage1, &(scanner->backup_pos) );
+ }
+ else
+ {
+ cvClearMemStorage( scanner->storage1 );
+ }
+ p = img[x];
+ goto resume_scan;
+ }
+
+ cvSaveMemStoragePos( scanner->storage2, &(scanner->backup_pos2) );
+ scanner->l_cinfo = l_cinfo;
+ scanner->pt.x = x + 1;
+ scanner->pt.y = y;
+ scanner->lnbd = lnbd;
+ scanner->img = (schar *) img;
+ scanner->nbd = nbd;
+ contour = l_cinfo->contour;
+
+ result = CV_OK;
+ goto exit_func;
+ resume_scan:
+ prev = p;
+ /* update lnbd */
+ if( prev & -2 )
+ {
+ lnbd.x = x;
+ }
+ } /* end of prev != p */
+ } /* end of loop on x */
+
+ lnbd.x = 0;
+ lnbd.y = y + 1;
+ x = 1;
+ prev = 0;
+
+ } /* end of loop on y */
+
+ exit_func:
+
+ if( result != 0 )
+ contour = 0;
+ if( result < 0 )
+ CV_ERROR_FROM_STATUS( result );
+
+ __END__;
+
+ return contour;
+}
+
+
+/*
+ The function add to tree the last retrieved/substituted contour,
+ releases temp_storage, restores state of dst_storage (if needed), and
+ returns pointer to root of the contour tree */
+CV_IMPL CvSeq *
+cvEndFindContours( CvContourScanner * _scanner )
+{
+ CvContourScanner scanner;
+ CvSeq *first = 0;
+
+ CV_FUNCNAME( "cvFindNextContour" );
+
+ __BEGIN__;
+
+ if( !_scanner )
+ CV_ERROR( CV_StsNullPtr, "" );
+ scanner = *_scanner;
+
+ if( scanner )
+ {
+ icvEndProcessContour( scanner );
+
+ if( scanner->storage1 != scanner->storage2 )
+ cvReleaseMemStorage( &(scanner->storage1) );
+
+ if( scanner->cinfo_storage )
+ cvReleaseMemStorage( &(scanner->cinfo_storage) );
+
+ first = scanner->frame.v_next;
+ cvFree( _scanner );
+ }
+
+ __END__;
+
+ return first;
+}
+
+
+#define ICV_SINGLE 0
+#define ICV_CONNECTING_ABOVE 1
+#define ICV_CONNECTING_BELOW -1
+#define ICV_IS_COMPONENT_POINT(val) ((val) != 0)
+
+#define CV_GET_WRITTEN_ELEM( writer ) ((writer).ptr - (writer).seq->elem_size)
+
+typedef struct CvLinkedRunPoint
+{
+ struct CvLinkedRunPoint* link;
+ struct CvLinkedRunPoint* next;
+ CvPoint pt;
+}
+CvLinkedRunPoint;
+
+
+static int
+icvFindContoursInInterval( const CvArr* src,
+ /*int minValue, int maxValue,*/
+ CvMemStorage* storage,
+ CvSeq** result,
+ int contourHeaderSize )
+{
+ int count = 0;
+ CvMemStorage* storage00 = 0;
+ CvMemStorage* storage01 = 0;
+ CvSeq* first = 0;
+
+ CV_FUNCNAME( "icvFindContoursInInterval" );
+
+ __BEGIN__;
+
+ int i, j, k, n;
+
+ uchar* src_data = 0;
+ int img_step = 0;
+ CvSize img_size;
+
+ int connect_flag;
+ int lower_total;
+ int upper_total;
+ int all_total;
+
+ CvSeq* runs;
+ CvLinkedRunPoint tmp;
+ CvLinkedRunPoint* tmp_prev;
+ CvLinkedRunPoint* upper_line = 0;
+ CvLinkedRunPoint* lower_line = 0;
+ CvLinkedRunPoint* last_elem;
+
+ CvLinkedRunPoint* upper_run = 0;
+ CvLinkedRunPoint* lower_run = 0;
+ CvLinkedRunPoint* prev_point = 0;
+
+ CvSeqWriter writer_ext;
+ CvSeqWriter writer_int;
+ CvSeqWriter writer;
+ CvSeqReader reader;
+
+ CvSeq* external_contours;
+ CvSeq* internal_contours;
+ CvSeq* prev = 0;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "NULL storage pointer" );
+
+ if( !result )
+ CV_ERROR( CV_StsNullPtr, "NULL double CvSeq pointer" );
+
+ if( contourHeaderSize < (int)sizeof(CvContour))
+ CV_ERROR( CV_StsBadSize, "Contour header size must be >= sizeof(CvContour)" );
+
+ CV_CALL( storage00 = cvCreateChildMemStorage(storage));
+ CV_CALL( storage01 = cvCreateChildMemStorage(storage));
+
+ {
+ CvMat stub, *mat;
+
+ CV_CALL( mat = cvGetMat( src, &stub ));
+ if( !CV_IS_MASK_ARR(mat))
+ CV_ERROR( CV_StsBadArg, "Input array must be 8uC1 or 8sC1" );
+ src_data = mat->data.ptr;
+ img_step = mat->step;
+ img_size = cvGetMatSize( mat );
+ }
+
+ // Create temporary sequences
+ runs = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvLinkedRunPoint), storage00 );
+ cvStartAppendToSeq( runs, &writer );
+
+ cvStartWriteSeq( 0, sizeof(CvSeq), sizeof(CvLinkedRunPoint*), storage01, &writer_ext );
+ cvStartWriteSeq( 0, sizeof(CvSeq), sizeof(CvLinkedRunPoint*), storage01, &writer_int );
+
+ tmp_prev = &(tmp);
+ tmp_prev->next = 0;
+ tmp_prev->link = 0;
+
+ // First line. None of runs is binded
+ tmp.pt.y = 0;
+ i = 0;
+ CV_WRITE_SEQ_ELEM( tmp, writer );
+ upper_line = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
+
+ tmp_prev = upper_line;
+ for( j = 0; j < img_size.width; )
+ {
+ for( ; j < img_size.width && !ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
+ ;
+ if( j == img_size.width )
+ break;
+
+ tmp.pt.x = j;
+ CV_WRITE_SEQ_ELEM( tmp, writer );
+ tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
+ tmp_prev = tmp_prev->next;
+
+ for( ; j < img_size.width && ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
+ ;
+
+ tmp.pt.x = j-1;
+ CV_WRITE_SEQ_ELEM( tmp, writer );
+ tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
+ tmp_prev->link = tmp_prev->next;
+ // First point of contour
+ CV_WRITE_SEQ_ELEM( tmp_prev, writer_ext );
+ tmp_prev = tmp_prev->next;
+ }
+ cvFlushSeqWriter( &writer );
+ upper_line = upper_line->next;
+ upper_total = runs->total - 1;
+ last_elem = tmp_prev;
+ tmp_prev->next = 0;
+
+ for( i = 1; i < img_size.height; i++ )
+ {
+//------// Find runs in next line
+ src_data += img_step;
+ tmp.pt.y = i;
+ all_total = runs->total;
+ for( j = 0; j < img_size.width; )
+ {
+ for( ; j < img_size.width && !ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
+ ;
+ if( j == img_size.width ) break;
+
+ tmp.pt.x = j;
+ CV_WRITE_SEQ_ELEM( tmp, writer );
+ tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
+ tmp_prev = tmp_prev->next;
+
+ for( ; j < img_size.width && ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
+ ;
+
+ tmp.pt.x = j-1;
+ CV_WRITE_SEQ_ELEM( tmp, writer );
+ tmp_prev = tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
+ }//j
+ cvFlushSeqWriter( &writer );
+ lower_line = last_elem->next;
+ lower_total = runs->total - all_total;
+ last_elem = tmp_prev;
+ tmp_prev->next = 0;
+//------//
+//------// Find links between runs of lower_line and upper_line
+ upper_run = upper_line;
+ lower_run = lower_line;
+ connect_flag = ICV_SINGLE;
+
+ for( k = 0, n = 0; k < upper_total/2 && n < lower_total/2; )
+ {
+ switch( connect_flag )
+ {
+ case ICV_SINGLE:
+ if( upper_run->next->pt.x < lower_run->next->pt.x )
+ {
+ if( upper_run->next->pt.x >= lower_run->pt.x -1 )
+ {
+ lower_run->link = upper_run;
+ connect_flag = ICV_CONNECTING_ABOVE;
+ prev_point = upper_run->next;
+ }
+ else
+ upper_run->next->link = upper_run;
+ k++;
+ upper_run = upper_run->next->next;
+ }
+ else
+ {
+ if( upper_run->pt.x <= lower_run->next->pt.x +1 )
+ {
+ lower_run->link = upper_run;
+ connect_flag = ICV_CONNECTING_BELOW;
+ prev_point = lower_run->next;
+ }
+ else
+ {
+ lower_run->link = lower_run->next;
+ // First point of contour
+ CV_WRITE_SEQ_ELEM( lower_run, writer_ext );
+ }
+ n++;
+ lower_run = lower_run->next->next;
+ }
+ break;
+ case ICV_CONNECTING_ABOVE:
+ if( upper_run->pt.x > lower_run->next->pt.x +1 )
+ {
+ prev_point->link = lower_run->next;
+ connect_flag = ICV_SINGLE;
+ n++;
+ lower_run = lower_run->next->next;
+ }
+ else
+ {
+ prev_point->link = upper_run;
+ if( upper_run->next->pt.x < lower_run->next->pt.x )
+ {
+ k++;
+ prev_point = upper_run->next;
+ upper_run = upper_run->next->next;
+ }
+ else
+ {
+ connect_flag = ICV_CONNECTING_BELOW;
+ prev_point = lower_run->next;
+ n++;
+ lower_run = lower_run->next->next;
+ }
+ }
+ break;
+ case ICV_CONNECTING_BELOW:
+ if( lower_run->pt.x > upper_run->next->pt.x +1 )
+ {
+ upper_run->next->link = prev_point;
+ connect_flag = ICV_SINGLE;
+ k++;
+ upper_run = upper_run->next->next;
+ }
+ else
+ {
+ // First point of contour
+ CV_WRITE_SEQ_ELEM( lower_run, writer_int );
+
+ lower_run->link = prev_point;
+ if( lower_run->next->pt.x < upper_run->next->pt.x )
+ {
+ n++;
+ prev_point = lower_run->next;
+ lower_run = lower_run->next->next;
+ }
+ else
+ {
+ connect_flag = ICV_CONNECTING_ABOVE;
+ k++;
+ prev_point = upper_run->next;
+ upper_run = upper_run->next->next;
+ }
+ }
+ break;
+ }
+ }// k, n
+
+ for( ; n < lower_total/2; n++ )
+ {
+ if( connect_flag != ICV_SINGLE )
+ {
+ prev_point->link = lower_run->next;
+ connect_flag = ICV_SINGLE;
+ lower_run = lower_run->next->next;
+ continue;
+ }
+ lower_run->link = lower_run->next;
+
+ //First point of contour
+ CV_WRITE_SEQ_ELEM( lower_run, writer_ext );
+
+ lower_run = lower_run->next->next;
+ }
+
+ for( ; k < upper_total/2; k++ )
+ {
+ if( connect_flag != ICV_SINGLE )
+ {
+ upper_run->next->link = prev_point;
+ connect_flag = ICV_SINGLE;
+ upper_run = upper_run->next->next;
+ continue;
+ }
+ upper_run->next->link = upper_run;
+ upper_run = upper_run->next->next;
+ }
+ upper_line = lower_line;
+ upper_total = lower_total;
+ }//i
+
+ upper_run = upper_line;
+
+ //the last line of image
+ for( k = 0; k < upper_total/2; k++ )
+ {
+ upper_run->next->link = upper_run;
+ upper_run = upper_run->next->next;
+ }
+
+//------//
+//------//Find end read contours
+ external_contours = cvEndWriteSeq( &writer_ext );
+ internal_contours = cvEndWriteSeq( &writer_int );
+
+ for( k = 0; k < 2; k++ )
+ {
+ CvSeq* contours = k == 0 ? external_contours : internal_contours;
+
+ cvStartReadSeq( contours, &reader );
+
+ for( j = 0; j < contours->total; j++, count++ )
+ {
+ CvLinkedRunPoint* p_temp;
+ CvLinkedRunPoint* p00;
+ CvLinkedRunPoint* p01;
+ CvSeq* contour;
+
+ CV_READ_SEQ_ELEM( p00, reader );
+ p01 = p00;
+
+ if( !p00->link )
+ continue;
+
+ cvStartWriteSeq( CV_SEQ_ELTYPE_POINT | CV_SEQ_POLYLINE | CV_SEQ_FLAG_CLOSED,
+ contourHeaderSize, sizeof(CvPoint), storage, &writer );
+ do
+ {
+ CV_WRITE_SEQ_ELEM( p00->pt, writer );
+ p_temp = p00;
+ p00 = p00->link;
+ p_temp->link = 0;
+ }
+ while( p00 != p01 );
+
+ contour = cvEndWriteSeq( &writer );
+ cvBoundingRect( contour, 1 );
+
+ if( k != 0 )
+ contour->flags |= CV_SEQ_FLAG_HOLE;
+
+ if( !first )
+ prev = first = contour;
+ else
+ {
+ contour->h_prev = prev;
+ prev = prev->h_next = contour;
+ }
+ }
+ }
+
+ __END__;
+
+ if( !first )
+ count = -1;
+
+ if( result )
+ *result = first;
+
+ cvReleaseMemStorage(&storage00);
+ cvReleaseMemStorage(&storage01);
+
+ return count;
+}
+
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvFindContours
+// Purpose:
+// Finds all the contours on the bi-level image.
+// Context:
+// Parameters:
+// img - source image.
+// Non-zero pixels are considered as 1-pixels
+// and zero pixels as 0-pixels.
+// step - full width of source image in bytes.
+// size - width and height of the image in pixels
+// storage - pointer to storage where will the output contours be placed.
+// header_size - header size of resulting contours
+// mode - mode of contour retrieval.
+// method - method of approximation that is applied to contours
+// first_contour - pointer to first contour pointer
+// Returns:
+// CV_OK or error code
+// Notes:
+//F*/
+CV_IMPL int
+cvFindContours( void* img, CvMemStorage* storage,
+ CvSeq** firstContour, int cntHeaderSize,
+ int mode,
+ int method, CvPoint offset )
+{
+ CvContourScanner scanner = 0;
+ CvSeq *contour = 0;
+ int count = -1;
+
+ CV_FUNCNAME( "cvFindContours" );
+
+ __BEGIN__;
+
+ if( !firstContour )
+ CV_ERROR( CV_StsNullPtr, "NULL double CvSeq pointer" );
+
+ if( method == CV_LINK_RUNS )
+ {
+ if( offset.x != 0 || offset.y != 0 )
+ CV_ERROR( CV_StsOutOfRange,
+ "Nonzero offset is not supported in CV_LINK_RUNS yet" );
+
+ CV_CALL( count = icvFindContoursInInterval( img, storage,
+ firstContour, cntHeaderSize ));
+ }
+ else
+ {
+ CV_CALL( scanner = cvStartFindContours( img, storage,
+ cntHeaderSize, mode, method, offset ));
+ assert( scanner );
+
+ do
+ {
+ count++;
+ contour = cvFindNextContour( scanner );
+ }
+ while( contour != 0 );
+
+ *firstContour = cvEndFindContours( &scanner );
+ }
+
+ __END__;
+
+ return count;
+}
+
+
+/* End of file. */
diff --git a/cv/src/cvcontourtree.cpp b/cv/src/cvcontourtree.cpp
new file mode 100644
index 0000000..a3d99c8
--- /dev/null
+++ b/cv/src/cvcontourtree.cpp
@@ -0,0 +1,804 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+#define CV_MATCH_CHECK( status, cvFun ) \
+ { \
+ status = cvFun; \
+ if( status != CV_OK ) \
+ goto M_END; \
+ }
+
+static CvStatus
+icvCalcTriAttr( const CvSeq * contour, CvPoint t2, CvPoint t1, int n1,
+ CvPoint t3, int n3, double *s, double *s_c,
+ double *h, double *a, double *b );
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvCreateContourTree
+// Purpose:
+// Create binary tree representation for the contour
+// Context:
+// Parameters:
+// contour - pointer to input contour object.
+// storage - pointer to the current storage block
+// tree - output pointer to the binary tree representation
+// threshold - threshold for the binary tree building
+//
+//F*/
+static CvStatus
+icvCreateContourTree( const CvSeq * contour, CvMemStorage * storage,
+ CvContourTree ** tree, double threshold )
+{
+ CvPoint *pt_p; /* pointer to previos points */
+ CvPoint *pt_n; /* pointer to next points */
+ CvPoint *pt1, *pt2; /* pointer to current points */
+
+ CvPoint t, tp1, tp2, tp3, tn1, tn2, tn3;
+ int lpt, flag, i, j, i_tree, j_1, j_3, i_buf;
+ double s, sp1, sp2, sn1, sn2, s_c, sp1_c, sp2_c, sn1_c, sn2_c, h, hp1, hp2, hn1, hn2,
+ a, ap1, ap2, an1, an2, b, bp1, bp2, bn1, bn2;
+ double a_s_c, a_sp1_c;
+
+ _CvTrianAttr **ptr_p, **ptr_n, **ptr1, **ptr2; /* pointers to pointers of triangles */
+ _CvTrianAttr *cur_adr;
+
+ int *num_p, *num_n, *num1, *num2; /* numbers of input contour points */
+ int nm, nmp1, nmp2, nmp3, nmn1, nmn2, nmn3;
+ int seq_flags = 1, i_end, prev_null, prev2_null;
+ double koef = 1.5;
+ double eps = 1.e-7;
+ double e;
+ CvStatus status;
+ int hearder_size;
+ _CvTrianAttr tree_one, tree_two, *tree_end, *tree_root;
+
+ CvSeqWriter writer;
+
+ assert( contour != NULL && contour->total >= 4 );
+ status = CV_OK;
+
+ if( contour == NULL )
+ return CV_NULLPTR_ERR;
+ if( contour->total < 4 )
+ return CV_BADSIZE_ERR;
+
+ if( !CV_IS_SEQ_POLYGON( contour ))
+ return CV_BADFLAG_ERR;
+
+
+/* Convert Sequence to array */
+ lpt = contour->total;
+ pt_p = pt_n = NULL;
+ num_p = num_n = NULL;
+ ptr_p = ptr_n = ptr1 = ptr2 = NULL;
+ tree_end = NULL;
+
+ pt_p = (CvPoint *) cvAlloc( lpt * sizeof( CvPoint ));
+ pt_n = (CvPoint *) cvAlloc( lpt * sizeof( CvPoint ));
+
+ num_p = (int *) cvAlloc( lpt * sizeof( int ));
+ num_n = (int *) cvAlloc( lpt * sizeof( int ));
+
+ hearder_size = sizeof( CvContourTree );
+ seq_flags = CV_SEQ_POLYGON_TREE;
+ cvStartWriteSeq( seq_flags, hearder_size, sizeof( _CvTrianAttr ), storage, &writer );
+
+ ptr_p = (_CvTrianAttr **) cvAlloc( lpt * sizeof( _CvTrianAttr * ));
+ ptr_n = (_CvTrianAttr **) cvAlloc( lpt * sizeof( _CvTrianAttr * ));
+
+ memset( ptr_p, 0, lpt * sizeof( _CvTrianAttr * ));
+ memset( ptr_n, 0, lpt * sizeof( _CvTrianAttr * ));
+
+ if( pt_p == NULL || pt_n == NULL )
+ return CV_OUTOFMEM_ERR;
+ if( ptr_p == NULL || ptr_n == NULL )
+ return CV_OUTOFMEM_ERR;
+
+/* write fild for the binary tree root */
+/* start_writer = writer; */
+
+ tree_one.pt.x = tree_one.pt.y = 0;
+ tree_one.sign = 0;
+ tree_one.area = 0;
+ tree_one.r1 = tree_one.r2 = 0;
+ tree_one.next_v1 = tree_one.next_v2 = tree_one.prev_v = NULL;
+
+ CV_WRITE_SEQ_ELEM( tree_one, writer );
+ tree_root = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
+
+ if( cvCvtSeqToArray( contour, (char *) pt_p ) == (char *) contour )
+ return CV_BADPOINT_ERR;
+
+ for( i = 0; i < lpt; i++ )
+ num_p[i] = i;
+
+ i = lpt;
+ flag = 0;
+ i_tree = 0;
+ e = 20.; /* initial threshold value */
+ ptr1 = ptr_p;
+ ptr2 = ptr_n;
+ pt1 = pt_p;
+ pt2 = pt_n;
+ num1 = num_p;
+ num2 = num_n;
+/* binary tree constraction */
+ while( i > 4 )
+ {
+ if( flag == 0 )
+ {
+ ptr1 = ptr_p;
+ ptr2 = ptr_n;
+ pt1 = pt_p;
+ pt2 = pt_n;
+ num1 = num_p;
+ num2 = num_n;
+ flag = 1;
+ }
+ else
+ {
+ ptr1 = ptr_n;
+ ptr2 = ptr_p;
+ pt1 = pt_n;
+ pt2 = pt_p;
+ num1 = num_n;
+ num2 = num_p;
+ flag = 0;
+ }
+ t = pt1[0];
+ nm = num1[0];
+ tp1 = pt1[i - 1];
+ nmp1 = num1[i - 1];
+ tp2 = pt1[i - 2];
+ nmp2 = num1[i - 2];
+ tp3 = pt1[i - 3];
+ nmp3 = num1[i - 3];
+ tn1 = pt1[1];
+ nmn1 = num1[1];
+ tn2 = pt1[2];
+ nmn2 = num1[2];
+
+ i_buf = 0;
+ i_end = -1;
+ CV_MATCH_CHECK( status,
+ icvCalcTriAttr( contour, t, tp1, nmp1, tn1, nmn1, &s, &s_c, &h, &a,
+ &b ));
+ CV_MATCH_CHECK( status,
+ icvCalcTriAttr( contour, tp1, tp2, nmp2, t, nm, &sp1, &sp1_c, &hp1,
+ &ap1, &bp1 ));
+ CV_MATCH_CHECK( status,
+ icvCalcTriAttr( contour, tp2, tp3, nmp3, tp1, nmp1, &sp2, &sp2_c, &hp2,
+ &ap2, &bp2 ));
+ CV_MATCH_CHECK( status,
+ icvCalcTriAttr( contour, tn1, t, nm, tn2, nmn2, &sn1, &sn1_c, &hn1,
+ &an1, &bn1 ));
+
+
+ j_3 = 3;
+ prev_null = prev2_null = 0;
+ for( j = 0; j < i; j++ )
+ {
+ tn3 = pt1[j_3];
+ nmn3 = num1[j_3];
+ if( j == 0 )
+ j_1 = i - 1;
+ else
+ j_1 = j - 1;
+
+ CV_MATCH_CHECK( status, icvCalcTriAttr( contour, tn2, tn1, nmn1, tn3, nmn3,
+ &sn2, &sn2_c, &hn2, &an2, &bn2 ));
+
+ if( (s_c < sp1_c && s_c < sp2_c && s_c <= sn1_c && s_c <= sn2_c && s_c < e) ||
+ (((s_c == sp1_c && s_c <= sp2_c) || (s_c == sp2_c && s_c <= sp1_c)) &&
+ s_c <= sn1_c && s_c <= sn2_c && s_c < e && j > 1 && prev2_null == 0) ||
+ (s_c < eps && j > 0 && prev_null == 0) )
+ {
+ prev_null = prev2_null = 1;
+ if( s_c < threshold )
+ {
+ if( ptr1[j_1] == NULL && ptr1[j] == NULL )
+ {
+ if( i_buf > 0 )
+ ptr2[i_buf - 1] = NULL;
+ else
+ i_end = 0;
+ }
+ else
+ {
+/* form next vertex */
+ tree_one.pt = t;
+ tree_one.sign = (char) (CV_SIGN( s ));
+ tree_one.r1 = h / a;
+ tree_one.r2 = b / a;
+ tree_one.area = fabs( s );
+ tree_one.next_v1 = ptr1[j_1];
+ tree_one.next_v2 = ptr1[j];
+
+ CV_WRITE_SEQ_ELEM( tree_one, writer );
+ cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
+
+ if( ptr1[j_1] != NULL )
+ ptr1[j_1]->prev_v = cur_adr;
+ if( ptr1[j] != NULL )
+ ptr1[j]->prev_v = cur_adr;
+
+ if( i_buf > 0 )
+ ptr2[i_buf - 1] = cur_adr;
+ else
+ {
+ tree_end = (_CvTrianAttr *) writer.ptr;
+ i_end = 1;
+ }
+ i_tree++;
+ }
+ }
+ else
+/* form next vertex */
+ {
+ tree_one.pt = t;
+ tree_one.sign = (char) (CV_SIGN( s ));
+ tree_one.area = fabs( s );
+ tree_one.r1 = h / a;
+ tree_one.r2 = b / a;
+ tree_one.next_v1 = ptr1[j_1];
+ tree_one.next_v2 = ptr1[j];
+
+ CV_WRITE_SEQ_ELEM( tree_one, writer );
+ cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
+
+ if( ptr1[j_1] != NULL )
+ ptr1[j_1]->prev_v = cur_adr;
+ if( ptr1[j] != NULL )
+ ptr1[j]->prev_v = cur_adr;
+
+ if( i_buf > 0 )
+ ptr2[i_buf - 1] = cur_adr;
+ else
+ {
+ tree_end = cur_adr;
+ i_end = 1;
+ }
+ i_tree++;
+ }
+ }
+ else
+/* the current triangle is'not LMIAT */
+ {
+ prev_null = 0;
+ switch (prev2_null)
+ {
+ case 0:
+ break;
+ case 1:
+ {
+ prev2_null = 2;
+ break;
+ }
+ case 2:
+ {
+ prev2_null = 0;
+ break;
+ }
+ }
+ if( j != i - 1 || i_end == -1 )
+ ptr2[i_buf] = ptr1[j];
+ else if( i_end == 0 )
+ ptr2[i_buf] = NULL;
+ else
+ ptr2[i_buf] = tree_end;
+ pt2[i_buf] = t;
+ num2[i_buf] = num1[j];
+ i_buf++;
+ }
+/* go to next vertex */
+ tp3 = tp2;
+ tp2 = tp1;
+ tp1 = t;
+ t = tn1;
+ tn1 = tn2;
+ tn2 = tn3;
+ nmp3 = nmp2;
+ nmp2 = nmp1;
+ nmp1 = nm;
+ nm = nmn1;
+ nmn1 = nmn2;
+ nmn2 = nmn3;
+
+ sp2 = sp1;
+ sp1 = s;
+ s = sn1;
+ sn1 = sn2;
+ sp2_c = sp1_c;
+ sp1_c = s_c;
+ s_c = sn1_c;
+ sn1_c = sn2_c;
+
+ ap2 = ap1;
+ ap1 = a;
+ a = an1;
+ an1 = an2;
+ bp2 = bp1;
+ bp1 = b;
+ b = bn1;
+ bn1 = bn2;
+ hp2 = hp1;
+ hp1 = h;
+ h = hn1;
+ hn1 = hn2;
+ j_3++;
+ if( j_3 >= i )
+ j_3 = 0;
+ }
+
+ i = i_buf;
+ e = e * koef;
+ }
+
+/* constract tree root */
+ if( i != 4 )
+ return CV_BADFACTOR_ERR;
+
+ t = pt2[0];
+ tn1 = pt2[1];
+ tn2 = pt2[2];
+ tp1 = pt2[3];
+ nm = num2[0];
+ nmn1 = num2[1];
+ nmn2 = num2[2];
+ nmp1 = num2[3];
+/* first pair of the triangles */
+ CV_MATCH_CHECK( status,
+ icvCalcTriAttr( contour, t, tp1, nmp1, tn1, nmn1, &s, &s_c, &h, &a, &b ));
+ CV_MATCH_CHECK( status,
+ icvCalcTriAttr( contour, tn2, tn1, nmn1, tp1, nmp1, &sn2, &sn2_c, &hn2,
+ &an2, &bn2 ));
+/* second pair of the triangles */
+ CV_MATCH_CHECK( status,
+ icvCalcTriAttr( contour, tn1, t, nm, tn2, nmn2, &sn1, &sn1_c, &hn1, &an1,
+ &bn1 ));
+ CV_MATCH_CHECK( status,
+ icvCalcTriAttr( contour, tp1, tn2, nmn2, t, nm, &sp1, &sp1_c, &hp1, &ap1,
+ &bp1 ));
+
+ a_s_c = fabs( s_c - sn2_c );
+ a_sp1_c = fabs( sp1_c - sn1_c );
+
+ if( a_s_c > a_sp1_c )
+/* form child vertexs for the root */
+ {
+ tree_one.pt = t;
+ tree_one.sign = (char) (CV_SIGN( s ));
+ tree_one.area = fabs( s );
+ tree_one.r1 = h / a;
+ tree_one.r2 = b / a;
+ tree_one.next_v1 = ptr2[3];
+ tree_one.next_v2 = ptr2[0];
+
+ tree_two.pt = tn2;
+ tree_two.sign = (char) (CV_SIGN( sn2 ));
+ tree_two.area = fabs( sn2 );
+ tree_two.r1 = hn2 / an2;
+ tree_two.r2 = bn2 / an2;
+ tree_two.next_v1 = ptr2[1];
+ tree_two.next_v2 = ptr2[2];
+
+ CV_WRITE_SEQ_ELEM( tree_one, writer );
+ cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
+
+ if( s_c > sn2_c )
+ {
+ if( ptr2[3] != NULL )
+ ptr2[3]->prev_v = cur_adr;
+ if( ptr2[0] != NULL )
+ ptr2[0]->prev_v = cur_adr;
+ ptr1[0] = cur_adr;
+
+ i_tree++;
+
+ CV_WRITE_SEQ_ELEM( tree_two, writer );
+ cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
+
+ if( ptr2[1] != NULL )
+ ptr2[1]->prev_v = cur_adr;
+ if( ptr2[2] != NULL )
+ ptr2[2]->prev_v = cur_adr;
+ ptr1[1] = cur_adr;
+
+ i_tree++;
+
+ pt1[0] = tp1;
+ pt1[1] = tn1;
+ }
+ else
+ {
+ CV_WRITE_SEQ_ELEM( tree_two, writer );
+ cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
+
+ if( ptr2[1] != NULL )
+ ptr2[1]->prev_v = cur_adr;
+ if( ptr2[2] != NULL )
+ ptr2[2]->prev_v = cur_adr;
+ ptr1[0] = cur_adr;
+
+ i_tree++;
+
+ CV_WRITE_SEQ_ELEM( tree_one, writer );
+ cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
+
+ if( ptr2[3] != NULL )
+ ptr2[3]->prev_v = cur_adr;
+ if( ptr2[0] != NULL )
+ ptr2[0]->prev_v = cur_adr;
+ ptr1[1] = cur_adr;
+
+ i_tree++;
+
+ pt1[0] = tn1;
+ pt1[1] = tp1;
+ }
+ }
+ else
+ {
+ tree_one.pt = tp1;
+ tree_one.sign = (char) (CV_SIGN( sp1 ));
+ tree_one.area = fabs( sp1 );
+ tree_one.r1 = hp1 / ap1;
+ tree_one.r2 = bp1 / ap1;
+ tree_one.next_v1 = ptr2[2];
+ tree_one.next_v2 = ptr2[3];
+
+ tree_two.pt = tn1;
+ tree_two.sign = (char) (CV_SIGN( sn1 ));
+ tree_two.area = fabs( sn1 );
+ tree_two.r1 = hn1 / an1;
+ tree_two.r2 = bn1 / an1;
+ tree_two.next_v1 = ptr2[0];
+ tree_two.next_v2 = ptr2[1];
+
+ CV_WRITE_SEQ_ELEM( tree_one, writer );
+ cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
+
+ if( sp1_c > sn1_c )
+ {
+ if( ptr2[2] != NULL )
+ ptr2[2]->prev_v = cur_adr;
+ if( ptr2[3] != NULL )
+ ptr2[3]->prev_v = cur_adr;
+ ptr1[0] = cur_adr;
+
+ i_tree++;
+
+ CV_WRITE_SEQ_ELEM( tree_two, writer );
+ cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
+
+ if( ptr2[0] != NULL )
+ ptr2[0]->prev_v = cur_adr;
+ if( ptr2[1] != NULL )
+ ptr2[1]->prev_v = cur_adr;
+ ptr1[1] = cur_adr;
+
+ i_tree++;
+
+ pt1[0] = tn2;
+ pt1[1] = t;
+ }
+ else
+ {
+ CV_WRITE_SEQ_ELEM( tree_two, writer );
+ cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
+
+ if( ptr2[0] != NULL )
+ ptr2[0]->prev_v = cur_adr;
+ if( ptr2[1] != NULL )
+ ptr2[1]->prev_v = cur_adr;
+ ptr1[0] = cur_adr;
+
+ i_tree++;
+
+ CV_WRITE_SEQ_ELEM( tree_one, writer );
+ cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
+
+ if( ptr2[2] != NULL )
+ ptr2[2]->prev_v = cur_adr;
+ if( ptr2[3] != NULL )
+ ptr2[3]->prev_v = cur_adr;
+ ptr1[1] = cur_adr;
+
+ i_tree++;
+
+ pt1[0] = t;
+ pt1[1] = tn2;
+
+ }
+ }
+
+/* form root */
+ s = cvContourArea( contour );
+
+ tree_root->pt = pt1[1];
+ tree_root->sign = 0;
+ tree_root->area = fabs( s );
+ tree_root->r1 = 0;
+ tree_root->r2 = 0;
+ tree_root->next_v1 = ptr1[0];
+ tree_root->next_v2 = ptr1[1];
+ tree_root->prev_v = NULL;
+
+ ptr1[0]->prev_v = (_CvTrianAttr *) tree_root;
+ ptr1[1]->prev_v = (_CvTrianAttr *) tree_root;
+
+/* write binary tree root */
+/* CV_WRITE_SEQ_ELEM (tree_one, start_writer); */
+ i_tree++;
+/* create Sequence hearder */
+ *((CvSeq **) tree) = cvEndWriteSeq( &writer );
+/* write points for the main segment into sequence header */
+ (*tree)->p1 = pt1[0];
+
+ M_END:
+
+ cvFree( &ptr_n );
+ cvFree( &ptr_p );
+ cvFree( &num_n );
+ cvFree( &num_p );
+ cvFree( &pt_n );
+ cvFree( &pt_p );
+
+ return status;
+}
+
+/****************************************************************************************\
+
+ triangle attributes calculations
+
+\****************************************************************************************/
+static CvStatus
+icvCalcTriAttr( const CvSeq * contour, CvPoint t2, CvPoint t1, int n1,
+ CvPoint t3, int n3, double *s, double *s_c,
+ double *h, double *a, double *b )
+{
+ double x13, y13, x12, y12, l_base, nx, ny, qq;
+ double eps = 1.e-5;
+
+ x13 = t3.x - t1.x;
+ y13 = t3.y - t1.y;
+ x12 = t2.x - t1.x;
+ y12 = t2.y - t1.y;
+ qq = x13 * x13 + y13 * y13;
+ l_base = cvSqrt( (float) (qq) );
+ if( l_base > eps )
+ {
+ nx = y13 / l_base;
+ ny = -x13 / l_base;
+
+ *h = nx * x12 + ny * y12;
+
+ *s = (*h) * l_base / 2.;
+
+ *b = nx * y12 - ny * x12;
+
+ *a = l_base;
+/* calculate interceptive area */
+ *s_c = cvContourArea( contour, cvSlice(n1, n3+1));
+ }
+ else
+ {
+ *h = 0;
+ *s = 0;
+ *s_c = 0;
+ *b = 0;
+ *a = 0;
+ }
+
+ return CV_OK;
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvCreateContourTree
+// Purpose:
+// Create binary tree representation for the contour
+// Context:
+// Parameters:
+// contour - pointer to input contour object.
+// storage - pointer to the current storage block
+// tree - output pointer to the binary tree representation
+// threshold - threshold for the binary tree building
+//
+//F*/
+CV_IMPL CvContourTree*
+cvCreateContourTree( const CvSeq* contour, CvMemStorage* storage, double threshold )
+{
+ CvContourTree* tree = 0;
+
+ CV_FUNCNAME( "cvCreateContourTree" );
+ __BEGIN__;
+
+ IPPI_CALL( icvCreateContourTree( contour, storage, &tree, threshold ));
+
+ __CLEANUP__;
+ __END__;
+
+ return tree;
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvContourFromContourTree
+// Purpose:
+// reconstracts contour from binary tree representation
+// Context:
+// Parameters:
+// tree - pointer to the input binary tree representation
+// storage - pointer to the current storage block
+// contour - pointer to output contour object.
+// criteria - criteria for the definition threshold value
+// for the contour reconstracting (level or precision)
+//F*/
+CV_IMPL CvSeq*
+cvContourFromContourTree( const CvContourTree* tree,
+ CvMemStorage* storage,
+ CvTermCriteria criteria )
+{
+ CvSeq* contour = 0;
+ _CvTrianAttr **ptr_buf = 0; /* pointer to the pointer's buffer */
+ int *level_buf = 0;
+ int i_buf;
+
+ int lpt;
+ double area_all;
+ double threshold;
+ int cur_level;
+ int level;
+ int seq_flags;
+ char log_iter, log_eps;
+ int out_hearder_size;
+ _CvTrianAttr *tree_one = 0, tree_root; /* current vertex */
+
+ CvSeqReader reader;
+ CvSeqWriter writer;
+
+ CV_FUNCNAME("cvContourFromContourTree");
+
+ __BEGIN__;
+
+ if( !tree )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !CV_IS_SEQ_POLYGON_TREE( tree ))
+ CV_ERROR_FROM_STATUS( CV_BADFLAG_ERR );
+
+ criteria = cvCheckTermCriteria( criteria, 0., 100 );
+
+ lpt = tree->total;
+ ptr_buf = NULL;
+ level_buf = NULL;
+ i_buf = 0;
+ cur_level = 0;
+ log_iter = (char) (criteria.type == CV_TERMCRIT_ITER ||
+ (criteria.type == CV_TERMCRIT_ITER + CV_TERMCRIT_EPS));
+ log_eps = (char) (criteria.type == CV_TERMCRIT_EPS ||
+ (criteria.type == CV_TERMCRIT_ITER + CV_TERMCRIT_EPS));
+
+ cvStartReadSeq( (CvSeq *) tree, &reader, 0 );
+
+ out_hearder_size = sizeof( CvContour );
+
+ seq_flags = CV_SEQ_POLYGON;
+ cvStartWriteSeq( seq_flags, out_hearder_size, sizeof( CvPoint ), storage, &writer );
+
+ ptr_buf = (_CvTrianAttr **) cvAlloc( lpt * sizeof( _CvTrianAttr * ));
+ if( ptr_buf == NULL )
+ CV_ERROR_FROM_STATUS( CV_OUTOFMEM_ERR );
+ if( log_iter )
+ {
+ level_buf = (int *) cvAlloc( lpt * (sizeof( int )));
+
+ if( level_buf == NULL )
+ CV_ERROR_FROM_STATUS( CV_OUTOFMEM_ERR );
+ }
+
+ memset( ptr_buf, 0, lpt * sizeof( _CvTrianAttr * ));
+
+/* write the first tree root's point as a start point of the result contour */
+ CV_WRITE_SEQ_ELEM( tree->p1, writer );
+/* write the second tree root"s point into buffer */
+
+/* read the root of the tree */
+ CV_READ_SEQ_ELEM( tree_root, reader );
+
+ tree_one = &tree_root;
+ area_all = tree_one->area;
+
+ if( log_eps )
+ threshold = criteria.epsilon * area_all;
+ else
+ threshold = 10 * area_all;
+
+ if( log_iter )
+ level = criteria.max_iter;
+ else
+ level = -1;
+
+/* contour from binary tree constraction */
+ while( i_buf >= 0 )
+ {
+ if( tree_one != NULL && (cur_level <= level || tree_one->area >= threshold) )
+/* go to left sub tree for the vertex and save pointer to the right vertex */
+/* into the buffer */
+ {
+ ptr_buf[i_buf] = tree_one;
+ if( log_iter )
+ {
+ level_buf[i_buf] = cur_level;
+ cur_level++;
+ }
+ i_buf++;
+ tree_one = tree_one->next_v1;
+ }
+ else
+ {
+ i_buf--;
+ if( i_buf >= 0 )
+ {
+ CvPoint pt = ptr_buf[i_buf]->pt;
+ CV_WRITE_SEQ_ELEM( pt, writer );
+ tree_one = ptr_buf[i_buf]->next_v2;
+ if( log_iter )
+ {
+ cur_level = level_buf[i_buf] + 1;
+ }
+ }
+ }
+ }
+
+ contour = cvEndWriteSeq( &writer );
+ cvBoundingRect( contour, 1 );
+
+ __CLEANUP__;
+ __END__;
+
+ cvFree( &level_buf );
+ cvFree( &ptr_buf );
+
+ return contour;
+}
+
diff --git a/cv/src/cvconvhull.cpp b/cv/src/cvconvhull.cpp
new file mode 100644
index 0000000..eafc568
--- /dev/null
+++ b/cv/src/cvconvhull.cpp
@@ -0,0 +1,851 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+static int
+icvSklansky_32s( CvPoint** array, int start, int end, int* stack, int nsign, int sign2 )
+{
+ int incr = end > start ? 1 : -1;
+ /* prepare first triangle */
+ int pprev = start, pcur = pprev + incr, pnext = pcur + incr;
+ int stacksize = 3;
+
+ if( start == end ||
+ (array[start]->x == array[end]->x &&
+ array[start]->y == array[end]->y) )
+ {
+ stack[0] = start;
+ return 1;
+ }
+
+ stack[0] = pprev;
+ stack[1] = pcur;
+ stack[2] = pnext;
+
+ end += incr; /* make end = afterend */
+
+ while( pnext != end )
+ {
+ /* check the angle p1,p2,p3 */
+ int cury = array[pcur]->y;
+ int nexty = array[pnext]->y;
+ int by = nexty - cury;
+
+ if( CV_SIGN(by) != nsign )
+ {
+ int ax = array[pcur]->x - array[pprev]->x;
+ int bx = array[pnext]->x - array[pcur]->x;
+ int ay = cury - array[pprev]->y;
+ int convexity = ay*bx - ax*by;/* if >0 then convex angle */
+
+ if( CV_SIGN(convexity) == sign2 && (ax != 0 || ay != 0) )
+ {
+ pprev = pcur;
+ pcur = pnext;
+ pnext += incr;
+ stack[stacksize] = pnext;
+ stacksize++;
+ }
+ else
+ {
+ if( pprev == start )
+ {
+ pcur = pnext;
+ stack[1] = pcur;
+ pnext += incr;
+ stack[2] = pnext;
+ }
+ else
+ {
+ stack[stacksize-2] = pnext;
+ pcur = pprev;
+ pprev = stack[stacksize-4];
+ stacksize--;
+ }
+ }
+ }
+ else
+ {
+ pnext += incr;
+ stack[stacksize-1] = pnext;
+ }
+ }
+
+ return --stacksize;
+}
+
+
+static int
+icvSklansky_32f( CvPoint2D32f** array, int start, int end, int* stack, int nsign, int sign2 )
+{
+ int incr = end > start ? 1 : -1;
+ /* prepare first triangle */
+ int pprev = start, pcur = pprev + incr, pnext = pcur + incr;
+ int stacksize = 3;
+
+ if( start == end ||
+ (array[start]->x == array[end]->x &&
+ array[start]->y == array[end]->y) )
+ {
+ stack[0] = start;
+ return 1;
+ }
+
+ stack[0] = pprev;
+ stack[1] = pcur;
+ stack[2] = pnext;
+
+ end += incr; /* make end = afterend */
+
+ while( pnext != end )
+ {
+ /* check the angle p1,p2,p3 */
+ float cury = array[pcur]->y;
+ float nexty = array[pnext]->y;
+ float by = nexty - cury;
+
+ if( CV_SIGN( by ) != nsign )
+ {
+ float ax = array[pcur]->x - array[pprev]->x;
+ float bx = array[pnext]->x - array[pcur]->x;
+ float ay = cury - array[pprev]->y;
+ float convexity = ay*bx - ax*by;/* if >0 then convex angle */
+
+ if( CV_SIGN( convexity ) == sign2 && (ax != 0 || ay != 0) )
+ {
+ pprev = pcur;
+ pcur = pnext;
+ pnext += incr;
+ stack[stacksize] = pnext;
+ stacksize++;
+ }
+ else
+ {
+ if( pprev == start )
+ {
+ pcur = pnext;
+ stack[1] = pcur;
+ pnext += incr;
+ stack[2] = pnext;
+
+ }
+ else
+ {
+ stack[stacksize-2] = pnext;
+ pcur = pprev;
+ pprev = stack[stacksize-4];
+ stacksize--;
+ }
+ }
+ }
+ else
+ {
+ pnext += incr;
+ stack[stacksize-1] = pnext;
+ }
+ }
+
+ return --stacksize;
+}
+
+typedef int (*sklansky_func)( CvPoint** points, int start, int end,
+ int* stack, int sign, int sign2 );
+
+#define cmp_pts( pt1, pt2 ) \
+ ((pt1)->x < (pt2)->x || ((pt1)->x <= (pt2)->x && (pt1)->y < (pt2)->y))
+static CV_IMPLEMENT_QSORT( icvSortPointsByPointers_32s, CvPoint*, cmp_pts )
+static CV_IMPLEMENT_QSORT( icvSortPointsByPointers_32f, CvPoint2D32f*, cmp_pts )
+
+static void
+icvCalcAndWritePtIndices( CvPoint** pointer, int* stack, int start, int end,
+ CvSeq* ptseq, CvSeqWriter* writer )
+{
+ CV_FUNCNAME( "icvCalcAndWritePtIndices" );
+
+ __BEGIN__;
+
+ int i, incr = start < end ? 1 : -1;
+ int idx, first_idx = ptseq->first->start_index;
+
+ for( i = start; i != end; i += incr )
+ {
+ CvPoint* ptr = (CvPoint*)pointer[stack[i]];
+ CvSeqBlock* block = ptseq->first;
+ while( (unsigned)(idx = (int)(ptr - (CvPoint*)block->data)) >= (unsigned)block->count )
+ {
+ block = block->next;
+ if( block == ptseq->first )
+ CV_ERROR( CV_StsError, "Internal error" );
+ }
+ idx += block->start_index - first_idx;
+ CV_WRITE_SEQ_ELEM( idx, *writer );
+ }
+
+ __END__;
+}
+
+
+CV_IMPL CvSeq*
+cvConvexHull2( const CvArr* array, void* hull_storage,
+ int orientation, int return_points )
+{
+ union { CvContour* c; CvSeq* s; } hull;
+ CvPoint** pointer = 0;
+ CvPoint2D32f** pointerf = 0;
+ int* stack = 0;
+
+ CV_FUNCNAME( "cvConvexHull2" );
+
+ hull.s = 0;
+
+ __BEGIN__;
+
+ CvMat* mat = 0;
+ CvSeqReader reader;
+ CvSeqWriter writer;
+ CvContour contour_header;
+ union { CvContour c; CvSeq s; } hull_header;
+ CvSeqBlock block, hullblock;
+ CvSeq* ptseq = 0;
+ CvSeq* hullseq = 0;
+ int is_float;
+ int* t_stack;
+ int t_count;
+ int i, miny_ind = 0, maxy_ind = 0, total;
+ int hulltype;
+ int stop_idx;
+ sklansky_func sklansky;
+
+ if( CV_IS_SEQ( array ))
+ {
+ ptseq = (CvSeq*)array;
+ if( !CV_IS_SEQ_POINT_SET( ptseq ))
+ CV_ERROR( CV_StsBadArg, "Unsupported sequence type" );
+ if( hull_storage == 0 )
+ hull_storage = ptseq->storage;
+ }
+ else
+ {
+ CV_CALL( ptseq = cvPointSeqFromMat(
+ CV_SEQ_KIND_GENERIC, array, &contour_header, &block ));
+ }
+
+ if( CV_IS_STORAGE( hull_storage ))
+ {
+ if( return_points )
+ {
+ CV_CALL( hullseq = cvCreateSeq(
+ CV_SEQ_KIND_CURVE|CV_SEQ_ELTYPE(ptseq)|
+ CV_SEQ_FLAG_CLOSED|CV_SEQ_FLAG_CONVEX,
+ sizeof(CvContour), sizeof(CvPoint),(CvMemStorage*)hull_storage ));
+ }
+ else
+ {
+ CV_CALL( hullseq = cvCreateSeq(
+ CV_SEQ_KIND_CURVE|CV_SEQ_ELTYPE_PPOINT|
+ CV_SEQ_FLAG_CLOSED|CV_SEQ_FLAG_CONVEX,
+ sizeof(CvContour), sizeof(CvPoint*), (CvMemStorage*)hull_storage ));
+ }
+ }
+ else
+ {
+ if( !CV_IS_MAT( hull_storage ))
+ CV_ERROR(CV_StsBadArg, "Destination must be valid memory storage or matrix");
+
+ mat = (CvMat*)hull_storage;
+
+ if( (mat->cols != 1 && mat->rows != 1) || !CV_IS_MAT_CONT(mat->type))
+ CV_ERROR( CV_StsBadArg,
+ "The hull matrix should be continuous and have a single row or a single column" );
+
+ if( mat->cols + mat->rows - 1 < ptseq->total )
+ CV_ERROR( CV_StsBadSize, "The hull matrix size might be not enough to fit the hull" );
+
+ if( CV_MAT_TYPE(mat->type) != CV_SEQ_ELTYPE(ptseq) &&
+ CV_MAT_TYPE(mat->type) != CV_32SC1 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "The hull matrix must have the same type as input or 32sC1 (integers)" );
+
+ CV_CALL( hullseq = cvMakeSeqHeaderForArray(
+ CV_SEQ_KIND_CURVE|CV_MAT_TYPE(mat->type)|CV_SEQ_FLAG_CLOSED,
+ sizeof(contour_header), CV_ELEM_SIZE(mat->type), mat->data.ptr,
+ mat->cols + mat->rows - 1, &hull_header.s, &hullblock ));
+
+ cvClearSeq( hullseq );
+ }
+
+ total = ptseq->total;
+ if( total == 0 )
+ {
+ if( mat )
+ CV_ERROR( CV_StsBadSize,
+ "Point sequence can not be empty if the output is matrix" );
+ EXIT;
+ }
+
+ cvStartAppendToSeq( hullseq, &writer );
+
+ is_float = CV_SEQ_ELTYPE(ptseq) == CV_32FC2;
+ hulltype = CV_SEQ_ELTYPE(hullseq);
+ sklansky = !is_float ? (sklansky_func)icvSklansky_32s :
+ (sklansky_func)icvSklansky_32f;
+
+ CV_CALL( pointer = (CvPoint**)cvAlloc( ptseq->total*sizeof(pointer[0]) ));
+ CV_CALL( stack = (int*)cvAlloc( (ptseq->total + 2)*sizeof(stack[0]) ));
+ pointerf = (CvPoint2D32f**)pointer;
+
+ cvStartReadSeq( ptseq, &reader );
+
+ for( i = 0; i < total; i++ )
+ {
+ pointer[i] = (CvPoint*)reader.ptr;
+ CV_NEXT_SEQ_ELEM( ptseq->elem_size, reader );
+ }
+
+ // sort the point set by x-coordinate, find min and max y
+ if( !is_float )
+ {
+ icvSortPointsByPointers_32s( pointer, total, 0 );
+ for( i = 1; i < total; i++ )
+ {
+ int y = pointer[i]->y;
+ if( pointer[miny_ind]->y > y )
+ miny_ind = i;
+ if( pointer[maxy_ind]->y < y )
+ maxy_ind = i;
+ }
+ }
+ else
+ {
+ icvSortPointsByPointers_32f( pointerf, total, 0 );
+ for( i = 1; i < total; i++ )
+ {
+ float y = pointerf[i]->y;
+ if( pointerf[miny_ind]->y > y )
+ miny_ind = i;
+ if( pointerf[maxy_ind]->y < y )
+ maxy_ind = i;
+ }
+ }
+
+ if( pointer[0]->x == pointer[total-1]->x &&
+ pointer[0]->y == pointer[total-1]->y )
+ {
+ if( hulltype == CV_SEQ_ELTYPE_PPOINT )
+ {
+ CV_WRITE_SEQ_ELEM( pointer[0], writer );
+ }
+ else if( hulltype == CV_SEQ_ELTYPE_INDEX )
+ {
+ int index = 0;
+ CV_WRITE_SEQ_ELEM( index, writer );
+ }
+ else
+ {
+ CvPoint pt = pointer[0][0];
+ CV_WRITE_SEQ_ELEM( pt, writer );
+ }
+ goto finish_hull;
+ }
+
+ /*upper half */
+ {
+ int *tl_stack = stack;
+ int tl_count = sklansky( pointer, 0, maxy_ind, tl_stack, -1, 1 );
+ int *tr_stack = tl_stack + tl_count;
+ int tr_count = sklansky( pointer, ptseq->total - 1, maxy_ind, tr_stack, -1, -1 );
+
+ /* gather upper part of convex hull to output */
+ if( orientation == CV_COUNTER_CLOCKWISE )
+ {
+ CV_SWAP( tl_stack, tr_stack, t_stack );
+ CV_SWAP( tl_count, tr_count, t_count );
+ }
+
+ if( hulltype == CV_SEQ_ELTYPE_PPOINT )
+ {
+ for( i = 0; i < tl_count - 1; i++ )
+ CV_WRITE_SEQ_ELEM( pointer[tl_stack[i]], writer );
+
+ for( i = tr_count - 1; i > 0; i-- )
+ CV_WRITE_SEQ_ELEM( pointer[tr_stack[i]], writer );
+ }
+ else if( hulltype == CV_SEQ_ELTYPE_INDEX )
+ {
+ CV_CALL( icvCalcAndWritePtIndices( pointer, tl_stack,
+ 0, tl_count-1, ptseq, &writer ));
+ CV_CALL( icvCalcAndWritePtIndices( pointer, tr_stack,
+ tr_count-1, 0, ptseq, &writer ));
+ }
+ else
+ {
+ for( i = 0; i < tl_count - 1; i++ )
+ CV_WRITE_SEQ_ELEM( pointer[tl_stack[i]][0], writer );
+
+ for( i = tr_count - 1; i > 0; i-- )
+ CV_WRITE_SEQ_ELEM( pointer[tr_stack[i]][0], writer );
+ }
+ stop_idx = tr_count > 2 ? tr_stack[1] : tl_count > 2 ? tl_stack[tl_count - 2] : -1;
+ }
+
+ /* lower half */
+ {
+ int *bl_stack = stack;
+ int bl_count = sklansky( pointer, 0, miny_ind, bl_stack, 1, -1 );
+ int *br_stack = stack + bl_count;
+ int br_count = sklansky( pointer, ptseq->total - 1, miny_ind, br_stack, 1, 1 );
+
+ if( orientation != CV_COUNTER_CLOCKWISE )
+ {
+ CV_SWAP( bl_stack, br_stack, t_stack );
+ CV_SWAP( bl_count, br_count, t_count );
+ }
+
+ if( stop_idx >= 0 )
+ {
+ int check_idx = bl_count > 2 ? bl_stack[1] :
+ bl_count + br_count > 2 ? br_stack[2-bl_count] : -1;
+ if( check_idx == stop_idx || (check_idx >= 0 &&
+ pointer[check_idx]->x == pointer[stop_idx]->x &&
+ pointer[check_idx]->y == pointer[stop_idx]->y) )
+ {
+ /* if all the points lie on the same line, then
+ the bottom part of the convex hull is the mirrored top part
+ (except the exteme points).*/
+ bl_count = MIN( bl_count, 2 );
+ br_count = MIN( br_count, 2 );
+ }
+ }
+
+ if( hulltype == CV_SEQ_ELTYPE_PPOINT )
+ {
+ for( i = 0; i < bl_count - 1; i++ )
+ CV_WRITE_SEQ_ELEM( pointer[bl_stack[i]], writer );
+
+ for( i = br_count - 1; i > 0; i-- )
+ CV_WRITE_SEQ_ELEM( pointer[br_stack[i]], writer );
+ }
+ else if( hulltype == CV_SEQ_ELTYPE_INDEX )
+ {
+ CV_CALL( icvCalcAndWritePtIndices( pointer, bl_stack,
+ 0, bl_count-1, ptseq, &writer ));
+ CV_CALL( icvCalcAndWritePtIndices( pointer, br_stack,
+ br_count-1, 0, ptseq, &writer ));
+ }
+ else
+ {
+ for( i = 0; i < bl_count - 1; i++ )
+ CV_WRITE_SEQ_ELEM( pointer[bl_stack[i]][0], writer );
+
+ for( i = br_count - 1; i > 0; i-- )
+ CV_WRITE_SEQ_ELEM( pointer[br_stack[i]][0], writer );
+ }
+ }
+
+finish_hull:
+ CV_CALL( cvEndWriteSeq( &writer ));
+
+ if( mat )
+ {
+ if( mat->rows > mat->cols )
+ mat->rows = hullseq->total;
+ else
+ mat->cols = hullseq->total;
+ }
+ else
+ {
+ hull.s = hullseq;
+ hull.c->rect = cvBoundingRect( ptseq,
+ ptseq->header_size < (int)sizeof(CvContour) ||
+ &ptseq->flags == &contour_header.flags );
+
+ /*if( ptseq != (CvSeq*)&contour_header )
+ hullseq->v_prev = ptseq;*/
+ }
+
+ __END__;
+
+ cvFree( &pointer );
+ cvFree( &stack );
+
+ return hull.s;
+}
+
+
+/* contour must be a simple polygon */
+/* it must have more than 3 points */
+CV_IMPL CvSeq*
+cvConvexityDefects( const CvArr* array,
+ const CvArr* hullarray,
+ CvMemStorage* storage )
+{
+ CvSeq* defects = 0;
+
+ CV_FUNCNAME( "cvConvexityDefects" );
+
+ __BEGIN__;
+
+ int i, index;
+ CvPoint* hull_cur;
+
+ /* is orientation of hull different from contour one */
+ int rev_orientation;
+
+ CvContour contour_header;
+ union { CvContour c; CvSeq s; } hull_header;
+ CvSeqBlock block, hullblock;
+ CvSeq *ptseq = (CvSeq*)array, *hull = (CvSeq*)hullarray;
+
+ CvSeqReader hull_reader;
+ CvSeqReader ptseq_reader;
+ CvSeqWriter writer;
+ int is_index;
+
+ if( CV_IS_SEQ( ptseq ))
+ {
+ if( !CV_IS_SEQ_POINT_SET( ptseq ))
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Input sequence is not a sequence of points" );
+ if( !storage )
+ storage = ptseq->storage;
+ }
+ else
+ {
+ CV_CALL( ptseq = cvPointSeqFromMat(
+ CV_SEQ_KIND_GENERIC, array, &contour_header, &block ));
+ }
+
+ if( CV_SEQ_ELTYPE( ptseq ) != CV_32SC2 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Floating-point coordinates are not supported here" );
+
+ if( CV_IS_SEQ( hull ))
+ {
+ int hulltype = CV_SEQ_ELTYPE( hull );
+ if( hulltype != CV_SEQ_ELTYPE_PPOINT && hulltype != CV_SEQ_ELTYPE_INDEX )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Convex hull must represented as a sequence "
+ "of indices or sequence of pointers" );
+ if( !storage )
+ storage = hull->storage;
+ }
+ else
+ {
+ CvMat* mat = (CvMat*)hull;
+
+ if( !CV_IS_MAT( hull ))
+ CV_ERROR(CV_StsBadArg, "Convex hull is neither sequence nor matrix");
+
+ if( (mat->cols != 1 && mat->rows != 1) ||
+ !CV_IS_MAT_CONT(mat->type) || CV_MAT_TYPE(mat->type) != CV_32SC1 )
+ CV_ERROR( CV_StsBadArg,
+ "The matrix should be 1-dimensional and continuous array of int's" );
+
+ if( mat->cols + mat->rows - 1 > ptseq->total )
+ CV_ERROR( CV_StsBadSize, "Convex hull is larger than the point sequence" );
+
+ CV_CALL( hull = cvMakeSeqHeaderForArray(
+ CV_SEQ_KIND_CURVE|CV_MAT_TYPE(mat->type)|CV_SEQ_FLAG_CLOSED,
+ sizeof(CvContour), CV_ELEM_SIZE(mat->type), mat->data.ptr,
+ mat->cols + mat->rows - 1, &hull_header.s, &hullblock ));
+ }
+
+ is_index = CV_SEQ_ELTYPE(hull) == CV_SEQ_ELTYPE_INDEX;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "NULL storage pointer" );
+
+ CV_CALL( defects = cvCreateSeq( CV_SEQ_KIND_GENERIC, sizeof(CvSeq),
+ sizeof(CvConvexityDefect), storage ));
+
+ if( ptseq->total < 4 || hull->total < 3)
+ {
+ //CV_ERROR( CV_StsBadSize,
+ // "point seq size must be >= 4, convex hull size must be >= 3" );
+ EXIT;
+ }
+
+ /* recognize co-orientation of ptseq and its hull */
+ {
+ int sign = 0;
+ int index1, index2, index3;
+
+ if( !is_index )
+ {
+ CvPoint* pos = *CV_SEQ_ELEM( hull, CvPoint*, 0 );
+ CV_CALL( index1 = cvSeqElemIdx( ptseq, pos ));
+
+ pos = *CV_SEQ_ELEM( hull, CvPoint*, 1 );
+ CV_CALL( index2 = cvSeqElemIdx( ptseq, pos ));
+
+ pos = *CV_SEQ_ELEM( hull, CvPoint*, 2 );
+ CV_CALL( index3 = cvSeqElemIdx( ptseq, pos ));
+ }
+ else
+ {
+ index1 = *CV_SEQ_ELEM( hull, int, 0 );
+ index2 = *CV_SEQ_ELEM( hull, int, 1 );
+ index3 = *CV_SEQ_ELEM( hull, int, 2 );
+ }
+
+ sign += (index2 > index1) ? 1 : 0;
+ sign += (index3 > index2) ? 1 : 0;
+ sign += (index1 > index3) ? 1 : 0;
+
+ rev_orientation = (sign == 2) ? 0 : 1;
+ }
+
+ cvStartReadSeq( ptseq, &ptseq_reader, 0 );
+ cvStartReadSeq( hull, &hull_reader, rev_orientation );
+
+ if( !is_index )
+ {
+ hull_cur = *(CvPoint**)hull_reader.prev_elem;
+ index = cvSeqElemIdx( ptseq, (char*)hull_cur, 0 );
+ }
+ else
+ {
+ index = *(int*)hull_reader.prev_elem;
+ hull_cur = CV_GET_SEQ_ELEM( CvPoint, ptseq, index );
+ }
+ cvSetSeqReaderPos( &ptseq_reader, index );
+ cvStartAppendToSeq( defects, &writer );
+
+ /* cycle through ptseq and hull with computing defects */
+ for( i = 0; i < hull->total; i++ )
+ {
+ CvConvexityDefect defect;
+ int is_defect = 0;
+ double dx0, dy0;
+ double depth = 0, scale;
+ CvPoint* hull_next;
+
+ if( !is_index )
+ hull_next = *(CvPoint**)hull_reader.ptr;
+ else
+ {
+ int t = *(int*)hull_reader.ptr;
+ hull_next = CV_GET_SEQ_ELEM( CvPoint, ptseq, t );
+ }
+
+ dx0 = (double)hull_next->x - (double)hull_cur->x;
+ dy0 = (double)hull_next->y - (double)hull_cur->y;
+ assert( dx0 != 0 || dy0 != 0 );
+ scale = 1./sqrt(dx0*dx0 + dy0*dy0);
+
+ defect.start = hull_cur;
+ defect.end = hull_next;
+
+ for(;;)
+ {
+ /* go through ptseq to achieve next hull point */
+ CV_NEXT_SEQ_ELEM( sizeof(CvPoint), ptseq_reader );
+
+ if( ptseq_reader.ptr == (schar*)hull_next )
+ break;
+ else
+ {
+ CvPoint* cur = (CvPoint*)ptseq_reader.ptr;
+
+ /* compute distance from current point to hull edge */
+ double dx = (double)cur->x - (double)hull_cur->x;
+ double dy = (double)cur->y - (double)hull_cur->y;
+
+ /* compute depth */
+ double dist = fabs(-dy0*dx + dx0*dy) * scale;
+
+ if( dist > depth )
+ {
+ depth = dist;
+ defect.depth_point = cur;
+ defect.depth = (float)depth;
+ is_defect = 1;
+ }
+ }
+ }
+ if( is_defect )
+ {
+ CV_WRITE_SEQ_ELEM( defect, writer );
+ }
+
+ hull_cur = hull_next;
+ if( rev_orientation )
+ {
+ CV_PREV_SEQ_ELEM( hull->elem_size, hull_reader );
+ }
+ else
+ {
+ CV_NEXT_SEQ_ELEM( hull->elem_size, hull_reader );
+ }
+ }
+
+ defects = cvEndWriteSeq( &writer );
+
+ __END__;
+
+ return defects;
+}
+
+
+CV_IMPL int
+cvCheckContourConvexity( const CvArr* array )
+{
+ int flag = -1;
+
+ CV_FUNCNAME( "cvCheckContourConvexity" );
+
+ __BEGIN__;
+
+ int i;
+ int orientation = 0;
+ CvSeqReader reader;
+ CvContour contour_header;
+ CvSeqBlock block;
+ CvSeq* contour = (CvSeq*)array;
+
+ if( CV_IS_SEQ(contour) )
+ {
+ if( !CV_IS_SEQ_POLYGON(contour))
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Input sequence must be polygon (closed 2d curve)" );
+ }
+ else
+ {
+ CV_CALL( contour = cvPointSeqFromMat(
+ CV_SEQ_KIND_CURVE|CV_SEQ_FLAG_CLOSED, array, &contour_header, &block ));
+ }
+
+ if( contour->total == 0 )
+ EXIT;
+
+ cvStartReadSeq( contour, &reader, 0 );
+
+ flag = 1;
+
+ if( CV_SEQ_ELTYPE( contour ) == CV_32SC2 )
+ {
+ CvPoint *prev_pt = (CvPoint*)reader.prev_elem;
+ CvPoint *cur_pt = (CvPoint*)reader.ptr;
+
+ int dx0 = cur_pt->x - prev_pt->x;
+ int dy0 = cur_pt->y - prev_pt->y;
+
+ for( i = 0; i < contour->total; i++ )
+ {
+ int dxdy0, dydx0;
+ int dx, dy;
+
+ /*int orient; */
+ CV_NEXT_SEQ_ELEM( sizeof(CvPoint), reader );
+ prev_pt = cur_pt;
+ cur_pt = (CvPoint *) reader.ptr;
+
+ dx = cur_pt->x - prev_pt->x;
+ dy = cur_pt->y - prev_pt->y;
+ dxdy0 = dx * dy0;
+ dydx0 = dy * dx0;
+
+ /* find orientation */
+ /*orient = -dy0 * dx + dx0 * dy;
+ orientation |= (orient > 0) ? 1 : 2;
+ */
+ orientation |= (dydx0 > dxdy0) ? 1 : ((dydx0 < dxdy0) ? 2 : 3);
+
+ if( orientation == 3 )
+ {
+ flag = 0;
+ break;
+ }
+
+ dx0 = dx;
+ dy0 = dy;
+ }
+ }
+ else
+ {
+ assert( CV_SEQ_ELTYPE(contour) == CV_32FC2 );
+
+ CvPoint2D32f *prev_pt = (CvPoint2D32f*)reader.prev_elem;
+ CvPoint2D32f *cur_pt = (CvPoint2D32f*)reader.ptr;
+
+ float dx0 = cur_pt->x - prev_pt->x;
+ float dy0 = cur_pt->y - prev_pt->y;
+
+ for( i = 0; i < contour->total; i++ )
+ {
+ float dxdy0, dydx0;
+ float dx, dy;
+
+ /*int orient; */
+ CV_NEXT_SEQ_ELEM( sizeof(CvPoint2D32f), reader );
+ prev_pt = cur_pt;
+ cur_pt = (CvPoint2D32f*) reader.ptr;
+
+ dx = cur_pt->x - prev_pt->x;
+ dy = cur_pt->y - prev_pt->y;
+ dxdy0 = dx * dy0;
+ dydx0 = dy * dx0;
+
+ /* find orientation */
+ /*orient = -dy0 * dx + dx0 * dy;
+ orientation |= (orient > 0) ? 1 : 2;
+ */
+ orientation |= (dydx0 > dxdy0) ? 1 : ((dydx0 < dxdy0) ? 2 : 3);
+
+ if( orientation == 3 )
+ {
+ flag = 0;
+ break;
+ }
+
+ dx0 = dx;
+ dy0 = dy;
+ }
+ }
+
+ __END__;
+
+ return flag;
+}
+
+
+/* End of file. */
diff --git a/cv/src/cvcorner.cpp b/cv/src/cvcorner.cpp
new file mode 100644
index 0000000..b2ce599
--- /dev/null
+++ b/cv/src/cvcorner.cpp
@@ -0,0 +1,706 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+#include <stdio.h>
+
+
+static void
+icvCalcMinEigenVal( const float* cov, int cov_step, float* dst,
+ int dst_step, CvSize size, CvMat* buffer )
+{
+ int j;
+ float* buf = buffer->data.fl;
+ cov_step /= sizeof(cov[0]);
+ dst_step /= sizeof(dst[0]);
+ buffer->rows = 1;
+
+ for( ; size.height--; cov += cov_step, dst += dst_step )
+ {
+ for( j = 0; j < size.width; j++ )
+ {
+ double a = cov[j*3]*0.5;
+ double b = cov[j*3+1];
+ double c = cov[j*3+2]*0.5;
+
+ buf[j + size.width] = (float)(a + c);
+ buf[j] = (float)((a - c)*(a - c) + b*b);
+ }
+
+ cvPow( buffer, buffer, 0.5 );
+
+ for( j = 0; j < size.width ; j++ )
+ dst[j] = (float)(buf[j + size.width] - buf[j]);
+ }
+}
+
+
+static void
+icvCalcHarris( const float* cov, int cov_step, float* dst,
+ int dst_step, CvSize size, CvMat* /*buffer*/, double k )
+{
+ int j;
+ cov_step /= sizeof(cov[0]);
+ dst_step /= sizeof(dst[0]);
+
+ for( ; size.height--; cov += cov_step, dst += dst_step )
+ {
+ for( j = 0; j < size.width; j++ )
+ {
+ double a = cov[j*3];
+ double b = cov[j*3+1];
+ double c = cov[j*3+2];
+ dst[j] = (float)(a*c - b*b - k*(a + c)*(a + c));
+ }
+ }
+}
+
+
+static void
+icvCalcEigenValsVecs( const float* cov, int cov_step, float* dst,
+ int dst_step, CvSize size, CvMat* buffer )
+{
+ static int y0 = 0;
+
+ int j;
+ float* buf = buffer->data.fl;
+ cov_step /= sizeof(cov[0]);
+ dst_step /= sizeof(dst[0]);
+
+ for( ; size.height--; cov += cov_step, dst += dst_step )
+ {
+ for( j = 0; j < size.width; j++ )
+ {
+ double a = cov[j*3]*0.5;
+ double b = cov[j*3+1];
+ double c = cov[j*3+2]*0.5;
+
+ buf[j + size.width] = (float)(a + c);
+ buf[j] = (float)((a - c)*(a - c) + b*b);
+ }
+
+ buffer->rows = 1;
+ cvPow( buffer, buffer, 0.5 );
+
+ for( j = 0; j < size.width; j++ )
+ {
+ double a = cov[j*3];
+ double b = cov[j*3+1];
+ double c = cov[j*3+2];
+
+ double l1 = buf[j + size.width] + buf[j];
+ double l2 = buf[j + size.width] - buf[j];
+
+ double x = b;
+ double y = l1 - a;
+ double e = fabs(x);
+
+ if( e + fabs(y) < 1e-4 )
+ {
+ y = b;
+ x = l1 - c;
+ e = fabs(x);
+ if( e + fabs(y) < 1e-4 )
+ {
+ e = 1./(e + fabs(y) + FLT_EPSILON);
+ x *= e, y *= e;
+ }
+ }
+
+ buf[j] = (float)(x*x + y*y + DBL_EPSILON);
+ dst[6*j] = (float)l1;
+ dst[6*j + 2] = (float)x;
+ dst[6*j + 3] = (float)y;
+
+ x = b;
+ y = l2 - a;
+ e = fabs(x);
+
+ if( e + fabs(y) < 1e-4 )
+ {
+ y = b;
+ x = l2 - c;
+ e = fabs(x);
+ if( e + fabs(y) < 1e-4 )
+ {
+ e = 1./(e + fabs(y) + FLT_EPSILON);
+ x *= e, y *= e;
+ }
+ }
+
+ buf[j + size.width] = (float)(x*x + y*y + DBL_EPSILON);
+ dst[6*j + 1] = (float)l2;
+ dst[6*j + 4] = (float)x;
+ dst[6*j + 5] = (float)y;
+ }
+
+ buffer->rows = 2;
+ cvPow( buffer, buffer, -0.5 );
+
+ for( j = 0; j < size.width; j++ )
+ {
+ double t0 = buf[j]*dst[6*j + 2];
+ double t1 = buf[j]*dst[6*j + 3];
+
+ dst[6*j + 2] = (float)t0;
+ dst[6*j + 3] = (float)t1;
+
+ t0 = buf[j + size.width]*dst[6*j + 4];
+ t1 = buf[j + size.width]*dst[6*j + 5];
+
+ dst[6*j + 4] = (float)t0;
+ dst[6*j + 5] = (float)t1;
+ }
+
+ y0++;
+ }
+}
+
+
+#define ICV_MINEIGENVAL 0
+#define ICV_HARRIS 1
+#define ICV_EIGENVALSVECS 2
+
+static void
+icvCornerEigenValsVecs( const CvMat* src, CvMat* eigenv, int block_size,
+ int aperture_size, int op_type, double k=0. )
+{
+ CvSepFilter dx_filter, dy_filter;
+ CvBoxFilter blur_filter;
+ CvMat *tempsrc = 0;
+ CvMat *Dx = 0, *Dy = 0, *cov = 0;
+ CvMat *sqrt_buf = 0;
+
+ int buf_size = 1 << 12;
+
+ CV_FUNCNAME( "icvCornerEigenValsVecs" );
+
+ __BEGIN__;
+
+ int i, j, y, dst_y = 0, max_dy, delta = 0;
+ int aperture_size0 = aperture_size;
+ int temp_step = 0, d_step;
+ uchar* shifted_ptr = 0;
+ int depth, d_depth;
+ int stage = CV_START;
+ CvSobelFixedIPPFunc ipp_sobel_vert = 0, ipp_sobel_horiz = 0;
+ CvFilterFixedIPPFunc ipp_scharr_vert = 0, ipp_scharr_horiz = 0;
+ CvSize el_size, size, stripe_size;
+ int aligned_width;
+ CvPoint el_anchor;
+ double factorx, factory;
+ bool use_ipp = false;
+
+ if( block_size < 3 || !(block_size & 1) )
+ CV_ERROR( CV_StsOutOfRange, "averaging window size must be an odd number >= 3" );
+
+ if( (aperture_size < 3 && aperture_size != CV_SCHARR) || !(aperture_size & 1) )
+ CV_ERROR( CV_StsOutOfRange,
+ "Derivative filter aperture size must be a positive odd number >=3 or CV_SCHARR" );
+
+ depth = CV_MAT_DEPTH(src->type);
+ d_depth = depth == CV_8U ? CV_16S : CV_32F;
+
+ size = cvGetMatSize(src);
+ aligned_width = cvAlign(size.width, 4);
+
+ aperture_size = aperture_size == CV_SCHARR ? 3 : aperture_size;
+ el_size = cvSize( aperture_size, aperture_size );
+ el_anchor = cvPoint( aperture_size/2, aperture_size/2 );
+
+ if( aperture_size <= 5 && icvFilterSobelVert_8u16s_C1R_p )
+ {
+ if( depth == CV_8U && aperture_size0 == CV_SCHARR )
+ {
+ ipp_scharr_vert = icvFilterScharrVert_8u16s_C1R_p;
+ ipp_scharr_horiz = icvFilterScharrHoriz_8u16s_C1R_p;
+ }
+ else if( depth == CV_32F && aperture_size0 == CV_SCHARR )
+ {
+ ipp_scharr_vert = icvFilterScharrVert_32f_C1R_p;
+ ipp_scharr_horiz = icvFilterScharrHoriz_32f_C1R_p;
+ }
+ else if( depth == CV_8U )
+ {
+ ipp_sobel_vert = icvFilterSobelVert_8u16s_C1R_p;
+ ipp_sobel_horiz = icvFilterSobelHoriz_8u16s_C1R_p;
+ }
+ else if( depth == CV_32F )
+ {
+ ipp_sobel_vert = icvFilterSobelVert_32f_C1R_p;
+ ipp_sobel_horiz = icvFilterSobelHoriz_32f_C1R_p;
+ }
+ }
+
+ if( (ipp_sobel_vert && ipp_sobel_horiz) ||
+ (ipp_scharr_vert && ipp_scharr_horiz) )
+ {
+ CV_CALL( tempsrc = icvIPPFilterInit( src, buf_size,
+ cvSize(el_size.width,el_size.height + block_size)));
+ shifted_ptr = tempsrc->data.ptr + el_anchor.y*tempsrc->step +
+ el_anchor.x*CV_ELEM_SIZE(depth);
+ temp_step = tempsrc->step ? tempsrc->step : CV_STUB_STEP;
+ max_dy = tempsrc->rows - aperture_size + 1;
+ use_ipp = true;
+ }
+ else
+ {
+ ipp_sobel_vert = ipp_sobel_horiz = 0;
+ ipp_scharr_vert = ipp_scharr_horiz = 0;
+
+ CV_CALL( dx_filter.init_deriv( size.width, depth, d_depth, 1, 0, aperture_size0 ));
+ CV_CALL( dy_filter.init_deriv( size.width, depth, d_depth, 0, 1, aperture_size0 ));
+ max_dy = buf_size / src->cols;
+ max_dy = MAX( max_dy, aperture_size + block_size );
+ }
+
+ CV_CALL( Dx = cvCreateMat( max_dy, aligned_width, d_depth ));
+ CV_CALL( Dy = cvCreateMat( max_dy, aligned_width, d_depth ));
+ CV_CALL( cov = cvCreateMat( max_dy + block_size + 1, size.width, CV_32FC3 ));
+ CV_CALL( sqrt_buf = cvCreateMat( 2, size.width, CV_32F ));
+ Dx->cols = Dy->cols = size.width;
+
+ if( !use_ipp )
+ max_dy -= aperture_size - 1;
+ d_step = Dx->step ? Dx->step : CV_STUB_STEP;
+
+ CV_CALL(blur_filter.init(size.width, CV_32FC3, CV_32FC3, 0, cvSize(block_size,block_size)));
+ stripe_size = size;
+
+ factorx = (double)(1 << (aperture_size - 1)) * block_size;
+ if( aperture_size0 == CV_SCHARR )
+ factorx *= 2;
+ if( depth == CV_8U )
+ factorx *= 255.;
+ factory = factorx = 1./factorx;
+ if( ipp_sobel_vert )
+ factory = -factory;
+
+ for( y = 0; y < size.height; y += delta )
+ {
+ if( !use_ipp )
+ {
+ delta = MIN( size.height - y, max_dy );
+ if( y + delta == size.height )
+ stage = stage & CV_START ? CV_START + CV_END : CV_END;
+ dx_filter.process( src, Dx, cvRect(0,y,-1,delta), cvPoint(0,0), stage );
+ stripe_size.height = dy_filter.process( src, Dy, cvRect(0,y,-1,delta),
+ cvPoint(0,0), stage );
+ }
+ else
+ {
+ delta = icvIPPFilterNextStripe( src, tempsrc, y, el_size, el_anchor );
+ stripe_size.height = delta;
+
+ if( ipp_sobel_vert )
+ {
+ IPPI_CALL( ipp_sobel_vert( shifted_ptr, temp_step,
+ Dx->data.ptr, d_step, stripe_size,
+ aperture_size*10 + aperture_size ));
+ IPPI_CALL( ipp_sobel_horiz( shifted_ptr, temp_step,
+ Dy->data.ptr, d_step, stripe_size,
+ aperture_size*10 + aperture_size ));
+ }
+ else /*if( ipp_scharr_vert )*/
+ {
+ IPPI_CALL( ipp_scharr_vert( shifted_ptr, temp_step,
+ Dx->data.ptr, d_step, stripe_size ));
+ IPPI_CALL( ipp_scharr_horiz( shifted_ptr, temp_step,
+ Dy->data.ptr, d_step, stripe_size ));
+ }
+ }
+
+ for( i = 0; i < stripe_size.height; i++ )
+ {
+ float* cov_data = (float*)(cov->data.ptr + i*cov->step);
+ if( d_depth == CV_16S )
+ {
+ const short* dxdata = (const short*)(Dx->data.ptr + i*Dx->step);
+ const short* dydata = (const short*)(Dy->data.ptr + i*Dy->step);
+
+ for( j = 0; j < size.width; j++ )
+ {
+ double dx = dxdata[j]*factorx;
+ double dy = dydata[j]*factory;
+
+ cov_data[j*3] = (float)(dx*dx);
+ cov_data[j*3+1] = (float)(dx*dy);
+ cov_data[j*3+2] = (float)(dy*dy);
+ }
+ }
+ else
+ {
+ const float* dxdata = (const float*)(Dx->data.ptr + i*Dx->step);
+ const float* dydata = (const float*)(Dy->data.ptr + i*Dy->step);
+
+ for( j = 0; j < size.width; j++ )
+ {
+ double dx = dxdata[j]*factorx;
+ double dy = dydata[j]*factory;
+
+ cov_data[j*3] = (float)(dx*dx);
+ cov_data[j*3+1] = (float)(dx*dy);
+ cov_data[j*3+2] = (float)(dy*dy);
+ }
+ }
+ }
+
+ if( y + stripe_size.height >= size.height )
+ stage = stage & CV_START ? CV_START + CV_END : CV_END;
+
+ stripe_size.height = blur_filter.process(cov,cov,
+ cvRect(0,0,-1,stripe_size.height),cvPoint(0,0),stage+CV_ISOLATED_ROI);
+
+ if( op_type == ICV_MINEIGENVAL )
+ icvCalcMinEigenVal( cov->data.fl, cov->step,
+ (float*)(eigenv->data.ptr + dst_y*eigenv->step), eigenv->step,
+ stripe_size, sqrt_buf );
+ else if( op_type == ICV_HARRIS )
+ icvCalcHarris( cov->data.fl, cov->step,
+ (float*)(eigenv->data.ptr + dst_y*eigenv->step), eigenv->step,
+ stripe_size, sqrt_buf, k );
+ else if( op_type == ICV_EIGENVALSVECS )
+ icvCalcEigenValsVecs( cov->data.fl, cov->step,
+ (float*)(eigenv->data.ptr + dst_y*eigenv->step), eigenv->step,
+ stripe_size, sqrt_buf );
+
+ dst_y += stripe_size.height;
+ stage = CV_MIDDLE;
+ }
+
+ __END__;
+
+ cvReleaseMat( &Dx );
+ cvReleaseMat( &Dy );
+ cvReleaseMat( &cov );
+ cvReleaseMat( &sqrt_buf );
+ cvReleaseMat( &tempsrc );
+}
+
+
+CV_IMPL void
+cvCornerMinEigenVal( const void* srcarr, void* eigenvarr,
+ int block_size, int aperture_size )
+{
+ CV_FUNCNAME( "cvCornerMinEigenVal" );
+
+ __BEGIN__;
+
+ CvMat stub, *src = (CvMat*)srcarr;
+ CvMat eigstub, *eigenv = (CvMat*)eigenvarr;
+
+ CV_CALL( src = cvGetMat( srcarr, &stub ));
+ CV_CALL( eigenv = cvGetMat( eigenv, &eigstub ));
+
+ if( (CV_MAT_TYPE(src->type) != CV_8UC1 && CV_MAT_TYPE(src->type) != CV_32FC1) ||
+ CV_MAT_TYPE(eigenv->type) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Input must be 8uC1 or 32fC1, output must be 32fC1" );
+
+ if( !CV_ARE_SIZES_EQ( src, eigenv ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ CV_CALL( icvCornerEigenValsVecs( src, eigenv, block_size, aperture_size, ICV_MINEIGENVAL ));
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvCornerHarris( const CvArr* srcarr, CvArr* harris_responce,
+ int block_size, int aperture_size, double k )
+{
+ CV_FUNCNAME( "cvCornerHarris" );
+
+ __BEGIN__;
+
+ CvMat stub, *src = (CvMat*)srcarr;
+ CvMat eigstub, *eigenv = (CvMat*)harris_responce;
+
+ CV_CALL( src = cvGetMat( srcarr, &stub ));
+ CV_CALL( eigenv = cvGetMat( eigenv, &eigstub ));
+
+ if( (CV_MAT_TYPE(src->type) != CV_8UC1 && CV_MAT_TYPE(src->type) != CV_32FC1) ||
+ CV_MAT_TYPE(eigenv->type) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Input must be 8uC1 or 32fC1, output must be 32fC1" );
+
+ if( !CV_ARE_SIZES_EQ( src, eigenv ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ CV_CALL( icvCornerEigenValsVecs( src, eigenv, block_size, aperture_size, ICV_HARRIS, k ));
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvCornerEigenValsAndVecs( const void* srcarr, void* eigenvarr,
+ int block_size, int aperture_size )
+{
+ CV_FUNCNAME( "cvCornerEigenValsAndVecs" );
+
+ __BEGIN__;
+
+ CvMat stub, *src = (CvMat*)srcarr;
+ CvMat eigstub, *eigenv = (CvMat*)eigenvarr;
+
+ CV_CALL( src = cvGetMat( srcarr, &stub ));
+ CV_CALL( eigenv = cvGetMat( eigenv, &eigstub ));
+
+ if( CV_MAT_CN(eigenv->type)*eigenv->cols != src->cols*6 ||
+ eigenv->rows != src->rows )
+ CV_ERROR( CV_StsUnmatchedSizes, "Output array should be 6 times "
+ "wider than the input array and they should have the same height");
+
+ if( (CV_MAT_TYPE(src->type) != CV_8UC1 && CV_MAT_TYPE(src->type) != CV_32FC1) ||
+ CV_MAT_TYPE(eigenv->type) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Input must be 8uC1 or 32fC1, output must be 32fC1" );
+
+ CV_CALL( icvCornerEigenValsVecs( src, eigenv, block_size, aperture_size, ICV_EIGENVALSVECS ));
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvPreCornerDetect( const void* srcarr, void* dstarr, int aperture_size )
+{
+ CvSepFilter dx_filter, dy_filter, d2x_filter, d2y_filter, dxy_filter;
+ CvMat *Dx = 0, *Dy = 0, *D2x = 0, *D2y = 0, *Dxy = 0;
+ CvMat *tempsrc = 0;
+
+ int buf_size = 1 << 12;
+
+ CV_FUNCNAME( "cvPreCornerDetect" );
+
+ __BEGIN__;
+
+ int i, j, y, dst_y = 0, max_dy, delta = 0;
+ int temp_step = 0, d_step;
+ uchar* shifted_ptr = 0;
+ int depth, d_depth;
+ int stage = CV_START;
+ CvSobelFixedIPPFunc ipp_sobel_vert = 0, ipp_sobel_horiz = 0,
+ ipp_sobel_vert_second = 0, ipp_sobel_horiz_second = 0,
+ ipp_sobel_cross = 0;
+ CvSize el_size, size, stripe_size;
+ int aligned_width;
+ CvPoint el_anchor;
+ double factor;
+ CvMat stub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ bool use_ipp = false;
+
+ CV_CALL( src = cvGetMat( srcarr, &stub ));
+ CV_CALL( dst = cvGetMat( dst, &dststub ));
+
+ if( (CV_MAT_TYPE(src->type) != CV_8UC1 && CV_MAT_TYPE(src->type) != CV_32FC1) ||
+ CV_MAT_TYPE(dst->type) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Input must be 8uC1 or 32fC1, output must be 32fC1" );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( aperture_size == CV_SCHARR )
+ CV_ERROR( CV_StsOutOfRange, "CV_SCHARR is not supported by this function" );
+
+ if( aperture_size < 3 || aperture_size > 7 || !(aperture_size & 1) )
+ CV_ERROR( CV_StsOutOfRange,
+ "Derivative filter aperture size must be 3, 5 or 7" );
+
+ depth = CV_MAT_DEPTH(src->type);
+ d_depth = depth == CV_8U ? CV_16S : CV_32F;
+
+ size = cvGetMatSize(src);
+ aligned_width = cvAlign(size.width, 4);
+
+ el_size = cvSize( aperture_size, aperture_size );
+ el_anchor = cvPoint( aperture_size/2, aperture_size/2 );
+
+ if( aperture_size <= 5 && icvFilterSobelVert_8u16s_C1R_p )
+ {
+ if( depth == CV_8U )
+ {
+ ipp_sobel_vert = icvFilterSobelVert_8u16s_C1R_p;
+ ipp_sobel_horiz = icvFilterSobelHoriz_8u16s_C1R_p;
+ ipp_sobel_vert_second = icvFilterSobelVertSecond_8u16s_C1R_p;
+ ipp_sobel_horiz_second = icvFilterSobelHorizSecond_8u16s_C1R_p;
+ ipp_sobel_cross = icvFilterSobelCross_8u16s_C1R_p;
+ }
+ else if( depth == CV_32F )
+ {
+ ipp_sobel_vert = icvFilterSobelVert_32f_C1R_p;
+ ipp_sobel_horiz = icvFilterSobelHoriz_32f_C1R_p;
+ ipp_sobel_vert_second = icvFilterSobelVertSecond_32f_C1R_p;
+ ipp_sobel_horiz_second = icvFilterSobelHorizSecond_32f_C1R_p;
+ ipp_sobel_cross = icvFilterSobelCross_32f_C1R_p;
+ }
+ }
+
+ if( ipp_sobel_vert && ipp_sobel_horiz && ipp_sobel_vert_second &&
+ ipp_sobel_horiz_second && ipp_sobel_cross )
+ {
+ CV_CALL( tempsrc = icvIPPFilterInit( src, buf_size, el_size ));
+ shifted_ptr = tempsrc->data.ptr + el_anchor.y*tempsrc->step +
+ el_anchor.x*CV_ELEM_SIZE(depth);
+ temp_step = tempsrc->step ? tempsrc->step : CV_STUB_STEP;
+ max_dy = tempsrc->rows - aperture_size + 1;
+ use_ipp = true;
+ }
+ else
+ {
+ ipp_sobel_vert = ipp_sobel_horiz = 0;
+ ipp_sobel_vert_second = ipp_sobel_horiz_second = ipp_sobel_cross = 0;
+ dx_filter.init_deriv( size.width, depth, d_depth, 1, 0, aperture_size );
+ dy_filter.init_deriv( size.width, depth, d_depth, 0, 1, aperture_size );
+ d2x_filter.init_deriv( size.width, depth, d_depth, 2, 0, aperture_size );
+ d2y_filter.init_deriv( size.width, depth, d_depth, 0, 2, aperture_size );
+ dxy_filter.init_deriv( size.width, depth, d_depth, 1, 1, aperture_size );
+ max_dy = buf_size / src->cols;
+ max_dy = MAX( max_dy, aperture_size );
+ }
+
+ CV_CALL( Dx = cvCreateMat( max_dy, aligned_width, d_depth ));
+ CV_CALL( Dy = cvCreateMat( max_dy, aligned_width, d_depth ));
+ CV_CALL( D2x = cvCreateMat( max_dy, aligned_width, d_depth ));
+ CV_CALL( D2y = cvCreateMat( max_dy, aligned_width, d_depth ));
+ CV_CALL( Dxy = cvCreateMat( max_dy, aligned_width, d_depth ));
+ Dx->cols = Dy->cols = D2x->cols = D2y->cols = Dxy->cols = size.width;
+
+ if( !use_ipp )
+ max_dy -= aperture_size - 1;
+ d_step = Dx->step ? Dx->step : CV_STUB_STEP;
+
+ stripe_size = size;
+
+ factor = 1 << (aperture_size - 1);
+ if( depth == CV_8U )
+ factor *= 255;
+ factor = 1./(factor * factor * factor);
+
+ aperture_size = aperture_size * 10 + aperture_size;
+
+ for( y = 0; y < size.height; y += delta )
+ {
+ if( !use_ipp )
+ {
+ delta = MIN( size.height - y, max_dy );
+ CvRect roi = cvRect(0,y,size.width,delta);
+ CvPoint origin=cvPoint(0,0);
+
+ if( y + delta == size.height )
+ stage = stage & CV_START ? CV_START + CV_END : CV_END;
+
+ dx_filter.process(src,Dx,roi,origin,stage);
+ dy_filter.process(src,Dy,roi,origin,stage);
+ d2x_filter.process(src,D2x,roi,origin,stage);
+ d2y_filter.process(src,D2y,roi,origin,stage);
+ stripe_size.height = dxy_filter.process(src,Dxy,roi,origin,stage);
+ }
+ else
+ {
+ delta = icvIPPFilterNextStripe( src, tempsrc, y, el_size, el_anchor );
+ stripe_size.height = delta;
+
+ IPPI_CALL( ipp_sobel_vert( shifted_ptr, temp_step,
+ Dx->data.ptr, d_step, stripe_size, aperture_size ));
+ IPPI_CALL( ipp_sobel_horiz( shifted_ptr, temp_step,
+ Dy->data.ptr, d_step, stripe_size, aperture_size ));
+ IPPI_CALL( ipp_sobel_vert_second( shifted_ptr, temp_step,
+ D2x->data.ptr, d_step, stripe_size, aperture_size ));
+ IPPI_CALL( ipp_sobel_horiz_second( shifted_ptr, temp_step,
+ D2y->data.ptr, d_step, stripe_size, aperture_size ));
+ IPPI_CALL( ipp_sobel_cross( shifted_ptr, temp_step,
+ Dxy->data.ptr, d_step, stripe_size, aperture_size ));
+ }
+
+ for( i = 0; i < stripe_size.height; i++, dst_y++ )
+ {
+ float* dstdata = (float*)(dst->data.ptr + dst_y*dst->step);
+
+ if( d_depth == CV_16S )
+ {
+ const short* dxdata = (const short*)(Dx->data.ptr + i*Dx->step);
+ const short* dydata = (const short*)(Dy->data.ptr + i*Dy->step);
+ const short* d2xdata = (const short*)(D2x->data.ptr + i*D2x->step);
+ const short* d2ydata = (const short*)(D2y->data.ptr + i*D2y->step);
+ const short* dxydata = (const short*)(Dxy->data.ptr + i*Dxy->step);
+
+ for( j = 0; j < stripe_size.width; j++ )
+ {
+ double dx = dxdata[j];
+ double dx2 = dx * dx;
+ double dy = dydata[j];
+ double dy2 = dy * dy;
+
+ dstdata[j] = (float)(factor*(dx2*d2ydata[j] + dy2*d2xdata[j] - 2*dx*dy*dxydata[j]));
+ }
+ }
+ else
+ {
+ const float* dxdata = (const float*)(Dx->data.ptr + i*Dx->step);
+ const float* dydata = (const float*)(Dy->data.ptr + i*Dy->step);
+ const float* d2xdata = (const float*)(D2x->data.ptr + i*D2x->step);
+ const float* d2ydata = (const float*)(D2y->data.ptr + i*D2y->step);
+ const float* dxydata = (const float*)(Dxy->data.ptr + i*Dxy->step);
+
+ for( j = 0; j < stripe_size.width; j++ )
+ {
+ double dx = dxdata[j];
+ double dy = dydata[j];
+ dstdata[j] = (float)(factor*(dx*dx*d2ydata[j] + dy*dy*d2xdata[j] - 2*dx*dy*dxydata[j]));
+ }
+ }
+ }
+
+ stage = CV_MIDDLE;
+ }
+
+ __END__;
+
+ cvReleaseMat( &Dx );
+ cvReleaseMat( &Dy );
+ cvReleaseMat( &D2x );
+ cvReleaseMat( &D2y );
+ cvReleaseMat( &Dxy );
+ cvReleaseMat( &tempsrc );
+}
+
+/* End of file */
diff --git a/cv/src/cvcornersubpix.cpp b/cv/src/cvcornersubpix.cpp
new file mode 100644
index 0000000..5eb282c
--- /dev/null
+++ b/cv/src/cvcornersubpix.cpp
@@ -0,0 +1,268 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+CV_IMPL void
+cvFindCornerSubPix( const void* srcarr, CvPoint2D32f* corners,
+ int count, CvSize win, CvSize zeroZone,
+ CvTermCriteria criteria )
+{
+ float* buffer = 0;
+
+ CV_FUNCNAME( "cvFindCornerSubPix" );
+
+ __BEGIN__;
+
+ const int MAX_ITERS = 100;
+ const float drv_x[] = { -1.f, 0.f, 1.f };
+ const float drv_y[] = { 0.f, 0.5f, 0.f };
+ float *maskX;
+ float *maskY;
+ float *mask;
+ float *src_buffer;
+ float *gx_buffer;
+ float *gy_buffer;
+ int win_w = win.width * 2 + 1, win_h = win.height * 2 + 1;
+ int win_rect_size = (win_w + 4) * (win_h + 4);
+ double coeff;
+ CvSize size, src_buf_size;
+ int i, j, k, pt_i;
+ int max_iters, buffer_size;
+ double eps;
+
+ CvMat stub, *src = (CvMat*)srcarr;
+ CV_CALL( src = cvGetMat( srcarr, &stub ));
+
+ if( CV_MAT_TYPE( src->type ) != CV_8UC1 )
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !corners )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( count < 0 )
+ CV_ERROR( CV_StsBadSize, "" );
+
+ if( count == 0 )
+ EXIT;
+
+ if( win.width <= 0 || win.height <= 0 )
+ CV_ERROR( CV_StsBadSize, "" );
+
+ size = cvGetMatSize( src );
+
+ if( size.width < win_w + 4 || size.height < win_h + 4 )
+ CV_ERROR( CV_StsBadSize, "" );
+
+ /* initialize variables, controlling loop termination */
+ switch( criteria.type )
+ {
+ case CV_TERMCRIT_ITER:
+ eps = 0.f;
+ max_iters = criteria.max_iter;
+ break;
+ case CV_TERMCRIT_EPS:
+ eps = criteria.epsilon;
+ max_iters = MAX_ITERS;
+ break;
+ case CV_TERMCRIT_ITER | CV_TERMCRIT_EPS:
+ eps = criteria.epsilon;
+ max_iters = criteria.max_iter;
+ break;
+ default:
+ assert( 0 );
+ CV_ERROR( CV_StsBadFlag, "" );
+ }
+
+ eps = MAX( eps, 0 );
+ eps *= eps; /* use square of error in comparsion operations. */
+
+ max_iters = MAX( max_iters, 1 );
+ max_iters = MIN( max_iters, MAX_ITERS );
+
+ /* setup buffer */
+ buffer_size = (win_rect_size * 5 + win_w + win_h + 32) * sizeof(float);
+ buffer = (float*)cvAlloc( buffer_size );
+
+ /* assign pointers */
+ maskX = buffer;
+ maskY = maskX + win_w + 4;
+ mask = maskY + win_h + 4;
+ src_buffer = mask + win_w * win_h;
+ gx_buffer = src_buffer + win_rect_size;
+ gy_buffer = gx_buffer + win_rect_size;
+
+ coeff = 1. / (win.width * win.width);
+
+ /* calculate mask */
+ for( i = -win.width, k = 0; i <= win.width; i++, k++ )
+ {
+ maskX[k] = (float)exp( -i * i * coeff );
+ }
+
+ if( win.width == win.height )
+ {
+ maskY = maskX;
+ }
+ else
+ {
+ coeff = 1. / (win.height * win.height);
+ for( i = -win.height, k = 0; i <= win.height; i++, k++ )
+ {
+ maskY[k] = (float) exp( -i * i * coeff );
+ }
+ }
+
+ for( i = 0; i < win_h; i++ )
+ {
+ for( j = 0; j < win_w; j++ )
+ {
+ mask[i * win_w + j] = maskX[j] * maskY[i];
+ }
+ }
+
+
+ /* make zero_zone */
+ if( zeroZone.width >= 0 && zeroZone.height >= 0 &&
+ zeroZone.width * 2 + 1 < win_w && zeroZone.height * 2 + 1 < win_h )
+ {
+ for( i = win.height - zeroZone.height; i <= win.height + zeroZone.height; i++ )
+ {
+ for( j = win.width - zeroZone.width; j <= win.width + zeroZone.width; j++ )
+ {
+ mask[i * win_w + j] = 0;
+ }
+ }
+ }
+
+ /* set sizes of image rectangles, used in convolutions */
+ src_buf_size.width = win_w + 2;
+ src_buf_size.height = win_h + 2;
+
+ /* do optimization loop for all the points */
+ for( pt_i = 0; pt_i < count; pt_i++ )
+ {
+ CvPoint2D32f cT = corners[pt_i], cI = cT;
+ int iter = 0;
+ double err;
+
+ do
+ {
+ CvPoint2D32f cI2;
+ double a, b, c, bb1, bb2;
+
+ IPPI_CALL( icvGetRectSubPix_8u32f_C1R( (uchar*)src->data.ptr, src->step, size,
+ src_buffer, (win_w + 2) * sizeof( src_buffer[0] ),
+ cvSize( win_w + 2, win_h + 2 ), cI ));
+
+ /* calc derivatives */
+ icvSepConvSmall3_32f( src_buffer, src_buf_size.width * sizeof(src_buffer[0]),
+ gx_buffer, win_w * sizeof(gx_buffer[0]),
+ src_buf_size, drv_x, drv_y, buffer );
+
+ icvSepConvSmall3_32f( src_buffer, src_buf_size.width * sizeof(src_buffer[0]),
+ gy_buffer, win_w * sizeof(gy_buffer[0]),
+ src_buf_size, drv_y, drv_x, buffer );
+
+ a = b = c = bb1 = bb2 = 0;
+
+ /* process gradient */
+ for( i = 0, k = 0; i < win_h; i++ )
+ {
+ double py = i - win.height;
+
+ for( j = 0; j < win_w; j++, k++ )
+ {
+ double m = mask[k];
+ double tgx = gx_buffer[k];
+ double tgy = gy_buffer[k];
+ double gxx = tgx * tgx * m;
+ double gxy = tgx * tgy * m;
+ double gyy = tgy * tgy * m;
+ double px = j - win.width;
+
+ a += gxx;
+ b += gxy;
+ c += gyy;
+
+ bb1 += gxx * px + gxy * py;
+ bb2 += gxy * px + gyy * py;
+ }
+ }
+
+ {
+ double A[4];
+ double InvA[4];
+ CvMat matA, matInvA;
+
+ A[0] = a;
+ A[1] = A[2] = b;
+ A[3] = c;
+
+ cvInitMatHeader( &matA, 2, 2, CV_64F, A );
+ cvInitMatHeader( &matInvA, 2, 2, CV_64FC1, InvA );
+
+ cvInvert( &matA, &matInvA, CV_SVD );
+ cI2.x = (float)(cI.x + InvA[0]*bb1 + InvA[1]*bb2);
+ cI2.y = (float)(cI.y + InvA[2]*bb1 + InvA[3]*bb2);
+ }
+
+ err = (cI2.x - cI.x) * (cI2.x - cI.x) + (cI2.y - cI.y) * (cI2.y - cI.y);
+ cI = cI2;
+ }
+ while( ++iter < max_iters && err > eps );
+
+ /* if new point is too far from initial, it means poor convergence.
+ leave initial point as the result */
+ if( fabs( cI.x - cT.x ) > win.width || fabs( cI.y - cT.y ) > win.height )
+ {
+ cI = cT;
+ }
+
+ corners[pt_i] = cI; /* store result */
+ }
+
+ __CLEANUP__;
+ __END__;
+
+ cvFree( &buffer );
+}
+
+/* End of file. */
diff --git a/cv/src/cvderiv.cpp b/cv/src/cvderiv.cpp
new file mode 100644
index 0000000..b373f83
--- /dev/null
+++ b/cv/src/cvderiv.cpp
@@ -0,0 +1,879 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+/****************************************************************************************/
+
+/* lightweight convolution with 3x3 kernel */
+void icvSepConvSmall3_32f( float* src, int src_step, float* dst, int dst_step,
+ CvSize src_size, const float* kx, const float* ky, float* buffer )
+{
+ int dst_width, buffer_step = 0;
+ int x, y;
+
+ assert( src && dst && src_size.width > 2 && src_size.height > 2 &&
+ (src_step & 3) == 0 && (dst_step & 3) == 0 &&
+ (kx || ky) && (buffer || !kx || !ky));
+
+ src_step /= sizeof(src[0]);
+ dst_step /= sizeof(dst[0]);
+
+ dst_width = src_size.width - 2;
+
+ if( !kx )
+ {
+ /* set vars, so that vertical convolution
+ will write results into destination ROI and
+ horizontal convolution won't run */
+ src_size.width = dst_width;
+ buffer_step = dst_step;
+ buffer = dst;
+ dst_width = 0;
+ }
+
+ assert( src_step >= src_size.width && dst_step >= dst_width );
+
+ src_size.height -= 3;
+ if( !ky )
+ {
+ /* set vars, so that vertical convolution won't run and
+ horizontal convolution will write results into destination ROI */
+ src_size.height += 3;
+ buffer_step = src_step;
+ buffer = src;
+ src_size.width = 0;
+ }
+
+ for( y = 0; y <= src_size.height; y++, src += src_step,
+ dst += dst_step,
+ buffer += buffer_step )
+ {
+ float* src2 = src + src_step;
+ float* src3 = src + src_step*2;
+ for( x = 0; x < src_size.width; x++ )
+ {
+ buffer[x] = (float)(ky[0]*src[x] + ky[1]*src2[x] + ky[2]*src3[x]);
+ }
+
+ for( x = 0; x < dst_width; x++ )
+ {
+ dst[x] = (float)(kx[0]*buffer[x] + kx[1]*buffer[x+1] + kx[2]*buffer[x+2]);
+ }
+ }
+}
+
+
+/****************************************************************************************\
+ Sobel & Scharr Derivative Filters
+\****************************************************************************************/
+
+/////////////////////////////// Old IPP derivative filters ///////////////////////////////
+// still used in corner detectors (see cvcorner.cpp)
+
+icvFilterSobelVert_8u16s_C1R_t icvFilterSobelVert_8u16s_C1R_p = 0;
+icvFilterSobelHoriz_8u16s_C1R_t icvFilterSobelHoriz_8u16s_C1R_p = 0;
+icvFilterSobelVertSecond_8u16s_C1R_t icvFilterSobelVertSecond_8u16s_C1R_p = 0;
+icvFilterSobelHorizSecond_8u16s_C1R_t icvFilterSobelHorizSecond_8u16s_C1R_p = 0;
+icvFilterSobelCross_8u16s_C1R_t icvFilterSobelCross_8u16s_C1R_p = 0;
+
+icvFilterSobelVert_32f_C1R_t icvFilterSobelVert_32f_C1R_p = 0;
+icvFilterSobelHoriz_32f_C1R_t icvFilterSobelHoriz_32f_C1R_p = 0;
+icvFilterSobelVertSecond_32f_C1R_t icvFilterSobelVertSecond_32f_C1R_p = 0;
+icvFilterSobelHorizSecond_32f_C1R_t icvFilterSobelHorizSecond_32f_C1R_p = 0;
+icvFilterSobelCross_32f_C1R_t icvFilterSobelCross_32f_C1R_p = 0;
+
+icvFilterScharrVert_8u16s_C1R_t icvFilterScharrVert_8u16s_C1R_p = 0;
+icvFilterScharrHoriz_8u16s_C1R_t icvFilterScharrHoriz_8u16s_C1R_p = 0;
+icvFilterScharrVert_32f_C1R_t icvFilterScharrVert_32f_C1R_p = 0;
+icvFilterScharrHoriz_32f_C1R_t icvFilterScharrHoriz_32f_C1R_p = 0;
+
+///////////////////////////////// New IPP derivative filters /////////////////////////////
+
+#define IPCV_FILTER_PTRS( name ) \
+icvFilter##name##GetBufSize_8u16s_C1R_t \
+ icvFilter##name##GetBufSize_8u16s_C1R_p = 0; \
+icvFilter##name##Border_8u16s_C1R_t \
+ icvFilter##name##Border_8u16s_C1R_p = 0; \
+icvFilter##name##GetBufSize_32f_C1R_t \
+ icvFilter##name##GetBufSize_32f_C1R_p = 0; \
+icvFilter##name##Border_32f_C1R_t \
+ icvFilter##name##Border_32f_C1R_p = 0;
+
+IPCV_FILTER_PTRS( ScharrHoriz )
+IPCV_FILTER_PTRS( ScharrVert )
+IPCV_FILTER_PTRS( SobelHoriz )
+IPCV_FILTER_PTRS( SobelNegVert )
+IPCV_FILTER_PTRS( SobelHorizSecond )
+IPCV_FILTER_PTRS( SobelVertSecond )
+IPCV_FILTER_PTRS( SobelCross )
+IPCV_FILTER_PTRS( Laplacian )
+
+typedef CvStatus (CV_STDCALL * CvDeriv3x3GetBufSizeIPPFunc)
+ ( CvSize roi, int* bufsize );
+
+typedef CvStatus (CV_STDCALL * CvDerivGetBufSizeIPPFunc)
+ ( CvSize roi, int masksize, int* bufsize );
+
+typedef CvStatus (CV_STDCALL * CvDeriv3x3IPPFunc_8u )
+ ( const void* src, int srcstep, void* dst, int dststep,
+ CvSize size, int bordertype, uchar bordervalue, void* buffer );
+
+typedef CvStatus (CV_STDCALL * CvDeriv3x3IPPFunc_32f )
+ ( const void* src, int srcstep, void* dst, int dststep,
+ CvSize size, int bordertype, float bordervalue, void* buffer );
+
+typedef CvStatus (CV_STDCALL * CvDerivIPPFunc_8u )
+ ( const void* src, int srcstep, void* dst, int dststep,
+ CvSize size, int masksize, int bordertype,
+ uchar bordervalue, void* buffer );
+
+typedef CvStatus (CV_STDCALL * CvDerivIPPFunc_32f )
+ ( const void* src, int srcstep, void* dst, int dststep,
+ CvSize size, int masksize, int bordertype,
+ float bordervalue, void* buffer );
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+CV_IMPL void
+cvSobel( const void* srcarr, void* dstarr, int dx, int dy, int aperture_size )
+{
+ CvSepFilter filter;
+ void* buffer = 0;
+ int local_alloc = 0;
+
+ CV_FUNCNAME( "cvSobel" );
+
+ __BEGIN__;
+
+ int origin = 0;
+ int src_type, dst_type;
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+
+ if( !CV_IS_MAT(src) )
+ CV_CALL( src = cvGetMat( src, &srcstub ));
+ if( !CV_IS_MAT(dst) )
+ CV_CALL( dst = cvGetMat( dst, &dststub ));
+
+ if( CV_IS_IMAGE_HDR( srcarr ))
+ origin = ((IplImage*)srcarr)->origin;
+
+ src_type = CV_MAT_TYPE( src->type );
+ dst_type = CV_MAT_TYPE( dst->type );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsBadArg, "src and dst have different sizes" );
+
+ if( ((aperture_size == CV_SCHARR || aperture_size == 3 || aperture_size == 5) &&
+ dx <= 2 && dy <= 2 && dx + dy <= 2 && icvFilterSobelNegVertBorder_8u16s_C1R_p) &&
+ (src_type == CV_8UC1 && dst_type == CV_16SC1/* ||
+ src_type == CV_32FC1 && dst_type == CV_32FC1*/) )
+ {
+ CvDerivGetBufSizeIPPFunc ipp_sobel_getbufsize_func = 0;
+ CvDerivIPPFunc_8u ipp_sobel_func_8u = 0;
+ CvDerivIPPFunc_32f ipp_sobel_func_32f = 0;
+
+ CvDeriv3x3GetBufSizeIPPFunc ipp_scharr_getbufsize_func = 0;
+ CvDeriv3x3IPPFunc_8u ipp_scharr_func_8u = 0;
+ CvDeriv3x3IPPFunc_32f ipp_scharr_func_32f = 0;
+
+ if( aperture_size == CV_SCHARR )
+ {
+ if( dx == 1 && dy == 0 )
+ {
+ if( src_type == CV_8U )
+ ipp_scharr_func_8u = icvFilterScharrVertBorder_8u16s_C1R_p,
+ ipp_scharr_getbufsize_func = icvFilterScharrVertGetBufSize_8u16s_C1R_p;
+ else
+ ipp_scharr_func_32f = icvFilterScharrVertBorder_32f_C1R_p,
+ ipp_scharr_getbufsize_func = icvFilterScharrVertGetBufSize_32f_C1R_p;
+ }
+ else if( dx == 0 && dy == 1 )
+ {
+ if( src_type == CV_8U )
+ ipp_scharr_func_8u = icvFilterScharrHorizBorder_8u16s_C1R_p,
+ ipp_scharr_getbufsize_func = icvFilterScharrHorizGetBufSize_8u16s_C1R_p;
+ else
+ ipp_scharr_func_32f = icvFilterScharrHorizBorder_32f_C1R_p,
+ ipp_scharr_getbufsize_func = icvFilterScharrHorizGetBufSize_32f_C1R_p;
+ }
+ else
+ CV_ERROR( CV_StsBadArg, "Scharr filter can only be used to compute 1st image derivatives" );
+ }
+ else
+ {
+ if( dx == 1 && dy == 0 )
+ {
+ if( src_type == CV_8U )
+ ipp_sobel_func_8u = icvFilterSobelNegVertBorder_8u16s_C1R_p,
+ ipp_sobel_getbufsize_func = icvFilterSobelNegVertGetBufSize_8u16s_C1R_p;
+ else
+ ipp_sobel_func_32f = icvFilterSobelNegVertBorder_32f_C1R_p,
+ ipp_sobel_getbufsize_func = icvFilterSobelNegVertGetBufSize_32f_C1R_p;
+ }
+ else if( dx == 0 && dy == 1 )
+ {
+ if( src_type == CV_8U )
+ ipp_sobel_func_8u = icvFilterSobelHorizBorder_8u16s_C1R_p,
+ ipp_sobel_getbufsize_func = icvFilterSobelHorizGetBufSize_8u16s_C1R_p;
+ else
+ ipp_sobel_func_32f = icvFilterSobelHorizBorder_32f_C1R_p,
+ ipp_sobel_getbufsize_func = icvFilterSobelHorizGetBufSize_32f_C1R_p;
+ }
+ else if( dx == 2 && dy == 0 )
+ {
+ if( src_type == CV_8U )
+ ipp_sobel_func_8u = icvFilterSobelVertSecondBorder_8u16s_C1R_p,
+ ipp_sobel_getbufsize_func = icvFilterSobelVertSecondGetBufSize_8u16s_C1R_p;
+ else
+ ipp_sobel_func_32f = icvFilterSobelVertSecondBorder_32f_C1R_p,
+ ipp_sobel_getbufsize_func = icvFilterSobelVertSecondGetBufSize_32f_C1R_p;
+ }
+ else if( dx == 0 && dy == 2 )
+ {
+ if( src_type == CV_8U )
+ ipp_sobel_func_8u = icvFilterSobelHorizSecondBorder_8u16s_C1R_p,
+ ipp_sobel_getbufsize_func = icvFilterSobelHorizSecondGetBufSize_8u16s_C1R_p;
+ else
+ ipp_sobel_func_32f = icvFilterSobelHorizSecondBorder_32f_C1R_p,
+ ipp_sobel_getbufsize_func = icvFilterSobelHorizSecondGetBufSize_32f_C1R_p;
+ }
+ else if( dx == 1 && dy == 1 )
+ {
+ if( src_type == CV_8U )
+ ipp_sobel_func_8u = icvFilterSobelCrossBorder_8u16s_C1R_p,
+ ipp_sobel_getbufsize_func = icvFilterSobelCrossGetBufSize_8u16s_C1R_p;
+ else
+ ipp_sobel_func_32f = icvFilterSobelCrossBorder_32f_C1R_p,
+ ipp_sobel_getbufsize_func = icvFilterSobelCrossGetBufSize_32f_C1R_p;
+ }
+ }
+
+ if( ((ipp_sobel_func_8u || ipp_sobel_func_32f) && ipp_sobel_getbufsize_func) ||
+ ((ipp_scharr_func_8u || ipp_scharr_func_32f) && ipp_scharr_getbufsize_func) )
+ {
+ int bufsize = 0, masksize = aperture_size == 3 ? 33 : 55;
+ CvSize size = cvGetMatSize( src );
+ uchar* src_ptr = src->data.ptr;
+ uchar* dst_ptr = dst->data.ptr;
+ int src_step = src->step ? src->step : CV_STUB_STEP;
+ int dst_step = dst->step ? dst->step : CV_STUB_STEP;
+ const int bordertype = 1; // replication border
+ CvStatus status;
+
+ status = ipp_sobel_getbufsize_func ?
+ ipp_sobel_getbufsize_func( size, masksize, &bufsize ) :
+ ipp_scharr_getbufsize_func( size, &bufsize );
+
+ if( status >= 0 )
+ {
+ if( bufsize <= CV_MAX_LOCAL_SIZE )
+ {
+ buffer = cvStackAlloc( bufsize );
+ local_alloc = 1;
+ }
+ else
+ CV_CALL( buffer = cvAlloc( bufsize ));
+
+ status =
+ ipp_sobel_func_8u ? ipp_sobel_func_8u( src_ptr, src_step, dst_ptr, dst_step,
+ size, masksize, bordertype, 0, buffer ) :
+ ipp_sobel_func_32f ? ipp_sobel_func_32f( src_ptr, src_step, dst_ptr, dst_step,
+ size, masksize, bordertype, 0, buffer ) :
+ ipp_scharr_func_8u ? ipp_scharr_func_8u( src_ptr, src_step, dst_ptr, dst_step,
+ size, bordertype, 0, buffer ) :
+ ipp_scharr_func_32f ? ipp_scharr_func_32f( src_ptr, src_step, dst_ptr, dst_step,
+ size, bordertype, 0, buffer ) :
+ CV_NOTDEFINED_ERR;
+ }
+
+ if( status >= 0 &&
+ ((dx == 0 && dy == 1 && origin) || (dx == 1 && dy == 1 && !origin))) // negate the output
+ cvSubRS( dst, cvScalarAll(0), dst );
+
+ if( status >= 0 )
+ EXIT;
+ }
+ }
+
+ CV_CALL( filter.init_deriv( src->cols, src_type, dst_type, dx, dy,
+ aperture_size, origin ? CvSepFilter::FLIP_KERNEL : 0));
+ CV_CALL( filter.process( src, dst ));
+
+ __END__;
+
+ if( buffer && !local_alloc )
+ cvFree( &buffer );
+}
+
+
+/****************************************************************************************\
+ Laplacian Filter
+\****************************************************************************************/
+
+static void icvLaplaceRow_8u32s( const uchar* src, int* dst, void* params );
+static void icvLaplaceRow_8u32f( const uchar* src, float* dst, void* params );
+static void icvLaplaceRow_32f( const float* src, float* dst, void* params );
+static void icvLaplaceCol_32s16s( const int** src, short* dst, int dst_step,
+ int count, void* params );
+static void icvLaplaceCol_32f( const float** src, float* dst, int dst_step,
+ int count, void* params );
+
+CvLaplaceFilter::CvLaplaceFilter()
+{
+ normalized = basic_laplacian = false;
+}
+
+
+CvLaplaceFilter::CvLaplaceFilter( int _max_width, int _src_type, int _dst_type, bool _normalized,
+ int _ksize, int _border_mode, CvScalar _border_value )
+{
+ normalized = basic_laplacian = false;
+ init( _max_width, _src_type, _dst_type, _normalized, _ksize, _border_mode, _border_value );
+}
+
+
+CvLaplaceFilter::~CvLaplaceFilter()
+{
+ clear();
+}
+
+
+void CvLaplaceFilter::get_work_params()
+{
+ int min_rows = max_ky*2 + 3, rows = MAX(min_rows,10), row_sz;
+ int width = max_width, trow_sz = 0;
+ int dst_depth = CV_MAT_DEPTH(dst_type);
+ int work_depth = dst_depth < CV_32F ? CV_32S : CV_32F;
+ work_type = CV_MAKETYPE( work_depth, CV_MAT_CN(dst_type)*2 );
+ trow_sz = cvAlign( (max_width + ksize.width - 1)*CV_ELEM_SIZE(src_type), ALIGN );
+ row_sz = cvAlign( width*CV_ELEM_SIZE(work_type), ALIGN );
+ buf_size = rows*row_sz;
+ buf_size = MIN( buf_size, 1 << 16 );
+ buf_size = MAX( buf_size, min_rows*row_sz );
+ max_rows = (buf_size/row_sz)*3 + max_ky*2 + 8;
+ buf_size += trow_sz;
+}
+
+
+void CvLaplaceFilter::init( int _max_width, int _src_type, int _dst_type, bool _normalized,
+ int _ksize0, int _border_mode, CvScalar _border_value )
+{
+ CvMat *kx = 0, *ky = 0;
+
+ CV_FUNCNAME( "CvLaplaceFilter::init" );
+
+ __BEGIN__;
+
+ int src_depth = CV_MAT_DEPTH(_src_type), dst_depth = CV_MAT_DEPTH(_dst_type);
+ int _ksize = MAX( _ksize0, 3 );
+
+ normalized = _normalized;
+ basic_laplacian = _ksize0 == 1;
+
+ if( ((src_depth != CV_8U || (dst_depth != CV_16S && dst_depth != CV_32F)) &&
+ (src_depth != CV_32F || dst_depth != CV_32F)) ||
+ CV_MAT_CN(_src_type) != CV_MAT_CN(_dst_type) )
+ CV_ERROR( CV_StsUnmatchedFormats,
+ "Laplacian can either transform 8u->16s, or 8u->32f, or 32f->32f.\n"
+ "The number of channels must be the same." );
+
+ if( _ksize < 1 || _ksize > CV_MAX_SOBEL_KSIZE || _ksize % 2 == 0 )
+ CV_ERROR( CV_StsOutOfRange, "kernel size must be within 1..7 and odd" );
+
+ CV_CALL( kx = cvCreateMat( 1, _ksize, CV_32F ));
+ CV_CALL( ky = cvCreateMat( 1, _ksize, CV_32F ));
+
+ CvSepFilter::init_sobel_kernel( kx, ky, 2, 0, 0 );
+ CvSepFilter::init( _max_width, _src_type, _dst_type, kx, ky,
+ cvPoint(-1,-1), _border_mode, _border_value );
+
+ x_func = 0;
+ y_func = 0;
+
+ if( src_depth == CV_8U )
+ {
+ if( dst_depth == CV_16S )
+ {
+ x_func = (CvRowFilterFunc)icvLaplaceRow_8u32s;
+ y_func = (CvColumnFilterFunc)icvLaplaceCol_32s16s;
+ }
+ else if( dst_depth == CV_32F )
+ {
+ x_func = (CvRowFilterFunc)icvLaplaceRow_8u32f;
+ y_func = (CvColumnFilterFunc)icvLaplaceCol_32f;
+ }
+ }
+ else if( src_depth == CV_32F )
+ {
+ if( dst_depth == CV_32F )
+ {
+ x_func = (CvRowFilterFunc)icvLaplaceRow_32f;
+ y_func = (CvColumnFilterFunc)icvLaplaceCol_32f;
+ }
+ }
+
+ if( !x_func || !y_func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ __END__;
+
+ cvReleaseMat( &kx );
+ cvReleaseMat( &ky );
+}
+
+
+void CvLaplaceFilter::init( int _max_width, int _src_type, int _dst_type,
+ bool _is_separable, CvSize _ksize,
+ CvPoint _anchor, int _border_mode,
+ CvScalar _border_value )
+{
+ CvSepFilter::init( _max_width, _src_type, _dst_type, _is_separable,
+ _ksize, _anchor, _border_mode, _border_value );
+}
+
+
+void CvLaplaceFilter::init( int _max_width, int _src_type, int _dst_type,
+ const CvMat* _kx, const CvMat* _ky,
+ CvPoint _anchor, int _border_mode,
+ CvScalar _border_value )
+{
+ CvSepFilter::init( _max_width, _src_type, _dst_type, _kx, _ky,
+ _anchor, _border_mode, _border_value );
+}
+
+
+#define ICV_LAPLACE_ROW( flavor, srctype, dsttype, load_macro ) \
+static void \
+icvLaplaceRow_##flavor( const srctype* src, dsttype* dst, void* params )\
+{ \
+ const CvLaplaceFilter* state = (const CvLaplaceFilter*)params; \
+ const CvMat* _kx = state->get_x_kernel(); \
+ const CvMat* _ky = state->get_y_kernel(); \
+ const dsttype* kx = (dsttype*)_kx->data.ptr; \
+ const dsttype* ky = (dsttype*)_ky->data.ptr; \
+ int ksize = _kx->cols + _kx->rows - 1; \
+ int i = 0, j, k, width = state->get_width(); \
+ int cn = CV_MAT_CN(state->get_src_type()); \
+ int ksize2 = ksize/2, ksize2n = ksize2*cn; \
+ const srctype* s = src + ksize2n; \
+ bool basic_laplacian = state->is_basic_laplacian(); \
+ \
+ kx += ksize2; \
+ ky += ksize2; \
+ width *= cn; \
+ \
+ if( basic_laplacian ) \
+ for( i = 0; i < width; i++ ) \
+ { \
+ dsttype s0 = load_macro(s[i]); \
+ dsttype s1 = (dsttype)(s[i-cn] - s0*2 + s[i+cn]); \
+ dst[i] = s0; dst[i+width] = s1; \
+ } \
+ else if( ksize == 3 ) \
+ for( i = 0; i < width; i++ ) \
+ { \
+ dsttype s0 = (dsttype)(s[i-cn] + s[i]*2 + s[i+cn]); \
+ dsttype s1 = (dsttype)(s[i-cn] - s[i]*2 + s[i+cn]); \
+ dst[i] = s0; dst[i+width] = s1; \
+ } \
+ else if( ksize == 5 ) \
+ for( i = 0; i < width; i++ ) \
+ { \
+ dsttype s0 = (dsttype)(s[i-2*cn]+(s[i-cn]+s[i+cn])*4+s[i]*6+s[i+2*cn]);\
+ dsttype s1 = (dsttype)(s[i-2*cn]-s[i]*2+s[i+2*cn]); \
+ dst[i] = s0; dst[i+width] = s1; \
+ } \
+ else \
+ for( i = 0; i < width; i++, s++ ) \
+ { \
+ dsttype s0 = ky[0]*load_macro(s[0]), s1 = kx[0]*load_macro(s[0]);\
+ for( k = 1, j = cn; k <= ksize2; k++, j += cn ) \
+ { \
+ dsttype t = load_macro(s[j] + s[-j]); \
+ s0 += ky[k]*t; s1 += kx[k]*t; \
+ } \
+ dst[i] = s0; dst[i+width] = s1; \
+ } \
+}
+
+ICV_LAPLACE_ROW( 8u32s, uchar, int, CV_NOP )
+ICV_LAPLACE_ROW( 8u32f, uchar, float, CV_8TO32F )
+ICV_LAPLACE_ROW( 32f, float, float, CV_NOP )
+
+static void
+icvLaplaceCol_32s16s( const int** src, short* dst,
+ int dst_step, int count, void* params )
+{
+ const CvLaplaceFilter* state = (const CvLaplaceFilter*)params;
+ const CvMat* _kx = state->get_x_kernel();
+ const CvMat* _ky = state->get_y_kernel();
+ const int* kx = (const int*)_kx->data.ptr;
+ const int* ky = (const int*)_ky->data.ptr;
+ int ksize = _kx->cols + _kx->rows - 1, ksize2 = ksize/2;
+ int i = 0, k, width = state->get_width();
+ int cn = CV_MAT_CN(state->get_src_type());
+ bool basic_laplacian = state->is_basic_laplacian();
+ bool normalized = state->is_normalized();
+ int shift = ksize - 1, delta = (1 << shift) >> 1;
+
+ width *= cn;
+ src += ksize2;
+ kx += ksize2;
+ ky += ksize2;
+ dst_step /= sizeof(dst[0]);
+
+ if( basic_laplacian || !normalized )
+ {
+ normalized = false;
+ shift = delta = 0;
+ }
+
+ for( ; count--; dst += dst_step, src++ )
+ {
+ if( ksize == 3 )
+ {
+ const int *src0 = src[-1], *src1 = src[0], *src2 = src[1];
+ if( basic_laplacian )
+ {
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = src0[i] - src1[i]*2 + src2[i] + src1[i+width];
+ int s1 = src0[i+1] - src1[i+1]*2 + src2[i+1] + src1[i+width+1];
+ dst[i] = (short)s0; dst[i+1] = (short)s1;
+ }
+
+ for( ; i < width; i++ )
+ dst[i] = (short)(src0[i] - src1[i]*2 + src2[i] + src1[i+width]);
+ }
+ else if( !normalized )
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = src0[i] - src1[i]*2 + src2[i] +
+ src0[i+width] + src1[i+width]*2 + src2[i+width];
+ int s1 = src0[i+1] - src1[i+1]*2 + src2[i+1] +
+ src0[i+width+1] + src1[i+width+1]*2 + src2[i+width+1];
+ dst[i] = (short)s0; dst[i+1] = (short)s1;
+ }
+ else
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = CV_DESCALE(src0[i] - src1[i]*2 + src2[i] +
+ src0[i+width] + src1[i+width]*2 + src2[i+width], 2);
+ int s1 = CV_DESCALE(src0[i+1] - src1[i+1]*2 + src2[i+1] +
+ src0[i+width+1] + src1[i+width+1]*2 + src2[i+width+1],2);
+ dst[i] = (short)s0; dst[i+1] = (short)s1;
+ }
+ }
+ else if( ksize == 5 )
+ {
+ const int *src0 = src[-2], *src1 = src[-1], *src2 = src[0], *src3 = src[1], *src4 = src[2];
+
+ if( !normalized )
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = src0[i] - src2[i]*2 + src4[i] + src0[i+width] + src4[i+width] +
+ (src1[i+width] + src3[i+width])*4 + src2[i+width]*6;
+ int s1 = src0[i+1] - src2[i+1]*2 + src4[i+1] + src0[i+width+1] +
+ src4[i+width+1] + (src1[i+width+1] + src3[i+width+1])*4 +
+ src2[i+width+1]*6;
+ dst[i] = (short)s0; dst[i+1] = (short)s1;
+ }
+ else
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = CV_DESCALE(src0[i] - src2[i]*2 + src4[i] +
+ src0[i+width] + src4[i+width] +
+ (src1[i+width] + src3[i+width])*4 + src2[i+width]*6, 4);
+ int s1 = CV_DESCALE(src0[i+1] - src2[i+1]*2 + src4[i+1] +
+ src0[i+width+1] + src4[i+width+1] +
+ (src1[i+width+1] + src3[i+width+1])*4 + src2[i+width+1]*6, 4);
+ dst[i] = (short)s0; dst[i+1] = (short)s1;
+ }
+ }
+ else
+ {
+ if( !normalized )
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = kx[0]*src[0][i] + ky[0]*src[0][i+width];
+ int s1 = kx[0]*src[0][i+1] + ky[0]*src[0][i+width+1];
+
+ for( k = 1; k <= ksize2; k++ )
+ {
+ const int* src1 = src[k] + i, *src2 = src[-k] + i;
+ int fx = kx[k], fy = ky[k];
+ s0 += fx*(src1[0] + src2[0]) + fy*(src1[width] + src2[width]);
+ s1 += fx*(src1[1] + src2[1]) + fy*(src1[width+1] + src2[width+1]);
+ }
+
+ dst[i] = CV_CAST_16S(s0); dst[i+1] = CV_CAST_16S(s1);
+ }
+ else
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = kx[0]*src[0][i] + ky[0]*src[0][i+width];
+ int s1 = kx[0]*src[0][i+1] + ky[0]*src[0][i+width+1];
+
+ for( k = 1; k <= ksize2; k++ )
+ {
+ const int* src1 = src[k] + i, *src2 = src[-k] + i;
+ int fx = kx[k], fy = ky[k];
+ s0 += fx*(src1[0] + src2[0]) + fy*(src1[width] + src2[width]);
+ s1 += fx*(src1[1] + src2[1]) + fy*(src1[width+1] + src2[width+1]);
+ }
+
+ s0 = CV_DESCALE( s0, shift ); s1 = CV_DESCALE( s1, shift );
+ dst[i] = (short)s0; dst[i+1] = (short)s1;
+ }
+ }
+
+ for( ; i < width; i++ )
+ {
+ int s0 = kx[0]*src[0][i] + ky[0]*src[0][i+width];
+ for( k = 1; k <= ksize2; k++ )
+ {
+ const int* src1 = src[k] + i, *src2 = src[-k] + i;
+ s0 += kx[k]*(src1[0] + src2[0]) + ky[k]*(src1[width] + src2[width]);
+ }
+ s0 = (s0 + delta) >> shift;
+ dst[i] = CV_CAST_16S(s0);
+ }
+ }
+}
+
+
+static void
+icvLaplaceCol_32f( const float** src, float* dst,
+ int dst_step, int count, void* params )
+{
+ const CvLaplaceFilter* state = (const CvLaplaceFilter*)params;
+ const CvMat* _kx = state->get_x_kernel();
+ const CvMat* _ky = state->get_y_kernel();
+ const float* kx = (const float*)_kx->data.ptr;
+ const float* ky = (const float*)_ky->data.ptr;
+ int ksize = _kx->cols + _kx->rows - 1, ksize2 = ksize/2;
+ int i = 0, k, width = state->get_width();
+ int cn = CV_MAT_CN(state->get_src_type());
+ bool basic_laplacian = state->is_basic_laplacian();
+ bool normalized = state->is_normalized();
+ float scale = 1.f/(1 << (ksize - 1));
+
+ width *= cn;
+ src += ksize2;
+ kx += ksize2;
+ ky += ksize2;
+ dst_step /= sizeof(dst[0]);
+
+ if( basic_laplacian || !normalized )
+ {
+ normalized = false;
+ scale = 1.f;
+ }
+
+ for( ; count--; dst += dst_step, src++ )
+ {
+ if( ksize == 3 )
+ {
+ const float *src0 = src[-1], *src1 = src[0], *src2 = src[1];
+ if( basic_laplacian )
+ {
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ float s0 = src0[i] - src1[i]*2 + src2[i] + src1[i+width];
+ float s1 = src0[i+1] - src1[i+1]*2 + src2[i+1] + src1[i+width+1];
+ dst[i] = s0; dst[i+1] = s1;
+ }
+
+ for( ; i < width; i++ )
+ dst[i] = src0[i] - src1[i]*2 + src2[i] + src1[i+width];
+ }
+ else if( !normalized )
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ float s0 = src0[i] - src1[i]*2 + src2[i] +
+ src0[i+width] + src1[i+width]*2 + src2[i+width];
+ float s1 = src0[i+1] - src1[i+1]*2 + src2[i+1] +
+ src0[i+width+1] + src1[i+width+1]*2 + src2[i+width+1];
+ dst[i] = s0; dst[i+1] = s1;
+ }
+ else
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ float s0 = (src0[i] - src1[i]*2 + src2[i] +
+ src0[i+width] + src1[i+width]*2 + src2[i+width])*scale;
+ float s1 = (src0[i+1] - src1[i+1]*2 + src2[i+1] +
+ src0[i+width+1] + src1[i+width+1]*2 + src2[i+width+1])*scale;
+ dst[i] = s0; dst[i+1] = s1;
+ }
+ }
+ else if( ksize == 5 )
+ {
+ const float *src0 = src[-2], *src1 = src[-1], *src2 = src[0], *src3 = src[1], *src4 = src[2];
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ float s0 = (src0[i] - src2[i]*2 + src4[i] +
+ src0[i+width] + src4[i+width] +
+ (src1[i+width] + src3[i+width])*4 + src2[i+width]*6)*scale;
+ float s1 = (src0[i+1] - src2[i+1]*2 + src4[i+1] +
+ src0[i+width+1] + src4[i+width+1] +
+ (src1[i+width+1] + src3[i+width+1])*4 + src2[i+width+1]*6)*scale;
+ dst[i] = s0; dst[i+1] = s1;
+ }
+ }
+ else
+ {
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ float s0 = kx[0]*src[0][i] + ky[0]*src[0][i+width];
+ float s1 = kx[0]*src[0][i+1] + ky[0]*src[0][i+width+1];
+
+ for( k = 1; k <= ksize2; k++ )
+ {
+ const float* src1 = src[k] + i, *src2 = src[-k] + i;
+ float fx = kx[k], fy = ky[k];
+ s0 += fx*(src1[0] + src2[0]) + fy*(src1[width] + src2[width]);
+ s1 += fx*(src1[1] + src2[1]) + fy*(src1[width+1] + src2[width+1]);
+ }
+
+ s0 *= scale; s1 *= scale;
+ dst[i] = s0; dst[i+1] = s1;
+ }
+ }
+
+ for( ; i < width; i++ )
+ {
+ float s0 = kx[0]*src[0][i] + ky[0]*src[0][i+width];
+ for( k = 1; k <= ksize2; k++ )
+ {
+ const float* src1 = src[k] + i, *src2 = src[-k] + i;
+ s0 += kx[k]*(src1[0] + src2[0]) + ky[k]*(src1[width] + src2[width]);
+ }
+ dst[i] = s0*scale;
+ }
+ }
+}
+
+
+CV_IMPL void
+cvLaplace( const void* srcarr, void* dstarr, int aperture_size )
+{
+ CvLaplaceFilter laplacian;
+ void* buffer = 0;
+ int local_alloc = 0;
+
+ CV_FUNCNAME( "cvLaplace" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ int src_type, dst_type;
+
+ CV_CALL( src = cvGetMat( src, &srcstub ));
+ CV_CALL( dst = cvGetMat( dst, &dststub ));
+
+ src_type = CV_MAT_TYPE(src->type);
+ dst_type = CV_MAT_TYPE(dst->type);
+
+ if( (aperture_size == 3 || aperture_size == 5) &&
+ (src_type == CV_8UC1 && dst_type == CV_16SC1/* ||
+ src_type == CV_32FC1 && dst_type == CV_32FC1*/) )
+ {
+ CvDerivGetBufSizeIPPFunc ipp_laplace_getbufsize_func = 0;
+ CvDerivIPPFunc_8u ipp_laplace_func_8u = 0;
+ CvDerivIPPFunc_32f ipp_laplace_func_32f = 0;
+
+ if( src_type == CV_8U )
+ ipp_laplace_func_8u = icvFilterLaplacianBorder_8u16s_C1R_p,
+ ipp_laplace_getbufsize_func = icvFilterLaplacianGetBufSize_8u16s_C1R_p;
+ else
+ ipp_laplace_func_32f = icvFilterLaplacianBorder_32f_C1R_p,
+ ipp_laplace_getbufsize_func = icvFilterLaplacianGetBufSize_32f_C1R_p;
+
+ if( (ipp_laplace_func_8u || ipp_laplace_func_32f) && ipp_laplace_getbufsize_func )
+ {
+ int bufsize = 0, masksize = aperture_size == 3 ? 33 : 55;
+ CvSize size = cvGetMatSize( src );
+ uchar* src_ptr = src->data.ptr;
+ uchar* dst_ptr = dst->data.ptr;
+ int src_step = src->step ? src->step : CV_STUB_STEP;
+ int dst_step = dst->step ? dst->step : CV_STUB_STEP;
+ const int bordertype = 1; // replication border
+ CvStatus status;
+
+ status = ipp_laplace_getbufsize_func( size, masksize, &bufsize );
+
+ if( status >= 0 )
+ {
+ if( bufsize <= CV_MAX_LOCAL_SIZE )
+ {
+ buffer = cvStackAlloc( bufsize );
+ local_alloc = 1;
+ }
+ else
+ CV_CALL( buffer = cvAlloc( bufsize ));
+
+ status =
+ ipp_laplace_func_8u ? ipp_laplace_func_8u( src_ptr, src_step, dst_ptr, dst_step,
+ size, masksize, bordertype, 0, buffer ) :
+ ipp_laplace_func_32f ? ipp_laplace_func_32f( src_ptr, src_step, dst_ptr, dst_step,
+ size, masksize, bordertype, 0, buffer ) :
+ CV_NOTDEFINED_ERR;
+ }
+
+ if( status >= 0 )
+ EXIT;
+ }
+ }
+
+ CV_CALL( laplacian.init( src->cols, src_type, dst_type,
+ false, aperture_size ));
+ CV_CALL( laplacian.process( src, dst ));
+
+ __END__;
+
+ if( buffer && !local_alloc )
+ cvFree( &buffer );
+}
+
+/* End of file. */
diff --git a/cv/src/cvdistransform.cpp b/cv/src/cvdistransform.cpp
new file mode 100644
index 0000000..51452f5
--- /dev/null
+++ b/cv/src/cvdistransform.cpp
@@ -0,0 +1,859 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+#define ICV_DIST_SHIFT 16
+#define ICV_INIT_DIST0 (INT_MAX >> 2)
+
+static CvStatus
+icvInitTopBottom( int* temp, int tempstep, CvSize size, int border )
+{
+ int i, j;
+ for( i = 0; i < border; i++ )
+ {
+ int* ttop = (int*)(temp + i*tempstep);
+ int* tbottom = (int*)(temp + (size.height + border*2 - i - 1)*tempstep);
+
+ for( j = 0; j < size.width + border*2; j++ )
+ {
+ ttop[j] = ICV_INIT_DIST0;
+ tbottom[j] = ICV_INIT_DIST0;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvDistanceTransform_3x3_C1R( const uchar* src, int srcstep, int* temp,
+ int step, float* dist, int dststep, CvSize size, const float* metrics )
+{
+ const int BORDER = 1;
+ int i, j;
+ const int HV_DIST = CV_FLT_TO_FIX( metrics[0], ICV_DIST_SHIFT );
+ const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], ICV_DIST_SHIFT );
+ const float scale = 1.f/(1 << ICV_DIST_SHIFT);
+
+ srcstep /= sizeof(src[0]);
+ step /= sizeof(temp[0]);
+ dststep /= sizeof(dist[0]);
+
+ icvInitTopBottom( temp, step, size, BORDER );
+
+ // forward pass
+ for( i = 0; i < size.height; i++ )
+ {
+ const uchar* s = src + i*srcstep;
+ int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
+
+ for( j = 0; j < BORDER; j++ )
+ tmp[-j-1] = tmp[size.width + j] = ICV_INIT_DIST0;
+
+ for( j = 0; j < size.width; j++ )
+ {
+ if( !s[j] )
+ tmp[j] = 0;
+ else
+ {
+ int t0 = tmp[j-step-1] + DIAG_DIST;
+ int t = tmp[j-step] + HV_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j-step+1] + DIAG_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j-1] + HV_DIST;
+ if( t0 > t ) t0 = t;
+ tmp[j] = t0;
+ }
+ }
+ }
+
+ // backward pass
+ for( i = size.height - 1; i >= 0; i-- )
+ {
+ float* d = (float*)(dist + i*dststep);
+ int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
+
+ for( j = size.width - 1; j >= 0; j-- )
+ {
+ int t0 = tmp[j];
+ if( t0 > HV_DIST )
+ {
+ int t = tmp[j+step+1] + DIAG_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j+step] + HV_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j+step-1] + DIAG_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j+1] + HV_DIST;
+ if( t0 > t ) t0 = t;
+ tmp[j] = t0;
+ }
+ d[j] = (float)(t0 * scale);
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvDistanceTransform_5x5_C1R( const uchar* src, int srcstep, int* temp,
+ int step, float* dist, int dststep, CvSize size, const float* metrics )
+{
+ const int BORDER = 2;
+ int i, j;
+ const int HV_DIST = CV_FLT_TO_FIX( metrics[0], ICV_DIST_SHIFT );
+ const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], ICV_DIST_SHIFT );
+ const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], ICV_DIST_SHIFT );
+ const float scale = 1.f/(1 << ICV_DIST_SHIFT);
+
+ srcstep /= sizeof(src[0]);
+ step /= sizeof(temp[0]);
+ dststep /= sizeof(dist[0]);
+
+ icvInitTopBottom( temp, step, size, BORDER );
+
+ // forward pass
+ for( i = 0; i < size.height; i++ )
+ {
+ const uchar* s = src + i*srcstep;
+ int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
+
+ for( j = 0; j < BORDER; j++ )
+ tmp[-j-1] = tmp[size.width + j] = ICV_INIT_DIST0;
+
+ for( j = 0; j < size.width; j++ )
+ {
+ if( !s[j] )
+ tmp[j] = 0;
+ else
+ {
+ int t0 = tmp[j-step*2-1] + LONG_DIST;
+ int t = tmp[j-step*2+1] + LONG_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j-step-2] + LONG_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j-step-1] + DIAG_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j-step] + HV_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j-step+1] + DIAG_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j-step+2] + LONG_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j-1] + HV_DIST;
+ if( t0 > t ) t0 = t;
+ tmp[j] = t0;
+ }
+ }
+ }
+
+ // backward pass
+ for( i = size.height - 1; i >= 0; i-- )
+ {
+ float* d = (float*)(dist + i*dststep);
+ int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
+
+ for( j = size.width - 1; j >= 0; j-- )
+ {
+ int t0 = tmp[j];
+ if( t0 > HV_DIST )
+ {
+ int t = tmp[j+step*2+1] + LONG_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j+step*2-1] + LONG_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j+step+2] + LONG_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j+step+1] + DIAG_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j+step] + HV_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j+step-1] + DIAG_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j+step-2] + LONG_DIST;
+ if( t0 > t ) t0 = t;
+ t = tmp[j+1] + HV_DIST;
+ if( t0 > t ) t0 = t;
+ tmp[j] = t0;
+ }
+ d[j] = (float)(t0 * scale);
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvDistanceTransformEx_5x5_C1R( const uchar* src, int srcstep, int* temp,
+ int step, float* dist, int dststep, int* labels, int lstep,
+ CvSize size, const float* metrics )
+{
+ const int BORDER = 2;
+
+ int i, j;
+ const int HV_DIST = CV_FLT_TO_FIX( metrics[0], ICV_DIST_SHIFT );
+ const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], ICV_DIST_SHIFT );
+ const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], ICV_DIST_SHIFT );
+ const float scale = 1.f/(1 << ICV_DIST_SHIFT);
+
+ srcstep /= sizeof(src[0]);
+ step /= sizeof(temp[0]);
+ dststep /= sizeof(dist[0]);
+ lstep /= sizeof(labels[0]);
+
+ icvInitTopBottom( temp, step, size, BORDER );
+
+ // forward pass
+ for( i = 0; i < size.height; i++ )
+ {
+ const uchar* s = src + i*srcstep;
+ int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
+ int* lls = (int*)(labels + i*lstep);
+
+ for( j = 0; j < BORDER; j++ )
+ tmp[-j-1] = tmp[size.width + j] = ICV_INIT_DIST0;
+
+ for( j = 0; j < size.width; j++ )
+ {
+ if( !s[j] )
+ {
+ tmp[j] = 0;
+ //assert( lls[j] != 0 );
+ }
+ else
+ {
+ int t0 = ICV_INIT_DIST0, t;
+ int l0 = 0;
+
+ t = tmp[j-step*2-1] + LONG_DIST;
+ if( t0 > t )
+ {
+ t0 = t;
+ l0 = lls[j-lstep*2-1];
+ }
+ t = tmp[j-step*2+1] + LONG_DIST;
+ if( t0 > t )
+ {
+ t0 = t;
+ l0 = lls[j-lstep*2+1];
+ }
+ t = tmp[j-step-2] + LONG_DIST;
+ if( t0 > t )
+ {
+ t0 = t;
+ l0 = lls[j-lstep-2];
+ }
+ t = tmp[j-step-1] + DIAG_DIST;
+ if( t0 > t )
+ {
+ t0 = t;
+ l0 = lls[j-lstep-1];
+ }
+ t = tmp[j-step] + HV_DIST;
+ if( t0 > t )
+ {
+ t0 = t;
+ l0 = lls[j-lstep];
+ }
+ t = tmp[j-step+1] + DIAG_DIST;
+ if( t0 > t )
+ {
+ t0 = t;
+ l0 = lls[j-lstep+1];
+ }
+ t = tmp[j-step+2] + LONG_DIST;
+ if( t0 > t )
+ {
+ t0 = t;
+ l0 = lls[j-lstep+2];
+ }
+ t = tmp[j-1] + HV_DIST;
+ if( t0 > t )
+ {
+ t0 = t;
+ l0 = lls[j-1];
+ }
+
+ tmp[j] = t0;
+ lls[j] = l0;
+ }
+ }
+ }
+
+ // backward pass
+ for( i = size.height - 1; i >= 0; i-- )
+ {
+ float* d = (float*)(dist + i*dststep);
+ int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
+ int* lls = (int*)(labels + i*lstep);
+
+ for( j = size.width - 1; j >= 0; j-- )
+ {
+ int t0 = tmp[j];
+ int l0 = lls[j];
+ if( t0 > HV_DIST )
+ {
+ int t = tmp[j+step*2+1] + LONG_DIST;
+ if( t0 > t )
+ {
+ t0 = t;
+ l0 = lls[j+lstep*2+1];
+ }
+ t = tmp[j+step*2-1] + LONG_DIST;
+ if( t0 > t )
+ {
+ t0 = t;
+ l0 = lls[j+lstep*2-1];
+ }
+ t = tmp[j+step+2] + LONG_DIST;
+ if( t0 > t )
+ {
+ t0 = t;
+ l0 = lls[j+lstep+2];
+ }
+ t = tmp[j+step+1] + DIAG_DIST;
+ if( t0 > t )
+ {
+ t0 = t;
+ l0 = lls[j+lstep+1];
+ }
+ t = tmp[j+step] + HV_DIST;
+ if( t0 > t )
+ {
+ t0 = t;
+ l0 = lls[j+lstep];
+ }
+ t = tmp[j+step-1] + DIAG_DIST;
+ if( t0 > t )
+ {
+ t0 = t;
+ l0 = lls[j+lstep-1];
+ }
+ t = tmp[j+step-2] + LONG_DIST;
+ if( t0 > t )
+ {
+ t0 = t;
+ l0 = lls[j+lstep-2];
+ }
+ t = tmp[j+1] + HV_DIST;
+ if( t0 > t )
+ {
+ t0 = t;
+ l0 = lls[j+1];
+ }
+ tmp[j] = t0;
+ lls[j] = l0;
+ }
+ d[j] = (float)(t0 * scale);
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus
+icvGetDistanceTransformMask( int maskType, float *metrics )
+{
+ if( !metrics )
+ return CV_NULLPTR_ERR;
+
+ switch (maskType)
+ {
+ case 30:
+ metrics[0] = 1.0f;
+ metrics[1] = 1.0f;
+ break;
+
+ case 31:
+ metrics[0] = 1.0f;
+ metrics[1] = 2.0f;
+ break;
+
+ case 32:
+ metrics[0] = 0.955f;
+ metrics[1] = 1.3693f;
+ break;
+
+ case 50:
+ metrics[0] = 1.0f;
+ metrics[1] = 1.0f;
+ metrics[2] = 2.0f;
+ break;
+
+ case 51:
+ metrics[0] = 1.0f;
+ metrics[1] = 2.0f;
+ metrics[2] = 3.0f;
+ break;
+
+ case 52:
+ metrics[0] = 1.0f;
+ metrics[1] = 1.4f;
+ metrics[2] = 2.1969f;
+ break;
+ default:
+ return CV_BADRANGE_ERR;
+ }
+
+ return CV_OK;
+}
+
+
+static void
+icvTrueDistTrans( const CvMat* src, CvMat* dst )
+{
+ CvMat* buffer = 0;
+
+ CV_FUNCNAME( "cvDistTransform2" );
+
+ __BEGIN__;
+
+ int i, m, n;
+ int sstep, dstep;
+ const float inf = 1e6f;
+ int thread_count = cvGetNumThreads();
+ int pass1_sz, pass2_sz;
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( CV_MAT_TYPE(src->type) != CV_8UC1 ||
+ CV_MAT_TYPE(dst->type) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "The input image must have 8uC1 type and the output one must have 32fC1 type" );
+
+ m = src->rows;
+ n = src->cols;
+
+ // (see stage 1 below):
+ // sqr_tab: 2*m, sat_tab: 3*m + 1, d: m*thread_count,
+ pass1_sz = src->rows*(5 + thread_count) + 1;
+ // (see stage 2):
+ // sqr_tab & inv_tab: n each; f & v: n*thread_count each; z: (n+1)*thread_count
+ pass2_sz = src->cols*(2 + thread_count*3) + thread_count;
+ CV_CALL( buffer = cvCreateMat( 1, MAX(pass1_sz, pass2_sz), CV_32FC1 ));
+
+ sstep = src->step;
+ dstep = dst->step / sizeof(float);
+
+ // stage 1: compute 1d distance transform of each column
+ {
+ float* sqr_tab = buffer->data.fl;
+ int* sat_tab = (int*)(sqr_tab + m*2);
+ const int shift = m*2;
+
+ for( i = 0; i < m; i++ )
+ sqr_tab[i] = (float)(i*i);
+ for( i = m; i < m*2; i++ )
+ sqr_tab[i] = inf;
+ for( i = 0; i < shift; i++ )
+ sat_tab[i] = 0;
+ for( ; i <= m*3; i++ )
+ sat_tab[i] = i - shift;
+
+#ifdef _OPENMP
+ #pragma omp parallel for num_threads(thread_count)
+#endif
+ for( i = 0; i < n; i++ )
+ {
+ const uchar* sptr = src->data.ptr + i + (m-1)*sstep;
+ float* dptr = dst->data.fl + i;
+ int* d = (int*)(sat_tab + m*3+1+m*cvGetThreadNum());
+ int j, dist = m-1;
+
+ for( j = m-1; j >= 0; j--, sptr -= sstep )
+ {
+ dist = (dist + 1) & (sptr[0] == 0 ? 0 : -1);
+ d[j] = dist;
+ }
+
+ dist = m-1;
+ for( j = 0; j < m; j++, dptr += dstep )
+ {
+ dist = dist + 1 - sat_tab[dist + 1 - d[j] + shift];
+ d[j] = dist;
+ dptr[0] = sqr_tab[dist];
+ }
+ }
+ }
+
+ // stage 2: compute modified distance transform for each row
+ {
+ float* inv_tab = buffer->data.fl;
+ float* sqr_tab = inv_tab + n;
+
+ inv_tab[0] = sqr_tab[0] = 0.f;
+ for( i = 1; i < n; i++ )
+ {
+ inv_tab[i] = (float)(0.5/i);
+ sqr_tab[i] = (float)(i*i);
+ }
+
+#ifdef _OPENMP
+ #pragma omp parallel for num_threads(thread_count) schedule(dynamic)
+#endif
+ for( i = 0; i < m; i++ )
+ {
+ float* d = (float*)(dst->data.ptr + i*dst->step);
+ float* f = sqr_tab + n + (n*3+1)*cvGetThreadNum();
+ float* z = f + n;
+ int* v = (int*)(z + n + 1);
+ int p, q, k;
+
+ v[0] = 0;
+ z[0] = -inf;
+ z[1] = inf;
+ f[0] = d[0];
+
+ for( q = 1, k = 0; q < n; q++ )
+ {
+ float fq = d[q];
+ f[q] = fq;
+
+ for(;;k--)
+ {
+ p = v[k];
+ float s = (fq + sqr_tab[q] - d[p] - sqr_tab[p])*inv_tab[q - p];
+ if( s > z[k] )
+ {
+ k++;
+ v[k] = q;
+ z[k] = s;
+ z[k+1] = inf;
+ break;
+ }
+ }
+ }
+
+ for( q = 0, k = 0; q < n; q++ )
+ {
+ while( z[k+1] < q )
+ k++;
+ p = v[k];
+ d[q] = sqr_tab[abs(q - p)] + f[p];
+ }
+ }
+ }
+
+ cvPow( dst, dst, 0.5 );
+
+ __END__;
+
+ cvReleaseMat( &buffer );
+}
+
+
+/*********************************** IPP functions *********************************/
+
+icvDistanceTransform_3x3_8u32f_C1R_t icvDistanceTransform_3x3_8u32f_C1R_p = 0;
+icvDistanceTransform_5x5_8u32f_C1R_t icvDistanceTransform_5x5_8u32f_C1R_p = 0;
+icvDistanceTransform_3x3_8u_C1IR_t icvDistanceTransform_3x3_8u_C1IR_p = 0;
+icvDistanceTransform_3x3_8u_C1R_t icvDistanceTransform_3x3_8u_C1R_p = 0;
+
+typedef CvStatus (CV_STDCALL * CvIPPDistTransFunc)( const uchar* src, int srcstep,
+ void* dst, int dststep,
+ CvSize size, const void* metrics );
+
+typedef CvStatus (CV_STDCALL * CvIPPDistTransFunc2)( uchar* src, int srcstep,
+ CvSize size, const int* metrics );
+
+/***********************************************************************************/
+
+typedef CvStatus (CV_STDCALL * CvDistTransFunc)( const uchar* src, int srcstep,
+ int* temp, int tempstep,
+ float* dst, int dststep,
+ CvSize size, const float* metrics );
+
+
+/****************************************************************************************\
+ User-contributed code:
+
+ Non-inplace and Inplace 8u->8u Distance Transform for CityBlock (a.k.a. L1) metric
+ (C) 2006 by Jay Stavinzky.
+\****************************************************************************************/
+
+//BEGIN ATS ADDITION
+/* 8-bit grayscale distance transform function */
+static void
+icvDistanceATS_L1_8u( const CvMat* src, CvMat* dst )
+{
+ CV_FUNCNAME( "cvDistanceATS" );
+
+ __BEGIN__;
+
+ int width = src->cols, height = src->rows;
+
+ int a;
+ uchar lut[256];
+ int x, y;
+
+ const uchar *sbase = src->data.ptr;
+ uchar *dbase = dst->data.ptr;
+ int srcstep = src->step;
+ int dststep = dst->step;
+
+ CV_ASSERT( CV_IS_MASK_ARR( src ) && CV_MAT_TYPE( dst->type ) == CV_8UC1 );
+ CV_ASSERT( CV_ARE_SIZES_EQ( src, dst ));
+
+ ////////////////////// forward scan ////////////////////////
+ for( x = 0; x < 256; x++ )
+ lut[x] = CV_CAST_8U(x+1);
+
+ //init first pixel to max (we're going to be skipping it)
+ dbase[0] = (uchar)(sbase[0] == 0 ? 0 : 255);
+
+ //first row (scan west only, skip first pixel)
+ for( x = 1; x < width; x++ )
+ dbase[x] = (uchar)(sbase[x] == 0 ? 0 : lut[dbase[x-1]]);
+
+ for( y = 1; y < height; y++ )
+ {
+ sbase += srcstep;
+ dbase += dststep;
+
+ //for left edge, scan north only
+ a = sbase[0] == 0 ? 0 : lut[dbase[-dststep]];
+ dbase[0] = (uchar)a;
+
+ for( x = 1; x < width; x++ )
+ {
+ a = sbase[x] == 0 ? 0 : lut[MIN(a, dbase[x - dststep])];
+ dbase[x] = (uchar)a;
+ }
+ }
+
+ ////////////////////// backward scan ///////////////////////
+
+ a = dbase[width-1];
+
+ // do last row east pixel scan here (skip bottom right pixel)
+ for( x = width - 2; x >= 0; x-- )
+ {
+ a = lut[a];
+ dbase[x] = (uchar)(CV_CALC_MIN_8U(a, dbase[x]));
+ }
+
+ // right edge is the only error case
+ for( y = height - 2; y >= 0; y-- )
+ {
+ dbase -= dststep;
+
+ // do right edge
+ a = lut[dbase[width-1+dststep]];
+ dbase[width-1] = (uchar)(MIN(a, dbase[width-1]));
+
+ for( x = width - 2; x >= 0; x-- )
+ {
+ int b = dbase[x+dststep];
+ a = lut[MIN(a, b)];
+ dbase[x] = (uchar)(MIN(a, dbase[x]));
+ }
+ }
+
+ __END__;
+}
+//END ATS ADDITION
+
+
+/* Wrapper function for distance transform group */
+CV_IMPL void
+cvDistTransform( const void* srcarr, void* dstarr,
+ int distType, int maskSize,
+ const float *mask,
+ void* labelsarr )
+{
+ CvMat* temp = 0;
+ CvMat* src_copy = 0;
+ CvMemStorage* st = 0;
+
+ CV_FUNCNAME( "cvDistTransform" );
+
+ __BEGIN__;
+
+ float _mask[5] = {0};
+ int _imask[3];
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvMat lstub, *labels = (CvMat*)labelsarr;
+ CvSize size;
+ CvIPPDistTransFunc ipp_func = 0;
+ CvIPPDistTransFunc2 ipp_inp_func = 0;
+
+ CV_CALL( src = cvGetMat( src, &srcstub ));
+ CV_CALL( dst = cvGetMat( dst, &dststub ));
+
+ if( !CV_IS_MASK_ARR( src ) || (CV_MAT_TYPE( dst->type ) != CV_32FC1 &&
+ (CV_MAT_TYPE(dst->type) != CV_8UC1 || distType != CV_DIST_L1 || labels)) )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "source image must be 8uC1 and the distance map must be 32fC1 "
+ "(or 8uC1 in case of simple L1 distance transform)" );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "the source and the destination images must be of the same size" );
+
+ if( maskSize != CV_DIST_MASK_3 && maskSize != CV_DIST_MASK_5 && maskSize != CV_DIST_MASK_PRECISE )
+ CV_ERROR( CV_StsBadSize, "Mask size should be 3 or 5 or 0 (presize)" );
+
+ if( distType == CV_DIST_C || distType == CV_DIST_L1 )
+ maskSize = !labels ? CV_DIST_MASK_3 : CV_DIST_MASK_5;
+ else if( distType == CV_DIST_L2 && labels )
+ maskSize = CV_DIST_MASK_5;
+
+ if( maskSize == CV_DIST_MASK_PRECISE )
+ {
+ CV_CALL( icvTrueDistTrans( src, dst ));
+ EXIT;
+ }
+
+ if( labels )
+ {
+ CV_CALL( labels = cvGetMat( labels, &lstub ));
+ if( CV_MAT_TYPE( labels->type ) != CV_32SC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "the output array of labels must be 32sC1" );
+
+ if( !CV_ARE_SIZES_EQ( labels, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "the array of labels has a different size" );
+
+ if( maskSize == CV_DIST_MASK_3 )
+ CV_ERROR( CV_StsNotImplemented,
+ "3x3 mask can not be used for \"labeled\" distance transform. Use 5x5 mask" );
+ }
+
+ if( distType == CV_DIST_C || distType == CV_DIST_L1 || distType == CV_DIST_L2 )
+ {
+ icvGetDistanceTransformMask( (distType == CV_DIST_C ? 0 :
+ distType == CV_DIST_L1 ? 1 : 2) + maskSize*10, _mask );
+ }
+ else if( distType == CV_DIST_USER )
+ {
+ if( !mask )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ memcpy( _mask, mask, (maskSize/2 + 1)*sizeof(float));
+ }
+
+ if( !labels )
+ {
+ if( CV_MAT_TYPE(dst->type) == CV_32FC1 )
+ ipp_func = (CvIPPDistTransFunc)(maskSize == CV_DIST_MASK_3 ?
+ icvDistanceTransform_3x3_8u32f_C1R_p : icvDistanceTransform_5x5_8u32f_C1R_p);
+ else if( src->data.ptr != dst->data.ptr )
+ ipp_func = (CvIPPDistTransFunc)icvDistanceTransform_3x3_8u_C1R_p;
+ else
+ ipp_inp_func = icvDistanceTransform_3x3_8u_C1IR_p;
+ }
+
+ size = cvGetMatSize(src);
+
+ if( (ipp_func || ipp_inp_func) && src->cols >= 4 && src->rows >= 2 )
+ {
+ _imask[0] = cvRound(_mask[0]);
+ _imask[1] = cvRound(_mask[1]);
+ _imask[2] = cvRound(_mask[2]);
+
+ if( ipp_func )
+ {
+ IPPI_CALL( ipp_func( src->data.ptr, src->step,
+ dst->data.fl, dst->step, size,
+ CV_MAT_TYPE(dst->type) == CV_8UC1 ?
+ (void*)_imask : (void*)_mask ));
+ }
+ else
+ {
+ IPPI_CALL( ipp_inp_func( src->data.ptr, src->step, size, _imask ));
+ }
+ }
+ else if( CV_MAT_TYPE(dst->type) == CV_8UC1 )
+ {
+ CV_CALL( icvDistanceATS_L1_8u( src, dst ));
+ }
+ else
+ {
+ int border = maskSize == CV_DIST_MASK_3 ? 1 : 2;
+ CV_CALL( temp = cvCreateMat( size.height + border*2, size.width + border*2, CV_32SC1 ));
+
+ if( !labels )
+ {
+ CvDistTransFunc func = maskSize == CV_DIST_MASK_3 ?
+ icvDistanceTransform_3x3_C1R :
+ icvDistanceTransform_5x5_C1R;
+
+ func( src->data.ptr, src->step, temp->data.i, temp->step,
+ dst->data.fl, dst->step, size, _mask );
+ }
+ else
+ {
+ CvSeq *contours = 0;
+ CvPoint top_left = {0,0}, bottom_right = {size.width-1,size.height-1};
+ int label;
+
+ CV_CALL( st = cvCreateMemStorage() );
+ CV_CALL( src_copy = cvCreateMat( size.height, size.width, src->type ));
+ cvCmpS( src, 0, src_copy, CV_CMP_EQ );
+ cvFindContours( src_copy, st, &contours, sizeof(CvContour),
+ CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
+ cvZero( labels );
+ for( label = 1; contours != 0; contours = contours->h_next, label++ )
+ {
+ CvScalar area_color = cvScalarAll(label);
+ cvDrawContours( labels, contours, area_color, area_color, -255, -1, 8 );
+ }
+
+ cvCopy( src, src_copy );
+ cvRectangle( src_copy, top_left, bottom_right, cvScalarAll(255), 1, 8 );
+
+ icvDistanceTransformEx_5x5_C1R( src_copy->data.ptr, src_copy->step, temp->data.i, temp->step,
+ dst->data.fl, dst->step, labels->data.i, labels->step, size, _mask );
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &temp );
+ cvReleaseMat( &src_copy );
+ cvReleaseMemStorage( &st );
+}
+
+/* End of file. */
diff --git a/cv/src/cvdominants.cpp b/cv/src/cvdominants.cpp
new file mode 100644
index 0000000..6ac6f69
--- /dev/null
+++ b/cv/src/cvdominants.cpp
@@ -0,0 +1,407 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+typedef struct _PointInfo
+{
+ CvPoint pt;
+ int left_neigh;
+ int right_neigh;
+
+}
+icvPointInfo;
+
+
+static CvStatus
+icvFindDominantPointsIPAN( CvSeq * contour,
+ CvMemStorage * storage,
+ CvSeq ** corners, int dmin2, int dmax2, int dneigh2, float amax )
+{
+ CvStatus status = CV_OK;
+
+ /* variables */
+ int n = contour->total;
+
+ float *sharpness;
+ float *distance;
+ icvPointInfo *ptInf;
+
+ int i, j, k;
+
+ CvSeqWriter writer;
+
+ float mincos = (float) cos( 3.14159265359 * amax / 180 );
+
+ /* check bad arguments */
+ if( contour == NULL )
+ return CV_NULLPTR_ERR;
+ if( storage == NULL )
+ return CV_NULLPTR_ERR;
+ if( corners == NULL )
+ return CV_NULLPTR_ERR;
+ if( dmin2 < 0 )
+ return CV_BADSIZE_ERR;
+ if( dmax2 < dmin2 )
+ return CV_BADSIZE_ERR;
+ if( (dneigh2 > dmax2) || (dneigh2 < 0) )
+ return CV_BADSIZE_ERR;
+ if( (amax < 0) || (amax > 180) )
+ return CV_BADSIZE_ERR;
+
+ sharpness = (float *) cvAlloc( n * sizeof( float ));
+ distance = (float *) cvAlloc( n * sizeof( float ));
+
+ ptInf = (icvPointInfo *) cvAlloc( n * sizeof( icvPointInfo ));
+
+/*****************************************************************************************/
+/* First pass */
+/*****************************************************************************************/
+
+ if( CV_IS_SEQ_CHAIN_CONTOUR( contour ))
+ {
+ CvChainPtReader reader;
+
+ cvStartReadChainPoints( (CvChain *) contour, &reader );
+
+ for( i = 0; i < n; i++ )
+ {
+ CV_READ_CHAIN_POINT( ptInf[i].pt, reader );
+ }
+ }
+ else if( CV_IS_SEQ_POLYGON( contour ))
+ {
+ CvSeqReader reader;
+
+ cvStartReadSeq( contour, &reader, 0 );
+
+ for( i = 0; i < n; i++ )
+ {
+ CV_READ_SEQ_ELEM( ptInf[i].pt, reader );
+ }
+ }
+ else
+ {
+ return CV_BADFLAG_ERR;
+ }
+
+ for( i = 0; i < n; i++ )
+ {
+ /* find nearest suitable points
+ which satisfy distance constraint >dmin */
+ int left_near = 0;
+ int right_near = 0;
+ int left_far, right_far;
+
+ float dist_l = 0;
+ float dist_r = 0;
+
+ int i_plus = 0;
+ int i_minus = 0;
+
+ float max_cos_alpha;
+
+ /* find right minimum */
+ while( dist_r < dmin2 )
+ {
+ float dx, dy;
+ int ind;
+
+ if( i_plus >= n )
+ goto error;
+
+ right_near = i_plus;
+
+ if( dist_r < dneigh2 )
+ ptInf[i].right_neigh = i_plus;
+
+ i_plus++;
+
+ ind = (i + i_plus) % n;
+ dx = (float) (ptInf[i].pt.x - ptInf[ind].pt.x);
+ dy = (float) (ptInf[i].pt.y - ptInf[ind].pt.y);
+ dist_r = dx * dx + dy * dy;
+ }
+ /* find right maximum */
+ while( dist_r <= dmax2 )
+ {
+ float dx, dy;
+ int ind;
+
+ if( i_plus >= n )
+ goto error;
+
+ distance[(i + i_plus) % n] = cvSqrt( dist_r );
+
+ if( dist_r < dneigh2 )
+ ptInf[i].right_neigh = i_plus;
+
+ i_plus++;
+
+ right_far = i_plus;
+
+ ind = (i + i_plus) % n;
+
+ dx = (float) (ptInf[i].pt.x - ptInf[ind].pt.x);
+ dy = (float) (ptInf[i].pt.y - ptInf[ind].pt.y);
+ dist_r = dx * dx + dy * dy;
+ }
+ right_far = i_plus;
+
+ /* left minimum */
+ while( dist_l < dmin2 )
+ {
+ float dx, dy;
+ int ind;
+
+ if( i_minus <= -n )
+ goto error;
+
+ left_near = i_minus;
+
+ if( dist_l < dneigh2 )
+ ptInf[i].left_neigh = i_minus;
+
+ i_minus--;
+
+ ind = i + i_minus;
+ ind = (ind < 0) ? (n + ind) : ind;
+
+ dx = (float) (ptInf[i].pt.x - ptInf[ind].pt.x);
+ dy = (float) (ptInf[i].pt.y - ptInf[ind].pt.y);
+ dist_l = dx * dx + dy * dy;
+ }
+
+ /* find left maximum */
+ while( dist_l <= dmax2 )
+ {
+ float dx, dy;
+ int ind;
+
+ if( i_minus <= -n )
+ goto error;
+
+ ind = i + i_minus;
+ ind = (ind < 0) ? (n + ind) : ind;
+
+ distance[ind] = cvSqrt( dist_l );
+
+ if( dist_l < dneigh2 )
+ ptInf[i].left_neigh = i_minus;
+
+ i_minus--;
+
+ left_far = i_minus;
+
+ ind = i + i_minus;
+ ind = (ind < 0) ? (n + ind) : ind;
+
+ dx = (float) (ptInf[i].pt.x - ptInf[ind].pt.x);
+ dy = (float) (ptInf[i].pt.y - ptInf[ind].pt.y);
+ dist_l = dx * dx + dy * dy;
+ }
+ left_far = i_minus;
+
+ if( (i_plus - i_minus) > n + 2 )
+ goto error;
+
+ max_cos_alpha = -1;
+ for( j = left_far + 1; j < left_near; j++ )
+ {
+ float dx, dy;
+ float a, a2;
+ int leftind = i + j;
+
+ leftind = (leftind < 0) ? (n + leftind) : leftind;
+
+ a = distance[leftind];
+ a2 = a * a;
+
+ for( k = right_near + 1; k < right_far; k++ )
+ {
+ int ind = (i + k) % n;
+ float c2, cosalpha;
+ float b = distance[ind];
+ float b2 = b * b;
+
+ /* compute cosinus */
+ dx = (float) (ptInf[leftind].pt.x - ptInf[ind].pt.x);
+ dy = (float) (ptInf[leftind].pt.y - ptInf[ind].pt.y);
+
+ c2 = dx * dx + dy * dy;
+ cosalpha = (a2 + b2 - c2) / (2 * a * b);
+
+ max_cos_alpha = MAX( max_cos_alpha, cosalpha );
+
+ if( max_cos_alpha < mincos )
+ max_cos_alpha = -1;
+
+ sharpness[i] = max_cos_alpha;
+ }
+ }
+ }
+/*****************************************************************************************/
+/* Second pass */
+/*****************************************************************************************/
+
+ cvStartWriteSeq( (contour->flags & ~CV_SEQ_ELTYPE_MASK) | CV_SEQ_ELTYPE_INDEX,
+ sizeof( CvSeq ), sizeof( int ), storage, &writer );
+
+ /* second pass - nonmaxima suppression */
+ /* neighborhood of point < dneigh2 */
+ for( i = 0; i < n; i++ )
+ {
+ int suppressed = 0;
+ if( sharpness[i] == -1 )
+ continue;
+
+ for( j = 1; (j <= ptInf[i].right_neigh) && (suppressed == 0); j++ )
+ {
+ if( sharpness[i] < sharpness[(i + j) % n] )
+ suppressed = 1;
+ }
+
+ for( j = -1; (j >= ptInf[i].left_neigh) && (suppressed == 0); j-- )
+ {
+ int ind = i + j;
+
+ ind = (ind < 0) ? (n + ind) : ind;
+ if( sharpness[i] < sharpness[ind] )
+ suppressed = 1;
+ }
+
+ if( !suppressed )
+ CV_WRITE_SEQ_ELEM( i, writer );
+ }
+
+ *corners = cvEndWriteSeq( &writer );
+
+ cvFree( &sharpness );
+ cvFree( &distance );
+ cvFree( &ptInf );
+
+ return status;
+
+ error:
+ /* dmax is so big (more than contour diameter)
+ that algorithm could become infinite cycle */
+ cvFree( &sharpness );
+ cvFree( &distance );
+ cvFree( &ptInf );
+
+ return CV_BADRANGE_ERR;
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvFindDominantPoints
+// Purpose:
+// Applies some algorithm to find dominant points ( corners ) of contour
+//
+// Context:
+// Parameters:
+// contours - pointer to input contour object.
+// out_numbers - array of dominant points indices
+// count - length of out_numbers array on input
+// and numbers of founded dominant points on output
+//
+// method - only CV_DOMINANT_IPAN now
+// parameters - array of parameters
+// for IPAN algorithm
+// [0] - minimal distance
+// [1] - maximal distance
+// [2] - neighborhood distance (must be not greater than dmaximal distance)
+// [3] - maximal possible angle of curvature
+// Returns:
+// CV_OK or error code
+// Notes:
+// User must allocate out_numbers array. If it is small - function fills array
+// with part of points and returns error
+//F*/
+CV_IMPL CvSeq*
+cvFindDominantPoints( CvSeq * contour, CvMemStorage * storage, int method,
+ double parameter1, double parameter2, double parameter3, double parameter4 )
+{
+ CvSeq* corners = 0;
+
+ CV_FUNCNAME( "cvFindDominantPoints" );
+ __BEGIN__;
+
+ if( !contour )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !storage )
+ storage = contour->storage;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ switch (method)
+ {
+ case CV_DOMINANT_IPAN:
+ {
+ int dmin = cvRound(parameter1);
+ int dmax = cvRound(parameter2);
+ int dneigh = cvRound(parameter3);
+ int amax = cvRound(parameter4);
+
+ if( amax == 0 )
+ amax = 150;
+ if( dmin == 0 )
+ dmin = 7;
+ if( dmax == 0 )
+ dmax = dmin + 2;
+ if( dneigh == 0 )
+ dneigh = dmin;
+
+ IPPI_CALL( icvFindDominantPointsIPAN( contour, storage, &corners,
+ dmin*dmin, dmax*dmax, dneigh*dneigh, (float)amax ));
+ }
+ break;
+ default:
+ CV_ERROR_FROM_STATUS( CV_BADFLAG_ERR );
+ }
+
+ __END__;
+
+ return corners;
+}
+
+/* End of file. */
diff --git a/cv/src/cvemd.cpp b/cv/src/cvemd.cpp
new file mode 100644
index 0000000..82be363
--- /dev/null
+++ b/cv/src/cvemd.cpp
@@ -0,0 +1,1164 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/*
+ Partially based on Yossi Rubner code:
+ =========================================================================
+ emd.c
+
+ Last update: 3/14/98
+
+ An implementation of the Earth Movers Distance.
+ Based of the solution for the Transportation problem as described in
+ "Introduction to Mathematical Programming" by F. S. Hillier and
+ G. J. Lieberman, McGraw-Hill, 1990.
+
+ Copyright (C) 1998 Yossi Rubner
+ Computer Science Department, Stanford University
+ E-Mail: rubner@cs.stanford.edu URL: http://vision.stanford.edu/~rubner
+ ==========================================================================
+*/
+#include "_cv.h"
+
+#define MAX_ITERATIONS 500
+#define CV_EMD_INF ((float)1e20)
+#define CV_EMD_EPS ((float)1e-5)
+
+/* CvNode1D is used for lists, representing 1D sparse array */
+typedef struct CvNode1D
+{
+ float val;
+ struct CvNode1D *next;
+}
+CvNode1D;
+
+/* CvNode2D is used for lists, representing 2D sparse matrix */
+typedef struct CvNode2D
+{
+ float val;
+ struct CvNode2D *next[2]; /* next row & next column */
+ int i, j;
+}
+CvNode2D;
+
+
+typedef struct CvEMDState
+{
+ int ssize, dsize;
+
+ float **cost;
+ CvNode2D *_x;
+ CvNode2D *end_x;
+ CvNode2D *enter_x;
+ char **is_x;
+
+ CvNode2D **rows_x;
+ CvNode2D **cols_x;
+
+ CvNode1D *u;
+ CvNode1D *v;
+
+ int* idx1;
+ int* idx2;
+
+ /* find_loop buffers */
+ CvNode2D **loop;
+ char *is_used;
+
+ /* russel buffers */
+ float *s;
+ float *d;
+ float **delta;
+
+ float weight, max_cost;
+ char *buffer;
+}
+CvEMDState;
+
+/* static function declaration */
+static CvStatus icvInitEMD( const float *signature1, int size1,
+ const float *signature2, int size2,
+ int dims, CvDistanceFunction dist_func, void *user_param,
+ const float* cost, int cost_step,
+ CvEMDState * state, float *lower_bound,
+ char *local_buffer, int local_buffer_size );
+
+static CvStatus icvFindBasicVariables( float **cost, char **is_x,
+ CvNode1D * u, CvNode1D * v, int ssize, int dsize );
+
+static float icvIsOptimal( float **cost, char **is_x,
+ CvNode1D * u, CvNode1D * v,
+ int ssize, int dsize, CvNode2D * enter_x );
+
+static void icvRussel( CvEMDState * state );
+
+
+static CvStatus icvNewSolution( CvEMDState * state );
+static int icvFindLoop( CvEMDState * state );
+
+static void icvAddBasicVariable( CvEMDState * state,
+ int min_i, int min_j,
+ CvNode1D * prev_u_min_i,
+ CvNode1D * prev_v_min_j,
+ CvNode1D * u_head );
+
+static float icvDistL2( const float *x, const float *y, void *user_param );
+static float icvDistL1( const float *x, const float *y, void *user_param );
+static float icvDistC( const float *x, const float *y, void *user_param );
+
+/* The main function */
+CV_IMPL float
+cvCalcEMD2( const CvArr* signature_arr1,
+ const CvArr* signature_arr2,
+ int dist_type,
+ CvDistanceFunction dist_func,
+ const CvArr* cost_matrix,
+ CvArr* flow_matrix,
+ float *lower_bound,
+ void *user_param )
+{
+ char local_buffer[16384];
+ char *local_buffer_ptr = (char *)cvAlignPtr(local_buffer,16);
+ CvEMDState state;
+ float emd = 0;
+
+ CV_FUNCNAME( "cvCalcEMD2" );
+
+ memset( &state, 0, sizeof(state));
+
+ __BEGIN__;
+
+ double total_cost = 0;
+ CvStatus result = CV_NO_ERR;
+ float eps, min_delta;
+ CvNode2D *xp = 0;
+ CvMat sign_stub1, *signature1 = (CvMat*)signature_arr1;
+ CvMat sign_stub2, *signature2 = (CvMat*)signature_arr2;
+ CvMat cost_stub, *cost = &cost_stub;
+ CvMat flow_stub, *flow = (CvMat*)flow_matrix;
+ int dims, size1, size2;
+
+ CV_CALL( signature1 = cvGetMat( signature1, &sign_stub1 ));
+ CV_CALL( signature2 = cvGetMat( signature2, &sign_stub2 ));
+
+ if( signature1->cols != signature2->cols )
+ CV_ERROR( CV_StsUnmatchedSizes, "The arrays must have equal number of columns (which is number of dimensions but 1)" );
+
+ dims = signature1->cols - 1;
+ size1 = signature1->rows;
+ size2 = signature2->rows;
+
+ if( !CV_ARE_TYPES_EQ( signature1, signature2 ))
+ CV_ERROR( CV_StsUnmatchedFormats, "The array must have equal types" );
+
+ if( CV_MAT_TYPE( signature1->type ) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "The signatures must be 32fC1" );
+
+ if( flow )
+ {
+ CV_CALL( flow = cvGetMat( flow, &flow_stub ));
+
+ if( flow->rows != size1 || flow->cols != size2 )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The flow matrix size does not match to the signatures' sizes" );
+
+ if( CV_MAT_TYPE( flow->type ) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "The flow matrix must be 32fC1" );
+ }
+
+ cost->data.fl = 0;
+ cost->step = 0;
+
+ if( dist_type < 0 )
+ {
+ if( cost_matrix )
+ {
+ if( dist_func )
+ CV_ERROR( CV_StsBadArg,
+ "Only one of cost matrix or distance function should be non-NULL in case of user-defined distance" );
+
+ if( lower_bound )
+ CV_ERROR( CV_StsBadArg,
+ "The lower boundary can not be calculated if the cost matrix is used" );
+
+ CV_CALL( cost = cvGetMat( cost_matrix, &cost_stub ));
+ if( cost->rows != size1 || cost->cols != size2 )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The cost matrix size does not match to the signatures' sizes" );
+
+ if( CV_MAT_TYPE( cost->type ) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "The cost matrix must be 32fC1" );
+ }
+ else if( !dist_func )
+ CV_ERROR( CV_StsNullPtr, "In case of user-defined distance Distance function is undefined" );
+ }
+ else
+ {
+ if( dims == 0 )
+ CV_ERROR( CV_StsBadSize,
+ "Number of dimensions can be 0 only if a user-defined metric is used" );
+ user_param = (void *) (size_t)dims;
+ switch (dist_type)
+ {
+ case CV_DIST_L1:
+ dist_func = icvDistL1;
+ break;
+ case CV_DIST_L2:
+ dist_func = icvDistL2;
+ break;
+ case CV_DIST_C:
+ dist_func = icvDistC;
+ break;
+ default:
+ CV_ERROR( CV_StsBadFlag, "Bad or unsupported metric type" );
+ }
+ }
+
+ IPPI_CALL( result = icvInitEMD( signature1->data.fl, size1,
+ signature2->data.fl, size2,
+ dims, dist_func, user_param,
+ cost->data.fl, cost->step,
+ &state, lower_bound, local_buffer_ptr,
+ sizeof( local_buffer ) - 16 ));
+
+ if( result > 0 && lower_bound )
+ {
+ emd = *lower_bound;
+ EXIT;
+ }
+
+ eps = CV_EMD_EPS * state.max_cost;
+
+ /* if ssize = 1 or dsize = 1 then we are done, else ... */
+ if( state.ssize > 1 && state.dsize > 1 )
+ {
+ int itr;
+
+ for( itr = 1; itr < MAX_ITERATIONS; itr++ )
+ {
+ /* find basic variables */
+ result = icvFindBasicVariables( state.cost, state.is_x,
+ state.u, state.v, state.ssize, state.dsize );
+ if( result < 0 )
+ break;
+
+ /* check for optimality */
+ min_delta = icvIsOptimal( state.cost, state.is_x,
+ state.u, state.v,
+ state.ssize, state.dsize, state.enter_x );
+
+ if( min_delta == CV_EMD_INF )
+ {
+ CV_ERROR( CV_StsNoConv, "" );
+ }
+
+ /* if no negative deltamin, we found the optimal solution */
+ if( min_delta >= -eps )
+ break;
+
+ /* improve solution */
+ IPPI_CALL( icvNewSolution( &state ));
+ }
+ }
+
+ /* compute the total flow */
+ for( xp = state._x; xp < state.end_x; xp++ )
+ {
+ float val = xp->val;
+ int i = xp->i;
+ int j = xp->j;
+ int ci = state.idx1[i];
+ int cj = state.idx2[j];
+
+ if( xp != state.enter_x && ci >= 0 && cj >= 0 )
+ {
+ total_cost += (double)val * state.cost[i][j];
+ if( flow )
+ ((float*)(flow->data.ptr + flow->step*ci))[cj] = val;
+ }
+ }
+
+ emd = (float) (total_cost / state.weight);
+
+ __END__;
+
+ if( state.buffer && state.buffer != local_buffer_ptr )
+ cvFree( &state.buffer );
+
+ return emd;
+}
+
+
+/************************************************************************************\
+* initialize structure, allocate buffers and generate initial golution *
+\************************************************************************************/
+static CvStatus
+icvInitEMD( const float* signature1, int size1,
+ const float* signature2, int size2,
+ int dims, CvDistanceFunction dist_func, void* user_param,
+ const float* cost, int cost_step,
+ CvEMDState* state, float* lower_bound,
+ char* local_buffer, int local_buffer_size )
+{
+ float s_sum = 0, d_sum = 0, diff;
+ int i, j;
+ int ssize = 0, dsize = 0;
+ int equal_sums = 1;
+ int buffer_size;
+ float max_cost = 0;
+ char *buffer, *buffer_end;
+
+ memset( state, 0, sizeof( *state ));
+ assert( cost_step % sizeof(float) == 0 );
+ cost_step /= sizeof(float);
+
+ /* calculate buffer size */
+ buffer_size = (size1+1) * (size2+1) * (sizeof( float ) + /* cost */
+ sizeof( char ) + /* is_x */
+ sizeof( float )) + /* delta matrix */
+ (size1 + size2 + 2) * (sizeof( CvNode2D ) + /* _x */
+ sizeof( CvNode2D * ) + /* cols_x & rows_x */
+ sizeof( CvNode1D ) + /* u & v */
+ sizeof( float ) + /* s & d */
+ sizeof( int ) + sizeof(CvNode2D*)) + /* idx1 & idx2 */
+ (size1+1) * (sizeof( float * ) + sizeof( char * ) + /* rows pointers for */
+ sizeof( float * )) + 256; /* cost, is_x and delta */
+
+ if( buffer_size < (int) (dims * 2 * sizeof( float )))
+ {
+ buffer_size = dims * 2 * sizeof( float );
+ }
+
+ /* allocate buffers */
+ if( local_buffer != 0 && local_buffer_size >= buffer_size )
+ {
+ buffer = local_buffer;
+ }
+ else
+ {
+ buffer = (char*)cvAlloc( buffer_size );
+ if( !buffer )
+ return CV_OUTOFMEM_ERR;
+ }
+
+ state->buffer = buffer;
+ buffer_end = buffer + buffer_size;
+
+ state->idx1 = (int*) buffer;
+ buffer += (size1 + 1) * sizeof( int );
+
+ state->idx2 = (int*) buffer;
+ buffer += (size2 + 1) * sizeof( int );
+
+ state->s = (float *) buffer;
+ buffer += (size1 + 1) * sizeof( float );
+
+ state->d = (float *) buffer;
+ buffer += (size2 + 1) * sizeof( float );
+
+ /* sum up the supply and demand */
+ for( i = 0; i < size1; i++ )
+ {
+ float weight = signature1[i * (dims + 1)];
+
+ if( weight > 0 )
+ {
+ s_sum += weight;
+ state->s[ssize] = weight;
+ state->idx1[ssize++] = i;
+
+ }
+ else if( weight < 0 )
+ return CV_BADRANGE_ERR;
+ }
+
+ for( i = 0; i < size2; i++ )
+ {
+ float weight = signature2[i * (dims + 1)];
+
+ if( weight > 0 )
+ {
+ d_sum += weight;
+ state->d[dsize] = weight;
+ state->idx2[dsize++] = i;
+ }
+ else if( weight < 0 )
+ return CV_BADRANGE_ERR;
+ }
+
+ if( ssize == 0 || dsize == 0 )
+ return CV_BADRANGE_ERR;
+
+ /* if supply different than the demand, add a zero-cost dummy cluster */
+ diff = s_sum - d_sum;
+ if( fabs( diff ) >= CV_EMD_EPS * s_sum )
+ {
+ equal_sums = 0;
+ if( diff < 0 )
+ {
+ state->s[ssize] = -diff;
+ state->idx1[ssize++] = -1;
+ }
+ else
+ {
+ state->d[dsize] = diff;
+ state->idx2[dsize++] = -1;
+ }
+ }
+
+ state->ssize = ssize;
+ state->dsize = dsize;
+ state->weight = s_sum > d_sum ? s_sum : d_sum;
+
+ if( lower_bound && equal_sums ) /* check lower bound */
+ {
+ int sz1 = size1 * (dims + 1), sz2 = size2 * (dims + 1);
+ float lb = 0;
+
+ float* xs = (float *) buffer;
+ float* xd = xs + dims;
+
+ memset( xs, 0, dims*sizeof(xs[0]));
+ memset( xd, 0, dims*sizeof(xd[0]));
+
+ for( j = 0; j < sz1; j += dims + 1 )
+ {
+ float weight = signature1[j];
+ for( i = 0; i < dims; i++ )
+ xs[i] += signature1[j + i + 1] * weight;
+ }
+
+ for( j = 0; j < sz2; j += dims + 1 )
+ {
+ float weight = signature2[j];
+ for( i = 0; i < dims; i++ )
+ xd[i] += signature2[j + i + 1] * weight;
+ }
+
+ lb = dist_func( xs, xd, user_param ) / state->weight;
+ i = *lower_bound <= lb;
+ *lower_bound = lb;
+ if( i )
+ return ( CvStatus ) 1;
+ }
+
+ /* assign pointers */
+ state->is_used = (char *) buffer;
+ /* init delta matrix */
+ state->delta = (float **) buffer;
+ buffer += ssize * sizeof( float * );
+
+ for( i = 0; i < ssize; i++ )
+ {
+ state->delta[i] = (float *) buffer;
+ buffer += dsize * sizeof( float );
+ }
+
+ state->loop = (CvNode2D **) buffer;
+ buffer += (ssize + dsize + 1) * sizeof(CvNode2D*);
+
+ state->_x = state->end_x = (CvNode2D *) buffer;
+ buffer += (ssize + dsize) * sizeof( CvNode2D );
+
+ /* init cost matrix */
+ state->cost = (float **) buffer;
+ buffer += ssize * sizeof( float * );
+
+ /* compute the distance matrix */
+ for( i = 0; i < ssize; i++ )
+ {
+ int ci = state->idx1[i];
+
+ state->cost[i] = (float *) buffer;
+ buffer += dsize * sizeof( float );
+
+ if( ci >= 0 )
+ {
+ for( j = 0; j < dsize; j++ )
+ {
+ int cj = state->idx2[j];
+ if( cj < 0 )
+ state->cost[i][j] = 0;
+ else
+ {
+ float val;
+ if( dist_func )
+ {
+ val = dist_func( signature1 + ci * (dims + 1) + 1,
+ signature2 + cj * (dims + 1) + 1,
+ user_param );
+ }
+ else
+ {
+ assert( cost );
+ val = cost[cost_step*ci + cj];
+ }
+ state->cost[i][j] = val;
+ if( max_cost < val )
+ max_cost = val;
+ }
+ }
+ }
+ else
+ {
+ for( j = 0; j < dsize; j++ )
+ state->cost[i][j] = 0;
+ }
+ }
+
+ state->max_cost = max_cost;
+
+ memset( buffer, 0, buffer_end - buffer );
+
+ state->rows_x = (CvNode2D **) buffer;
+ buffer += ssize * sizeof( CvNode2D * );
+
+ state->cols_x = (CvNode2D **) buffer;
+ buffer += dsize * sizeof( CvNode2D * );
+
+ state->u = (CvNode1D *) buffer;
+ buffer += ssize * sizeof( CvNode1D );
+
+ state->v = (CvNode1D *) buffer;
+ buffer += dsize * sizeof( CvNode1D );
+
+ /* init is_x matrix */
+ state->is_x = (char **) buffer;
+ buffer += ssize * sizeof( char * );
+
+ for( i = 0; i < ssize; i++ )
+ {
+ state->is_x[i] = buffer;
+ buffer += dsize;
+ }
+
+ assert( buffer <= buffer_end );
+
+ icvRussel( state );
+
+ state->enter_x = (state->end_x)++;
+ return CV_NO_ERR;
+}
+
+
+/****************************************************************************************\
+* icvFindBasicVariables *
+\****************************************************************************************/
+static CvStatus
+icvFindBasicVariables( float **cost, char **is_x,
+ CvNode1D * u, CvNode1D * v, int ssize, int dsize )
+{
+ int i, j, found;
+ int u_cfound, v_cfound;
+ CvNode1D u0_head, u1_head, *cur_u, *prev_u;
+ CvNode1D v0_head, v1_head, *cur_v, *prev_v;
+
+ /* initialize the rows list (u) and the columns list (v) */
+ u0_head.next = u;
+ for( i = 0; i < ssize; i++ )
+ {
+ u[i].next = u + i + 1;
+ }
+ u[ssize - 1].next = 0;
+ u1_head.next = 0;
+
+ v0_head.next = ssize > 1 ? v + 1 : 0;
+ for( i = 1; i < dsize; i++ )
+ {
+ v[i].next = v + i + 1;
+ }
+ v[dsize - 1].next = 0;
+ v1_head.next = 0;
+
+ /* there are ssize+dsize variables but only ssize+dsize-1 independent equations,
+ so set v[0]=0 */
+ v[0].val = 0;
+ v1_head.next = v;
+ v1_head.next->next = 0;
+
+ /* loop until all variables are found */
+ u_cfound = v_cfound = 0;
+ while( u_cfound < ssize || v_cfound < dsize )
+ {
+ found = 0;
+ if( v_cfound < dsize )
+ {
+ /* loop over all marked columns */
+ prev_v = &v1_head;
+
+ for( found |= (cur_v = v1_head.next) != 0; cur_v != 0; cur_v = cur_v->next )
+ {
+ float cur_v_val = cur_v->val;
+
+ j = (int)(cur_v - v);
+ /* find the variables in column j */
+ prev_u = &u0_head;
+ for( cur_u = u0_head.next; cur_u != 0; )
+ {
+ i = (int)(cur_u - u);
+ if( is_x[i][j] )
+ {
+ /* compute u[i] */
+ cur_u->val = cost[i][j] - cur_v_val;
+ /* ...and add it to the marked list */
+ prev_u->next = cur_u->next;
+ cur_u->next = u1_head.next;
+ u1_head.next = cur_u;
+ cur_u = prev_u->next;
+ }
+ else
+ {
+ prev_u = cur_u;
+ cur_u = cur_u->next;
+ }
+ }
+ prev_v->next = cur_v->next;
+ v_cfound++;
+ }
+ }
+
+ if( u_cfound < ssize )
+ {
+ /* loop over all marked rows */
+ prev_u = &u1_head;
+ for( found |= (cur_u = u1_head.next) != 0; cur_u != 0; cur_u = cur_u->next )
+ {
+ float cur_u_val = cur_u->val;
+ float *_cost;
+ char *_is_x;
+
+ i = (int)(cur_u - u);
+ _cost = cost[i];
+ _is_x = is_x[i];
+ /* find the variables in rows i */
+ prev_v = &v0_head;
+ for( cur_v = v0_head.next; cur_v != 0; )
+ {
+ j = (int)(cur_v - v);
+ if( _is_x[j] )
+ {
+ /* compute v[j] */
+ cur_v->val = _cost[j] - cur_u_val;
+ /* ...and add it to the marked list */
+ prev_v->next = cur_v->next;
+ cur_v->next = v1_head.next;
+ v1_head.next = cur_v;
+ cur_v = prev_v->next;
+ }
+ else
+ {
+ prev_v = cur_v;
+ cur_v = cur_v->next;
+ }
+ }
+ prev_u->next = cur_u->next;
+ u_cfound++;
+ }
+ }
+
+ if( !found )
+ {
+ return CV_NOTDEFINED_ERR;
+ }
+ }
+
+ return CV_NO_ERR;
+}
+
+
+/****************************************************************************************\
+* icvIsOptimal *
+\****************************************************************************************/
+static float
+icvIsOptimal( float **cost, char **is_x,
+ CvNode1D * u, CvNode1D * v, int ssize, int dsize, CvNode2D * enter_x )
+{
+ float delta, min_delta = CV_EMD_INF;
+ int i, j, min_i = 0, min_j = 0;
+
+ /* find the minimal cij-ui-vj over all i,j */
+ for( i = 0; i < ssize; i++ )
+ {
+ float u_val = u[i].val;
+ float *_cost = cost[i];
+ char *_is_x = is_x[i];
+
+ for( j = 0; j < dsize; j++ )
+ {
+ if( !_is_x[j] )
+ {
+ delta = _cost[j] - u_val - v[j].val;
+ if( min_delta > delta )
+ {
+ min_delta = delta;
+ min_i = i;
+ min_j = j;
+ }
+ }
+ }
+ }
+
+ enter_x->i = min_i;
+ enter_x->j = min_j;
+
+ return min_delta;
+}
+
+/****************************************************************************************\
+* icvNewSolution *
+\****************************************************************************************/
+static CvStatus
+icvNewSolution( CvEMDState * state )
+{
+ int i, j;
+ float min_val = CV_EMD_INF;
+ int steps;
+ CvNode2D head, *cur_x, *next_x, *leave_x = 0;
+ CvNode2D *enter_x = state->enter_x;
+ CvNode2D **loop = state->loop;
+
+ /* enter the new basic variable */
+ i = enter_x->i;
+ j = enter_x->j;
+ state->is_x[i][j] = 1;
+ enter_x->next[0] = state->rows_x[i];
+ enter_x->next[1] = state->cols_x[j];
+ enter_x->val = 0;
+ state->rows_x[i] = enter_x;
+ state->cols_x[j] = enter_x;
+
+ /* find a chain reaction */
+ steps = icvFindLoop( state );
+
+ if( steps == 0 )
+ return CV_NOTDEFINED_ERR;
+
+ /* find the largest value in the loop */
+ for( i = 1; i < steps; i += 2 )
+ {
+ float temp = loop[i]->val;
+
+ if( min_val > temp )
+ {
+ leave_x = loop[i];
+ min_val = temp;
+ }
+ }
+
+ /* update the loop */
+ for( i = 0; i < steps; i += 2 )
+ {
+ float temp0 = loop[i]->val + min_val;
+ float temp1 = loop[i + 1]->val - min_val;
+
+ loop[i]->val = temp0;
+ loop[i + 1]->val = temp1;
+ }
+
+ /* remove the leaving basic variable */
+ i = leave_x->i;
+ j = leave_x->j;
+ state->is_x[i][j] = 0;
+
+ head.next[0] = state->rows_x[i];
+ cur_x = &head;
+ while( (next_x = cur_x->next[0]) != leave_x )
+ {
+ cur_x = next_x;
+ assert( cur_x );
+ }
+ cur_x->next[0] = next_x->next[0];
+ state->rows_x[i] = head.next[0];
+
+ head.next[1] = state->cols_x[j];
+ cur_x = &head;
+ while( (next_x = cur_x->next[1]) != leave_x )
+ {
+ cur_x = next_x;
+ assert( cur_x );
+ }
+ cur_x->next[1] = next_x->next[1];
+ state->cols_x[j] = head.next[1];
+
+ /* set enter_x to be the new empty slot */
+ state->enter_x = leave_x;
+
+ return CV_NO_ERR;
+}
+
+
+
+/****************************************************************************************\
+* icvFindLoop *
+\****************************************************************************************/
+static int
+icvFindLoop( CvEMDState * state )
+{
+ int i, steps = 1;
+ CvNode2D *new_x;
+ CvNode2D **loop = state->loop;
+ CvNode2D *enter_x = state->enter_x, *_x = state->_x;
+ char *is_used = state->is_used;
+
+ memset( is_used, 0, state->ssize + state->dsize );
+
+ new_x = loop[0] = enter_x;
+ is_used[enter_x - _x] = 1;
+ steps = 1;
+
+ do
+ {
+ if( (steps & 1) == 1 )
+ {
+ /* find an unused x in the row */
+ new_x = state->rows_x[new_x->i];
+ while( new_x != 0 && is_used[new_x - _x] )
+ new_x = new_x->next[0];
+ }
+ else
+ {
+ /* find an unused x in the column, or the entering x */
+ new_x = state->cols_x[new_x->j];
+ while( new_x != 0 && is_used[new_x - _x] && new_x != enter_x )
+ new_x = new_x->next[1];
+ if( new_x == enter_x )
+ break;
+ }
+
+ if( new_x != 0 ) /* found the next x */
+ {
+ /* add x to the loop */
+ loop[steps++] = new_x;
+ is_used[new_x - _x] = 1;
+ }
+ else /* didn't find the next x */
+ {
+ /* backtrack */
+ do
+ {
+ i = steps & 1;
+ new_x = loop[steps - 1];
+ do
+ {
+ new_x = new_x->next[i];
+ }
+ while( new_x != 0 && is_used[new_x - _x] );
+
+ if( new_x == 0 )
+ {
+ is_used[loop[--steps] - _x] = 0;
+ }
+ }
+ while( new_x == 0 && steps > 0 );
+
+ is_used[loop[steps - 1] - _x] = 0;
+ loop[steps - 1] = new_x;
+ is_used[new_x - _x] = 1;
+ }
+ }
+ while( steps > 0 );
+
+ return steps;
+}
+
+
+
+/****************************************************************************************\
+* icvRussel *
+\****************************************************************************************/
+static void
+icvRussel( CvEMDState * state )
+{
+ int i, j, min_i = -1, min_j = -1;
+ float min_delta, diff;
+ CvNode1D u_head, *cur_u, *prev_u;
+ CvNode1D v_head, *cur_v, *prev_v;
+ CvNode1D *prev_u_min_i = 0, *prev_v_min_j = 0, *remember;
+ CvNode1D *u = state->u, *v = state->v;
+ int ssize = state->ssize, dsize = state->dsize;
+ float eps = CV_EMD_EPS * state->max_cost;
+ float **cost = state->cost;
+ float **delta = state->delta;
+
+ /* initialize the rows list (ur), and the columns list (vr) */
+ u_head.next = u;
+ for( i = 0; i < ssize; i++ )
+ {
+ u[i].next = u + i + 1;
+ }
+ u[ssize - 1].next = 0;
+
+ v_head.next = v;
+ for( i = 0; i < dsize; i++ )
+ {
+ v[i].val = -CV_EMD_INF;
+ v[i].next = v + i + 1;
+ }
+ v[dsize - 1].next = 0;
+
+ /* find the maximum row and column values (ur[i] and vr[j]) */
+ for( i = 0; i < ssize; i++ )
+ {
+ float u_val = -CV_EMD_INF;
+ float *cost_row = cost[i];
+
+ for( j = 0; j < dsize; j++ )
+ {
+ float temp = cost_row[j];
+
+ if( u_val < temp )
+ u_val = temp;
+ if( v[j].val < temp )
+ v[j].val = temp;
+ }
+ u[i].val = u_val;
+ }
+
+ /* compute the delta matrix */
+ for( i = 0; i < ssize; i++ )
+ {
+ float u_val = u[i].val;
+ float *delta_row = delta[i];
+ float *cost_row = cost[i];
+
+ for( j = 0; j < dsize; j++ )
+ {
+ delta_row[j] = cost_row[j] - u_val - v[j].val;
+ }
+ }
+
+ /* find the basic variables */
+ do
+ {
+ /* find the smallest delta[i][j] */
+ min_i = -1;
+ min_delta = CV_EMD_INF;
+ prev_u = &u_head;
+ for( cur_u = u_head.next; cur_u != 0; cur_u = cur_u->next )
+ {
+ i = (int)(cur_u - u);
+ float *delta_row = delta[i];
+
+ prev_v = &v_head;
+ for( cur_v = v_head.next; cur_v != 0; cur_v = cur_v->next )
+ {
+ j = (int)(cur_v - v);
+ if( min_delta > delta_row[j] )
+ {
+ min_delta = delta_row[j];
+ min_i = i;
+ min_j = j;
+ prev_u_min_i = prev_u;
+ prev_v_min_j = prev_v;
+ }
+ prev_v = cur_v;
+ }
+ prev_u = cur_u;
+ }
+
+ if( min_i < 0 )
+ break;
+
+ /* add x[min_i][min_j] to the basis, and adjust supplies and cost */
+ remember = prev_u_min_i->next;
+ icvAddBasicVariable( state, min_i, min_j, prev_u_min_i, prev_v_min_j, &u_head );
+
+ /* update the necessary delta[][] */
+ if( remember == prev_u_min_i->next ) /* line min_i was deleted */
+ {
+ for( cur_v = v_head.next; cur_v != 0; cur_v = cur_v->next )
+ {
+ j = (int)(cur_v - v);
+ if( cur_v->val == cost[min_i][j] ) /* column j needs updating */
+ {
+ float max_val = -CV_EMD_INF;
+
+ /* find the new maximum value in the column */
+ for( cur_u = u_head.next; cur_u != 0; cur_u = cur_u->next )
+ {
+ float temp = cost[cur_u - u][j];
+
+ if( max_val < temp )
+ max_val = temp;
+ }
+
+ /* if needed, adjust the relevant delta[*][j] */
+ diff = max_val - cur_v->val;
+ cur_v->val = max_val;
+ if( fabs( diff ) < eps )
+ {
+ for( cur_u = u_head.next; cur_u != 0; cur_u = cur_u->next )
+ delta[cur_u - u][j] += diff;
+ }
+ }
+ }
+ }
+ else /* column min_j was deleted */
+ {
+ for( cur_u = u_head.next; cur_u != 0; cur_u = cur_u->next )
+ {
+ i = (int)(cur_u - u);
+ if( cur_u->val == cost[i][min_j] ) /* row i needs updating */
+ {
+ float max_val = -CV_EMD_INF;
+
+ /* find the new maximum value in the row */
+ for( cur_v = v_head.next; cur_v != 0; cur_v = cur_v->next )
+ {
+ float temp = cost[i][cur_v - v];
+
+ if( max_val < temp )
+ max_val = temp;
+ }
+
+ /* if needed, adjust the relevant delta[i][*] */
+ diff = max_val - cur_u->val;
+ cur_u->val = max_val;
+
+ if( fabs( diff ) < eps )
+ {
+ for( cur_v = v_head.next; cur_v != 0; cur_v = cur_v->next )
+ delta[i][cur_v - v] += diff;
+ }
+ }
+ }
+ }
+ }
+ while( u_head.next != 0 || v_head.next != 0 );
+}
+
+
+
+/****************************************************************************************\
+* icvAddBasicVariable *
+\****************************************************************************************/
+static void
+icvAddBasicVariable( CvEMDState * state,
+ int min_i, int min_j,
+ CvNode1D * prev_u_min_i, CvNode1D * prev_v_min_j, CvNode1D * u_head )
+{
+ float temp;
+ CvNode2D *end_x = state->end_x;
+
+ if( state->s[min_i] < state->d[min_j] + state->weight * CV_EMD_EPS )
+ { /* supply exhausted */
+ temp = state->s[min_i];
+ state->s[min_i] = 0;
+ state->d[min_j] -= temp;
+ }
+ else /* demand exhausted */
+ {
+ temp = state->d[min_j];
+ state->d[min_j] = 0;
+ state->s[min_i] -= temp;
+ }
+
+ /* x(min_i,min_j) is a basic variable */
+ state->is_x[min_i][min_j] = 1;
+
+ end_x->val = temp;
+ end_x->i = min_i;
+ end_x->j = min_j;
+ end_x->next[0] = state->rows_x[min_i];
+ end_x->next[1] = state->cols_x[min_j];
+ state->rows_x[min_i] = end_x;
+ state->cols_x[min_j] = end_x;
+ state->end_x = end_x + 1;
+
+ /* delete supply row only if the empty, and if not last row */
+ if( state->s[min_i] == 0 && u_head->next->next != 0 )
+ prev_u_min_i->next = prev_u_min_i->next->next; /* remove row from list */
+ else
+ prev_v_min_j->next = prev_v_min_j->next->next; /* remove column from list */
+}
+
+
+/****************************************************************************************\
+* standard metrics *
+\****************************************************************************************/
+static float
+icvDistL1( const float *x, const float *y, void *user_param )
+{
+ int i, dims = (int)(size_t)user_param;
+ double s = 0;
+
+ for( i = 0; i < dims; i++ )
+ {
+ double t = x[i] - y[i];
+
+ s += fabs( t );
+ }
+ return (float)s;
+}
+
+static float
+icvDistL2( const float *x, const float *y, void *user_param )
+{
+ int i, dims = (int)(size_t)user_param;
+ double s = 0;
+
+ for( i = 0; i < dims; i++ )
+ {
+ double t = x[i] - y[i];
+
+ s += t * t;
+ }
+ return cvSqrt( (float)s );
+}
+
+static float
+icvDistC( const float *x, const float *y, void *user_param )
+{
+ int i, dims = (int)(size_t)user_param;
+ double s = 0;
+
+ for( i = 0; i < dims; i++ )
+ {
+ double t = fabs( x[i] - y[i] );
+
+ if( s < t )
+ s = t;
+ }
+ return (float)s;
+}
+
+/* End of file. */
+
diff --git a/cv/src/cvfeatureselect.cpp b/cv/src/cvfeatureselect.cpp
new file mode 100644
index 0000000..acda3fc
--- /dev/null
+++ b/cv/src/cvfeatureselect.cpp
@@ -0,0 +1,234 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+#define cmp_features( f1, f2 ) (*(f1) > *(f2))
+
+static CV_IMPLEMENT_QSORT( icvSortFeatures, int *, cmp_features )
+
+CV_IMPL void
+cvGoodFeaturesToTrack( const void* image, void* eigImage, void* tempImage,
+ CvPoint2D32f* corners, int *corner_count,
+ double quality_level, double min_distance,
+ const void* maskImage, int block_size,
+ int use_harris, double harris_k )
+{
+ CvMat* _eigImg = 0;
+ CvMat* _tmpImg = 0;
+
+ CV_FUNCNAME( "cvGoodFeaturesToTrack" );
+
+ __BEGIN__;
+
+ double max_val = 0;
+ int max_count = 0;
+ int count = 0;
+ int x, y, i, k = 0;
+ int min_dist;
+ int eig_step, tmp_step;
+
+ /* when selecting points, use integer coordinates */
+ CvPoint *ptr = (CvPoint *) corners;
+
+ /* process floating-point images using integer arithmetics */
+ int *eig_data = 0;
+ int *tmp_data = 0;
+ int **ptr_data = 0;
+ uchar *mask_data = 0;
+ int mask_step = 0;
+ CvSize size;
+
+ int coi1 = 0, coi2 = 0, coi3 = 0;
+ CvMat stub, *img = (CvMat*)image;
+ CvMat eig_stub, *eig = (CvMat*)eigImage;
+ CvMat tmp_stub, *tmp = (CvMat*)tempImage;
+ CvMat mask_stub, *mask = (CvMat*)maskImage;
+
+ if( corner_count )
+ {
+ max_count = *corner_count;
+ *corner_count = 0;
+ }
+
+ CV_CALL( img = cvGetMat( img, &stub, &coi1 ));
+ if( eig )
+ {
+ CV_CALL( eig = cvGetMat( eig, &eig_stub, &coi2 ));
+ }
+ else
+ {
+ CV_CALL( _eigImg = cvCreateMat( img->rows, img->cols, CV_32FC1 ));
+ eig = _eigImg;
+ }
+
+ if( tmp )
+ {
+ CV_CALL( tmp = cvGetMat( tmp, &tmp_stub, &coi3 ));
+ }
+ else
+ {
+ CV_CALL( _tmpImg = cvCreateMat( img->rows, img->cols, CV_32FC1 ));
+ tmp = _tmpImg;
+ }
+
+ if( mask )
+ {
+ CV_CALL( mask = cvGetMat( mask, &mask_stub ));
+ if( !CV_IS_MASK_ARR( mask ))
+ {
+ CV_ERROR( CV_StsBadMask, "" );
+ }
+ }
+
+ if( coi1 != 0 || coi2 != 0 || coi3 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ if( CV_MAT_CN(img->type) != 1 ||
+ CV_MAT_CN(eig->type) != 1 ||
+ CV_MAT_CN(tmp->type) != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+
+ if( CV_MAT_DEPTH(tmp->type) != CV_32F ||
+ CV_MAT_DEPTH(eig->type) != CV_32F )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+
+ if( !corners || !corner_count )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( max_count <= 0 )
+ CV_ERROR( CV_StsBadArg, "maximal corners number is non positive" );
+
+ if( quality_level <= 0 || min_distance < 0 )
+ CV_ERROR( CV_StsBadArg, "quality level or min distance are non positive" );
+
+ if( use_harris )
+ {
+ CV_CALL( cvCornerHarris( img, eig, block_size, 3, harris_k ));
+ }
+ else
+ {
+ CV_CALL( cvCornerMinEigenVal( img, eig, block_size, 3 ));
+ }
+ CV_CALL( cvMinMaxLoc( eig, 0, &max_val, 0, 0, mask ));
+ CV_CALL( cvThreshold( eig, eig, max_val * quality_level,
+ 0, CV_THRESH_TOZERO ));
+ CV_CALL( cvDilate( eig, tmp ));
+
+ min_dist = cvRound( min_distance * min_distance );
+
+ size = cvGetMatSize( img );
+ ptr_data = (int**)(tmp->data.ptr);
+ eig_data = (int*)(eig->data.ptr);
+ tmp_data = (int*)(tmp->data.ptr);
+ if( mask )
+ {
+ mask_data = (uchar*)(mask->data.ptr);
+ mask_step = mask->step;
+ }
+
+ eig_step = eig->step / sizeof(eig_data[0]);
+ tmp_step = tmp->step / sizeof(tmp_data[0]);
+
+ /* collect list of pointers to features - put them into temporary image */
+ for( y = 1, k = 0; y < size.height - 1; y++ )
+ {
+ eig_data += eig_step;
+ tmp_data += tmp_step;
+ mask_data += mask_step;
+
+ for( x = 1; x < size.width - 1; x++ )
+ {
+ int val = eig_data[x];
+ if( val != 0 && val == tmp_data[x] && (!mask || mask_data[x]) )
+ ptr_data[k++] = eig_data + x;
+ }
+ }
+
+ icvSortFeatures( ptr_data, k, 0 );
+
+ /* select the strongest features */
+ for( i = 0; i < k; i++ )
+ {
+ int j = count, ofs = (int)((uchar*)(ptr_data[i]) - eig->data.ptr);
+ y = ofs / eig->step;
+ x = (ofs - y * eig->step)/sizeof(float);
+
+ if( min_dist != 0 )
+ {
+ for( j = 0; j < count; j++ )
+ {
+ int dx = x - ptr[j].x;
+ int dy = y - ptr[j].y;
+ int dist = dx * dx + dy * dy;
+
+ if( dist < min_dist )
+ break;
+ }
+ }
+
+ if( j == count )
+ {
+ ptr[count].x = x;
+ ptr[count].y = y;
+ if( ++count >= max_count )
+ break;
+ }
+ }
+
+ /* convert points to floating-point format */
+ for( i = 0; i < count; i++ )
+ {
+ assert( (unsigned)ptr[i].x < (unsigned)size.width &&
+ (unsigned)ptr[i].y < (unsigned)size.height );
+
+ corners[i].x = (float)ptr[i].x;
+ corners[i].y = (float)ptr[i].y;
+ }
+
+ *corner_count = count;
+
+ __END__;
+
+ cvReleaseMat( &_eigImg );
+ cvReleaseMat( &_tmpImg );
+}
+
+/* End of file. */
diff --git a/cv/src/cvfilter.cpp b/cv/src/cvfilter.cpp
new file mode 100644
index 0000000..f95fcca
--- /dev/null
+++ b/cv/src/cvfilter.cpp
@@ -0,0 +1,2710 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+
+/****************************************************************************************\
+ Base Image Filter
+\****************************************************************************************/
+
+static void default_x_filter_func( const uchar*, uchar*, void* )
+{
+}
+
+static void default_y_filter_func( uchar**, uchar*, int, int, void* )
+{
+}
+
+CvBaseImageFilter::CvBaseImageFilter()
+{
+ min_depth = CV_8U;
+ buffer = 0;
+ rows = 0;
+ max_width = 0;
+ x_func = default_x_filter_func;
+ y_func = default_y_filter_func;
+}
+
+
+CvBaseImageFilter::CvBaseImageFilter( int _max_width, int _src_type, int _dst_type,
+ bool _is_separable, CvSize _ksize, CvPoint _anchor,
+ int _border_mode, CvScalar _border_value )
+{
+ min_depth = CV_8U;
+ buffer = 0;
+ rows = 0;
+ max_width = 0;
+ x_func = default_x_filter_func;
+ y_func = default_y_filter_func;
+
+ init( _max_width, _src_type, _dst_type, _is_separable,
+ _ksize, _anchor, _border_mode, _border_value );
+}
+
+
+void CvBaseImageFilter::clear()
+{
+ cvFree( &buffer );
+ rows = 0;
+}
+
+
+CvBaseImageFilter::~CvBaseImageFilter()
+{
+ clear();
+}
+
+
+void CvBaseImageFilter::get_work_params()
+{
+ int min_rows = max_ky*2 + 3, rows = MAX(min_rows,10), row_sz;
+ int width = max_width, trow_sz = 0;
+
+ if( is_separable )
+ {
+ int max_depth = MAX(CV_MAT_DEPTH(src_type), CV_MAT_DEPTH(dst_type));
+ int max_cn = MAX(CV_MAT_CN(src_type), CV_MAT_CN(dst_type));
+ max_depth = MAX( max_depth, min_depth );
+ work_type = CV_MAKETYPE( max_depth, max_cn );
+ trow_sz = cvAlign( (max_width + ksize.width - 1)*CV_ELEM_SIZE(src_type), ALIGN );
+ }
+ else
+ {
+ work_type = src_type;
+ width += ksize.width - 1;
+ }
+ row_sz = cvAlign( width*CV_ELEM_SIZE(work_type), ALIGN );
+ buf_size = rows*row_sz;
+ buf_size = MIN( buf_size, 1 << 16 );
+ buf_size = MAX( buf_size, min_rows*row_sz );
+ max_rows = (buf_size/row_sz)*3 + max_ky*2 + 8;
+ buf_size += trow_sz;
+}
+
+
+void CvBaseImageFilter::init( int _max_width, int _src_type, int _dst_type,
+ bool _is_separable, CvSize _ksize, CvPoint _anchor,
+ int _border_mode, CvScalar _border_value )
+{
+ CV_FUNCNAME( "CvBaseImageFilter::init" );
+
+ __BEGIN__;
+
+ int total_buf_sz, src_pix_sz, row_tab_sz, bsz;
+ uchar* ptr;
+
+ if( !(buffer && _max_width <= max_width && _src_type == src_type &&
+ _dst_type == dst_type && _is_separable == is_separable &&
+ _ksize.width == ksize.width && _ksize.height == ksize.height &&
+ _anchor.x == anchor.x && _anchor.y == anchor.y) )
+ clear();
+
+ is_separable = _is_separable != 0;
+ max_width = _max_width; //MAX(_max_width,_ksize.width);
+ src_type = CV_MAT_TYPE(_src_type);
+ dst_type = CV_MAT_TYPE(_dst_type);
+ ksize = _ksize;
+ anchor = _anchor;
+
+ if( anchor.x == -1 )
+ anchor.x = ksize.width / 2;
+ if( anchor.y == -1 )
+ anchor.y = ksize.height / 2;
+
+ max_ky = MAX( anchor.y, ksize.height - anchor.y - 1 );
+ border_mode = _border_mode;
+ border_value = _border_value;
+
+ if( ksize.width <= 0 || ksize.height <= 0 ||
+ (unsigned)anchor.x >= (unsigned)ksize.width ||
+ (unsigned)anchor.y >= (unsigned)ksize.height )
+ CV_ERROR( CV_StsOutOfRange, "invalid kernel size and/or anchor position" );
+
+ if( border_mode != IPL_BORDER_CONSTANT && border_mode != IPL_BORDER_REPLICATE &&
+ border_mode != IPL_BORDER_REFLECT && border_mode != IPL_BORDER_REFLECT_101 )
+ CV_ERROR( CV_StsBadArg, "Invalid/unsupported border mode" );
+
+ get_work_params();
+
+ prev_width = 0;
+ prev_x_range = cvSlice(0,0);
+
+ buf_size = cvAlign( buf_size, ALIGN );
+
+ src_pix_sz = CV_ELEM_SIZE(src_type);
+ border_tab_sz1 = anchor.x*src_pix_sz;
+ border_tab_sz = (ksize.width-1)*src_pix_sz;
+ bsz = cvAlign( border_tab_sz*sizeof(int), ALIGN );
+
+ assert( max_rows > max_ky*2 );
+ row_tab_sz = cvAlign( max_rows*sizeof(uchar*), ALIGN );
+ total_buf_sz = buf_size + row_tab_sz + bsz;
+
+ CV_CALL( ptr = buffer = (uchar*)cvAlloc( total_buf_sz ));
+
+ rows = (uchar**)ptr;
+ ptr += row_tab_sz;
+ border_tab = (int*)ptr;
+ ptr += bsz;
+
+ buf_start = ptr;
+ const_row = 0;
+
+ if( border_mode == IPL_BORDER_CONSTANT )
+ cvScalarToRawData( &border_value, border_tab, src_type, 0 );
+
+ __END__;
+}
+
+
+void CvBaseImageFilter::start_process( CvSlice x_range, int width )
+{
+ int mode = border_mode;
+ int pix_sz = CV_ELEM_SIZE(src_type), work_pix_sz = CV_ELEM_SIZE(work_type);
+ int bsz = buf_size, bw = x_range.end_index - x_range.start_index, bw1 = bw + ksize.width - 1;
+ int tr_step = cvAlign(bw1*pix_sz, ALIGN );
+ int i, j, k, ofs;
+
+ if( x_range.start_index == prev_x_range.start_index &&
+ x_range.end_index == prev_x_range.end_index &&
+ width == prev_width )
+ return;
+
+ prev_x_range = x_range;
+ prev_width = width;
+
+ if( !is_separable )
+ bw = bw1;
+ else
+ bsz -= tr_step;
+
+ buf_step = cvAlign(bw*work_pix_sz, ALIGN);
+
+ if( mode == IPL_BORDER_CONSTANT )
+ bsz -= buf_step;
+ buf_max_count = bsz/buf_step;
+ buf_max_count = MIN( buf_max_count, max_rows - max_ky*2 );
+ buf_end = buf_start + buf_max_count*buf_step;
+
+ if( mode == IPL_BORDER_CONSTANT )
+ {
+ int i, tab_len = ksize.width*pix_sz;
+ uchar* bt = (uchar*)border_tab;
+ uchar* trow = buf_end;
+ const_row = buf_end + (is_separable ? 1 : 0)*tr_step;
+
+ for( i = pix_sz; i < tab_len; i++ )
+ bt[i] = bt[i - pix_sz];
+ for( i = 0; i < pix_sz; i++ )
+ trow[i] = bt[i];
+ for( i = pix_sz; i < tr_step; i++ )
+ trow[i] = trow[i - pix_sz];
+ if( is_separable )
+ x_func( trow, const_row, this );
+ return;
+ }
+
+ if( x_range.end_index - x_range.start_index <= 1 )
+ mode = IPL_BORDER_REPLICATE;
+
+ width = (width - 1)*pix_sz;
+ ofs = (anchor.x-x_range.start_index)*pix_sz;
+
+ for( k = 0; k < 2; k++ )
+ {
+ int idx, delta;
+ int i1, i2, di;
+
+ if( k == 0 )
+ {
+ idx = (x_range.start_index - 1)*pix_sz;
+ delta = di = -pix_sz;
+ i1 = border_tab_sz1 - pix_sz;
+ i2 = -pix_sz;
+ }
+ else
+ {
+ idx = x_range.end_index*pix_sz;
+ delta = di = pix_sz;
+ i1 = border_tab_sz1;
+ i2 = border_tab_sz;
+ }
+
+ if( (unsigned)idx > (unsigned)width )
+ {
+ int shift = mode == IPL_BORDER_REFLECT_101 ? pix_sz : 0;
+ idx = k == 0 ? shift : width - shift;
+ delta = -delta;
+ }
+
+ for( i = i1; i != i2; i += di )
+ {
+ for( j = 0; j < pix_sz; j++ )
+ border_tab[i + j] = idx + ofs + j;
+ if( mode != IPL_BORDER_REPLICATE )
+ {
+ if( (delta > 0 && idx == width) ||
+ (delta < 0 && idx == 0) )
+ {
+ if( mode == IPL_BORDER_REFLECT_101 )
+ idx -= delta*2;
+ delta = -delta;
+ }
+ else
+ idx += delta;
+ }
+ }
+ }
+}
+
+
+void CvBaseImageFilter::make_y_border( int row_count, int top_rows, int bottom_rows )
+{
+ int i;
+
+ if( border_mode == IPL_BORDER_CONSTANT ||
+ border_mode == IPL_BORDER_REPLICATE )
+ {
+ uchar* row1 = border_mode == IPL_BORDER_CONSTANT ? const_row : rows[max_ky];
+
+ for( i = 0; i < top_rows && rows[i] == 0; i++ )
+ rows[i] = row1;
+
+ row1 = border_mode == IPL_BORDER_CONSTANT ? const_row : rows[row_count-1];
+ for( i = 0; i < bottom_rows; i++ )
+ rows[i + row_count] = row1;
+ }
+ else
+ {
+ int j, dj = 1, shift = border_mode == IPL_BORDER_REFLECT_101;
+
+ for( i = top_rows-1, j = top_rows+shift; i >= 0; i-- )
+ {
+ if( rows[i] == 0 )
+ rows[i] = rows[j];
+ j += dj;
+ if( dj > 0 && j >= row_count )
+ {
+ if( !bottom_rows )
+ break;
+ j -= 1 + shift;
+ dj = -dj;
+ }
+ }
+
+ for( i = 0, j = row_count-1-shift; i < bottom_rows; i++, j-- )
+ rows[i + row_count] = rows[j];
+ }
+}
+
+
+int CvBaseImageFilter::fill_cyclic_buffer( const uchar* src, int src_step,
+ int y0, int y1, int y2 )
+{
+ int i, y = y0, bsz1 = border_tab_sz1, bsz = border_tab_sz;
+ int pix_size = CV_ELEM_SIZE(src_type);
+ int width = prev_x_range.end_index - prev_x_range.start_index, width_n = width*pix_size;
+ bool can_use_src_as_trow = false; //is_separable && width >= ksize.width;
+
+ // fill the cyclic buffer
+ for( ; buf_count < buf_max_count && y < y2; buf_count++, y++, src += src_step )
+ {
+ uchar* trow = is_separable ? buf_end : buf_tail;
+ uchar* bptr = can_use_src_as_trow && y1 < y && y+1 < y2 ? (uchar*)(src - bsz1) : trow;
+
+ if( bptr != trow )
+ {
+ for( i = 0; i < bsz1; i++ )
+ trow[i] = bptr[i];
+ for( ; i < bsz; i++ )
+ trow[i] = bptr[i + width_n];
+ }
+ else if( !(((size_t)(bptr + bsz1)|(size_t)src|width_n) & (sizeof(int)-1)) )
+ for( i = 0; i < width_n; i += sizeof(int) )
+ *(int*)(bptr + i + bsz1) = *(int*)(src + i);
+ else
+ for( i = 0; i < width_n; i++ )
+ bptr[i + bsz1] = src[i];
+
+ if( border_mode != IPL_BORDER_CONSTANT )
+ {
+ for( i = 0; i < bsz1; i++ )
+ {
+ int j = border_tab[i];
+ bptr[i] = bptr[j];
+ }
+ for( ; i < bsz; i++ )
+ {
+ int j = border_tab[i];
+ bptr[i + width_n] = bptr[j];
+ }
+ }
+ else
+ {
+ const uchar *bt = (uchar*)border_tab;
+ for( i = 0; i < bsz1; i++ )
+ bptr[i] = bt[i];
+
+ for( ; i < bsz; i++ )
+ bptr[i + width_n] = bt[i];
+ }
+
+ if( is_separable )
+ {
+ x_func( bptr, buf_tail, this );
+ if( bptr != trow )
+ {
+ for( i = 0; i < bsz1; i++ )
+ bptr[i] = trow[i];
+ for( ; i < bsz; i++ )
+ bptr[i + width_n] = trow[i];
+ }
+ }
+
+ buf_tail += buf_step;
+ if( buf_tail >= buf_end )
+ buf_tail = buf_start;
+ }
+
+ return y - y0;
+}
+
+int CvBaseImageFilter::process( const CvMat* src, CvMat* dst,
+ CvRect src_roi, CvPoint dst_origin, int flags )
+{
+ int rows_processed = 0;
+
+ /*
+ check_parameters
+ initialize_horizontal_border_reloc_tab_if_not_initialized_yet
+
+ for_each_source_row: src starts from src_roi.y, buf starts with the first available row
+ 1) if separable,
+ 1a.1) copy source row to temporary buffer, form a border using border reloc tab.
+ 1a.2) apply row-wise filter (symmetric, asymmetric or generic)
+ else
+ 1b.1) copy source row to the buffer, form a border
+ 2) if the buffer is full, or it is the last source row:
+ 2.1) if stage != middle, form the pointers to other "virtual" rows.
+ if separable
+ 2a.2) apply column-wise filter, store the results.
+ else
+ 2b.2) form a sparse (offset,weight) tab
+ 2b.3) apply generic non-separable filter, store the results
+ 3) update row pointers etc.
+ */
+
+ CV_FUNCNAME( "CvBaseImageFilter::process" );
+
+ __BEGIN__;
+
+ int i, width, _src_y1, _src_y2;
+ int src_x, src_y, src_y1, src_y2, dst_y;
+ int pix_size = CV_ELEM_SIZE(src_type);
+ uchar *sptr = 0, *dptr;
+ int phase = flags & (CV_START|CV_END|CV_MIDDLE);
+ bool isolated_roi = (flags & CV_ISOLATED_ROI) != 0;
+
+ if( !CV_IS_MAT(src) )
+ CV_ERROR( CV_StsBadArg, "" );
+
+ if( CV_MAT_TYPE(src->type) != src_type )
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ width = src->cols;
+
+ if( src_roi.width == -1 && src_roi.x == 0 )
+ src_roi.width = width;
+
+ if( src_roi.height == -1 && src_roi.y == 0 )
+ {
+ src_roi.y = 0;
+ src_roi.height = src->rows;
+ }
+
+ if( src_roi.width > max_width ||
+ src_roi.x < 0 || src_roi.width < 0 ||
+ src_roi.y < 0 || src_roi.height < 0 ||
+ src_roi.x + src_roi.width > width ||
+ src_roi.y + src_roi.height > src->rows )
+ CV_ERROR( CV_StsOutOfRange, "Too large source image or its ROI" );
+
+ src_x = src_roi.x;
+ _src_y1 = 0;
+ _src_y2 = src->rows;
+
+ if( isolated_roi )
+ {
+ src_roi.x = 0;
+ width = src_roi.width;
+ _src_y1 = src_roi.y;
+ _src_y2 = src_roi.y + src_roi.height;
+ }
+
+ if( !CV_IS_MAT(dst) )
+ CV_ERROR( CV_StsBadArg, "" );
+
+ if( CV_MAT_TYPE(dst->type) != dst_type )
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( dst_origin.x < 0 || dst_origin.y < 0 )
+ CV_ERROR( CV_StsOutOfRange, "Incorrect destination ROI origin" );
+
+ if( phase == CV_WHOLE )
+ phase = CV_START | CV_END;
+ phase &= CV_START | CV_END | CV_MIDDLE;
+
+ // initialize horizontal border relocation tab if it is not initialized yet
+ if( phase & CV_START )
+ start_process( cvSlice(src_roi.x, src_roi.x + src_roi.width), width );
+ else if( prev_width != width || prev_x_range.start_index != src_roi.x ||
+ prev_x_range.end_index != src_roi.x + src_roi.width )
+ CV_ERROR( CV_StsBadArg,
+ "In a middle or at the end the horizontal placement of the stripe can not be changed" );
+
+ dst_y = dst_origin.y;
+ src_y1 = src_roi.y;
+ src_y2 = src_roi.y + src_roi.height;
+
+ if( phase & CV_START )
+ {
+ for( i = 0; i <= max_ky*2; i++ )
+ rows[i] = 0;
+
+ src_y1 -= max_ky;
+ top_rows = bottom_rows = 0;
+
+ if( src_y1 < _src_y1 )
+ {
+ top_rows = _src_y1 - src_y1;
+ src_y1 = _src_y1;
+ }
+
+ buf_head = buf_tail = buf_start;
+ buf_count = 0;
+ }
+
+ if( phase & CV_END )
+ {
+ src_y2 += max_ky;
+
+ if( src_y2 > _src_y2 )
+ {
+ bottom_rows = src_y2 - _src_y2;
+ src_y2 = _src_y2;
+ }
+ }
+
+ dptr = dst->data.ptr + dst_origin.y*dst->step + dst_origin.x*CV_ELEM_SIZE(dst_type);
+ sptr = src->data.ptr + src_y1*src->step + src_x*pix_size;
+
+ for( src_y = src_y1; src_y < src_y2; )
+ {
+ uchar* bptr;
+ int row_count, delta;
+
+ delta = fill_cyclic_buffer( sptr, src->step, src_y, src_y1, src_y2 );
+
+ src_y += delta;
+ sptr += src->step*delta;
+
+ // initialize the cyclic buffer row pointers
+ bptr = buf_head;
+ for( i = 0; i < buf_count; i++ )
+ {
+ rows[i+top_rows] = bptr;
+ bptr += buf_step;
+ if( bptr >= buf_end )
+ bptr = buf_start;
+ }
+
+ row_count = top_rows + buf_count;
+
+ if( !rows[0] || ((phase & CV_END) && src_y == src_y2) )
+ {
+ int br = (phase & CV_END) && src_y == src_y2 ? bottom_rows : 0;
+ make_y_border( row_count, top_rows, br );
+ row_count += br;
+ }
+
+ if( rows[0] && row_count > max_ky*2 )
+ {
+ int count = row_count - max_ky*2;
+ if( dst_y + count > dst->rows )
+ CV_ERROR( CV_StsOutOfRange, "The destination image can not fit the result" );
+
+ assert( count >= 0 );
+ y_func( rows + max_ky - anchor.y, dptr, dst->step, count, this );
+ row_count -= count;
+ dst_y += count;
+ dptr += dst->step*count;
+ for( bptr = row_count > 0 ?rows[count] : 0; buf_head != bptr && buf_count > 0; buf_count-- )
+ {
+ buf_head += buf_step;
+ if( buf_head >= buf_end )
+ buf_head = buf_start;
+ }
+ rows_processed += count;
+ top_rows = MAX(top_rows - count, 0);
+ }
+ }
+
+ __END__;
+
+ return rows_processed;
+}
+
+
+/****************************************************************************************\
+ Separable Linear Filter
+\****************************************************************************************/
+
+static void icvFilterRowSymm_8u32s( const uchar* src, int* dst, void* params );
+static void icvFilterColSymm_32s8u( const int** src, uchar* dst, int dst_step,
+ int count, void* params );
+static void icvFilterColSymm_32s16s( const int** src, short* dst, int dst_step,
+ int count, void* params );
+static void icvFilterRowSymm_8u32f( const uchar* src, float* dst, void* params );
+static void icvFilterRow_8u32f( const uchar* src, float* dst, void* params );
+static void icvFilterRowSymm_16s32f( const short* src, float* dst, void* params );
+static void icvFilterRow_16s32f( const short* src, float* dst, void* params );
+static void icvFilterRowSymm_16u32f( const ushort* src, float* dst, void* params );
+static void icvFilterRow_16u32f( const ushort* src, float* dst, void* params );
+static void icvFilterRowSymm_32f( const float* src, float* dst, void* params );
+static void icvFilterRow_32f( const float* src, float* dst, void* params );
+
+static void icvFilterColSymm_32f8u( const float** src, uchar* dst, int dst_step,
+ int count, void* params );
+static void icvFilterCol_32f8u( const float** src, uchar* dst, int dst_step,
+ int count, void* params );
+static void icvFilterColSymm_32f16s( const float** src, short* dst, int dst_step,
+ int count, void* params );
+static void icvFilterCol_32f16s( const float** src, short* dst, int dst_step,
+ int count, void* params );
+static void icvFilterColSymm_32f16u( const float** src, ushort* dst, int dst_step,
+ int count, void* params );
+static void icvFilterCol_32f16u( const float** src, ushort* dst, int dst_step,
+ int count, void* params );
+static void icvFilterColSymm_32f( const float** src, float* dst, int dst_step,
+ int count, void* params );
+static void icvFilterCol_32f( const float** src, float* dst, int dst_step,
+ int count, void* params );
+
+CvSepFilter::CvSepFilter()
+{
+ min_depth = CV_32F;
+ kx = ky = 0;
+ kx_flags = ky_flags = 0;
+}
+
+
+CvSepFilter::CvSepFilter( int _max_width, int _src_type, int _dst_type,
+ const CvMat* _kx, const CvMat* _ky,
+ CvPoint _anchor, int _border_mode,
+ CvScalar _border_value )
+{
+ min_depth = CV_32F;
+ kx = ky = 0;
+ init( _max_width, _src_type, _dst_type, _kx, _ky, _anchor, _border_mode, _border_value );
+}
+
+
+void CvSepFilter::clear()
+{
+ cvReleaseMat( &kx );
+ cvReleaseMat( &ky );
+ CvBaseImageFilter::clear();
+}
+
+
+CvSepFilter::~CvSepFilter()
+{
+ clear();
+}
+
+
+#undef FILTER_BITS
+#define FILTER_BITS 8
+
+void CvSepFilter::init( int _max_width, int _src_type, int _dst_type,
+ const CvMat* _kx, const CvMat* _ky,
+ CvPoint _anchor, int _border_mode,
+ CvScalar _border_value )
+{
+ CV_FUNCNAME( "CvSepFilter::init" );
+
+ __BEGIN__;
+
+ CvSize _ksize;
+ int filter_type;
+ int i, xsz, ysz;
+ int convert_filters = 0;
+ double xsum = 0, ysum = 0;
+ const float eps = FLT_EPSILON*100.f;
+
+ if( !CV_IS_MAT(_kx) || !CV_IS_MAT(_ky) ||
+ (_kx->cols != 1 && _kx->rows != 1) ||
+ (_ky->cols != 1 && _ky->rows != 1) ||
+ CV_MAT_CN(_kx->type) != 1 || CV_MAT_CN(_ky->type) != 1 ||
+ !CV_ARE_TYPES_EQ(_kx,_ky) )
+ CV_ERROR( CV_StsBadArg,
+ "Both kernels must be valid 1d single-channel vectors of the same types" );
+
+ if( CV_MAT_CN(_src_type) != CV_MAT_CN(_dst_type) )
+ CV_ERROR( CV_StsUnmatchedFormats, "Input and output must have the same number of channels" );
+
+ filter_type = MAX( CV_32F, CV_MAT_DEPTH(_kx->type) );
+
+ _ksize.width = _kx->rows + _kx->cols - 1;
+ _ksize.height = _ky->rows + _ky->cols - 1;
+
+ CV_CALL( CvBaseImageFilter::init( _max_width, _src_type, _dst_type, 1, _ksize,
+ _anchor, _border_mode, _border_value ));
+
+ if( !(kx && CV_ARE_SIZES_EQ(kx,_kx)) )
+ {
+ cvReleaseMat( &kx );
+ CV_CALL( kx = cvCreateMat( _kx->rows, _kx->cols, filter_type ));
+ }
+
+ if( !(ky && CV_ARE_SIZES_EQ(ky,_ky)) )
+ {
+ cvReleaseMat( &ky );
+ CV_CALL( ky = cvCreateMat( _ky->rows, _ky->cols, filter_type ));
+ }
+
+ CV_CALL( cvConvert( _kx, kx ));
+ CV_CALL( cvConvert( _ky, ky ));
+
+ xsz = kx->rows + kx->cols - 1;
+ ysz = ky->rows + ky->cols - 1;
+ kx_flags = ky_flags = ASYMMETRICAL + SYMMETRICAL + POSITIVE + SUM_TO_1 + INTEGER;
+
+ if( !(xsz & 1) )
+ kx_flags &= ~(ASYMMETRICAL + SYMMETRICAL);
+ if( !(ysz & 1) )
+ ky_flags &= ~(ASYMMETRICAL + SYMMETRICAL);
+
+ for( i = 0; i < xsz; i++ )
+ {
+ float v = kx->data.fl[i];
+ xsum += v;
+ if( v < 0 )
+ kx_flags &= ~POSITIVE;
+ if( fabs(v - cvRound(v)) > eps )
+ kx_flags &= ~INTEGER;
+ if( fabs(v - kx->data.fl[xsz - i - 1]) > eps )
+ kx_flags &= ~SYMMETRICAL;
+ if( fabs(v + kx->data.fl[xsz - i - 1]) > eps )
+ kx_flags &= ~ASYMMETRICAL;
+ }
+
+ if( fabs(xsum - 1.) > eps )
+ kx_flags &= ~SUM_TO_1;
+
+ for( i = 0; i < ysz; i++ )
+ {
+ float v = ky->data.fl[i];
+ ysum += v;
+ if( v < 0 )
+ ky_flags &= ~POSITIVE;
+ if( fabs(v - cvRound(v)) > eps )
+ ky_flags &= ~INTEGER;
+ if( fabs(v - ky->data.fl[ysz - i - 1]) > eps )
+ ky_flags &= ~SYMMETRICAL;
+ if( fabs(v + ky->data.fl[ysz - i - 1]) > eps )
+ ky_flags &= ~ASYMMETRICAL;
+ }
+
+ if( fabs(ysum - 1.) > eps )
+ ky_flags &= ~SUM_TO_1;
+
+ x_func = 0;
+ y_func = 0;
+
+ if( CV_MAT_DEPTH(src_type) == CV_8U )
+ {
+ if( CV_MAT_DEPTH(dst_type) == CV_8U &&
+ ((kx_flags&ky_flags) & (SYMMETRICAL + POSITIVE + SUM_TO_1)) == SYMMETRICAL + POSITIVE + SUM_TO_1 )
+ {
+ x_func = (CvRowFilterFunc)icvFilterRowSymm_8u32s;
+ y_func = (CvColumnFilterFunc)icvFilterColSymm_32s8u;
+ kx_flags &= ~INTEGER;
+ ky_flags &= ~INTEGER;
+ convert_filters = 1;
+ }
+ else if( CV_MAT_DEPTH(dst_type) == CV_16S &&
+ (kx_flags & (SYMMETRICAL + ASYMMETRICAL)) && (kx_flags & INTEGER) &&
+ (ky_flags & (SYMMETRICAL + ASYMMETRICAL)) && (ky_flags & INTEGER) )
+ {
+ x_func = (CvRowFilterFunc)icvFilterRowSymm_8u32s;
+ y_func = (CvColumnFilterFunc)icvFilterColSymm_32s16s;
+ convert_filters = 1;
+ }
+ else
+ {
+ if( CV_MAT_DEPTH(dst_type) > CV_32F )
+ CV_ERROR( CV_StsUnsupportedFormat, "8u->64f separable filtering is not supported" );
+
+ if( kx_flags & (SYMMETRICAL + ASYMMETRICAL) )
+ x_func = (CvRowFilterFunc)icvFilterRowSymm_8u32f;
+ else
+ x_func = (CvRowFilterFunc)icvFilterRow_8u32f;
+ }
+ }
+ else if( CV_MAT_DEPTH(src_type) == CV_16U )
+ {
+ if( CV_MAT_DEPTH(dst_type) > CV_32F )
+ CV_ERROR( CV_StsUnsupportedFormat, "16u->64f separable filtering is not supported" );
+
+ if( kx_flags & (SYMMETRICAL + ASYMMETRICAL) )
+ x_func = (CvRowFilterFunc)icvFilterRowSymm_16u32f;
+ else
+ x_func = (CvRowFilterFunc)icvFilterRow_16u32f;
+ }
+ else if( CV_MAT_DEPTH(src_type) == CV_16S )
+ {
+ if( CV_MAT_DEPTH(dst_type) > CV_32F )
+ CV_ERROR( CV_StsUnsupportedFormat, "16s->64f separable filtering is not supported" );
+
+ if( kx_flags & (SYMMETRICAL + ASYMMETRICAL) )
+ x_func = (CvRowFilterFunc)icvFilterRowSymm_16s32f;
+ else
+ x_func = (CvRowFilterFunc)icvFilterRow_16s32f;
+ }
+ else if( CV_MAT_DEPTH(src_type) == CV_32F )
+ {
+ if( CV_MAT_DEPTH(dst_type) != CV_32F )
+ CV_ERROR( CV_StsUnsupportedFormat, "When the input has 32f data type, the output must also have 32f type" );
+
+ if( kx_flags & (SYMMETRICAL + ASYMMETRICAL) )
+ x_func = (CvRowFilterFunc)icvFilterRowSymm_32f;
+ else
+ x_func = (CvRowFilterFunc)icvFilterRow_32f;
+ }
+ else
+ CV_ERROR( CV_StsUnsupportedFormat, "Unknown or unsupported input data type" );
+
+ if( !y_func )
+ {
+ if( CV_MAT_DEPTH(dst_type) == CV_8U )
+ {
+ if( ky_flags & (SYMMETRICAL + ASYMMETRICAL) )
+ y_func = (CvColumnFilterFunc)icvFilterColSymm_32f8u;
+ else
+ y_func = (CvColumnFilterFunc)icvFilterCol_32f8u;
+ }
+ else if( CV_MAT_DEPTH(dst_type) == CV_16U )
+ {
+ if( ky_flags & (SYMMETRICAL + ASYMMETRICAL) )
+ y_func = (CvColumnFilterFunc)icvFilterColSymm_32f16u;
+ else
+ y_func = (CvColumnFilterFunc)icvFilterCol_32f16u;
+ }
+ else if( CV_MAT_DEPTH(dst_type) == CV_16S )
+ {
+ if( ky_flags & (SYMMETRICAL + ASYMMETRICAL) )
+ y_func = (CvColumnFilterFunc)icvFilterColSymm_32f16s;
+ else
+ y_func = (CvColumnFilterFunc)icvFilterCol_32f16s;
+ }
+ else if( CV_MAT_DEPTH(dst_type) == CV_32F )
+ {
+ if( ky_flags & (SYMMETRICAL + ASYMMETRICAL) )
+ y_func = (CvColumnFilterFunc)icvFilterColSymm_32f;
+ else
+ y_func = (CvColumnFilterFunc)icvFilterCol_32f;
+ }
+ else
+ CV_ERROR( CV_StsUnsupportedFormat, "Unknown or unsupported input data type" );
+ }
+
+ if( convert_filters )
+ {
+ int scale = kx_flags & ky_flags & INTEGER ? 1 : (1 << FILTER_BITS);
+ int sum;
+
+ for( i = sum = 0; i < xsz; i++ )
+ {
+ int t = cvRound(kx->data.fl[i]*scale);
+ kx->data.i[i] = t;
+ sum += t;
+ }
+ if( scale > 1 )
+ kx->data.i[xsz/2] += scale - sum;
+
+ for( i = sum = 0; i < ysz; i++ )
+ {
+ int t = cvRound(ky->data.fl[i]*scale);
+ ky->data.i[i] = t;
+ sum += t;
+ }
+ if( scale > 1 )
+ ky->data.i[ysz/2] += scale - sum;
+ kx->type = (kx->type & ~CV_MAT_DEPTH_MASK) | CV_32S;
+ ky->type = (ky->type & ~CV_MAT_DEPTH_MASK) | CV_32S;
+ }
+
+ __END__;
+}
+
+
+void CvSepFilter::init( int _max_width, int _src_type, int _dst_type,
+ bool _is_separable, CvSize _ksize,
+ CvPoint _anchor, int _border_mode,
+ CvScalar _border_value )
+{
+ CvBaseImageFilter::init( _max_width, _src_type, _dst_type, _is_separable,
+ _ksize, _anchor, _border_mode, _border_value );
+}
+
+
+static void
+icvFilterRowSymm_8u32s( const uchar* src, int* dst, void* params )
+{
+ const CvSepFilter* state = (const CvSepFilter*)params;
+ const CvMat* _kx = state->get_x_kernel();
+ const int* kx = _kx->data.i;
+ int ksize = _kx->cols + _kx->rows - 1;
+ int i = 0, j, k, width = state->get_width();
+ int cn = CV_MAT_CN(state->get_src_type());
+ int ksize2 = ksize/2, ksize2n = ksize2*cn;
+ int is_symm = state->get_x_kernel_flags() & CvSepFilter::SYMMETRICAL;
+ const uchar* s = src + ksize2n;
+
+ kx += ksize2;
+ width *= cn;
+
+ if( is_symm )
+ {
+ if( ksize == 1 && kx[0] == 1 )
+ {
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = s[i], s1 = s[i+1];
+ dst[i] = s0; dst[i+1] = s1;
+ }
+ s += i;
+ }
+ else if( ksize == 3 )
+ {
+ if( kx[0] == 2 && kx[1] == 1 )
+ for( ; i <= width - 2; i += 2, s += 2 )
+ {
+ int s0 = s[-cn] + s[0]*2 + s[cn], s1 = s[1-cn] + s[1]*2 + s[1+cn];
+ dst[i] = s0; dst[i+1] = s1;
+ }
+ else if( kx[0] == 10 && kx[1] == 3 )
+ for( ; i <= width - 2; i += 2, s += 2 )
+ {
+ int s0 = s[0]*10 + (s[-cn] + s[cn])*3, s1 = s[1]*10 + (s[1-cn] + s[1+cn])*3;
+ dst[i] = s0; dst[i+1] = s1;
+ }
+ else if( kx[0] == 2*64 && kx[1] == 1*64 )
+ for( ; i <= width - 2; i += 2, s += 2 )
+ {
+ int s0 = (s[0]*2 + s[-cn] + s[cn]) << 6;
+ int s1 = (s[1]*2 + s[1-cn] + s[1+cn]) << 6;
+ dst[i] = s0; dst[i+1] = s1;
+ }
+ else
+ {
+ int k0 = kx[0], k1 = kx[1];
+ for( ; i <= width - 2; i += 2, s += 2 )
+ {
+ int s0 = s[0]*k0 + (s[-cn] + s[cn])*k1, s1 = s[1]*k0 + (s[1-cn] + s[1+cn])*k1;
+ dst[i] = s0; dst[i+1] = s1;
+ }
+ }
+ }
+ else if( ksize == 5 )
+ {
+ int k0 = kx[0], k1 = kx[1], k2 = kx[2];
+ if( k0 == 6*16 && k1 == 4*16 && k2 == 1*16 )
+ for( ; i <= width - 2; i += 2, s += 2 )
+ {
+ int s0 = (s[0]*6 + (s[-cn] + s[cn])*4 + (s[-cn*2] + s[cn*2])*1) << 4;
+ int s1 = (s[1]*6 + (s[1-cn] + s[1+cn])*4 + (s[1-cn*2] + s[1+cn*2])*1) << 4;
+ dst[i] = s0; dst[i+1] = s1;
+ }
+ else
+ for( ; i <= width - 2; i += 2, s += 2 )
+ {
+ int s0 = s[0]*k0 + (s[-cn] + s[cn])*k1 + (s[-cn*2] + s[cn*2])*k2;
+ int s1 = s[1]*k0 + (s[1-cn] + s[1+cn])*k1 + (s[1-cn*2] + s[1+cn*2])*k2;
+ dst[i] = s0; dst[i+1] = s1;
+ }
+ }
+ else
+ for( ; i <= width - 4; i += 4, s += 4 )
+ {
+ int f = kx[0];
+ int s0 = f*s[0], s1 = f*s[1], s2 = f*s[2], s3 = f*s[3];
+ for( k = 1, j = cn; k <= ksize2; k++, j += cn )
+ {
+ f = kx[k];
+ s0 += f*(s[j] + s[-j]); s1 += f*(s[j+1] + s[-j+1]);
+ s2 += f*(s[j+2] + s[-j+2]); s3 += f*(s[j+3] + s[-j+3]);
+ }
+
+ dst[i] = s0; dst[i+1] = s1;
+ dst[i+2] = s2; dst[i+3] = s3;
+ }
+
+ for( ; i < width; i++, s++ )
+ {
+ int s0 = kx[0]*s[0];
+ for( k = 1, j = cn; k <= ksize2; k++, j += cn )
+ s0 += kx[k]*(s[j] + s[-j]);
+ dst[i] = s0;
+ }
+ }
+ else
+ {
+ if( ksize == 3 && kx[0] == 0 && kx[1] == 1 )
+ for( ; i <= width - 2; i += 2, s += 2 )
+ {
+ int s0 = s[cn] - s[-cn], s1 = s[1+cn] - s[1-cn];
+ dst[i] = s0; dst[i+1] = s1;
+ }
+ else
+ for( ; i <= width - 4; i += 4, s += 4 )
+ {
+ int s0 = 0, s1 = 0, s2 = 0, s3 = 0;
+ for( k = 1, j = cn; k <= ksize2; k++, j += cn )
+ {
+ int f = kx[k];
+ s0 += f*(s[j] - s[-j]); s1 += f*(s[j+1] - s[-j+1]);
+ s2 += f*(s[j+2] - s[-j+2]); s3 += f*(s[j+3] - s[-j+3]);
+ }
+
+ dst[i] = s0; dst[i+1] = s1;
+ dst[i+2] = s2; dst[i+3] = s3;
+ }
+
+ for( ; i < width; i++, s++ )
+ {
+ int s0 = kx[0]*s[0];
+ for( k = 1, j = cn; k <= ksize2; k++, j += cn )
+ s0 += kx[k]*(s[j] - s[-j]);
+ dst[i] = s0;
+ }
+ }
+}
+
+
+#define ICV_FILTER_ROW( flavor, srctype, dsttype, load_macro ) \
+static void \
+icvFilterRow_##flavor(const srctype* src, dsttype* dst, void*params)\
+{ \
+ const CvSepFilter* state = (const CvSepFilter*)params; \
+ const CvMat* _kx = state->get_x_kernel(); \
+ const dsttype* kx = (const dsttype*)(_kx->data.ptr); \
+ int ksize = _kx->cols + _kx->rows - 1; \
+ int i = 0, k, width = state->get_width(); \
+ int cn = CV_MAT_CN(state->get_src_type()); \
+ const srctype* s; \
+ \
+ width *= cn; \
+ \
+ for( ; i <= width - 4; i += 4 ) \
+ { \
+ double f = kx[0]; \
+ double s0=f*load_macro(src[i]), s1=f*load_macro(src[i+1]), \
+ s2=f*load_macro(src[i+2]), s3=f*load_macro(src[i+3]);\
+ for( k = 1, s = src + i + cn; k < ksize; k++, s += cn ) \
+ { \
+ f = kx[k]; \
+ s0 += f*load_macro(s[0]); \
+ s1 += f*load_macro(s[1]); \
+ s2 += f*load_macro(s[2]); \
+ s3 += f*load_macro(s[3]); \
+ } \
+ dst[i] = (dsttype)s0; dst[i+1] = (dsttype)s1; \
+ dst[i+2] = (dsttype)s2; dst[i+3] = (dsttype)s3; \
+ } \
+ \
+ for( ; i < width; i++ ) \
+ { \
+ double s0 = (double)kx[0]*load_macro(src[i]); \
+ for( k = 1, s = src + i + cn; k < ksize; k++, s += cn ) \
+ s0 += (double)kx[k]*load_macro(s[0]); \
+ dst[i] = (dsttype)s0; \
+ } \
+}
+
+
+ICV_FILTER_ROW( 8u32f, uchar, float, CV_8TO32F )
+ICV_FILTER_ROW( 16s32f, short, float, CV_NOP )
+ICV_FILTER_ROW( 16u32f, ushort, float, CV_NOP )
+ICV_FILTER_ROW( 32f, float, float, CV_NOP )
+
+
+#define ICV_FILTER_ROW_SYMM( flavor, srctype, dsttype, load_macro ) \
+static void \
+icvFilterRowSymm_##flavor( const srctype* src, \
+ dsttype* dst, void* params ) \
+{ \
+ const CvSepFilter* state = (const CvSepFilter*)params; \
+ const CvMat* _kx = state->get_x_kernel(); \
+ const dsttype* kx = (const dsttype*)(_kx->data.ptr); \
+ int ksize = _kx->cols + _kx->rows - 1; \
+ int i = 0, j, k, width = state->get_width(); \
+ int cn = CV_MAT_CN(state->get_src_type()); \
+ int is_symm=state->get_x_kernel_flags()&CvSepFilter::SYMMETRICAL;\
+ int ksize2 = ksize/2, ksize2n = ksize2*cn; \
+ const srctype* s = src + ksize2n; \
+ \
+ kx += ksize2; \
+ width *= cn; \
+ \
+ if( is_symm ) \
+ { \
+ for( ; i <= width - 4; i += 4, s += 4 ) \
+ { \
+ double f = kx[0]; \
+ double s0=f*load_macro(s[0]), s1=f*load_macro(s[1]), \
+ s2=f*load_macro(s[2]), s3=f*load_macro(s[3]); \
+ for( k = 1, j = cn; k <= ksize2; k++, j += cn ) \
+ { \
+ f = kx[k]; \
+ s0 += f*load_macro(s[j] + s[-j]); \
+ s1 += f*load_macro(s[j+1] + s[-j+1]); \
+ s2 += f*load_macro(s[j+2] + s[-j+2]); \
+ s3 += f*load_macro(s[j+3] + s[-j+3]); \
+ } \
+ \
+ dst[i] = (dsttype)s0; dst[i+1] = (dsttype)s1; \
+ dst[i+2] = (dsttype)s2; dst[i+3] = (dsttype)s3; \
+ } \
+ \
+ for( ; i < width; i++, s++ ) \
+ { \
+ double s0 = (double)kx[0]*load_macro(s[0]); \
+ for( k = 1, j = cn; k <= ksize2; k++, j += cn ) \
+ s0 += (double)kx[k]*load_macro(s[j] + s[-j]); \
+ dst[i] = (dsttype)s0; \
+ } \
+ } \
+ else \
+ { \
+ for( ; i <= width - 4; i += 4, s += 4 ) \
+ { \
+ double s0 = 0, s1 = 0, s2 = 0, s3 = 0; \
+ for( k = 1, j = cn; k <= ksize2; k++, j += cn ) \
+ { \
+ double f = kx[k]; \
+ s0 += f*load_macro(s[j] - s[-j]); \
+ s1 += f*load_macro(s[j+1] - s[-j+1]); \
+ s2 += f*load_macro(s[j+2] - s[-j+2]); \
+ s3 += f*load_macro(s[j+3] - s[-j+3]); \
+ } \
+ \
+ dst[i] = (dsttype)s0; dst[i+1] = (dsttype)s1; \
+ dst[i+2] = (dsttype)s2; dst[i+3] = (dsttype)s3; \
+ } \
+ \
+ for( ; i < width; i++, s++ ) \
+ { \
+ double s0 = 0; \
+ for( k = 1, j = cn; k <= ksize2; k++, j += cn ) \
+ s0 += (double)kx[k]*load_macro(s[j] - s[-j]); \
+ dst[i] = (dsttype)s0; \
+ } \
+ } \
+}
+
+
+ICV_FILTER_ROW_SYMM( 8u32f, uchar, float, CV_8TO32F )
+ICV_FILTER_ROW_SYMM( 16s32f, short, float, CV_NOP )
+ICV_FILTER_ROW_SYMM( 16u32f, ushort, float, CV_NOP )
+
+static void
+icvFilterRowSymm_32f( const float* src, float* dst, void* params )
+{
+ const CvSepFilter* state = (const CvSepFilter*)params;
+ const CvMat* _kx = state->get_x_kernel();
+ const float* kx = _kx->data.fl;
+ int ksize = _kx->cols + _kx->rows - 1;
+ int i = 0, j, k, width = state->get_width();
+ int cn = CV_MAT_CN(state->get_src_type());
+ int ksize2 = ksize/2, ksize2n = ksize2*cn;
+ int is_symm = state->get_x_kernel_flags() & CvSepFilter::SYMMETRICAL;
+ const float* s = src + ksize2n;
+
+ kx += ksize2;
+ width *= cn;
+
+ if( is_symm )
+ {
+ if( ksize == 3 && fabs(kx[0]-2.) <= FLT_EPSILON && fabs(kx[1]-1.) <= FLT_EPSILON )
+ for( ; i <= width - 2; i += 2, s += 2 )
+ {
+ float s0 = s[-cn] + s[0]*2 + s[cn], s1 = s[1-cn] + s[1]*2 + s[1+cn];
+ dst[i] = s0; dst[i+1] = s1;
+ }
+ else if( ksize == 3 && fabs(kx[0]-10.) <= FLT_EPSILON && fabs(kx[1]-3.) <= FLT_EPSILON )
+ for( ; i <= width - 2; i += 2, s += 2 )
+ {
+ float s0 = s[0]*10 + (s[-cn] + s[cn])*3, s1 = s[1]*10 + (s[1-cn] + s[1+cn])*3;
+ dst[i] = s0; dst[i+1] = s1;
+ }
+ else
+ for( ; i <= width - 4; i += 4, s += 4 )
+ {
+ double f = kx[0];
+ double s0 = f*s[0], s1 = f*s[1], s2 = f*s[2], s3 = f*s[3];
+ for( k = 1, j = cn; k <= ksize2; k++, j += cn )
+ {
+ f = kx[k];
+ s0 += f*(s[j] + s[-j]); s1 += f*(s[j+1] + s[-j+1]);
+ s2 += f*(s[j+2] + s[-j+2]); s3 += f*(s[j+3] + s[-j+3]);
+ }
+
+ dst[i] = (float)s0; dst[i+1] = (float)s1;
+ dst[i+2] = (float)s2; dst[i+3] = (float)s3;
+ }
+
+ for( ; i < width; i++, s++ )
+ {
+ double s0 = (double)kx[0]*s[0];
+ for( k = 1, j = cn; k <= ksize2; k++, j += cn )
+ s0 += (double)kx[k]*(s[j] + s[-j]);
+ dst[i] = (float)s0;
+ }
+ }
+ else
+ {
+ if( ksize == 3 && fabs(kx[0]) <= FLT_EPSILON && fabs(kx[1]-1.) <= FLT_EPSILON )
+ for( ; i <= width - 2; i += 2, s += 2 )
+ {
+ float s0 = s[cn] - s[-cn], s1 = s[1+cn] - s[1-cn];
+ dst[i] = s0; dst[i+1] = s1;
+ }
+ else
+ for( ; i <= width - 4; i += 4, s += 4 )
+ {
+ double s0 = 0, s1 = 0, s2 = 0, s3 = 0;
+ for( k = 1, j = cn; k <= ksize2; k++, j += cn )
+ {
+ double f = kx[k];
+ s0 += f*(s[j] - s[-j]); s1 += f*(s[j+1] - s[-j+1]);
+ s2 += f*(s[j+2] - s[-j+2]); s3 += f*(s[j+3] - s[-j+3]);
+ }
+
+ dst[i] = (float)s0; dst[i+1] = (float)s1;
+ dst[i+2] = (float)s2; dst[i+3] = (float)s3;
+ }
+
+ for( ; i < width; i++, s++ )
+ {
+ double s0 = (double)kx[0]*s[0];
+ for( k = 1, j = cn; k <= ksize2; k++, j += cn )
+ s0 += (double)kx[k]*(s[j] - s[-j]);
+ dst[i] = (float)s0;
+ }
+ }
+}
+
+
+static void
+icvFilterColSymm_32s8u( const int** src, uchar* dst, int dst_step, int count, void* params )
+{
+ const CvSepFilter* state = (const CvSepFilter*)params;
+ const CvMat* _ky = state->get_y_kernel();
+ const int* ky = _ky->data.i;
+ int ksize = _ky->cols + _ky->rows - 1, ksize2 = ksize/2;
+ int i, k, width = state->get_width();
+ int cn = CV_MAT_CN(state->get_src_type());
+
+ width *= cn;
+ src += ksize2;
+ ky += ksize2;
+
+ for( ; count--; dst += dst_step, src++ )
+ {
+ if( ksize == 3 )
+ {
+ const int* sptr0 = src[-1], *sptr1 = src[0], *sptr2 = src[1];
+ int k0 = ky[0], k1 = ky[1];
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = sptr1[i]*k0 + (sptr0[i] + sptr2[i])*k1;
+ int s1 = sptr1[i+1]*k0 + (sptr0[i+1] + sptr2[i+1])*k1;
+ s0 = CV_DESCALE(s0, FILTER_BITS*2);
+ s1 = CV_DESCALE(s1, FILTER_BITS*2);
+ dst[i] = (uchar)s0; dst[i+1] = (uchar)s1;
+ }
+ }
+ else if( ksize == 5 )
+ {
+ const int* sptr0 = src[-2], *sptr1 = src[-1],
+ *sptr2 = src[0], *sptr3 = src[1], *sptr4 = src[2];
+ int k0 = ky[0], k1 = ky[1], k2 = ky[2];
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = sptr2[i]*k0 + (sptr1[i] + sptr3[i])*k1 + (sptr0[i] + sptr4[i])*k2;
+ int s1 = sptr2[i+1]*k0 + (sptr1[i+1] + sptr3[i+1])*k1 + (sptr0[i+1] + sptr4[i+1])*k2;
+ s0 = CV_DESCALE(s0, FILTER_BITS*2);
+ s1 = CV_DESCALE(s1, FILTER_BITS*2);
+ dst[i] = (uchar)s0; dst[i+1] = (uchar)s1;
+ }
+ }
+ else
+ for( i = 0; i <= width - 4; i += 4 )
+ {
+ int f = ky[0];
+ const int* sptr = src[0] + i, *sptr2;
+ int s0 = f*sptr[0], s1 = f*sptr[1], s2 = f*sptr[2], s3 = f*sptr[3];
+ for( k = 1; k <= ksize2; k++ )
+ {
+ sptr = src[k] + i;
+ sptr2 = src[-k] + i;
+ f = ky[k];
+ s0 += f*(sptr[0] + sptr2[0]);
+ s1 += f*(sptr[1] + sptr2[1]);
+ s2 += f*(sptr[2] + sptr2[2]);
+ s3 += f*(sptr[3] + sptr2[3]);
+ }
+
+ s0 = CV_DESCALE(s0, FILTER_BITS*2);
+ s1 = CV_DESCALE(s1, FILTER_BITS*2);
+ dst[i] = (uchar)s0; dst[i+1] = (uchar)s1;
+ s2 = CV_DESCALE(s2, FILTER_BITS*2);
+ s3 = CV_DESCALE(s3, FILTER_BITS*2);
+ dst[i+2] = (uchar)s2; dst[i+3] = (uchar)s3;
+ }
+
+ for( ; i < width; i++ )
+ {
+ int s0 = ky[0]*src[0][i];
+ for( k = 1; k <= ksize2; k++ )
+ s0 += ky[k]*(src[k][i] + src[-k][i]);
+
+ s0 = CV_DESCALE(s0, FILTER_BITS*2);
+ dst[i] = (uchar)s0;
+ }
+ }
+}
+
+
+static void
+icvFilterColSymm_32s16s( const int** src, short* dst,
+ int dst_step, int count, void* params )
+{
+ const CvSepFilter* state = (const CvSepFilter*)params;
+ const CvMat* _ky = state->get_y_kernel();
+ const int* ky = (const int*)_ky->data.ptr;
+ int ksize = _ky->cols + _ky->rows - 1, ksize2 = ksize/2;
+ int i = 0, k, width = state->get_width();
+ int cn = CV_MAT_CN(state->get_src_type());
+ int is_symm = state->get_y_kernel_flags() & CvSepFilter::SYMMETRICAL;
+ int is_1_2_1 = is_symm && ksize == 3 && ky[1] == 2 && ky[2] == 1;
+ int is_3_10_3 = is_symm && ksize == 3 && ky[1] == 10 && ky[2] == 3;
+ int is_m1_0_1 = !is_symm && ksize == 3 && ky[1] == 0 &&
+ ky[2]*ky[2] == 1 ? (ky[2] > 0 ? 1 : -1) : 0;
+
+ width *= cn;
+ src += ksize2;
+ ky += ksize2;
+ dst_step /= sizeof(dst[0]);
+
+ if( is_symm )
+ {
+ for( ; count--; dst += dst_step, src++ )
+ {
+ if( is_1_2_1 )
+ {
+ const int *src0 = src[-1], *src1 = src[0], *src2 = src[1];
+
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = src0[i] + src1[i]*2 + src2[i],
+ s1 = src0[i+1] + src1[i+1]*2 + src2[i+1];
+
+ dst[i] = (short)s0; dst[i+1] = (short)s1;
+ }
+ }
+ else if( is_3_10_3 )
+ {
+ const int *src0 = src[-1], *src1 = src[0], *src2 = src[1];
+
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = src1[i]*10 + (src0[i] + src2[i])*3,
+ s1 = src1[i+1]*10 + (src0[i+1] + src2[i+1])*3;
+
+ dst[i] = (short)s0; dst[i+1] = (short)s1;
+ }
+ }
+ else
+ for( i = 0; i <= width - 4; i += 4 )
+ {
+ int f = ky[0];
+ const int* sptr = src[0] + i, *sptr2;
+ int s0 = f*sptr[0], s1 = f*sptr[1],
+ s2 = f*sptr[2], s3 = f*sptr[3];
+ for( k = 1; k <= ksize2; k++ )
+ {
+ sptr = src[k] + i; sptr2 = src[-k] + i; f = ky[k];
+ s0 += f*(sptr[0] + sptr2[0]); s1 += f*(sptr[1] + sptr2[1]);
+ s2 += f*(sptr[2] + sptr2[2]); s3 += f*(sptr[3] + sptr2[3]);
+ }
+
+ dst[i] = CV_CAST_16S(s0); dst[i+1] = CV_CAST_16S(s1);
+ dst[i+2] = CV_CAST_16S(s2); dst[i+3] = CV_CAST_16S(s3);
+ }
+
+ for( ; i < width; i++ )
+ {
+ int s0 = ky[0]*src[0][i];
+ for( k = 1; k <= ksize2; k++ )
+ s0 += ky[k]*(src[k][i] + src[-k][i]);
+ dst[i] = CV_CAST_16S(s0);
+ }
+ }
+ }
+ else
+ {
+ for( ; count--; dst += dst_step, src++ )
+ {
+ if( is_m1_0_1 )
+ {
+ const int *src0 = src[-is_m1_0_1], *src2 = src[is_m1_0_1];
+
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = src2[i] - src0[i], s1 = src2[i+1] - src0[i+1];
+ dst[i] = (short)s0; dst[i+1] = (short)s1;
+ }
+ }
+ else
+ for( i = 0; i <= width - 4; i += 4 )
+ {
+ int f = ky[0];
+ const int* sptr = src[0] + i, *sptr2;
+ int s0 = 0, s1 = 0, s2 = 0, s3 = 0;
+ for( k = 1; k <= ksize2; k++ )
+ {
+ sptr = src[k] + i; sptr2 = src[-k] + i; f = ky[k];
+ s0 += f*(sptr[0] - sptr2[0]); s1 += f*(sptr[1] - sptr2[1]);
+ s2 += f*(sptr[2] - sptr2[2]); s3 += f*(sptr[3] - sptr2[3]);
+ }
+
+ dst[i] = CV_CAST_16S(s0); dst[i+1] = CV_CAST_16S(s1);
+ dst[i+2] = CV_CAST_16S(s2); dst[i+3] = CV_CAST_16S(s3);
+ }
+
+ for( ; i < width; i++ )
+ {
+ int s0 = ky[0]*src[0][i];
+ for( k = 1; k <= ksize2; k++ )
+ s0 += ky[k]*(src[k][i] - src[-k][i]);
+ dst[i] = CV_CAST_16S(s0);
+ }
+ }
+ }
+}
+
+
+#define ICV_FILTER_COL( flavor, srctype, dsttype, worktype, \
+ cast_macro1, cast_macro2 ) \
+static void \
+icvFilterCol_##flavor( const srctype** src, dsttype* dst, \
+ int dst_step, int count, void* params ) \
+{ \
+ const CvSepFilter* state = (const CvSepFilter*)params; \
+ const CvMat* _ky = state->get_y_kernel(); \
+ const srctype* ky = (const srctype*)_ky->data.ptr; \
+ int ksize = _ky->cols + _ky->rows - 1; \
+ int i, k, width = state->get_width(); \
+ int cn = CV_MAT_CN(state->get_src_type()); \
+ \
+ width *= cn; \
+ dst_step /= sizeof(dst[0]); \
+ \
+ for( ; count--; dst += dst_step, src++ ) \
+ { \
+ for( i = 0; i <= width - 4; i += 4 ) \
+ { \
+ double f = ky[0]; \
+ const srctype* sptr = src[0] + i; \
+ double s0 = f*sptr[0], s1 = f*sptr[1], \
+ s2 = f*sptr[2], s3 = f*sptr[3]; \
+ worktype t0, t1; \
+ for( k = 1; k < ksize; k++ ) \
+ { \
+ sptr = src[k] + i; f = ky[k]; \
+ s0 += f*sptr[0]; s1 += f*sptr[1]; \
+ s2 += f*sptr[2]; s3 += f*sptr[3]; \
+ } \
+ \
+ t0 = cast_macro1(s0); t1 = cast_macro1(s1); \
+ dst[i]=cast_macro2(t0); dst[i+1]=cast_macro2(t1); \
+ t0 = cast_macro1(s2); t1 = cast_macro1(s3); \
+ dst[i+2]=cast_macro2(t0); dst[i+3]=cast_macro2(t1); \
+ } \
+ \
+ for( ; i < width; i++ ) \
+ { \
+ double s0 = (double)ky[0]*src[0][i]; \
+ worktype t0; \
+ for( k = 1; k < ksize; k++ ) \
+ s0 += (double)ky[k]*src[k][i]; \
+ t0 = cast_macro1(s0); \
+ dst[i] = cast_macro2(t0); \
+ } \
+ } \
+}
+
+
+ICV_FILTER_COL( 32f8u, float, uchar, int, cvRound, CV_CAST_8U )
+ICV_FILTER_COL( 32f16s, float, short, int, cvRound, CV_CAST_16S )
+ICV_FILTER_COL( 32f16u, float, ushort, int, cvRound, CV_CAST_16U )
+
+#define ICV_FILTER_COL_SYMM( flavor, srctype, dsttype, worktype, \
+ cast_macro1, cast_macro2 ) \
+static void \
+icvFilterColSymm_##flavor( const srctype** src, dsttype* dst, \
+ int dst_step, int count, void* params ) \
+{ \
+ const CvSepFilter* state = (const CvSepFilter*)params; \
+ const CvMat* _ky = state->get_y_kernel(); \
+ const srctype* ky = (const srctype*)_ky->data.ptr; \
+ int ksize = _ky->cols + _ky->rows - 1, ksize2 = ksize/2; \
+ int i, k, width = state->get_width(); \
+ int cn = CV_MAT_CN(state->get_src_type()); \
+ int is_symm = state->get_y_kernel_flags() & CvSepFilter::SYMMETRICAL;\
+ \
+ width *= cn; \
+ src += ksize2; \
+ ky += ksize2; \
+ dst_step /= sizeof(dst[0]); \
+ \
+ if( is_symm ) \
+ { \
+ for( ; count--; dst += dst_step, src++ ) \
+ { \
+ for( i = 0; i <= width - 4; i += 4 ) \
+ { \
+ double f = ky[0]; \
+ const srctype* sptr = src[0] + i, *sptr2; \
+ double s0 = f*sptr[0], s1 = f*sptr[1], \
+ s2 = f*sptr[2], s3 = f*sptr[3]; \
+ worktype t0, t1; \
+ for( k = 1; k <= ksize2; k++ ) \
+ { \
+ sptr = src[k] + i; \
+ sptr2 = src[-k] + i; \
+ f = ky[k]; \
+ s0 += f*(sptr[0] + sptr2[0]); \
+ s1 += f*(sptr[1] + sptr2[1]); \
+ s2 += f*(sptr[2] + sptr2[2]); \
+ s3 += f*(sptr[3] + sptr2[3]); \
+ } \
+ \
+ t0 = cast_macro1(s0); t1 = cast_macro1(s1); \
+ dst[i]=cast_macro2(t0); dst[i+1]=cast_macro2(t1); \
+ t0 = cast_macro1(s2); t1 = cast_macro1(s3); \
+ dst[i+2]=cast_macro2(t0); dst[i+3]=cast_macro2(t1); \
+ } \
+ \
+ for( ; i < width; i++ ) \
+ { \
+ double s0 = (double)ky[0]*src[0][i]; \
+ worktype t0; \
+ for( k = 1; k <= ksize2; k++ ) \
+ s0 += (double)ky[k]*(src[k][i] + src[-k][i]); \
+ t0 = cast_macro1(s0); \
+ dst[i] = cast_macro2(t0); \
+ } \
+ } \
+ } \
+ else \
+ { \
+ for( ; count--; dst += dst_step, src++ ) \
+ { \
+ for( i = 0; i <= width - 4; i += 4 ) \
+ { \
+ double f = ky[0]; \
+ const srctype* sptr = src[0] + i, *sptr2; \
+ double s0 = 0, s1 = 0, s2 = 0, s3 = 0; \
+ worktype t0, t1; \
+ for( k = 1; k <= ksize2; k++ ) \
+ { \
+ sptr = src[k] + i; \
+ sptr2 = src[-k] + i; \
+ f = ky[k]; \
+ s0 += f*(sptr[0] - sptr2[0]); \
+ s1 += f*(sptr[1] - sptr2[1]); \
+ s2 += f*(sptr[2] - sptr2[2]); \
+ s3 += f*(sptr[3] - sptr2[3]); \
+ } \
+ \
+ t0 = cast_macro1(s0); t1 = cast_macro1(s1); \
+ dst[i]=cast_macro2(t0); dst[i+1]=cast_macro2(t1); \
+ t0 = cast_macro1(s2); t1 = cast_macro1(s3); \
+ dst[i+2]=cast_macro2(t0); dst[i+3]=cast_macro2(t1); \
+ } \
+ \
+ for( ; i < width; i++ ) \
+ { \
+ double s0 = (double)ky[0]*src[0][i]; \
+ worktype t0; \
+ for( k = 1; k <= ksize2; k++ ) \
+ s0 += (double)ky[k]*(src[k][i] - src[-k][i]); \
+ t0 = cast_macro1(s0); \
+ dst[i] = cast_macro2(t0); \
+ } \
+ } \
+ } \
+}
+
+
+ICV_FILTER_COL_SYMM( 32f8u, float, uchar, int, cvRound, CV_CAST_8U )
+ICV_FILTER_COL_SYMM( 32f16s, float, short, int, cvRound, CV_CAST_16S )
+ICV_FILTER_COL_SYMM( 32f16u, float, ushort, int, cvRound, CV_CAST_16U )
+
+
+static void
+icvFilterCol_32f( const float** src, float* dst,
+ int dst_step, int count, void* params )
+{
+ const CvSepFilter* state = (const CvSepFilter*)params;
+ const CvMat* _ky = state->get_y_kernel();
+ const float* ky = (const float*)_ky->data.ptr;
+ int ksize = _ky->cols + _ky->rows - 1;
+ int i, k, width = state->get_width();
+ int cn = CV_MAT_CN(state->get_src_type());
+
+ width *= cn;
+ dst_step /= sizeof(dst[0]);
+
+ for( ; count--; dst += dst_step, src++ )
+ {
+ for( i = 0; i <= width - 4; i += 4 )
+ {
+ double f = ky[0];
+ const float* sptr = src[0] + i;
+ double s0 = f*sptr[0], s1 = f*sptr[1],
+ s2 = f*sptr[2], s3 = f*sptr[3];
+ for( k = 1; k < ksize; k++ )
+ {
+ sptr = src[k] + i; f = ky[k];
+ s0 += f*sptr[0]; s1 += f*sptr[1];
+ s2 += f*sptr[2]; s3 += f*sptr[3];
+ }
+
+ dst[i] = (float)s0; dst[i+1] = (float)s1;
+ dst[i+2] = (float)s2; dst[i+3] = (float)s3;
+ }
+
+ for( ; i < width; i++ )
+ {
+ double s0 = (double)ky[0]*src[0][i];
+ for( k = 1; k < ksize; k++ )
+ s0 += (double)ky[k]*src[k][i];
+ dst[i] = (float)s0;
+ }
+ }
+}
+
+
+static void
+icvFilterColSymm_32f( const float** src, float* dst,
+ int dst_step, int count, void* params )
+{
+ const CvSepFilter* state = (const CvSepFilter*)params;
+ const CvMat* _ky = state->get_y_kernel();
+ const float* ky = (const float*)_ky->data.ptr;
+ int ksize = _ky->cols + _ky->rows - 1, ksize2 = ksize/2;
+ int i = 0, k, width = state->get_width();
+ int cn = CV_MAT_CN(state->get_src_type());
+ int is_symm = state->get_y_kernel_flags() & CvSepFilter::SYMMETRICAL;
+ int is_1_2_1 = is_symm && ksize == 3 &&
+ fabs(ky[1] - 2.) <= FLT_EPSILON && fabs(ky[2] - 1.) <= FLT_EPSILON;
+ int is_3_10_3 = is_symm && ksize == 3 &&
+ fabs(ky[1] - 10.) <= FLT_EPSILON && fabs(ky[2] - 3.) <= FLT_EPSILON;
+ int is_m1_0_1 = !is_symm && ksize == 3 &&
+ fabs(ky[1]) <= FLT_EPSILON && fabs(ky[2]*ky[2] - 1.) <= FLT_EPSILON ?
+ (ky[2] > 0 ? 1 : -1) : 0;
+
+ width *= cn;
+ src += ksize2;
+ ky += ksize2;
+ dst_step /= sizeof(dst[0]);
+
+ if( is_symm )
+ {
+ for( ; count--; dst += dst_step, src++ )
+ {
+ if( is_1_2_1 )
+ {
+ const float *src0 = src[-1], *src1 = src[0], *src2 = src[1];
+
+ for( i = 0; i <= width - 4; i += 4 )
+ {
+ float s0 = src0[i] + src1[i]*2 + src2[i],
+ s1 = src0[i+1] + src1[i+1]*2 + src2[i+1],
+ s2 = src0[i+2] + src1[i+2]*2 + src2[i+2],
+ s3 = src0[i+3] + src1[i+3]*2 + src2[i+3];
+
+ dst[i] = s0; dst[i+1] = s1;
+ dst[i+2] = s2; dst[i+3] = s3;
+ }
+ }
+ else if( is_3_10_3 )
+ {
+ const float *src0 = src[-1], *src1 = src[0], *src2 = src[1];
+
+ for( i = 0; i <= width - 4; i += 4 )
+ {
+ float s0 = src1[i]*10 + (src0[i] + src2[i])*3,
+ s1 = src1[i+1]*10 + (src0[i+1] + src2[i+1])*3,
+ s2 = src1[i+2]*10 + (src0[i+2] + src2[i+2])*3,
+ s3 = src1[i+3]*10 + (src0[i+3] + src2[i+3])*3;
+
+ dst[i] = s0; dst[i+1] = s1;
+ dst[i+2] = s2; dst[i+3] = s3;
+ }
+ }
+ else
+ for( i = 0; i <= width - 4; i += 4 )
+ {
+ double f = ky[0];
+ const float* sptr = src[0] + i, *sptr2;
+ double s0 = f*sptr[0], s1 = f*sptr[1],
+ s2 = f*sptr[2], s3 = f*sptr[3];
+ for( k = 1; k <= ksize2; k++ )
+ {
+ sptr = src[k] + i; sptr2 = src[-k] + i; f = ky[k];
+ s0 += f*(sptr[0] + sptr2[0]); s1 += f*(sptr[1] + sptr2[1]);
+ s2 += f*(sptr[2] + sptr2[2]); s3 += f*(sptr[3] + sptr2[3]);
+ }
+
+ dst[i] = (float)s0; dst[i+1] = (float)s1;
+ dst[i+2] = (float)s2; dst[i+3] = (float)s3;
+ }
+
+ for( ; i < width; i++ )
+ {
+ double s0 = (double)ky[0]*src[0][i];
+ for( k = 1; k <= ksize2; k++ )
+ s0 += (double)ky[k]*(src[k][i] + src[-k][i]);
+ dst[i] = (float)s0;
+ }
+ }
+ }
+ else
+ {
+ for( ; count--; dst += dst_step, src++ )
+ {
+ if( is_m1_0_1 )
+ {
+ const float *src0 = src[-is_m1_0_1], *src2 = src[is_m1_0_1];
+
+ for( i = 0; i <= width - 4; i += 4 )
+ {
+ float s0 = src2[i] - src0[i], s1 = src2[i+1] - src0[i+1],
+ s2 = src2[i+2] - src0[i+2], s3 = src2[i+3] - src0[i+3];
+ dst[i] = s0; dst[i+1] = s1;
+ dst[i+2] = s2; dst[i+3] = s3;
+ }
+ }
+ else
+ for( i = 0; i <= width - 4; i += 4 )
+ {
+ double f = ky[0];
+ const float* sptr = src[0] + i, *sptr2;
+ double s0 = 0, s1 = 0, s2 = 0, s3 = 0;
+ for( k = 1; k <= ksize2; k++ )
+ {
+ sptr = src[k] + i; sptr2 = src[-k] + i; f = ky[k];
+ s0 += f*(sptr[0] - sptr2[0]); s1 += f*(sptr[1] - sptr2[1]);
+ s2 += f*(sptr[2] - sptr2[2]); s3 += f*(sptr[3] - sptr2[3]);
+ }
+
+ dst[i] = (float)s0; dst[i+1] = (float)s1;
+ dst[i+2] = (float)s2; dst[i+3] = (float)s3;
+ }
+
+ for( ; i < width; i++ )
+ {
+ double s0 = (double)ky[0]*src[0][i];
+ for( k = 1; k <= ksize2; k++ )
+ s0 += (double)ky[k]*(src[k][i] - src[-k][i]);
+ dst[i] = (float)s0;
+ }
+ }
+ }
+}
+
+
+#define SMALL_GAUSSIAN_SIZE 7
+
+void CvSepFilter::init_gaussian_kernel( CvMat* kernel, double sigma )
+{
+ static const float small_gaussian_tab[][SMALL_GAUSSIAN_SIZE/2+1] =
+ {
+ {1.f},
+ {0.5f, 0.25f},
+ {0.375f, 0.25f, 0.0625f},
+ {0.28125f, 0.21875f, 0.109375f, 0.03125f}
+ };
+
+ CV_FUNCNAME( "CvSepFilter::init_gaussian_kernel" );
+
+ __BEGIN__;
+
+ int type, i, n, step;
+ const float* fixed_kernel = 0;
+ double sigmaX, scale2X, sum;
+ float* cf;
+ double* cd;
+
+ if( !CV_IS_MAT(kernel) )
+ CV_ERROR( CV_StsBadArg, "kernel is not a valid matrix" );
+
+ type = CV_MAT_TYPE(kernel->type);
+
+ if( (kernel->cols != 1 && kernel->rows != 1) ||
+ (kernel->cols + kernel->rows - 1) % 2 == 0 ||
+ (type != CV_32FC1 && type != CV_64FC1) )
+ CV_ERROR( CV_StsBadSize, "kernel should be 1D floating-point vector of odd (2*k+1) size" );
+
+ n = kernel->cols + kernel->rows - 1;
+
+ if( n <= SMALL_GAUSSIAN_SIZE && sigma <= 0 )
+ fixed_kernel = small_gaussian_tab[n>>1];
+
+ sigmaX = sigma > 0 ? sigma : (n/2 - 1)*0.3 + 0.8;
+ scale2X = -0.5/(sigmaX*sigmaX);
+ step = kernel->rows == 1 ? 1 : kernel->step/CV_ELEM_SIZE1(type);
+ cf = kernel->data.fl;
+ cd = kernel->data.db;
+
+ sum = fixed_kernel ? -fixed_kernel[0] : -1.;
+
+ for( i = 0; i <= n/2; i++ )
+ {
+ double t = fixed_kernel ? (double)fixed_kernel[i] : exp(scale2X*i*i);
+ if( type == CV_32FC1 )
+ {
+ cf[(n/2+i)*step] = (float)t;
+ sum += cf[(n/2+i)*step]*2;
+ }
+ else
+ {
+ cd[(n/2+i)*step] = t;
+ sum += cd[(n/2+i)*step]*2;
+ }
+ }
+
+ sum = 1./sum;
+ for( i = 0; i <= n/2; i++ )
+ {
+ if( type == CV_32FC1 )
+ cf[(n/2+i)*step] = cf[(n/2-i)*step] = (float)(cf[(n/2+i)*step]*sum);
+ else
+ cd[(n/2+i)*step] = cd[(n/2-i)*step] = cd[(n/2+i)*step]*sum;
+ }
+
+ __END__;
+}
+
+
+void CvSepFilter::init_sobel_kernel( CvMat* _kx, CvMat* _ky, int dx, int dy, int flags )
+{
+ CV_FUNCNAME( "CvSepFilter::init_sobel_kernel" );
+
+ __BEGIN__;
+
+ int i, j, k, msz;
+ int* kerI;
+ bool normalize = (flags & NORMALIZE_KERNEL) != 0;
+ bool flip = (flags & FLIP_KERNEL) != 0;
+
+ if( !CV_IS_MAT(_kx) || !CV_IS_MAT(_ky) )
+ CV_ERROR( CV_StsBadArg, "One of the kernel matrices is not valid" );
+
+ msz = MAX( _kx->cols + _kx->rows, _ky->cols + _ky->rows );
+ if( msz > 32 )
+ CV_ERROR( CV_StsOutOfRange, "Too large kernel size" );
+
+ kerI = (int*)cvStackAlloc( msz*sizeof(kerI[0]) );
+
+ if( dx < 0 || dy < 0 || dx+dy <= 0 )
+ CV_ERROR( CV_StsOutOfRange,
+ "Both derivative orders (dx and dy) must be non-negative "
+ "and at least one of them must be positive." );
+
+ for( k = 0; k < 2; k++ )
+ {
+ CvMat* kernel = k == 0 ? _kx : _ky;
+ int order = k == 0 ? dx : dy;
+ int n = kernel->cols + kernel->rows - 1, step;
+ int type = CV_MAT_TYPE(kernel->type);
+ double scale = !normalize ? 1. : 1./(1 << (n-order-1));
+ int iscale = 1;
+
+ if( (kernel->cols != 1 && kernel->rows != 1) ||
+ (kernel->cols + kernel->rows - 1) % 2 == 0 ||
+ (type != CV_32FC1 && type != CV_64FC1 && type != CV_32SC1) )
+ CV_ERROR( CV_StsOutOfRange,
+ "Both kernels must be 1D floating-point or integer vectors of odd (2*k+1) size." );
+
+ if( normalize && n > 1 && type == CV_32SC1 )
+ CV_ERROR( CV_StsBadArg, "Integer kernel can not be normalized" );
+
+ if( n <= order )
+ CV_ERROR( CV_StsOutOfRange,
+ "Derivative order must be smaller than the corresponding kernel size" );
+
+ if( n == 1 )
+ kerI[0] = 1;
+ else if( n == 3 )
+ {
+ if( order == 0 )
+ kerI[0] = 1, kerI[1] = 2, kerI[2] = 1;
+ else if( order == 1 )
+ kerI[0] = -1, kerI[1] = 0, kerI[2] = 1;
+ else
+ kerI[0] = 1, kerI[1] = -2, kerI[2] = 1;
+ }
+ else
+ {
+ int oldval, newval;
+ kerI[0] = 1;
+ for( i = 0; i < n; i++ )
+ kerI[i+1] = 0;
+
+ for( i = 0; i < n - order - 1; i++ )
+ {
+ oldval = kerI[0];
+ for( j = 1; j <= n; j++ )
+ {
+ newval = kerI[j]+kerI[j-1];
+ kerI[j-1] = oldval;
+ oldval = newval;
+ }
+ }
+
+ for( i = 0; i < order; i++ )
+ {
+ oldval = -kerI[0];
+ for( j = 1; j <= n; j++ )
+ {
+ newval = kerI[j-1] - kerI[j];
+ kerI[j-1] = oldval;
+ oldval = newval;
+ }
+ }
+ }
+
+ step = kernel->rows == 1 ? 1 : kernel->step/CV_ELEM_SIZE1(type);
+ if( flip && (order & 1) && k )
+ iscale = -iscale, scale = -scale;
+
+ for( i = 0; i < n; i++ )
+ {
+ if( type == CV_32SC1 )
+ kernel->data.i[i*step] = kerI[i]*iscale;
+ else if( type == CV_32FC1 )
+ kernel->data.fl[i*step] = (float)(kerI[i]*scale);
+ else
+ kernel->data.db[i*step] = kerI[i]*scale;
+ }
+ }
+
+ __END__;
+}
+
+
+void CvSepFilter::init_scharr_kernel( CvMat* _kx, CvMat* _ky, int dx, int dy, int flags )
+{
+ CV_FUNCNAME( "CvSepFilter::init_scharr_kernel" );
+
+ __BEGIN__;
+
+ int i, k;
+ int kerI[3];
+ bool normalize = (flags & NORMALIZE_KERNEL) != 0;
+ bool flip = (flags & FLIP_KERNEL) != 0;
+
+ if( !CV_IS_MAT(_kx) || !CV_IS_MAT(_ky) )
+ CV_ERROR( CV_StsBadArg, "One of the kernel matrices is not valid" );
+
+ if( ((dx|dy)&~1) || dx+dy != 1 )
+ CV_ERROR( CV_StsOutOfRange,
+ "Scharr kernel can only be used for 1st order derivatives" );
+
+ for( k = 0; k < 2; k++ )
+ {
+ CvMat* kernel = k == 0 ? _kx : _ky;
+ int order = k == 0 ? dx : dy;
+ int n = kernel->cols + kernel->rows - 1, step;
+ int type = CV_MAT_TYPE(kernel->type);
+ double scale = !normalize ? 1. : order == 0 ? 1./16 : 1./2;
+ int iscale = 1;
+
+ if( (kernel->cols != 1 && kernel->rows != 1) ||
+ kernel->cols + kernel->rows - 1 != 3 ||
+ (type != CV_32FC1 && type != CV_64FC1 && type != CV_32SC1) )
+ CV_ERROR( CV_StsOutOfRange,
+ "Both kernels must be 1D floating-point or integer vectors containing 3 elements each." );
+
+ if( normalize && type == CV_32SC1 )
+ CV_ERROR( CV_StsBadArg, "Integer kernel can not be normalized" );
+
+ if( order == 0 )
+ kerI[0] = 3, kerI[1] = 10, kerI[2] = 3;
+ else
+ kerI[0] = -1, kerI[1] = 0, kerI[2] = 1;
+
+ step = kernel->rows == 1 ? 1 : kernel->step/CV_ELEM_SIZE1(type);
+ if( flip && (order & 1) && k )
+ iscale = -iscale, scale = -scale;
+
+ for( i = 0; i < n; i++ )
+ {
+ if( type == CV_32SC1 )
+ kernel->data.i[i*step] = kerI[i]*iscale;
+ else if( type == CV_32FC1 )
+ kernel->data.fl[i*step] = (float)(kerI[i]*scale);
+ else
+ kernel->data.db[i*step] = kerI[i]*scale;
+ }
+ }
+
+ __END__;
+}
+
+
+void CvSepFilter::init_deriv( int _max_width, int _src_type, int _dst_type,
+ int dx, int dy, int aperture_size, int flags )
+{
+ CV_FUNCNAME( "CvSepFilter::init_deriv" );
+
+ __BEGIN__;
+
+ int kx_size = aperture_size == CV_SCHARR ? 3 : aperture_size, ky_size = kx_size;
+ float kx_data[CV_MAX_SOBEL_KSIZE], ky_data[CV_MAX_SOBEL_KSIZE];
+ CvMat _kx, _ky;
+
+ if( kx_size <= 0 || ky_size > CV_MAX_SOBEL_KSIZE )
+ CV_ERROR( CV_StsOutOfRange, "Incorrect aperture_size" );
+
+ if( kx_size == 1 && dx )
+ kx_size = 3;
+ if( ky_size == 1 && dy )
+ ky_size = 3;
+
+ _kx = cvMat( 1, kx_size, CV_32FC1, kx_data );
+ _ky = cvMat( 1, ky_size, CV_32FC1, ky_data );
+
+ if( aperture_size == CV_SCHARR )
+ {
+ CV_CALL( init_scharr_kernel( &_kx, &_ky, dx, dy, flags ));
+ }
+ else
+ {
+ CV_CALL( init_sobel_kernel( &_kx, &_ky, dx, dy, flags ));
+ }
+
+ CV_CALL( init( _max_width, _src_type, _dst_type, &_kx, &_ky ));
+
+ __END__;
+}
+
+
+void CvSepFilter::init_gaussian( int _max_width, int _src_type, int _dst_type,
+ int gaussian_size, double sigma )
+{
+ float* kdata = 0;
+
+ CV_FUNCNAME( "CvSepFilter::init_gaussian" );
+
+ __BEGIN__;
+
+ CvMat _kernel;
+
+ if( gaussian_size <= 0 || gaussian_size > 1024 )
+ CV_ERROR( CV_StsBadSize, "Incorrect size of gaussian kernel" );
+
+ kdata = (float*)cvStackAlloc(gaussian_size*sizeof(kdata[0]));
+ _kernel = cvMat( 1, gaussian_size, CV_32F, kdata );
+
+ CV_CALL( init_gaussian_kernel( &_kernel, sigma ));
+ CV_CALL( init( _max_width, _src_type, _dst_type, &_kernel, &_kernel ));
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+ Non-separable Linear Filter
+\****************************************************************************************/
+
+static void icvLinearFilter_8u( const uchar** src, uchar* dst, int dst_step,
+ int count, void* params );
+static void icvLinearFilter_16s( const short** src, short* dst, int dst_step,
+ int count, void* params );
+static void icvLinearFilter_16u( const ushort** src, ushort* dst, int dst_step,
+ int count, void* params );
+static void icvLinearFilter_32f( const float** src, float* dst, int dst_step,
+ int count, void* params );
+
+CvLinearFilter::CvLinearFilter()
+{
+ kernel = 0;
+ k_sparse = 0;
+}
+
+CvLinearFilter::CvLinearFilter( int _max_width, int _src_type, int _dst_type,
+ const CvMat* _kernel, CvPoint _anchor,
+ int _border_mode, CvScalar _border_value )
+{
+ kernel = 0;
+ k_sparse = 0;
+ init( _max_width, _src_type, _dst_type, _kernel,
+ _anchor, _border_mode, _border_value );
+}
+
+
+void CvLinearFilter::clear()
+{
+ cvReleaseMat( &kernel );
+ cvFree( &k_sparse );
+ CvBaseImageFilter::clear();
+}
+
+
+CvLinearFilter::~CvLinearFilter()
+{
+ clear();
+}
+
+
+void CvLinearFilter::init( int _max_width, int _src_type, int _dst_type,
+ const CvMat* _kernel, CvPoint _anchor,
+ int _border_mode, CvScalar _border_value )
+{
+ CV_FUNCNAME( "CvLinearFilter::init" );
+
+ __BEGIN__;
+
+ int depth = CV_MAT_DEPTH(_src_type);
+ int cn = CV_MAT_CN(_src_type);
+ CvPoint* nz_loc;
+ float* coeffs;
+ int i, j, k = 0;
+
+ if( !CV_IS_MAT(_kernel) )
+ CV_ERROR( CV_StsBadArg, "kernel is not valid matrix" );
+
+ _src_type = CV_MAT_TYPE(_src_type);
+ _dst_type = CV_MAT_TYPE(_dst_type);
+
+ if( _src_type != _dst_type )
+ CV_ERROR( CV_StsUnmatchedFormats,
+ "The source and destination image types must be the same" );
+
+ CV_CALL( CvBaseImageFilter::init( _max_width, _src_type, _dst_type,
+ false, cvGetMatSize(_kernel), _anchor, _border_mode, _border_value ));
+
+ if( !(kernel && k_sparse && ksize.width == kernel->cols && ksize.height == kernel->rows ))
+ {
+ cvReleaseMat( &kernel );
+ cvFree( &k_sparse );
+ CV_CALL( kernel = cvCreateMat( ksize.height, ksize.width, CV_32FC1 ));
+ CV_CALL( k_sparse = (uchar*)cvAlloc(
+ ksize.width*ksize.height*(2*sizeof(int) + sizeof(uchar*) + sizeof(float))));
+ }
+
+ CV_CALL( cvConvert( _kernel, kernel ));
+
+ nz_loc = (CvPoint*)k_sparse;
+ for( i = 0; i < ksize.height; i++ )
+ {
+ for( j = 0; j < ksize.width; j++ )
+ if( fabs(((float*)(kernel->data.ptr + i*kernel->step))[j])>FLT_EPSILON )
+ nz_loc[k++] = cvPoint(j,i);
+ }
+ if( k == 0 )
+ nz_loc[k++] = anchor;
+ k_sparse_count = k;
+ coeffs = (float*)((uchar**)(nz_loc + k_sparse_count) + k_sparse_count);
+
+ for( k = 0; k < k_sparse_count; k++ )
+ {
+ coeffs[k] = CV_MAT_ELEM( *kernel, float, nz_loc[k].y, nz_loc[k].x );
+ nz_loc[k].x *= cn;
+ }
+
+ x_func = 0;
+ if( depth == CV_8U )
+ y_func = (CvColumnFilterFunc)icvLinearFilter_8u;
+ else if( depth == CV_16S )
+ y_func = (CvColumnFilterFunc)icvLinearFilter_16s;
+ else if( depth == CV_16U )
+ y_func = (CvColumnFilterFunc)icvLinearFilter_16u;
+ else if( depth == CV_32F )
+ y_func = (CvColumnFilterFunc)icvLinearFilter_32f;
+ else
+ CV_ERROR( CV_StsUnsupportedFormat, "Unsupported image type" );
+
+ __END__;
+}
+
+
+void CvLinearFilter::init( int _max_width, int _src_type, int _dst_type,
+ bool _is_separable, CvSize _ksize,
+ CvPoint _anchor, int _border_mode,
+ CvScalar _border_value )
+{
+ CvBaseImageFilter::init( _max_width, _src_type, _dst_type, _is_separable,
+ _ksize, _anchor, _border_mode, _border_value );
+}
+
+
+#define ICV_FILTER( flavor, arrtype, worktype, load_macro, \
+ cast_macro1, cast_macro2 ) \
+static void \
+icvLinearFilter_##flavor( const arrtype** src, arrtype* dst, \
+ int dst_step, int count, void* params ) \
+{ \
+ CvLinearFilter* state = (CvLinearFilter*)params; \
+ int width = state->get_width(); \
+ int cn = CV_MAT_CN(state->get_src_type()); \
+ int i, k; \
+ CvPoint* k_sparse = (CvPoint*)state->get_kernel_sparse_buf(); \
+ int k_count = state->get_kernel_sparse_count(); \
+ const arrtype** k_ptr = (const arrtype**)(k_sparse + k_count); \
+ const arrtype** k_end = k_ptr + k_count; \
+ const float* k_coeffs = (const float*)(k_ptr + k_count); \
+ \
+ width *= cn; \
+ dst_step /= sizeof(dst[0]); \
+ \
+ for( ; count > 0; count--, dst += dst_step, src++ ) \
+ { \
+ for( k = 0; k < k_count; k++ ) \
+ k_ptr[k] = src[k_sparse[k].y] + k_sparse[k].x; \
+ \
+ for( i = 0; i <= width - 4; i += 4 ) \
+ { \
+ const arrtype** kp = k_ptr; \
+ const float* kc = k_coeffs; \
+ double s0 = 0, s1 = 0, s2 = 0, s3 = 0; \
+ worktype t0, t1; \
+ \
+ while( kp != k_end ) \
+ { \
+ const arrtype* sptr = (*kp++) + i; \
+ float f = *kc++; \
+ s0 += f*load_macro(sptr[0]); \
+ s1 += f*load_macro(sptr[1]); \
+ s2 += f*load_macro(sptr[2]); \
+ s3 += f*load_macro(sptr[3]); \
+ } \
+ \
+ t0 = cast_macro1(s0); t1 = cast_macro1(s1); \
+ dst[i] = cast_macro2(t0); \
+ dst[i+1] = cast_macro2(t1); \
+ t0 = cast_macro1(s2); t1 = cast_macro1(s3); \
+ dst[i+2] = cast_macro2(t0); \
+ dst[i+3] = cast_macro2(t1); \
+ } \
+ \
+ for( ; i < width; i++ ) \
+ { \
+ const arrtype** kp = k_ptr; \
+ const float* kc = k_coeffs; \
+ double s0 = 0; \
+ worktype t0; \
+ \
+ while( kp != k_end ) \
+ { \
+ const arrtype* sptr = *kp++; \
+ float f = *kc++; \
+ s0 += f*load_macro(sptr[i]); \
+ } \
+ \
+ t0 = cast_macro1(s0); \
+ dst[i] = cast_macro2(t0); \
+ } \
+ } \
+}
+
+
+ICV_FILTER( 8u, uchar, int, CV_8TO32F, cvRound, CV_CAST_8U )
+ICV_FILTER( 16u, ushort, int, CV_NOP, cvRound, CV_CAST_16U )
+ICV_FILTER( 16s, short, int, CV_NOP, cvRound, CV_CAST_16S )
+ICV_FILTER( 32f, float, float, CV_NOP, CV_CAST_32F, CV_NOP )
+
+
+/////////////////////// common functions for working with IPP filters ////////////////////
+
+CvMat* icvIPPFilterInit( const CvMat* src, int stripe_size, CvSize ksize )
+{
+ CvSize temp_size;
+ int pix_size = CV_ELEM_SIZE(src->type);
+ temp_size.width = cvAlign(src->cols + ksize.width - 1,8/CV_ELEM_SIZE(src->type & CV_MAT_DEPTH_MASK));
+ //temp_size.width = src->cols + ksize.width - 1;
+ temp_size.height = (stripe_size*2 + temp_size.width*pix_size) / (temp_size.width*pix_size*2);
+ temp_size.height = MAX( temp_size.height, ksize.height );
+ temp_size.height = MIN( temp_size.height, src->rows + ksize.height - 1 );
+
+ return cvCreateMat( temp_size.height, temp_size.width, src->type );
+}
+
+
+int icvIPPFilterNextStripe( const CvMat* src, CvMat* temp, int y,
+ CvSize ksize, CvPoint anchor )
+{
+ int pix_size = CV_ELEM_SIZE(src->type);
+ int src_step = src->step ? src->step : CV_STUB_STEP;
+ int temp_step = temp->step ? temp->step : CV_STUB_STEP;
+ int i, dy, src_y1 = 0, src_y2;
+ int temp_rows;
+ uchar* temp_ptr = temp->data.ptr;
+ CvSize stripe_size, temp_size;
+
+ dy = MIN( temp->rows - ksize.height + 1, src->rows - y );
+ if( y > 0 )
+ {
+ int temp_ready = ksize.height - 1;
+
+ for( i = 0; i < temp_ready; i++ )
+ memcpy( temp_ptr + temp_step*i, temp_ptr +
+ temp_step*(temp->rows - temp_ready + i), temp_step );
+
+ temp_ptr += temp_ready*temp_step;
+ temp_rows = dy;
+ src_y1 = y + temp_ready - anchor.y;
+ src_y2 = src_y1 + dy;
+ if( src_y1 >= src->rows )
+ {
+ src_y1 = src->rows - 1;
+ src_y2 = src->rows;
+ }
+ }
+ else
+ {
+ temp_rows = dy + ksize.height - 1;
+ src_y2 = temp_rows - anchor.y;
+ }
+
+ src_y2 = MIN( src_y2, src->rows );
+
+ stripe_size = cvSize(src->cols, src_y2 - src_y1);
+ temp_size = cvSize(temp->cols, temp_rows);
+ icvCopyReplicateBorder_8u( src->data.ptr + src_y1*src_step, src_step,
+ stripe_size, temp_ptr, temp_step, temp_size,
+ (y == 0 ? anchor.y : 0), anchor.x, pix_size );
+ return dy;
+}
+
+
+/////////////////////////////// IPP separable filter functions ///////////////////////////
+
+icvFilterRow_8u_C1R_t icvFilterRow_8u_C1R_p = 0;
+icvFilterRow_8u_C3R_t icvFilterRow_8u_C3R_p = 0;
+icvFilterRow_8u_C4R_t icvFilterRow_8u_C4R_p = 0;
+icvFilterRow_16s_C1R_t icvFilterRow_16s_C1R_p = 0;
+icvFilterRow_16s_C3R_t icvFilterRow_16s_C3R_p = 0;
+icvFilterRow_16s_C4R_t icvFilterRow_16s_C4R_p = 0;
+icvFilterRow_32f_C1R_t icvFilterRow_32f_C1R_p = 0;
+icvFilterRow_32f_C3R_t icvFilterRow_32f_C3R_p = 0;
+icvFilterRow_32f_C4R_t icvFilterRow_32f_C4R_p = 0;
+
+icvFilterColumn_8u_C1R_t icvFilterColumn_8u_C1R_p = 0;
+icvFilterColumn_8u_C3R_t icvFilterColumn_8u_C3R_p = 0;
+icvFilterColumn_8u_C4R_t icvFilterColumn_8u_C4R_p = 0;
+icvFilterColumn_16s_C1R_t icvFilterColumn_16s_C1R_p = 0;
+icvFilterColumn_16s_C3R_t icvFilterColumn_16s_C3R_p = 0;
+icvFilterColumn_16s_C4R_t icvFilterColumn_16s_C4R_p = 0;
+icvFilterColumn_32f_C1R_t icvFilterColumn_32f_C1R_p = 0;
+icvFilterColumn_32f_C3R_t icvFilterColumn_32f_C3R_p = 0;
+icvFilterColumn_32f_C4R_t icvFilterColumn_32f_C4R_p = 0;
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+typedef CvStatus (CV_STDCALL * CvIPPSepFilterFunc)
+ ( const void* src, int srcstep, void* dst, int dststep,
+ CvSize size, const float* kernel, int ksize, int anchor );
+
+int icvIPPSepFilter( const CvMat* src, CvMat* dst, const CvMat* kernelX,
+ const CvMat* kernelY, CvPoint anchor )
+{
+ int result = 0;
+
+ CvMat* top_bottom = 0;
+ CvMat* vout_hin = 0;
+ CvMat* dst_buf = 0;
+
+ CV_FUNCNAME( "icvIPPSepFilter" );
+
+ __BEGIN__;
+
+ CvSize ksize;
+ CvPoint el_anchor;
+ CvSize size;
+ int type, depth, pix_size;
+ int i, x, y, dy = 0, prev_dy = 0, max_dy;
+ CvMat vout;
+ CvIPPSepFilterFunc x_func = 0, y_func = 0;
+ int src_step, top_bottom_step;
+ float *kx, *ky;
+ int align, stripe_size;
+
+ if( !icvFilterRow_8u_C1R_p )
+ EXIT;
+
+ if( !CV_ARE_TYPES_EQ( src, dst ) || !CV_ARE_SIZES_EQ( src, dst ) ||
+ !CV_IS_MAT_CONT(kernelX->type & kernelY->type) ||
+ CV_MAT_TYPE(kernelX->type) != CV_32FC1 ||
+ CV_MAT_TYPE(kernelY->type) != CV_32FC1 ||
+ (kernelX->cols != 1 && kernelX->rows != 1) ||
+ (kernelY->cols != 1 && kernelY->rows != 1) ||
+ (unsigned)anchor.x >= (unsigned)(kernelX->cols + kernelX->rows - 1) ||
+ (unsigned)anchor.y >= (unsigned)(kernelY->cols + kernelY->rows - 1) )
+ CV_ERROR( CV_StsError, "Internal Error: incorrect parameters" );
+
+ ksize.width = kernelX->cols + kernelX->rows - 1;
+ ksize.height = kernelY->cols + kernelY->rows - 1;
+
+ /*if( ksize.width <= 5 && ksize.height <= 5 )
+ {
+ float* ker = (float*)cvStackAlloc( ksize.width*ksize.height*sizeof(ker[0]));
+ CvMat kernel = cvMat( ksize.height, ksize.width, CV_32F, ker );
+ for( y = 0, i = 0; y < ksize.height; y++ )
+ for( x = 0; x < ksize.width; x++, i++ )
+ ker[i] = kernelY->data.fl[y]*kernelX->data.fl[x];
+
+ CV_CALL( cvFilter2D( src, dst, &kernel, anchor ));
+ EXIT;
+ }*/
+
+ type = CV_MAT_TYPE(src->type);
+ depth = CV_MAT_DEPTH(type);
+ pix_size = CV_ELEM_SIZE(type);
+
+ if( type == CV_8UC1 )
+ x_func = icvFilterRow_8u_C1R_p, y_func = icvFilterColumn_8u_C1R_p;
+ else if( type == CV_8UC3 )
+ x_func = icvFilterRow_8u_C3R_p, y_func = icvFilterColumn_8u_C3R_p;
+ else if( type == CV_8UC4 )
+ x_func = icvFilterRow_8u_C4R_p, y_func = icvFilterColumn_8u_C4R_p;
+ else if( type == CV_16SC1 )
+ x_func = icvFilterRow_16s_C1R_p, y_func = icvFilterColumn_16s_C1R_p;
+ else if( type == CV_16SC3 )
+ x_func = icvFilterRow_16s_C3R_p, y_func = icvFilterColumn_16s_C3R_p;
+ else if( type == CV_16SC4 )
+ x_func = icvFilterRow_16s_C4R_p, y_func = icvFilterColumn_16s_C4R_p;
+ else if( type == CV_32FC1 )
+ x_func = icvFilterRow_32f_C1R_p, y_func = icvFilterColumn_32f_C1R_p;
+ else if( type == CV_32FC3 )
+ x_func = icvFilterRow_32f_C3R_p, y_func = icvFilterColumn_32f_C3R_p;
+ else if( type == CV_32FC4 )
+ x_func = icvFilterRow_32f_C4R_p, y_func = icvFilterColumn_32f_C4R_p;
+ else
+ EXIT;
+
+ size = cvGetMatSize(src);
+ stripe_size = src->data.ptr == dst->data.ptr ? 1 << 15 : 1 << 16;
+ max_dy = MAX( ksize.height - 1, stripe_size/(size.width + ksize.width - 1));
+ max_dy = MIN( max_dy, size.height + ksize.height - 1 );
+
+ align = 8/CV_ELEM_SIZE(depth);
+
+ CV_CALL( top_bottom = cvCreateMat( ksize.height*2, cvAlign(size.width,align), type ));
+
+ CV_CALL( vout_hin = cvCreateMat( max_dy + ksize.height,
+ cvAlign(size.width + ksize.width - 1, align), type ));
+
+ if( src->data.ptr == dst->data.ptr && size.height )
+ CV_CALL( dst_buf = cvCreateMat( max_dy + ksize.height,
+ cvAlign(size.width, align), type ));
+
+ kx = (float*)cvStackAlloc( ksize.width*sizeof(kx[0]) );
+ ky = (float*)cvStackAlloc( ksize.height*sizeof(ky[0]) );
+
+ // mirror the kernels
+ for( i = 0; i < ksize.width; i++ )
+ kx[i] = kernelX->data.fl[ksize.width - i - 1];
+
+ for( i = 0; i < ksize.height; i++ )
+ ky[i] = kernelY->data.fl[ksize.height - i - 1];
+
+ el_anchor = cvPoint( ksize.width - anchor.x - 1, ksize.height - anchor.y - 1 );
+
+ cvGetCols( vout_hin, &vout, anchor.x, anchor.x + size.width );
+
+ src_step = src->step ? src->step : CV_STUB_STEP;
+ top_bottom_step = top_bottom->step ? top_bottom->step : CV_STUB_STEP;
+ vout.step = vout.step ? vout.step : CV_STUB_STEP;
+
+ for( y = 0; y < size.height; y += dy )
+ {
+ const CvMat *vin = src, *hout = dst;
+ int src_y = y, dst_y = y;
+ dy = MIN( max_dy, size.height - (ksize.height - anchor.y - 1) - y );
+
+ if( y < anchor.y || dy < anchor.y )
+ {
+ int ay = anchor.y;
+ CvSize src_stripe_size = size;
+
+ if( y < anchor.y )
+ {
+ src_y = 0;
+ dy = MIN( anchor.y, size.height );
+ src_stripe_size.height = MIN( dy + ksize.height - anchor.y - 1, size.height );
+ }
+ else
+ {
+ src_y = MAX( y - anchor.y, 0 );
+ dy = size.height - y;
+ src_stripe_size.height = MIN( dy + anchor.y, size.height );
+ ay = MAX( anchor.y - y, 0 );
+ }
+
+ icvCopyReplicateBorder_8u( src->data.ptr + src_y*src_step, src_step,
+ src_stripe_size, top_bottom->data.ptr, top_bottom_step,
+ cvSize(size.width, dy + ksize.height - 1), ay, 0, pix_size );
+ vin = top_bottom;
+ src_y = anchor.y;
+ }
+
+ // do vertical convolution
+ IPPI_CALL( y_func( vin->data.ptr + src_y*vin->step, vin->step ? vin->step : CV_STUB_STEP,
+ vout.data.ptr, vout.step, cvSize(size.width, dy),
+ ky, ksize.height, el_anchor.y ));
+
+ // now it's time to copy the previously processed stripe to the input/output image
+ if( src->data.ptr == dst->data.ptr )
+ {
+ for( i = 0; i < prev_dy; i++ )
+ memcpy( dst->data.ptr + (y - prev_dy + i)*dst->step,
+ dst_buf->data.ptr + i*dst_buf->step, size.width*pix_size );
+ if( y + dy < size.height )
+ {
+ hout = dst_buf;
+ dst_y = 0;
+ }
+ }
+
+ // create a border for every line by replicating the left-most/right-most elements
+ for( i = 0; i < dy; i++ )
+ {
+ uchar* ptr = vout.data.ptr + i*vout.step;
+ for( x = -1; x >= -anchor.x*pix_size; x-- )
+ ptr[x] = ptr[x + pix_size];
+ for( x = size.width*pix_size; x < (size.width+ksize.width-anchor.x-1)*pix_size; x++ )
+ ptr[x] = ptr[x - pix_size];
+ }
+
+ // do horizontal convolution
+ IPPI_CALL( x_func( vout.data.ptr, vout.step, hout->data.ptr + dst_y*hout->step,
+ hout->step ? hout->step : CV_STUB_STEP,
+ cvSize(size.width, dy), kx, ksize.width, el_anchor.x ));
+ prev_dy = dy;
+ }
+
+ result = 1;
+
+ __END__;
+
+ cvReleaseMat( &vout_hin );
+ cvReleaseMat( &dst_buf );
+ cvReleaseMat( &top_bottom );
+
+ return result;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////// IPP generic filter functions ////////////////////////////
+
+icvFilter_8u_C1R_t icvFilter_8u_C1R_p = 0;
+icvFilter_8u_C3R_t icvFilter_8u_C3R_p = 0;
+icvFilter_8u_C4R_t icvFilter_8u_C4R_p = 0;
+icvFilter_16s_C1R_t icvFilter_16s_C1R_p = 0;
+icvFilter_16s_C3R_t icvFilter_16s_C3R_p = 0;
+icvFilter_16s_C4R_t icvFilter_16s_C4R_p = 0;
+icvFilter_32f_C1R_t icvFilter_32f_C1R_p = 0;
+icvFilter_32f_C3R_t icvFilter_32f_C3R_p = 0;
+icvFilter_32f_C4R_t icvFilter_32f_C4R_p = 0;
+
+
+typedef CvStatus (CV_STDCALL * CvFilterIPPFunc)
+( const void* src, int srcstep, void* dst, int dststep, CvSize size,
+ const float* kernel, CvSize ksize, CvPoint anchor );
+
+CV_IMPL void
+cvFilter2D( const CvArr* _src, CvArr* _dst, const CvMat* kernel, CvPoint anchor )
+{
+ const int dft_filter_size = 100;
+
+ CvLinearFilter filter;
+ CvMat* ipp_kernel = 0;
+
+ // below that approximate size OpenCV is faster
+ const int ipp_lower_limit = 20;
+ CvMat* temp = 0;
+
+ CV_FUNCNAME( "cvFilter2D" );
+
+ __BEGIN__;
+
+ int coi1 = 0, coi2 = 0;
+ CvMat srcstub, *src = (CvMat*)_src;
+ CvMat dststub, *dst = (CvMat*)_dst;
+ int type;
+
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ type = CV_MAT_TYPE( src->type );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( anchor.x == -1 && anchor.y == -1 )
+ anchor = cvPoint(kernel->cols/2,kernel->rows/2);
+
+ if( kernel->cols*kernel->rows >= dft_filter_size &&
+ kernel->cols <= src->cols && kernel->rows <= src->rows )
+ {
+ if( src->data.ptr == dst->data.ptr )
+ {
+ temp = cvCloneMat( src );
+ src = temp;
+ }
+ icvCrossCorr( src, kernel, dst, anchor );
+ EXIT;
+ }
+
+ if( icvFilter_8u_C1R_p && (src->rows >= ipp_lower_limit || src->cols >= ipp_lower_limit) )
+ {
+ CvFilterIPPFunc ipp_func =
+ type == CV_8UC1 ? (CvFilterIPPFunc)icvFilter_8u_C1R_p :
+ type == CV_8UC3 ? (CvFilterIPPFunc)icvFilter_8u_C3R_p :
+ type == CV_8UC4 ? (CvFilterIPPFunc)icvFilter_8u_C4R_p :
+ type == CV_16SC1 ? (CvFilterIPPFunc)icvFilter_16s_C1R_p :
+ type == CV_16SC3 ? (CvFilterIPPFunc)icvFilter_16s_C3R_p :
+ type == CV_16SC4 ? (CvFilterIPPFunc)icvFilter_16s_C4R_p :
+ type == CV_32FC1 ? (CvFilterIPPFunc)icvFilter_32f_C1R_p :
+ type == CV_32FC3 ? (CvFilterIPPFunc)icvFilter_32f_C3R_p :
+ type == CV_32FC4 ? (CvFilterIPPFunc)icvFilter_32f_C4R_p : 0;
+
+ if( ipp_func )
+ {
+ CvSize el_size = { kernel->cols, kernel->rows };
+ CvPoint el_anchor;
+ int stripe_size = 1 << 16; // the optimal value may depend on CPU cache,
+ // overhead of current IPP code etc.
+ const uchar* shifted_ptr;
+ int i, j, y, dy = 0;
+ int temp_step, dst_step = dst->step ? dst->step : CV_STUB_STEP;
+
+ if( (unsigned)anchor.x >= (unsigned)kernel->cols ||
+ (unsigned)anchor.y >= (unsigned)kernel->rows )
+ CV_ERROR( CV_StsOutOfRange, "anchor point is out of kernel" );
+
+ el_anchor = cvPoint( el_size.width - anchor.x - 1, el_size.height - anchor.y - 1 );
+
+ CV_CALL( ipp_kernel = cvCreateMat( kernel->rows, kernel->cols, CV_32FC1 ));
+ CV_CALL( cvConvert( kernel, ipp_kernel ));
+
+ // mirror the kernel around the center
+ for( i = 0; i < (el_size.height+1)/2; i++ )
+ {
+ float* top_row = ipp_kernel->data.fl + el_size.width*i;
+ float* bottom_row = ipp_kernel->data.fl + el_size.width*(el_size.height - i - 1);
+
+ for( j = 0; j < (el_size.width+1)/2; j++ )
+ {
+ float a = top_row[j], b = top_row[el_size.width - j - 1];
+ float c = bottom_row[j], d = bottom_row[el_size.width - j - 1];
+ top_row[j] = d;
+ top_row[el_size.width - j - 1] = c;
+ bottom_row[j] = b;
+ bottom_row[el_size.width - j - 1] = a;
+ }
+ }
+
+ CV_CALL( temp = icvIPPFilterInit( src, stripe_size, el_size ));
+
+ shifted_ptr = temp->data.ptr +
+ anchor.y*temp->step + anchor.x*CV_ELEM_SIZE(type);
+ temp_step = temp->step ? temp->step : CV_STUB_STEP;
+
+ for( y = 0; y < src->rows; y += dy )
+ {
+ dy = icvIPPFilterNextStripe( src, temp, y, el_size, anchor );
+ IPPI_CALL( ipp_func( shifted_ptr, temp_step,
+ dst->data.ptr + y*dst_step, dst_step, cvSize(src->cols, dy),
+ ipp_kernel->data.fl, el_size, el_anchor ));
+ }
+ EXIT;
+ }
+ }
+
+ CV_CALL( filter.init( src->cols, type, type, kernel, anchor ));
+ CV_CALL( filter.process( src, dst ));
+
+ __END__;
+
+ cvReleaseMat( &temp );
+ cvReleaseMat( &ipp_kernel );
+}
+
+
+/* End of file. */
diff --git a/cv/src/cvfloodfill.cpp b/cv/src/cvfloodfill.cpp
new file mode 100644
index 0000000..ca6425a
--- /dev/null
+++ b/cv/src/cvfloodfill.cpp
@@ -0,0 +1,1160 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+typedef struct CvFFillSegment
+{
+ ushort y;
+ ushort l;
+ ushort r;
+ ushort prevl;
+ ushort prevr;
+ short dir;
+}
+CvFFillSegment;
+
+#define UP 1
+#define DOWN -1
+
+#define ICV_PUSH( Y, L, R, PREV_L, PREV_R, DIR )\
+{ \
+ tail->y = (ushort)(Y); \
+ tail->l = (ushort)(L); \
+ tail->r = (ushort)(R); \
+ tail->prevl = (ushort)(PREV_L); \
+ tail->prevr = (ushort)(PREV_R); \
+ tail->dir = (short)(DIR); \
+ if( ++tail >= buffer_end ) \
+ tail = buffer; \
+}
+
+
+#define ICV_POP( Y, L, R, PREV_L, PREV_R, DIR ) \
+{ \
+ Y = head->y; \
+ L = head->l; \
+ R = head->r; \
+ PREV_L = head->prevl; \
+ PREV_R = head->prevr; \
+ DIR = head->dir; \
+ if( ++head >= buffer_end ) \
+ head = buffer; \
+}
+
+
+#define ICV_EQ_C3( p1, p2 ) \
+ ((p1)[0] == (p2)[0] && (p1)[1] == (p2)[1] && (p1)[2] == (p2)[2])
+
+#define ICV_SET_C3( p, q ) \
+ ((p)[0] = (q)[0], (p)[1] = (q)[1], (p)[2] = (q)[2])
+
+/****************************************************************************************\
+* Simple Floodfill (repainting single-color connected component) *
+\****************************************************************************************/
+
+static CvStatus
+icvFloodFill_8u_CnIR( uchar* pImage, int step, CvSize roi, CvPoint seed,
+ uchar* _newVal, CvConnectedComp* region, int flags,
+ CvFFillSegment* buffer, int buffer_size, int cn )
+{
+ uchar* img = pImage + step * seed.y;
+ int i, L, R;
+ int area = 0;
+ int val0[] = {0,0,0};
+ uchar newVal[] = {0,0,0};
+ int XMin, XMax, YMin = seed.y, YMax = seed.y;
+ int _8_connectivity = (flags & 255) == 8;
+ CvFFillSegment* buffer_end = buffer + buffer_size, *head = buffer, *tail = buffer;
+
+ L = R = XMin = XMax = seed.x;
+
+ if( cn == 1 )
+ {
+ val0[0] = img[L];
+ newVal[0] = _newVal[0];
+
+ img[L] = newVal[0];
+
+ while( ++R < roi.width && img[R] == val0[0] )
+ img[R] = newVal[0];
+
+ while( --L >= 0 && img[L] == val0[0] )
+ img[L] = newVal[0];
+ }
+ else
+ {
+ assert( cn == 3 );
+ ICV_SET_C3( val0, img + L*3 );
+ ICV_SET_C3( newVal, _newVal );
+
+ ICV_SET_C3( img + L*3, newVal );
+
+ while( --L >= 0 && ICV_EQ_C3( img + L*3, val0 ))
+ ICV_SET_C3( img + L*3, newVal );
+
+ while( ++R < roi.width && ICV_EQ_C3( img + R*3, val0 ))
+ ICV_SET_C3( img + R*3, newVal );
+ }
+
+ XMax = --R;
+ XMin = ++L;
+ ICV_PUSH( seed.y, L, R, R + 1, R, UP );
+
+ while( head != tail )
+ {
+ int k, YC, PL, PR, dir;
+ ICV_POP( YC, L, R, PL, PR, dir );
+
+ int data[][3] =
+ {
+ {-dir, L - _8_connectivity, R + _8_connectivity},
+ {dir, L - _8_connectivity, PL - 1},
+ {dir, PR + 1, R + _8_connectivity}
+ };
+
+ if( region )
+ {
+ area += R - L + 1;
+
+ if( XMax < R ) XMax = R;
+ if( XMin > L ) XMin = L;
+ if( YMax < YC ) YMax = YC;
+ if( YMin > YC ) YMin = YC;
+ }
+
+ for( k = 0/*(unsigned)(YC - dir) >= (unsigned)roi.height*/; k < 3; k++ )
+ {
+ dir = data[k][0];
+ img = pImage + (YC + dir) * step;
+ int left = data[k][1];
+ int right = data[k][2];
+
+ if( (unsigned)(YC + dir) >= (unsigned)roi.height )
+ continue;
+
+ if( cn == 1 )
+ for( i = left; i <= right; i++ )
+ {
+ if( (unsigned)i < (unsigned)roi.width && img[i] == val0[0] )
+ {
+ int j = i;
+ img[i] = newVal[0];
+ while( --j >= 0 && img[j] == val0[0] )
+ img[j] = newVal[0];
+
+ while( ++i < roi.width && img[i] == val0[0] )
+ img[i] = newVal[0];
+
+ ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
+ }
+ }
+ else
+ for( i = left; i <= right; i++ )
+ {
+ if( (unsigned)i < (unsigned)roi.width && ICV_EQ_C3( img + i*3, val0 ))
+ {
+ int j = i;
+ ICV_SET_C3( img + i*3, newVal );
+ while( --j >= 0 && ICV_EQ_C3( img + j*3, val0 ))
+ ICV_SET_C3( img + j*3, newVal );
+
+ while( ++i < roi.width && ICV_EQ_C3( img + i*3, val0 ))
+ ICV_SET_C3( img + i*3, newVal );
+
+ ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
+ }
+ }
+ }
+ }
+
+ if( region )
+ {
+ region->area = area;
+ region->rect.x = XMin;
+ region->rect.y = YMin;
+ region->rect.width = XMax - XMin + 1;
+ region->rect.height = YMax - YMin + 1;
+ region->value = cvScalar(newVal[0], newVal[1], newVal[2], 0);
+ }
+
+ return CV_NO_ERR;
+}
+
+
+/* because all the operations on floats that are done during non-gradient floodfill
+ are just copying and comparison on equality,
+ we can do the whole op on 32-bit integers instead */
+static CvStatus
+icvFloodFill_32f_CnIR( int* pImage, int step, CvSize roi, CvPoint seed,
+ int* _newVal, CvConnectedComp* region, int flags,
+ CvFFillSegment* buffer, int buffer_size, int cn )
+{
+ int* img = pImage + (step /= sizeof(pImage[0])) * seed.y;
+ int i, L, R;
+ int area = 0;
+ int val0[] = {0,0,0};
+ int newVal[] = {0,0,0};
+ int XMin, XMax, YMin = seed.y, YMax = seed.y;
+ int _8_connectivity = (flags & 255) == 8;
+ CvFFillSegment* buffer_end = buffer + buffer_size, *head = buffer, *tail = buffer;
+
+ L = R = XMin = XMax = seed.x;
+
+ if( cn == 1 )
+ {
+ val0[0] = img[L];
+ newVal[0] = _newVal[0];
+
+ img[L] = newVal[0];
+
+ while( ++R < roi.width && img[R] == val0[0] )
+ img[R] = newVal[0];
+
+ while( --L >= 0 && img[L] == val0[0] )
+ img[L] = newVal[0];
+ }
+ else
+ {
+ assert( cn == 3 );
+ ICV_SET_C3( val0, img + L*3 );
+ ICV_SET_C3( newVal, _newVal );
+
+ ICV_SET_C3( img + L*3, newVal );
+
+ while( --L >= 0 && ICV_EQ_C3( img + L*3, val0 ))
+ ICV_SET_C3( img + L*3, newVal );
+
+ while( ++R < roi.width && ICV_EQ_C3( img + R*3, val0 ))
+ ICV_SET_C3( img + R*3, newVal );
+ }
+
+ XMax = --R;
+ XMin = ++L;
+ ICV_PUSH( seed.y, L, R, R + 1, R, UP );
+
+ while( head != tail )
+ {
+ int k, YC, PL, PR, dir;
+ ICV_POP( YC, L, R, PL, PR, dir );
+
+ int data[][3] =
+ {
+ {-dir, L - _8_connectivity, R + _8_connectivity},
+ {dir, L - _8_connectivity, PL - 1},
+ {dir, PR + 1, R + _8_connectivity}
+ };
+
+ if( region )
+ {
+ area += R - L + 1;
+
+ if( XMax < R ) XMax = R;
+ if( XMin > L ) XMin = L;
+ if( YMax < YC ) YMax = YC;
+ if( YMin > YC ) YMin = YC;
+ }
+
+ for( k = 0/*(unsigned)(YC - dir) >= (unsigned)roi.height*/; k < 3; k++ )
+ {
+ dir = data[k][0];
+ img = pImage + (YC + dir) * step;
+ int left = data[k][1];
+ int right = data[k][2];
+
+ if( (unsigned)(YC + dir) >= (unsigned)roi.height )
+ continue;
+
+ if( cn == 1 )
+ for( i = left; i <= right; i++ )
+ {
+ if( (unsigned)i < (unsigned)roi.width && img[i] == val0[0] )
+ {
+ int j = i;
+ img[i] = newVal[0];
+ while( --j >= 0 && img[j] == val0[0] )
+ img[j] = newVal[0];
+
+ while( ++i < roi.width && img[i] == val0[0] )
+ img[i] = newVal[0];
+
+ ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
+ }
+ }
+ else
+ for( i = left; i <= right; i++ )
+ {
+ if( (unsigned)i < (unsigned)roi.width && ICV_EQ_C3( img + i*3, val0 ))
+ {
+ int j = i;
+ ICV_SET_C3( img + i*3, newVal );
+ while( --j >= 0 && ICV_EQ_C3( img + j*3, val0 ))
+ ICV_SET_C3( img + j*3, newVal );
+
+ while( ++i < roi.width && ICV_EQ_C3( img + i*3, val0 ))
+ ICV_SET_C3( img + i*3, newVal );
+
+ ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
+ }
+ }
+ }
+ }
+
+ if( region )
+ {
+ Cv32suf v0, v1, v2;
+ region->area = area;
+ region->rect.x = XMin;
+ region->rect.y = YMin;
+ region->rect.width = XMax - XMin + 1;
+ region->rect.height = YMax - YMin + 1;
+ v0.i = newVal[0]; v1.i = newVal[1]; v2.i = newVal[2];
+ region->value = cvScalar( v0.f, v1.f, v2.f );
+ }
+
+ return CV_NO_ERR;
+}
+
+/****************************************************************************************\
+* Gradient Floodfill *
+\****************************************************************************************/
+
+#define DIFF_INT_C1(p1,p2) ((unsigned)((p1)[0] - (p2)[0] + d_lw[0]) <= interval[0])
+
+#define DIFF_INT_C3(p1,p2) ((unsigned)((p1)[0] - (p2)[0] + d_lw[0])<= interval[0] && \
+ (unsigned)((p1)[1] - (p2)[1] + d_lw[1])<= interval[1] && \
+ (unsigned)((p1)[2] - (p2)[2] + d_lw[2])<= interval[2])
+
+#define DIFF_FLT_C1(p1,p2) (fabs((p1)[0] - (p2)[0] + d_lw[0]) <= interval[0])
+
+#define DIFF_FLT_C3(p1,p2) (fabs((p1)[0] - (p2)[0] + d_lw[0]) <= interval[0] && \
+ fabs((p1)[1] - (p2)[1] + d_lw[1]) <= interval[1] && \
+ fabs((p1)[2] - (p2)[2] + d_lw[2]) <= interval[2])
+
+static CvStatus
+icvFloodFill_Grad_8u_CnIR( uchar* pImage, int step, uchar* pMask, int maskStep,
+ CvSize /*roi*/, CvPoint seed, uchar* _newVal, uchar* _d_lw,
+ uchar* _d_up, CvConnectedComp* region, int flags,
+ CvFFillSegment* buffer, int buffer_size, int cn )
+{
+ uchar* img = pImage + step*seed.y;
+ uchar* mask = (pMask += maskStep + 1) + maskStep*seed.y;
+ int i, L, R;
+ int area = 0;
+ int sum[] = {0,0,0}, val0[] = {0,0,0};
+ uchar newVal[] = {0,0,0};
+ int d_lw[] = {0,0,0};
+ unsigned interval[] = {0,0,0};
+ int XMin, XMax, YMin = seed.y, YMax = seed.y;
+ int _8_connectivity = (flags & 255) == 8;
+ int fixedRange = flags & CV_FLOODFILL_FIXED_RANGE;
+ int fillImage = (flags & CV_FLOODFILL_MASK_ONLY) == 0;
+ uchar newMaskVal = (uchar)(flags & 0xff00 ? flags >> 8 : 1);
+ CvFFillSegment* buffer_end = buffer + buffer_size, *head = buffer, *tail = buffer;
+
+ L = R = seed.x;
+ if( mask[L] )
+ return CV_OK;
+
+ mask[L] = newMaskVal;
+
+ for( i = 0; i < cn; i++ )
+ {
+ newVal[i] = _newVal[i];
+ d_lw[i] = _d_lw[i];
+ interval[i] = (unsigned)(_d_up[i] + _d_lw[i]);
+ if( fixedRange )
+ val0[i] = img[L*cn+i];
+ }
+
+ if( cn == 1 )
+ {
+ if( fixedRange )
+ {
+ while( !mask[R + 1] && DIFF_INT_C1( img + (R+1), val0 ))
+ mask[++R] = newMaskVal;
+
+ while( !mask[L - 1] && DIFF_INT_C1( img + (L-1), val0 ))
+ mask[--L] = newMaskVal;
+ }
+ else
+ {
+ while( !mask[R + 1] && DIFF_INT_C1( img + (R+1), img + R ))
+ mask[++R] = newMaskVal;
+
+ while( !mask[L - 1] && DIFF_INT_C1( img + (L-1), img + L ))
+ mask[--L] = newMaskVal;
+ }
+ }
+ else
+ {
+ if( fixedRange )
+ {
+ while( !mask[R + 1] && DIFF_INT_C3( img + (R+1)*3, val0 ))
+ mask[++R] = newMaskVal;
+
+ while( !mask[L - 1] && DIFF_INT_C3( img + (L-1)*3, val0 ))
+ mask[--L] = newMaskVal;
+ }
+ else
+ {
+ while( !mask[R + 1] && DIFF_INT_C3( img + (R+1)*3, img + R*3 ))
+ mask[++R] = newMaskVal;
+
+ while( !mask[L - 1] && DIFF_INT_C3( img + (L-1)*3, img + L*3 ))
+ mask[--L] = newMaskVal;
+ }
+ }
+
+ XMax = R;
+ XMin = L;
+ ICV_PUSH( seed.y, L, R, R + 1, R, UP );
+
+ while( head != tail )
+ {
+ int k, YC, PL, PR, dir, curstep;
+ ICV_POP( YC, L, R, PL, PR, dir );
+
+ int data[][3] =
+ {
+ {-dir, L - _8_connectivity, R + _8_connectivity},
+ {dir, L - _8_connectivity, PL - 1},
+ {dir, PR + 1, R + _8_connectivity}
+ };
+
+ unsigned length = (unsigned)(R-L);
+
+ if( region )
+ {
+ area += (int)length + 1;
+
+ if( XMax < R ) XMax = R;
+ if( XMin > L ) XMin = L;
+ if( YMax < YC ) YMax = YC;
+ if( YMin > YC ) YMin = YC;
+ }
+
+ if( cn == 1 )
+ {
+ for( k = 0; k < 3; k++ )
+ {
+ dir = data[k][0];
+ curstep = dir * step;
+ img = pImage + (YC + dir) * step;
+ mask = pMask + (YC + dir) * maskStep;
+ int left = data[k][1];
+ int right = data[k][2];
+
+ if( fixedRange )
+ for( i = left; i <= right; i++ )
+ {
+ if( !mask[i] && DIFF_INT_C1( img + i, val0 ))
+ {
+ int j = i;
+ mask[i] = newMaskVal;
+ while( !mask[--j] && DIFF_INT_C1( img + j, val0 ))
+ mask[j] = newMaskVal;
+
+ while( !mask[++i] && DIFF_INT_C1( img + i, val0 ))
+ mask[i] = newMaskVal;
+
+ ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
+ }
+ }
+ else if( !_8_connectivity )
+ for( i = left; i <= right; i++ )
+ {
+ if( !mask[i] && DIFF_INT_C1( img + i, img - curstep + i ))
+ {
+ int j = i;
+ mask[i] = newMaskVal;
+ while( !mask[--j] && DIFF_INT_C1( img + j, img + (j+1) ))
+ mask[j] = newMaskVal;
+
+ while( !mask[++i] &&
+ (DIFF_INT_C1( img + i, img + (i-1) ) ||
+ (DIFF_INT_C1( img + i, img + i - curstep) && i <= R)))
+ mask[i] = newMaskVal;
+
+ ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
+ }
+ }
+ else
+ for( i = left; i <= right; i++ )
+ {
+ int idx, val[1];
+
+ if( !mask[i] &&
+ (((val[0] = img[i],
+ (unsigned)(idx = i-L-1) <= length) &&
+ DIFF_INT_C1( val, img - curstep + (i-1))) ||
+ ((unsigned)(++idx) <= length &&
+ DIFF_INT_C1( val, img - curstep + i )) ||
+ ((unsigned)(++idx) <= length &&
+ DIFF_INT_C1( val, img - curstep + (i+1) ))))
+ {
+ int j = i;
+ mask[i] = newMaskVal;
+ while( !mask[--j] && DIFF_INT_C1( img + j, img + (j+1) ))
+ mask[j] = newMaskVal;
+
+ while( !mask[++i] &&
+ ((val[0] = img[i],
+ DIFF_INT_C1( val, img + (i-1) )) ||
+ (((unsigned)(idx = i-L-1) <= length &&
+ DIFF_INT_C1( val, img - curstep + (i-1) ))) ||
+ ((unsigned)(++idx) <= length &&
+ DIFF_INT_C1( val, img - curstep + i )) ||
+ ((unsigned)(++idx) <= length &&
+ DIFF_INT_C1( val, img - curstep + (i+1) ))))
+ mask[i] = newMaskVal;
+
+ ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
+ }
+ }
+ }
+
+ img = pImage + YC * step;
+ if( fillImage )
+ for( i = L; i <= R; i++ )
+ img[i] = newVal[0];
+ else if( region )
+ for( i = L; i <= R; i++ )
+ sum[0] += img[i];
+ }
+ else
+ {
+ for( k = 0; k < 3; k++ )
+ {
+ dir = data[k][0];
+ curstep = dir * step;
+ img = pImage + (YC + dir) * step;
+ mask = pMask + (YC + dir) * maskStep;
+ int left = data[k][1];
+ int right = data[k][2];
+
+ if( fixedRange )
+ for( i = left; i <= right; i++ )
+ {
+ if( !mask[i] && DIFF_INT_C3( img + i*3, val0 ))
+ {
+ int j = i;
+ mask[i] = newMaskVal;
+ while( !mask[--j] && DIFF_INT_C3( img + j*3, val0 ))
+ mask[j] = newMaskVal;
+
+ while( !mask[++i] && DIFF_INT_C3( img + i*3, val0 ))
+ mask[i] = newMaskVal;
+
+ ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
+ }
+ }
+ else if( !_8_connectivity )
+ for( i = left; i <= right; i++ )
+ {
+ if( !mask[i] && DIFF_INT_C3( img + i*3, img - curstep + i*3 ))
+ {
+ int j = i;
+ mask[i] = newMaskVal;
+ while( !mask[--j] && DIFF_INT_C3( img + j*3, img + (j+1)*3 ))
+ mask[j] = newMaskVal;
+
+ while( !mask[++i] &&
+ (DIFF_INT_C3( img + i*3, img + (i-1)*3 ) ||
+ (DIFF_INT_C3( img + i*3, img + i*3 - curstep) && i <= R)))
+ mask[i] = newMaskVal;
+
+ ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
+ }
+ }
+ else
+ for( i = left; i <= right; i++ )
+ {
+ int idx, val[3];
+
+ if( !mask[i] &&
+ (((ICV_SET_C3( val, img+i*3 ),
+ (unsigned)(idx = i-L-1) <= length) &&
+ DIFF_INT_C3( val, img - curstep + (i-1)*3 )) ||
+ ((unsigned)(++idx) <= length &&
+ DIFF_INT_C3( val, img - curstep + i*3 )) ||
+ ((unsigned)(++idx) <= length &&
+ DIFF_INT_C3( val, img - curstep + (i+1)*3 ))))
+ {
+ int j = i;
+ mask[i] = newMaskVal;
+ while( !mask[--j] && DIFF_INT_C3( img + j*3, img + (j+1)*3 ))
+ mask[j] = newMaskVal;
+
+ while( !mask[++i] &&
+ ((ICV_SET_C3( val, img + i*3 ),
+ DIFF_INT_C3( val, img + (i-1)*3 )) ||
+ (((unsigned)(idx = i-L-1) <= length &&
+ DIFF_INT_C3( val, img - curstep + (i-1)*3 ))) ||
+ ((unsigned)(++idx) <= length &&
+ DIFF_INT_C3( val, img - curstep + i*3 )) ||
+ ((unsigned)(++idx) <= length &&
+ DIFF_INT_C3( val, img - curstep + (i+1)*3 ))))
+ mask[i] = newMaskVal;
+
+ ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
+ }
+ }
+ }
+
+ img = pImage + YC * step;
+ if( fillImage )
+ for( i = L; i <= R; i++ )
+ ICV_SET_C3( img + i*3, newVal );
+ else if( region )
+ for( i = L; i <= R; i++ )
+ {
+ sum[0] += img[i*3];
+ sum[1] += img[i*3+1];
+ sum[2] += img[i*3+2];
+ }
+ }
+ }
+
+ if( region )
+ {
+ region->area = area;
+ region->rect.x = XMin;
+ region->rect.y = YMin;
+ region->rect.width = XMax - XMin + 1;
+ region->rect.height = YMax - YMin + 1;
+
+ if( fillImage )
+ region->value = cvScalar(newVal[0], newVal[1], newVal[2]);
+ else
+ {
+ double iarea = area ? 1./area : 0;
+ region->value = cvScalar(sum[0]*iarea, sum[1]*iarea, sum[2]*iarea);
+ }
+ }
+
+ return CV_NO_ERR;
+}
+
+
+static CvStatus
+icvFloodFill_Grad_32f_CnIR( float* pImage, int step, uchar* pMask, int maskStep,
+ CvSize /*roi*/, CvPoint seed, float* _newVal, float* _d_lw,
+ float* _d_up, CvConnectedComp* region, int flags,
+ CvFFillSegment* buffer, int buffer_size, int cn )
+{
+ float* img = pImage + (step /= sizeof(float))*seed.y;
+ uchar* mask = (pMask += maskStep + 1) + maskStep*seed.y;
+ int i, L, R;
+ int area = 0;
+ double sum[] = {0,0,0}, val0[] = {0,0,0};
+ float newVal[] = {0,0,0};
+ float d_lw[] = {0,0,0};
+ float interval[] = {0,0,0};
+ int XMin, XMax, YMin = seed.y, YMax = seed.y;
+ int _8_connectivity = (flags & 255) == 8;
+ int fixedRange = flags & CV_FLOODFILL_FIXED_RANGE;
+ int fillImage = (flags & CV_FLOODFILL_MASK_ONLY) == 0;
+ uchar newMaskVal = (uchar)(flags & 0xff00 ? flags >> 8 : 1);
+ CvFFillSegment* buffer_end = buffer + buffer_size, *head = buffer, *tail = buffer;
+
+ L = R = seed.x;
+ if( mask[L] )
+ return CV_OK;
+
+ mask[L] = newMaskVal;
+
+ for( i = 0; i < cn; i++ )
+ {
+ newVal[i] = _newVal[i];
+ d_lw[i] = 0.5f*(_d_lw[i] - _d_up[i]);
+ interval[i] = 0.5f*(_d_lw[i] + _d_up[i]);
+ if( fixedRange )
+ val0[i] = img[L*cn+i];
+ }
+
+ if( cn == 1 )
+ {
+ if( fixedRange )
+ {
+ while( !mask[R + 1] && DIFF_FLT_C1( img + (R+1), val0 ))
+ mask[++R] = newMaskVal;
+
+ while( !mask[L - 1] && DIFF_FLT_C1( img + (L-1), val0 ))
+ mask[--L] = newMaskVal;
+ }
+ else
+ {
+ while( !mask[R + 1] && DIFF_FLT_C1( img + (R+1), img + R ))
+ mask[++R] = newMaskVal;
+
+ while( !mask[L - 1] && DIFF_FLT_C1( img + (L-1), img + L ))
+ mask[--L] = newMaskVal;
+ }
+ }
+ else
+ {
+ if( fixedRange )
+ {
+ while( !mask[R + 1] && DIFF_FLT_C3( img + (R+1)*3, val0 ))
+ mask[++R] = newMaskVal;
+
+ while( !mask[L - 1] && DIFF_FLT_C3( img + (L-1)*3, val0 ))
+ mask[--L] = newMaskVal;
+ }
+ else
+ {
+ while( !mask[R + 1] && DIFF_FLT_C3( img + (R+1)*3, img + R*3 ))
+ mask[++R] = newMaskVal;
+
+ while( !mask[L - 1] && DIFF_FLT_C3( img + (L-1)*3, img + L*3 ))
+ mask[--L] = newMaskVal;
+ }
+ }
+
+ XMax = R;
+ XMin = L;
+ ICV_PUSH( seed.y, L, R, R + 1, R, UP );
+
+ while( head != tail )
+ {
+ int k, YC, PL, PR, dir, curstep;
+ ICV_POP( YC, L, R, PL, PR, dir );
+
+ int data[][3] =
+ {
+ {-dir, L - _8_connectivity, R + _8_connectivity},
+ {dir, L - _8_connectivity, PL - 1},
+ {dir, PR + 1, R + _8_connectivity}
+ };
+
+ unsigned length = (unsigned)(R-L);
+
+ if( region )
+ {
+ area += (int)length + 1;
+
+ if( XMax < R ) XMax = R;
+ if( XMin > L ) XMin = L;
+ if( YMax < YC ) YMax = YC;
+ if( YMin > YC ) YMin = YC;
+ }
+
+ if( cn == 1 )
+ {
+ for( k = 0; k < 3; k++ )
+ {
+ dir = data[k][0];
+ curstep = dir * step;
+ img = pImage + (YC + dir) * step;
+ mask = pMask + (YC + dir) * maskStep;
+ int left = data[k][1];
+ int right = data[k][2];
+
+ if( fixedRange )
+ for( i = left; i <= right; i++ )
+ {
+ if( !mask[i] && DIFF_FLT_C1( img + i, val0 ))
+ {
+ int j = i;
+ mask[i] = newMaskVal;
+ while( !mask[--j] && DIFF_FLT_C1( img + j, val0 ))
+ mask[j] = newMaskVal;
+
+ while( !mask[++i] && DIFF_FLT_C1( img + i, val0 ))
+ mask[i] = newMaskVal;
+
+ ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
+ }
+ }
+ else if( !_8_connectivity )
+ for( i = left; i <= right; i++ )
+ {
+ if( !mask[i] && DIFF_FLT_C1( img + i, img - curstep + i ))
+ {
+ int j = i;
+ mask[i] = newMaskVal;
+ while( !mask[--j] && DIFF_FLT_C1( img + j, img + (j+1) ))
+ mask[j] = newMaskVal;
+
+ while( !mask[++i] &&
+ (DIFF_FLT_C1( img + i, img + (i-1) ) ||
+ (DIFF_FLT_C1( img + i, img + i - curstep) && i <= R)))
+ mask[i] = newMaskVal;
+
+ ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
+ }
+ }
+ else
+ for( i = left; i <= right; i++ )
+ {
+ int idx;
+ float val[1];
+
+ if( !mask[i] &&
+ (((val[0] = img[i],
+ (unsigned)(idx = i-L-1) <= length) &&
+ DIFF_FLT_C1( val, img - curstep + (i-1) )) ||
+ ((unsigned)(++idx) <= length &&
+ DIFF_FLT_C1( val, img - curstep + i )) ||
+ ((unsigned)(++idx) <= length &&
+ DIFF_FLT_C1( val, img - curstep + (i+1) ))))
+ {
+ int j = i;
+ mask[i] = newMaskVal;
+ while( !mask[--j] && DIFF_FLT_C1( img + j, img + (j+1) ))
+ mask[j] = newMaskVal;
+
+ while( !mask[++i] &&
+ ((val[0] = img[i],
+ DIFF_FLT_C1( val, img + (i-1) )) ||
+ (((unsigned)(idx = i-L-1) <= length &&
+ DIFF_FLT_C1( val, img - curstep + (i-1) ))) ||
+ ((unsigned)(++idx) <= length &&
+ DIFF_FLT_C1( val, img - curstep + i )) ||
+ ((unsigned)(++idx) <= length &&
+ DIFF_FLT_C1( val, img - curstep + (i+1) ))))
+ mask[i] = newMaskVal;
+
+ ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
+ }
+ }
+ }
+
+ img = pImage + YC * step;
+ if( fillImage )
+ for( i = L; i <= R; i++ )
+ img[i] = newVal[0];
+ else if( region )
+ for( i = L; i <= R; i++ )
+ sum[0] += img[i];
+ }
+ else
+ {
+ for( k = 0; k < 3; k++ )
+ {
+ dir = data[k][0];
+ curstep = dir * step;
+ img = pImage + (YC + dir) * step;
+ mask = pMask + (YC + dir) * maskStep;
+ int left = data[k][1];
+ int right = data[k][2];
+
+ if( fixedRange )
+ for( i = left; i <= right; i++ )
+ {
+ if( !mask[i] && DIFF_FLT_C3( img + i*3, val0 ))
+ {
+ int j = i;
+ mask[i] = newMaskVal;
+ while( !mask[--j] && DIFF_FLT_C3( img + j*3, val0 ))
+ mask[j] = newMaskVal;
+
+ while( !mask[++i] && DIFF_FLT_C3( img + i*3, val0 ))
+ mask[i] = newMaskVal;
+
+ ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
+ }
+ }
+ else if( !_8_connectivity )
+ for( i = left; i <= right; i++ )
+ {
+ if( !mask[i] && DIFF_FLT_C3( img + i*3, img - curstep + i*3 ))
+ {
+ int j = i;
+ mask[i] = newMaskVal;
+ while( !mask[--j] && DIFF_FLT_C3( img + j*3, img + (j+1)*3 ))
+ mask[j] = newMaskVal;
+
+ while( !mask[++i] &&
+ (DIFF_FLT_C3( img + i*3, img + (i-1)*3 ) ||
+ (DIFF_FLT_C3( img + i*3, img + i*3 - curstep) && i <= R)))
+ mask[i] = newMaskVal;
+
+ ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
+ }
+ }
+ else
+ for( i = left; i <= right; i++ )
+ {
+ int idx;
+ float val[3];
+
+ if( !mask[i] &&
+ (((ICV_SET_C3( val, img+i*3 ),
+ (unsigned)(idx = i-L-1) <= length) &&
+ DIFF_FLT_C3( val, img - curstep + (i-1)*3 )) ||
+ ((unsigned)(++idx) <= length &&
+ DIFF_FLT_C3( val, img - curstep + i*3 )) ||
+ ((unsigned)(++idx) <= length &&
+ DIFF_FLT_C3( val, img - curstep + (i+1)*3 ))))
+ {
+ int j = i;
+ mask[i] = newMaskVal;
+ while( !mask[--j] && DIFF_FLT_C3( img + j*3, img + (j+1)*3 ))
+ mask[j] = newMaskVal;
+
+ while( !mask[++i] &&
+ ((ICV_SET_C3( val, img + i*3 ),
+ DIFF_FLT_C3( val, img + (i-1)*3 )) ||
+ (((unsigned)(idx = i-L-1) <= length &&
+ DIFF_FLT_C3( val, img - curstep + (i-1)*3 ))) ||
+ ((unsigned)(++idx) <= length &&
+ DIFF_FLT_C3( val, img - curstep + i*3 )) ||
+ ((unsigned)(++idx) <= length &&
+ DIFF_FLT_C3( val, img - curstep + (i+1)*3 ))))
+ mask[i] = newMaskVal;
+
+ ICV_PUSH( YC + dir, j+1, i-1, L, R, -dir );
+ }
+ }
+ }
+
+ img = pImage + YC * step;
+ if( fillImage )
+ for( i = L; i <= R; i++ )
+ ICV_SET_C3( img + i*3, newVal );
+ else if( region )
+ for( i = L; i <= R; i++ )
+ {
+ sum[0] += img[i*3];
+ sum[1] += img[i*3+1];
+ sum[2] += img[i*3+2];
+ }
+ }
+ }
+
+ if( region )
+ {
+ region->area = area;
+ region->rect.x = XMin;
+ region->rect.y = YMin;
+ region->rect.width = XMax - XMin + 1;
+ region->rect.height = YMax - YMin + 1;
+
+ if( fillImage )
+ region->value = cvScalar(newVal[0], newVal[1], newVal[2]);
+ else
+ {
+ double iarea = area ? 1./area : 0;
+ region->value = cvScalar(sum[0]*iarea, sum[1]*iarea, sum[2]*iarea);
+ }
+ }
+
+ return CV_NO_ERR;
+}
+
+
+/****************************************************************************************\
+* External Functions *
+\****************************************************************************************/
+
+typedef CvStatus (CV_CDECL* CvFloodFillFunc)(
+ void* img, int step, CvSize size, CvPoint seed, void* newval,
+ CvConnectedComp* comp, int flags, void* buffer, int buffer_size, int cn );
+
+typedef CvStatus (CV_CDECL* CvFloodFillGradFunc)(
+ void* img, int step, uchar* mask, int maskStep, CvSize size,
+ CvPoint seed, void* newval, void* d_lw, void* d_up, void* ccomp,
+ int flags, void* buffer, int buffer_size, int cn );
+
+static void icvInitFloodFill( void** ffill_tab,
+ void** ffillgrad_tab )
+{
+ ffill_tab[0] = (void*)icvFloodFill_8u_CnIR;
+ ffill_tab[1] = (void*)icvFloodFill_32f_CnIR;
+
+ ffillgrad_tab[0] = (void*)icvFloodFill_Grad_8u_CnIR;
+ ffillgrad_tab[1] = (void*)icvFloodFill_Grad_32f_CnIR;
+}
+
+
+CV_IMPL void
+cvFloodFill( CvArr* arr, CvPoint seed_point,
+ CvScalar newVal, CvScalar lo_diff, CvScalar up_diff,
+ CvConnectedComp* comp, int flags, CvArr* maskarr )
+{
+ static void* ffill_tab[4];
+ static void* ffillgrad_tab[4];
+ static int inittab = 0;
+
+ CvMat* tempMask = 0;
+ CvFFillSegment* buffer = 0;
+ CV_FUNCNAME( "cvFloodFill" );
+
+ if( comp )
+ memset( comp, 0, sizeof(*comp) );
+
+ __BEGIN__;
+
+ int i, type, depth, cn, is_simple, idx;
+ int buffer_size, connectivity = flags & 255;
+ double nv_buf[4] = {0,0,0,0};
+ union { uchar b[4]; float f[4]; } ld_buf, ud_buf;
+ CvMat stub, *img = (CvMat*)arr;
+ CvMat maskstub, *mask = (CvMat*)maskarr;
+ CvSize size;
+
+ if( !inittab )
+ {
+ icvInitFloodFill( ffill_tab, ffillgrad_tab );
+ inittab = 1;
+ }
+
+ CV_CALL( img = cvGetMat( img, &stub ));
+ type = CV_MAT_TYPE( img->type );
+ depth = CV_MAT_DEPTH(type);
+ cn = CV_MAT_CN(type);
+
+ idx = type == CV_8UC1 || type == CV_8UC3 ? 0 :
+ type == CV_32FC1 || type == CV_32FC3 ? 1 : -1;
+
+ if( idx < 0 )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( connectivity == 0 )
+ connectivity = 4;
+ else if( connectivity != 4 && connectivity != 8 )
+ CV_ERROR( CV_StsBadFlag, "Connectivity must be 4, 0(=4) or 8" );
+
+ is_simple = mask == 0 && (flags & CV_FLOODFILL_MASK_ONLY) == 0;
+
+ for( i = 0; i < cn; i++ )
+ {
+ if( lo_diff.val[i] < 0 || up_diff.val[i] < 0 )
+ CV_ERROR( CV_StsBadArg, "lo_diff and up_diff must be non-negative" );
+ is_simple &= fabs(lo_diff.val[i]) < DBL_EPSILON && fabs(up_diff.val[i]) < DBL_EPSILON;
+ }
+
+ size = cvGetMatSize( img );
+
+ if( (unsigned)seed_point.x >= (unsigned)size.width ||
+ (unsigned)seed_point.y >= (unsigned)size.height )
+ CV_ERROR( CV_StsOutOfRange, "Seed point is outside of image" );
+
+ cvScalarToRawData( &newVal, &nv_buf, type, 0 );
+ buffer_size = MAX( size.width, size.height )*2;
+ CV_CALL( buffer = (CvFFillSegment*)cvAlloc( buffer_size*sizeof(buffer[0])));
+
+ if( is_simple )
+ {
+ int elem_size = CV_ELEM_SIZE(type);
+ const uchar* seed_ptr = img->data.ptr + img->step*seed_point.y + elem_size*seed_point.x;
+ CvFloodFillFunc func = (CvFloodFillFunc)ffill_tab[idx];
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+ // check if the new value is different from the current value at the seed point.
+ // if they are exactly the same, use the generic version with mask to avoid infinite loops.
+ for( i = 0; i < elem_size; i++ )
+ if( seed_ptr[i] != ((uchar*)nv_buf)[i] )
+ break;
+ if( i < elem_size )
+ {
+ IPPI_CALL( func( img->data.ptr, img->step, size,
+ seed_point, &nv_buf, comp, flags,
+ buffer, buffer_size, cn ));
+ EXIT;
+ }
+ }
+
+ {
+ CvFloodFillGradFunc func = (CvFloodFillGradFunc)ffillgrad_tab[idx];
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( !mask )
+ {
+ /* created mask will be 8-byte aligned */
+ tempMask = cvCreateMat( size.height + 2, (size.width + 9) & -8, CV_8UC1 );
+ mask = tempMask;
+ }
+ else
+ {
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+ if( !CV_IS_MASK_ARR( mask ))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( mask->width != size.width + 2 || mask->height != size.height + 2 )
+ CV_ERROR( CV_StsUnmatchedSizes, "mask must be 2 pixel wider "
+ "and 2 pixel taller than filled image" );
+ }
+
+ {
+ int width = tempMask ? mask->step : size.width + 2;
+ uchar* mask_row = mask->data.ptr + mask->step;
+ memset( mask_row - mask->step, 1, width );
+
+ for( i = 1; i <= size.height; i++, mask_row += mask->step )
+ {
+ if( tempMask )
+ memset( mask_row, 0, width );
+ mask_row[0] = mask_row[size.width+1] = (uchar)1;
+ }
+ memset( mask_row, 1, width );
+ }
+
+ if( depth == CV_8U )
+ for( i = 0; i < cn; i++ )
+ {
+ int t = cvFloor(lo_diff.val[i]);
+ ld_buf.b[i] = CV_CAST_8U(t);
+ t = cvFloor(up_diff.val[i]);
+ ud_buf.b[i] = CV_CAST_8U(t);
+ }
+ else
+ for( i = 0; i < cn; i++ )
+ {
+ ld_buf.f[i] = (float)lo_diff.val[i];
+ ud_buf.f[i] = (float)up_diff.val[i];
+ }
+
+ IPPI_CALL( func( img->data.ptr, img->step, mask->data.ptr, mask->step,
+ size, seed_point, &nv_buf, ld_buf.f, ud_buf.f,
+ comp, flags, buffer, buffer_size, cn ));
+ }
+
+ __END__;
+
+ cvFree( &buffer );
+ cvReleaseMat( &tempMask );
+}
+
+/* End of file. */
diff --git a/cv/src/cvfundam.cpp b/cv/src/cvfundam.cpp
new file mode 100644
index 0000000..42adabf
--- /dev/null
+++ b/cv/src/cvfundam.cpp
@@ -0,0 +1,1438 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+template<typename T> int icvCompressPoints( T* ptr, const uchar* mask, int mstep, int count )
+{
+ int i, j;
+ for( i = j = 0; i < count; i++ )
+ if( mask[i*mstep] )
+ {
+ if( i > j )
+ ptr[j] = ptr[i];
+ j++;
+ }
+ return j;
+}
+
+class CvModelEstimator2
+{
+public:
+ CvModelEstimator2(int _modelPoints, CvSize _modelSize, int _maxBasicSolutions);
+ virtual ~CvModelEstimator2();
+
+ virtual int runKernel( const CvMat* m1, const CvMat* m2, CvMat* model )=0;
+ virtual bool runLMeDS( const CvMat* m1, const CvMat* m2, CvMat* model,
+ CvMat* mask, double confidence=0.99, int maxIters=1000 );
+ virtual bool runRANSAC( const CvMat* m1, const CvMat* m2, CvMat* model,
+ CvMat* mask, double threshold,
+ double confidence=0.99, int maxIters=1000 );
+ virtual bool refine( const CvMat*, const CvMat*, CvMat*, int ) { return true; }
+ virtual void setSeed( int64 seed );
+
+protected:
+ virtual void computeReprojError( const CvMat* m1, const CvMat* m2,
+ const CvMat* model, CvMat* error ) = 0;
+ virtual int findInliers( const CvMat* m1, const CvMat* m2,
+ const CvMat* model, CvMat* error,
+ CvMat* mask, double threshold );
+ virtual bool getSubset( const CvMat* m1, const CvMat* m2,
+ CvMat* ms1, CvMat* ms2, int maxAttempts=1000 );
+ virtual bool checkSubset( const CvMat* ms1, int count );
+
+ CvRNG rng;
+ int modelPoints;
+ CvSize modelSize;
+ int maxBasicSolutions;
+ bool checkPartialSubsets;
+};
+
+
+CvModelEstimator2::CvModelEstimator2(int _modelPoints, CvSize _modelSize, int _maxBasicSolutions)
+{
+ modelPoints = _modelPoints;
+ modelSize = _modelSize;
+ maxBasicSolutions = _maxBasicSolutions;
+ checkPartialSubsets = true;
+ rng = cvRNG(-1);
+}
+
+CvModelEstimator2::~CvModelEstimator2()
+{
+}
+
+void CvModelEstimator2::setSeed( int64 seed )
+{
+ rng = cvRNG(seed);
+}
+
+
+int CvModelEstimator2::findInliers( const CvMat* m1, const CvMat* m2,
+ const CvMat* model, CvMat* _err,
+ CvMat* _mask, double threshold )
+{
+ int i, count = _err->rows*_err->cols, goodCount = 0;
+ const float* err = _err->data.fl;
+ uchar* mask = _mask->data.ptr;
+
+ computeReprojError( m1, m2, model, _err );
+ threshold *= threshold;
+ for( i = 0; i < count; i++ )
+ goodCount += mask[i] = err[i] <= threshold;
+ return goodCount;
+}
+
+
+CV_IMPL int
+cvRANSACUpdateNumIters( double p, double ep,
+ int model_points, int max_iters )
+{
+ int result = 0;
+
+ CV_FUNCNAME( "cvRANSACUpdateNumIters" );
+
+ __BEGIN__;
+
+ double num, denom;
+
+ if( model_points <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "the number of model points should be positive" );
+
+ p = MAX(p, 0.);
+ p = MIN(p, 1.);
+ ep = MAX(ep, 0.);
+ ep = MIN(ep, 1.);
+
+ // avoid inf's & nan's
+ num = MAX(1. - p, DBL_MIN);
+ denom = 1. - pow(1. - ep,model_points);
+ if( denom < DBL_MIN )
+ EXIT;
+
+ num = log(num);
+ denom = log(denom);
+
+ result = denom >= 0 || -num >= max_iters*(-denom) ?
+ max_iters : cvRound(num/denom);
+
+ __END__;
+
+ return result;
+}
+
+bool CvModelEstimator2::runRANSAC( const CvMat* m1, const CvMat* m2, CvMat* model,
+ CvMat* mask, double reprojThreshold,
+ double confidence, int maxIters )
+{
+ bool result = false;
+ CvMat* mask0 = mask, *tmask = 0, *t;
+ CvMat* models = 0, *err = 0;
+ CvMat *ms1 = 0, *ms2 = 0;
+
+ CV_FUNCNAME( "CvModelEstimator2::estimateRansac" );
+
+ __BEGIN__;
+
+ int iter, niters = maxIters;
+ int count = m1->rows*m1->cols, maxGoodCount = 0;
+ CV_ASSERT( CV_ARE_SIZES_EQ(m1, m2) && CV_ARE_SIZES_EQ(m1, mask) );
+
+ if( count < modelPoints )
+ EXIT;
+
+ models = cvCreateMat( modelSize.height*maxBasicSolutions, modelSize.width, CV_64FC1 );
+ err = cvCreateMat( 1, count, CV_32FC1 );
+ tmask = cvCreateMat( 1, count, CV_8UC1 );
+
+ if( count > modelPoints )
+ {
+ ms1 = cvCreateMat( 1, modelPoints, m1->type );
+ ms2 = cvCreateMat( 1, modelPoints, m2->type );
+ }
+ else
+ {
+ niters = 1;
+ ms1 = (CvMat*)m1;
+ ms2 = (CvMat*)m2;
+ }
+
+ for( iter = 0; iter < niters; iter++ )
+ {
+ int i, goodCount, nmodels;
+ if( count > modelPoints )
+ {
+ bool found = getSubset( m1, m2, ms1, ms2, modelPoints );
+ if( !found )
+ {
+ if( iter == 0 )
+ EXIT;
+ break;
+ }
+ }
+
+ nmodels = runKernel( ms1, ms2, models );
+ if( nmodels <= 0 )
+ continue;
+ for( i = 0; i < nmodels; i++ )
+ {
+ CvMat model_i;
+ cvGetRows( models, &model_i, i*modelSize.height, (i+1)*modelSize.height );
+ goodCount = findInliers( m1, m2, &model_i, err, tmask, reprojThreshold );
+
+ if( goodCount > MAX(maxGoodCount, modelPoints-1) )
+ {
+ CV_SWAP( tmask, mask, t );
+ cvCopy( &model_i, model );
+ maxGoodCount = goodCount;
+ niters = cvRANSACUpdateNumIters( confidence,
+ (double)(count - goodCount)/count, modelPoints, niters );
+ }
+ }
+ }
+
+ if( maxGoodCount > 0 )
+ {
+ if( mask != mask0 )
+ {
+ CV_SWAP( tmask, mask, t );
+ cvCopy( tmask, mask );
+ }
+ result = true;
+ }
+
+ __END__;
+
+ if( ms1 != m1 )
+ cvReleaseMat( &ms1 );
+ if( ms2 != m2 )
+ cvReleaseMat( &ms2 );
+ cvReleaseMat( &models );
+ cvReleaseMat( &err );
+ cvReleaseMat( &tmask );
+ return result;
+}
+
+
+static CV_IMPLEMENT_QSORT( icvSortDistances, int, CV_LT )
+
+bool CvModelEstimator2::runLMeDS( const CvMat* m1, const CvMat* m2, CvMat* model,
+ CvMat* mask, double confidence, int maxIters )
+{
+ const double outlierRatio = 0.45;
+ bool result = false;
+ CvMat* models = 0;
+ CvMat *ms1 = 0, *ms2 = 0;
+ CvMat* err = 0;
+
+ CV_FUNCNAME( "CvModelEstimator2::estimateLMeDS" );
+
+ __BEGIN__;
+
+ int iter, niters = maxIters;
+ int count = m1->rows*m1->cols;
+ double minMedian = DBL_MAX, sigma;
+
+ CV_ASSERT( CV_ARE_SIZES_EQ(m1, m2) && CV_ARE_SIZES_EQ(m1, mask) );
+
+ if( count < modelPoints )
+ EXIT;
+
+ models = cvCreateMat( modelSize.height*maxBasicSolutions, modelSize.width, CV_64FC1 );
+ err = cvCreateMat( 1, count, CV_32FC1 );
+
+ if( count > modelPoints )
+ {
+ ms1 = cvCreateMat( 1, modelPoints, m1->type );
+ ms2 = cvCreateMat( 1, modelPoints, m2->type );
+ }
+ else
+ {
+ niters = 1;
+ ms1 = (CvMat*)m1;
+ ms2 = (CvMat*)m2;
+ }
+
+ niters = cvRound(log(1-confidence)/log(1-pow(1-outlierRatio,(double)modelPoints)));
+ niters = MIN( MAX(niters, 3), maxIters );
+
+ for( iter = 0; iter < niters; iter++ )
+ {
+ int i, nmodels;
+ if( count > modelPoints )
+ {
+ bool found = getSubset( m1, m2, ms1, ms2, 300 );
+ if( !found )
+ {
+ if( iter == 0 )
+ EXIT;
+ break;
+ }
+ }
+
+ nmodels = runKernel( ms1, ms2, models );
+ if( nmodels <= 0 )
+ continue;
+ for( i = 0; i < nmodels; i++ )
+ {
+ CvMat model_i;
+ cvGetRows( models, &model_i, i*modelSize.height, (i+1)*modelSize.height );
+ computeReprojError( m1, m2, &model_i, err );
+ icvSortDistances( err->data.i, count, 0 );
+
+ double median = count % 2 != 0 ?
+ err->data.fl[count/2] : (err->data.fl[count/2-1] + err->data.fl[count/2])*0.5;
+
+ if( median < minMedian )
+ {
+ minMedian = median;
+ cvCopy( &model_i, model );
+ }
+ }
+ }
+
+ if( minMedian < DBL_MAX )
+ {
+ sigma = 2.5*1.4826*(1 + 5./(count - modelPoints))*sqrt(minMedian);
+ sigma = MAX( sigma, FLT_EPSILON*100 );
+
+ count = findInliers( m1, m2, model, err, mask, sigma );
+ result = count >= modelPoints;
+ }
+
+ __END__;
+
+ if( ms1 != m1 )
+ cvReleaseMat( &ms1 );
+ if( ms2 != m2 )
+ cvReleaseMat( &ms2 );
+ cvReleaseMat( &models );
+ cvReleaseMat( &err );
+ return result;
+}
+
+
+bool CvModelEstimator2::getSubset( const CvMat* m1, const CvMat* m2,
+ CvMat* ms1, CvMat* ms2, int maxAttempts )
+{
+ int* idx = (int*)cvStackAlloc( modelPoints*sizeof(idx[0]) );
+ int i, j, k, idx_i, iters = 0;
+ int type = CV_MAT_TYPE(m1->type), elemSize = CV_ELEM_SIZE(type);
+ const int *m1ptr = m1->data.i, *m2ptr = m2->data.i;
+ int *ms1ptr = ms1->data.i, *ms2ptr = ms2->data.i;
+ int count = m1->cols*m1->rows;
+
+ assert( CV_IS_MAT_CONT(m1->type & m2->type) && (elemSize % sizeof(int) == 0) );
+ elemSize /= sizeof(int);
+
+ for(;;)
+ {
+ for( i = 0; i < modelPoints && iters < maxAttempts; iters++ )
+ {
+ idx[i] = idx_i = cvRandInt(&rng) % count;
+ for( j = 0; j < i; j++ )
+ if( idx_i == idx[j] )
+ break;
+ if( j < i )
+ continue;
+ for( k = 0; k < elemSize; k++ )
+ {
+ ms1ptr[i*elemSize + k] = m1ptr[idx_i*elemSize + k];
+ ms2ptr[i*elemSize + k] = m2ptr[idx_i*elemSize + k];
+ }
+ if( checkPartialSubsets && (!checkSubset( ms1, i+1 ) || !checkSubset( ms2, i+1 )))
+ continue;
+ i++;
+ iters = 0;
+ }
+ if( !checkPartialSubsets && i == modelPoints &&
+ (!checkSubset( ms1, i+1 ) || !checkSubset( ms2, i+1 )))
+ continue;
+ break;
+ }
+
+ return i == modelPoints;
+}
+
+
+bool CvModelEstimator2::checkSubset( const CvMat* m, int count )
+{
+ int j, k, i = count-1;
+ CvPoint2D64f* ptr = (CvPoint2D64f*)m->data.ptr;
+
+ assert( CV_MAT_TYPE(m->type) == CV_64FC2 );
+
+ // check that the i-th selected point does not belong
+ // to a line connecting some previously selected points
+ for( j = 0; j < i; j++ )
+ {
+ double dx1 = ptr[j].x - ptr[i].x;
+ double dy1 = ptr[j].y - ptr[i].y;
+ for( k = 0; k < j; k++ )
+ {
+ double dx2 = ptr[k].x - ptr[i].x;
+ double dy2 = ptr[k].y - ptr[i].y;
+ if( fabs(dx2*dy1 - dy2*dx1) < FLT_EPSILON*(fabs(dx1) + fabs(dy1) + fabs(dx2) + fabs(dy2)))
+ break;
+ }
+ if( k < j )
+ break;
+ }
+
+ return j == i;
+}
+
+
+class CvHomographyEstimator : public CvModelEstimator2
+{
+public:
+ CvHomographyEstimator( int modelPoints );
+
+ virtual int runKernel( const CvMat* m1, const CvMat* m2, CvMat* model );
+ virtual bool refine( const CvMat* m1, const CvMat* m2,
+ CvMat* model, int maxIters );
+protected:
+ virtual void computeReprojError( const CvMat* m1, const CvMat* m2,
+ const CvMat* model, CvMat* error );
+};
+
+
+CvHomographyEstimator::CvHomographyEstimator(int _modelPoints)
+ : CvModelEstimator2(_modelPoints, cvSize(3,3), 1)
+{
+ assert( _modelPoints == 4 || _modelPoints == 5 );
+}
+
+int CvHomographyEstimator::runKernel( const CvMat* m1, const CvMat* m2, CvMat* H )
+{
+ int i, count = m1->rows*m1->cols;
+ const CvPoint2D64f* M = (const CvPoint2D64f*)m1->data.ptr;
+ const CvPoint2D64f* m = (const CvPoint2D64f*)m2->data.ptr;
+
+ double LtL[9][9], W[9][9], V[9][9];
+ CvMat _LtL = cvMat( 9, 9, CV_64F, LtL );
+ CvMat _W = cvMat( 9, 9, CV_64F, W );
+ CvMat _V = cvMat( 9, 9, CV_64F, V );
+ CvMat _H0 = cvMat( 3, 3, CV_64F, V[8] );
+ CvMat _Htemp = cvMat( 3, 3, CV_64F, V[7] );
+ CvPoint2D64f cM={0,0}, cm={0,0}, sM={0,0}, sm={0,0};
+
+ for( i = 0; i < count; i++ )
+ {
+ cm.x += m[i].x; cm.y += m[i].y;
+ cM.x += M[i].x; cM.y += M[i].y;
+ }
+
+ cm.x /= count; cm.y /= count;
+ cM.x /= count; cM.y /= count;
+
+ for( i = 0; i < count; i++ )
+ {
+ sm.x += fabs(m[i].x - cm.x);
+ sm.y += fabs(m[i].y - cm.y);
+ sM.x += fabs(M[i].x - cM.x);
+ sM.y += fabs(M[i].y - cM.y);
+ }
+
+ sm.x = count/sm.x; sm.y = count/sm.y;
+ sM.x = count/sM.x; sM.y = count/sM.y;
+
+ double invHnorm[9] = { 1./sm.x, 0, cm.x, 0, 1./sm.y, cm.y, 0, 0, 1 };
+ double Hnorm2[9] = { sM.x, 0, -cM.x*sM.x, 0, sM.y, -cM.y*sM.y, 0, 0, 1 };
+ CvMat _invHnorm = cvMat( 3, 3, CV_64FC1, invHnorm );
+ CvMat _Hnorm2 = cvMat( 3, 3, CV_64FC1, Hnorm2 );
+
+ cvZero( &_LtL );
+ for( i = 0; i < count; i++ )
+ {
+ double x = (m[i].x - cm.x)*sm.x, y = (m[i].y - cm.y)*sm.y;
+ double X = (M[i].x - cM.x)*sM.x, Y = (M[i].y - cM.y)*sM.y;
+ double Lx[] = { X, Y, 1, 0, 0, 0, -x*X, -x*Y, -x };
+ double Ly[] = { 0, 0, 0, X, Y, 1, -y*X, -y*Y, -y };
+ int j, k;
+ for( j = 0; j < 9; j++ )
+ for( k = j; k < 9; k++ )
+ LtL[j][k] += Lx[j]*Lx[k] + Ly[j]*Ly[k];
+ }
+ cvCompleteSymm( &_LtL );
+
+ cvSVD( &_LtL, &_W, 0, &_V, CV_SVD_MODIFY_A + CV_SVD_V_T );
+ cvMatMul( &_invHnorm, &_H0, &_Htemp );
+ cvMatMul( &_Htemp, &_Hnorm2, &_H0 );
+ cvConvertScale( &_H0, H, 1./_H0.data.db[8] );
+
+ return 1;
+}
+
+
+void CvHomographyEstimator::computeReprojError( const CvMat* m1, const CvMat* m2,
+ const CvMat* model, CvMat* _err )
+{
+ int i, count = m1->rows*m1->cols;
+ const CvPoint2D64f* M = (const CvPoint2D64f*)m1->data.ptr;
+ const CvPoint2D64f* m = (const CvPoint2D64f*)m2->data.ptr;
+ const double* H = model->data.db;
+ float* err = _err->data.fl;
+
+ for( i = 0; i < count; i++ )
+ {
+ double ww = 1./(H[6]*M[i].x + H[7]*M[i].y + 1.);
+ double dx = (H[0]*M[i].x + H[1]*M[i].y + H[2])*ww - m[i].x;
+ double dy = (H[3]*M[i].x + H[4]*M[i].y + H[5])*ww - m[i].y;
+ err[i] = (float)(dx*dx + dy*dy);
+ }
+}
+
+bool CvHomographyEstimator::refine( const CvMat* m1, const CvMat* m2, CvMat* model, int maxIters )
+{
+ CvLevMarq solver(8, 0, cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, maxIters, DBL_EPSILON));
+ int i, j, k, count = m1->rows*m1->cols;
+ const CvPoint2D64f* M = (const CvPoint2D64f*)m1->data.ptr;
+ const CvPoint2D64f* m = (const CvPoint2D64f*)m2->data.ptr;
+ CvMat modelPart = cvMat( solver.param->rows, solver.param->cols, model->type, model->data.ptr );
+ cvCopy( &modelPart, solver.param );
+
+ for(;;)
+ {
+ const CvMat* _param = 0;
+ CvMat *_JtJ = 0, *_JtErr = 0;
+ double* _errNorm = 0;
+
+ if( !solver.updateAlt( _param, _JtJ, _JtErr, _errNorm ))
+ break;
+
+ for( i = 0; i < count; i++ )
+ {
+ const double* h = _param->data.db;
+ double Mx = M[i].x, My = M[i].y;
+ double ww = 1./(h[6]*Mx + h[7]*My + 1.);
+ double _xi = (h[0]*Mx + h[1]*My + h[2])*ww;
+ double _yi = (h[3]*Mx + h[4]*My + h[5])*ww;
+ double err[] = { _xi - m[i].x, _yi - m[i].y };
+ if( _JtJ || _JtErr )
+ {
+ double J[][8] =
+ {
+ { Mx*ww, My*ww, ww, 0, 0, 0, -Mx*ww*_xi, -My*ww*_xi },
+ { 0, 0, 0, Mx*ww, My*ww, ww, -Mx*ww*_yi, -My*ww*_yi }
+ };
+
+ for( j = 0; j < 8; j++ )
+ {
+ for( k = j; k < 8; k++ )
+ _JtJ->data.db[j*8+k] += J[0][j]*J[0][k] + J[1][j]*J[1][k];
+ _JtErr->data.db[j] += J[0][j]*err[0] + J[1][j]*err[1];
+ }
+ }
+ if( _errNorm )
+ *_errNorm += err[0]*err[0] + err[1]*err[1];
+ }
+ }
+
+ cvCopy( solver.param, &modelPart );
+ return true;
+}
+
+
+CV_IMPL int
+cvFindHomography( const CvMat* objectPoints, const CvMat* imagePoints,
+ CvMat* __H, int method, double ransacReprojThreshold,
+ CvMat* mask )
+{
+ const double confidence = 0.99;
+ bool result = false;
+ CvMat *m = 0, *M = 0, *tempMask = 0;
+
+ CV_FUNCNAME( "cvFindHomography" );
+
+ __BEGIN__;
+
+ double H[9];
+ CvMat _H = cvMat( 3, 3, CV_64FC1, H );
+ int count;
+
+ CV_ASSERT( CV_IS_MAT(imagePoints) && CV_IS_MAT(objectPoints) );
+
+ count = MAX(imagePoints->cols, imagePoints->rows);
+ CV_ASSERT( count >= 4 );
+
+ m = cvCreateMat( 1, count, CV_64FC2 );
+ cvConvertPointsHomogeneous( imagePoints, m );
+
+ M = cvCreateMat( 1, count, CV_64FC2 );
+ cvConvertPointsHomogeneous( objectPoints, M );
+
+ if( mask )
+ {
+ CV_ASSERT( CV_IS_MASK_ARR(mask) && CV_IS_MAT_CONT(mask->type) &&
+ (mask->rows == 1 || mask->cols == 1) &&
+ mask->rows*mask->cols == count );
+ tempMask = mask;
+ }
+ else if( count > 4 )
+ tempMask = cvCreateMat( 1, count, CV_8U );
+ if( tempMask )
+ cvSet( tempMask, cvScalarAll(1.) );
+
+ {
+ CvHomographyEstimator estimator( MIN(count, 5) );
+ if( count == 4 )
+ method = 0;
+ if( method == CV_LMEDS )
+ result = estimator.runLMeDS( M, m, &_H, tempMask, confidence );
+ else if( method == CV_RANSAC )
+ result = estimator.runRANSAC( M, m, &_H, tempMask, ransacReprojThreshold, confidence );
+ else
+ result = estimator.runKernel( M, m, &_H ) > 0;
+
+ if( result && count > 4 )
+ {
+ icvCompressPoints( (CvPoint2D64f*)M->data.ptr, tempMask->data.ptr, 1, count );
+ count = icvCompressPoints( (CvPoint2D64f*)m->data.ptr, tempMask->data.ptr, 1, count );
+ M->cols = m->cols = count;
+ estimator.refine( M, m, &_H, 10 );
+ }
+ }
+
+ if( result )
+ cvConvert( &_H, __H );
+
+ __END__;
+
+ cvReleaseMat( &m );
+ cvReleaseMat( &M );
+ if( tempMask != mask )
+ cvReleaseMat( &tempMask );
+
+ return (int)result;
+}
+
+
+/* Evaluation of Fundamental Matrix from point correspondences.
+ The original code has been written by Valery Mosyagin */
+
+/* The algorithms (except for RANSAC) and the notation have been taken from
+ Zhengyou Zhang's research report
+ "Determining the Epipolar Geometry and its Uncertainty: A Review"
+ that can be found at http://www-sop.inria.fr/robotvis/personnel/zzhang/zzhang-eng.html */
+
+/************************************** 7-point algorithm *******************************/
+class CvFMEstimator : public CvModelEstimator2
+{
+public:
+ CvFMEstimator( int _modelPoints );
+
+ virtual int runKernel( const CvMat* m1, const CvMat* m2, CvMat* model );
+ virtual int run7Point( const CvMat* m1, const CvMat* m2, CvMat* model );
+ virtual int run8Point( const CvMat* m1, const CvMat* m2, CvMat* model );
+protected:
+ virtual void computeReprojError( const CvMat* m1, const CvMat* m2,
+ const CvMat* model, CvMat* error );
+};
+
+CvFMEstimator::CvFMEstimator( int _modelPoints )
+: CvModelEstimator2( _modelPoints, cvSize(3,3), _modelPoints == 7 ? 3 : 1 )
+{
+ assert( _modelPoints == 7 || _modelPoints == 8 );
+}
+
+
+int CvFMEstimator::runKernel( const CvMat* m1, const CvMat* m2, CvMat* model )
+{
+ return modelPoints == 7 ? run7Point( m1, m2, model ) : run8Point( m1, m2, model );
+}
+
+int CvFMEstimator::run7Point( const CvMat* _m1, const CvMat* _m2, CvMat* _fmatrix )
+{
+ double a[7*9], w[7], v[9*9], c[4], r[3];
+ double* f1, *f2;
+ double t0, t1, t2;
+ CvMat A = cvMat( 7, 9, CV_64F, a );
+ CvMat V = cvMat( 9, 9, CV_64F, v );
+ CvMat W = cvMat( 7, 1, CV_64F, w );
+ CvMat coeffs = cvMat( 1, 4, CV_64F, c );
+ CvMat roots = cvMat( 1, 3, CV_64F, r );
+ const CvPoint2D64f* m1 = (const CvPoint2D64f*)_m1->data.ptr;
+ const CvPoint2D64f* m2 = (const CvPoint2D64f*)_m2->data.ptr;
+ double* fmatrix = _fmatrix->data.db;
+ int i, k, n;
+
+ // form a linear system: i-th row of A(=a) represents
+ // the equation: (m2[i], 1)'*F*(m1[i], 1) = 0
+ for( i = 0; i < 7; i++ )
+ {
+ double x0 = m1[i].x, y0 = m1[i].y;
+ double x1 = m2[i].x, y1 = m2[i].y;
+
+ a[i*9+0] = x1*x0;
+ a[i*9+1] = x1*y0;
+ a[i*9+2] = x1;
+ a[i*9+3] = y1*x0;
+ a[i*9+4] = y1*y0;
+ a[i*9+5] = y1;
+ a[i*9+6] = x0;
+ a[i*9+7] = y0;
+ a[i*9+8] = 1;
+ }
+
+ // A*(f11 f12 ... f33)' = 0 is singular (7 equations for 9 variables), so
+ // the solution is linear subspace of dimensionality 2.
+ // => use the last two singular vectors as a basis of the space
+ // (according to SVD properties)
+ cvSVD( &A, &W, 0, &V, CV_SVD_MODIFY_A + CV_SVD_V_T );
+ f1 = v + 7*9;
+ f2 = v + 8*9;
+
+ // f1, f2 is a basis => lambda*f1 + mu*f2 is an arbitrary f. matrix.
+ // as it is determined up to a scale, normalize lambda & mu (lambda + mu = 1),
+ // so f ~ lambda*f1 + (1 - lambda)*f2.
+ // use the additional constraint det(f) = det(lambda*f1 + (1-lambda)*f2) to find lambda.
+ // it will be a cubic equation.
+ // find c - polynomial coefficients.
+ for( i = 0; i < 9; i++ )
+ f1[i] -= f2[i];
+
+ t0 = f2[4]*f2[8] - f2[5]*f2[7];
+ t1 = f2[3]*f2[8] - f2[5]*f2[6];
+ t2 = f2[3]*f2[7] - f2[4]*f2[6];
+
+ c[3] = f2[0]*t0 - f2[1]*t1 + f2[2]*t2;
+
+ c[2] = f1[0]*t0 - f1[1]*t1 + f1[2]*t2 -
+ f1[3]*(f2[1]*f2[8] - f2[2]*f2[7]) +
+ f1[4]*(f2[0]*f2[8] - f2[2]*f2[6]) -
+ f1[5]*(f2[0]*f2[7] - f2[1]*f2[6]) +
+ f1[6]*(f2[1]*f2[5] - f2[2]*f2[4]) -
+ f1[7]*(f2[0]*f2[5] - f2[2]*f2[3]) +
+ f1[8]*(f2[0]*f2[4] - f2[1]*f2[3]);
+
+ t0 = f1[4]*f1[8] - f1[5]*f1[7];
+ t1 = f1[3]*f1[8] - f1[5]*f1[6];
+ t2 = f1[3]*f1[7] - f1[4]*f1[6];
+
+ c[1] = f2[0]*t0 - f2[1]*t1 + f2[2]*t2 -
+ f2[3]*(f1[1]*f1[8] - f1[2]*f1[7]) +
+ f2[4]*(f1[0]*f1[8] - f1[2]*f1[6]) -
+ f2[5]*(f1[0]*f1[7] - f1[1]*f1[6]) +
+ f2[6]*(f1[1]*f1[5] - f1[2]*f1[4]) -
+ f2[7]*(f1[0]*f1[5] - f1[2]*f1[3]) +
+ f2[8]*(f1[0]*f1[4] - f1[1]*f1[3]);
+
+ c[0] = f1[0]*t0 - f1[1]*t1 + f1[2]*t2;
+
+ // solve the cubic equation; there can be 1 to 3 roots ...
+ n = cvSolveCubic( &coeffs, &roots );
+
+ if( n < 1 || n > 3 )
+ return n;
+
+ for( k = 0; k < n; k++, fmatrix += 9 )
+ {
+ // for each root form the fundamental matrix
+ double lambda = r[k], mu = 1.;
+ double s = f1[8]*r[k] + f2[8];
+
+ // normalize each matrix, so that F(3,3) (~fmatrix[8]) == 1
+ if( fabs(s) > DBL_EPSILON )
+ {
+ mu = 1./s;
+ lambda *= mu;
+ fmatrix[8] = 1.;
+ }
+ else
+ fmatrix[8] = 0.;
+
+ for( i = 0; i < 8; i++ )
+ fmatrix[i] = f1[i]*lambda + f2[i]*mu;
+ }
+
+ return n;
+}
+
+
+int CvFMEstimator::run8Point( const CvMat* _m1, const CvMat* _m2, CvMat* _fmatrix )
+{
+ double a[9*9], w[9], v[9*9];
+ CvMat W = cvMat( 1, 9, CV_64F, w );
+ CvMat V = cvMat( 9, 9, CV_64F, v );
+ CvMat A = cvMat( 9, 9, CV_64F, a );
+ CvMat U, F0, TF;
+
+ CvPoint2D64f m0c = {0,0}, m1c = {0,0};
+ double t, scale0 = 0, scale1 = 0;
+
+ const CvPoint2D64f* m1 = (const CvPoint2D64f*)_m1->data.ptr;
+ const CvPoint2D64f* m2 = (const CvPoint2D64f*)_m2->data.ptr;
+ double* fmatrix = _fmatrix->data.db;
+ int i, j, k, count = _m1->cols*_m1->rows;
+
+ // compute centers and average distances for each of the two point sets
+ for( i = 0; i < count; i++ )
+ {
+ double x = m1[i].x, y = m1[i].y;
+ m0c.x += x; m0c.y += y;
+
+ x = m2[i].x, y = m2[i].y;
+ m1c.x += x; m1c.y += y;
+ }
+
+ // calculate the normalizing transformations for each of the point sets:
+ // after the transformation each set will have the mass center at the coordinate origin
+ // and the average distance from the origin will be ~sqrt(2).
+ t = 1./count;
+ m0c.x *= t; m0c.y *= t;
+ m1c.x *= t; m1c.y *= t;
+
+ for( i = 0; i < count; i++ )
+ {
+ double x = m1[i].x - m0c.x, y = m1[i].y - m0c.y;
+ scale0 += sqrt(x*x + y*y);
+
+ x = fabs(m2[i].x - m1c.x), y = fabs(m2[i].y - m1c.y);
+ scale1 += sqrt(x*x + y*y);
+ }
+
+ scale0 *= t;
+ scale1 *= t;
+
+ if( scale0 < FLT_EPSILON || scale1 < FLT_EPSILON )
+ return 0;
+
+ scale0 = sqrt(2.)/scale0;
+ scale1 = sqrt(2.)/scale1;
+
+ cvZero( &A );
+
+ // form a linear system Ax=0: for each selected pair of points m1 & m2,
+ // the row of A(=a) represents the coefficients of equation: (m2, 1)'*F*(m1, 1) = 0
+ // to save computation time, we compute (At*A) instead of A and then solve (At*A)x=0.
+ for( i = 0; i < count; i++ )
+ {
+ double x0 = (m1[i].x - m0c.x)*scale0;
+ double y0 = (m1[i].y - m0c.y)*scale0;
+ double x1 = (m2[i].x - m1c.x)*scale1;
+ double y1 = (m2[i].y - m1c.y)*scale1;
+ double r[9] = { x1*x0, x1*y0, x1, y1*x0, y1*y0, y1, x0, y0, 1 };
+ for( j = 0; j < 9; j++ )
+ for( k = 0; k < 9; k++ )
+ a[j*9+k] += r[j]*r[k];
+ }
+
+ cvSVD( &A, &W, 0, &V, CV_SVD_MODIFY_A + CV_SVD_V_T );
+
+ for( i = 0; i < 8; i++ )
+ {
+ if( fabs(w[i]) < DBL_EPSILON )
+ break;
+ }
+
+ if( i < 7 )
+ return 0;
+
+ F0 = cvMat( 3, 3, CV_64F, v + 9*8 ); // take the last column of v as a solution of Af = 0
+
+ // make F0 singular (of rank 2) by decomposing it with SVD,
+ // zeroing the last diagonal element of W and then composing the matrices back.
+
+ // use v as a temporary storage for different 3x3 matrices
+ W = U = V = TF = F0;
+ W.data.db = v;
+ U.data.db = v + 9;
+ V.data.db = v + 18;
+ TF.data.db = v + 27;
+
+ cvSVD( &F0, &W, &U, &V, CV_SVD_MODIFY_A + CV_SVD_U_T + CV_SVD_V_T );
+ W.data.db[8] = 0.;
+
+ // F0 <- U*diag([W(1), W(2), 0])*V'
+ cvGEMM( &U, &W, 1., 0, 0., &TF, CV_GEMM_A_T );
+ cvGEMM( &TF, &V, 1., 0, 0., &F0, 0/*CV_GEMM_B_T*/ );
+
+ // apply the transformation that is inverse
+ // to what we used to normalize the point coordinates
+ {
+ double tt0[] = { scale0, 0, -scale0*m0c.x, 0, scale0, -scale0*m0c.y, 0, 0, 1 };
+ double tt1[] = { scale1, 0, -scale1*m1c.x, 0, scale1, -scale1*m1c.y, 0, 0, 1 };
+ CvMat T0, T1;
+ T0 = T1 = F0;
+ T0.data.db = tt0;
+ T1.data.db = tt1;
+
+ // F0 <- T1'*F0*T0
+ cvGEMM( &T1, &F0, 1., 0, 0., &TF, CV_GEMM_A_T );
+ F0.data.db = fmatrix;
+ cvGEMM( &TF, &T0, 1., 0, 0., &F0, 0 );
+
+ // make F(3,3) = 1
+ if( fabs(F0.data.db[8]) > FLT_EPSILON )
+ cvScale( &F0, &F0, 1./F0.data.db[8] );
+ }
+
+ return 1;
+}
+
+
+void CvFMEstimator::computeReprojError( const CvMat* _m1, const CvMat* _m2,
+ const CvMat* model, CvMat* _err )
+{
+ int i, count = _m1->rows*_m1->cols;
+ const CvPoint2D64f* m1 = (const CvPoint2D64f*)_m1->data.ptr;
+ const CvPoint2D64f* m2 = (const CvPoint2D64f*)_m2->data.ptr;
+ const double* F = model->data.db;
+ float* err = _err->data.fl;
+
+ for( i = 0; i < count; i++ )
+ {
+ double a, b, c, d1, d2, s1, s2;
+
+ a = F[0]*m1[i].x + F[1]*m1[i].y + F[2];
+ b = F[3]*m1[i].x + F[4]*m1[i].y + F[5];
+ c = F[6]*m1[i].x + F[7]*m1[i].y + F[8];
+
+ s2 = 1./(a*a + b*b);
+ d2 = m2[i].x*a + m2[i].y*b + c;
+
+ a = F[0]*m2[i].x + F[3]*m2[i].y + F[6];
+ b = F[1]*m2[i].x + F[4]*m2[i].y + F[7];
+ c = F[2]*m2[i].x + F[5]*m2[i].y + F[8];
+
+ s1 = 1./(a*a + b*b);
+ d1 = m1[i].x*a + m1[i].y*b + c;
+
+ err[i] = (float)(d1*d1*s1 + d2*d2*s2);
+ }
+}
+
+
+CV_IMPL int
+cvFindFundamentalMat( const CvMat* points1, const CvMat* points2,
+ CvMat* fmatrix, int method,
+ double param1, double param2, CvMat* mask )
+{
+ int result = 0;
+ CvMat *m1 = 0, *m2 = 0, *tempMask = 0;
+
+ CV_FUNCNAME( "cvFindFundamentalMat" );
+
+ __BEGIN__;
+
+ double F[3*9];
+ CvMat _F3x3 = cvMat( 3, 3, CV_64FC1, F ), _F9x3 = cvMat( 9, 3, CV_64FC1, F );
+ int count;
+
+ CV_ASSERT( CV_IS_MAT(points1) && CV_IS_MAT(points2) && CV_ARE_SIZES_EQ(points1, points2) );
+ CV_ASSERT( CV_IS_MAT(fmatrix) && fmatrix->cols == 3 &&
+ (fmatrix->rows == 3 || (fmatrix->rows == 9 && method == CV_FM_7POINT)) );
+
+ count = MAX(points1->cols, points1->rows);
+ if( count < 7 )
+ EXIT;
+
+ m1 = cvCreateMat( 1, count, CV_64FC2 );
+ cvConvertPointsHomogeneous( points1, m1 );
+
+ m2 = cvCreateMat( 1, count, CV_64FC2 );
+ cvConvertPointsHomogeneous( points2, m2 );
+
+ if( mask )
+ {
+ CV_ASSERT( CV_IS_MASK_ARR(mask) && CV_IS_MAT_CONT(mask->type) &&
+ (mask->rows == 1 || mask->cols == 1) &&
+ mask->rows*mask->cols == count );
+ tempMask = mask;
+ }
+ else if( count > 8 )
+ tempMask = cvCreateMat( 1, count, CV_8U );
+ if( tempMask )
+ cvSet( tempMask, cvScalarAll(1.) );
+
+ {
+ CvFMEstimator estimator( MIN(count, (method & 3) == CV_FM_7POINT ? 7 : 8) );
+ if( count == 7 )
+ result = estimator.run7Point(m1, m2, &_F9x3);
+ else if( count == 8 || method == CV_FM_8POINT )
+ result = estimator.run8Point(m1, m2, &_F3x3);
+ else if( count > 8 )
+ {
+ if( param1 <= 0 )
+ param1 = 3;
+ if( param2 < DBL_EPSILON || param2 > 1 - DBL_EPSILON )
+ param2 = 0.99;
+
+ if( (method & ~3) == CV_RANSAC )
+ result = estimator.runRANSAC(m1, m2, &_F3x3, tempMask, param1, param2 );
+ else
+ result = estimator.runLMeDS(m1, m2, &_F3x3, tempMask, param2 );
+ if( result <= 0 )
+ EXIT;
+ icvCompressPoints( (CvPoint2D64f*)m1->data.ptr, tempMask->data.ptr, 1, count );
+ count = icvCompressPoints( (CvPoint2D64f*)m2->data.ptr, tempMask->data.ptr, 1, count );
+ assert( count >= 8 );
+ m1->cols = m2->cols = count;
+ estimator.run8Point(m1, m2, &_F3x3);
+ }
+ }
+
+ if( result )
+ cvConvert( fmatrix->rows == 3 ? &_F3x3 : &_F9x3, fmatrix );
+
+ __END__;
+
+ cvReleaseMat( &m1 );
+ cvReleaseMat( &m2 );
+ if( tempMask != mask )
+ cvReleaseMat( &tempMask );
+
+ return result;
+}
+
+
+CV_IMPL void
+cvComputeCorrespondEpilines( const CvMat* points, int pointImageID,
+ const CvMat* fmatrix, CvMat* lines )
+{
+ CV_FUNCNAME( "cvComputeCorrespondEpilines" );
+
+ __BEGIN__;
+
+ int abc_stride, abc_plane_stride, abc_elem_size;
+ int plane_stride, stride, elem_size;
+ int i, dims, count, depth, cn, abc_dims, abc_count, abc_depth, abc_cn;
+ uchar *ap, *bp, *cp;
+ const uchar *xp, *yp, *zp;
+ double f[9];
+ CvMat F = cvMat( 3, 3, CV_64F, f );
+
+ if( !CV_IS_MAT(points) )
+ CV_ERROR( !points ? CV_StsNullPtr : CV_StsBadArg, "points parameter is not a valid matrix" );
+
+ depth = CV_MAT_DEPTH(points->type);
+ cn = CV_MAT_CN(points->type);
+ if( (depth != CV_32F && depth != CV_64F) || (cn != 1 && cn != 2 && cn != 3) )
+ CV_ERROR( CV_StsUnsupportedFormat, "The format of point matrix is unsupported" );
+
+ if( points->rows > points->cols )
+ {
+ dims = cn*points->cols;
+ count = points->rows;
+ }
+ else
+ {
+ if( (points->rows > 1 && cn > 1) || (points->rows == 1 && cn == 1) )
+ CV_ERROR( CV_StsBadSize, "The point matrix does not have a proper layout (2xn, 3xn, nx2 or nx3)" );
+ dims = cn * points->rows;
+ count = points->cols;
+ }
+
+ if( dims != 2 && dims != 3 )
+ CV_ERROR( CV_StsOutOfRange, "The dimensionality of points must be 2 or 3" );
+
+ if( !CV_IS_MAT(fmatrix) )
+ CV_ERROR( !fmatrix ? CV_StsNullPtr : CV_StsBadArg, "fmatrix is not a valid matrix" );
+
+ if( CV_MAT_TYPE(fmatrix->type) != CV_32FC1 && CV_MAT_TYPE(fmatrix->type) != CV_64FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "fundamental matrix must have 32fC1 or 64fC1 type" );
+
+ if( fmatrix->cols != 3 || fmatrix->rows != 3 )
+ CV_ERROR( CV_StsBadSize, "fundamental matrix must be 3x3" );
+
+ if( !CV_IS_MAT(lines) )
+ CV_ERROR( !lines ? CV_StsNullPtr : CV_StsBadArg, "lines parameter is not a valid matrix" );
+
+ abc_depth = CV_MAT_DEPTH(lines->type);
+ abc_cn = CV_MAT_CN(lines->type);
+ if( (abc_depth != CV_32F && abc_depth != CV_64F) || (abc_cn != 1 && abc_cn != 3) )
+ CV_ERROR( CV_StsUnsupportedFormat, "The format of the matrix of lines is unsupported" );
+
+ if( lines->rows > lines->cols )
+ {
+ abc_dims = abc_cn*lines->cols;
+ abc_count = lines->rows;
+ }
+ else
+ {
+ if( (lines->rows > 1 && abc_cn > 1) || (lines->rows == 1 && abc_cn == 1) )
+ CV_ERROR( CV_StsBadSize, "The lines matrix does not have a proper layout (3xn or nx3)" );
+ abc_dims = abc_cn * lines->rows;
+ abc_count = lines->cols;
+ }
+
+ if( abc_dims != 3 )
+ CV_ERROR( CV_StsOutOfRange, "The lines matrix does not have a proper layout (3xn or nx3)" );
+
+ if( abc_count != count )
+ CV_ERROR( CV_StsUnmatchedSizes, "The numbers of points and lines are different" );
+
+ elem_size = CV_ELEM_SIZE(depth);
+ abc_elem_size = CV_ELEM_SIZE(abc_depth);
+
+ if( points->rows == dims )
+ {
+ plane_stride = points->step;
+ stride = elem_size;
+ }
+ else
+ {
+ plane_stride = elem_size;
+ stride = points->rows == 1 ? dims*elem_size : points->step;
+ }
+
+ if( lines->rows == 3 )
+ {
+ abc_plane_stride = lines->step;
+ abc_stride = abc_elem_size;
+ }
+ else
+ {
+ abc_plane_stride = abc_elem_size;
+ abc_stride = lines->rows == 1 ? 3*abc_elem_size : lines->step;
+ }
+
+ CV_CALL( cvConvert( fmatrix, &F ));
+ if( pointImageID == 2 )
+ cvTranspose( &F, &F );
+
+ xp = points->data.ptr;
+ yp = xp + plane_stride;
+ zp = dims == 3 ? yp + plane_stride : 0;
+
+ ap = lines->data.ptr;
+ bp = ap + abc_plane_stride;
+ cp = bp + abc_plane_stride;
+
+ for( i = 0; i < count; i++ )
+ {
+ double x, y, z = 1.;
+ double a, b, c, nu;
+
+ if( depth == CV_32F )
+ {
+ x = *(float*)xp; y = *(float*)yp;
+ if( zp )
+ z = *(float*)zp, zp += stride;
+ }
+ else
+ {
+ x = *(double*)xp; y = *(double*)yp;
+ if( zp )
+ z = *(double*)zp, zp += stride;
+ }
+
+ xp += stride; yp += stride;
+
+ a = f[0]*x + f[1]*y + f[2]*z;
+ b = f[3]*x + f[4]*y + f[5]*z;
+ c = f[6]*x + f[7]*y + f[8]*z;
+ nu = a*a + b*b;
+ nu = nu ? 1./sqrt(nu) : 1.;
+ a *= nu; b *= nu; c *= nu;
+
+ if( abc_depth == CV_32F )
+ {
+ *(float*)ap = (float)a;
+ *(float*)bp = (float)b;
+ *(float*)cp = (float)c;
+ }
+ else
+ {
+ *(double*)ap = a;
+ *(double*)bp = b;
+ *(double*)cp = c;
+ }
+
+ ap += abc_stride;
+ bp += abc_stride;
+ cp += abc_stride;
+ }
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvConvertPointsHomogeneous( const CvMat* src, CvMat* dst )
+{
+ CvMat* temp = 0;
+ CvMat* denom = 0;
+
+ CV_FUNCNAME( "cvConvertPointsHomogeneous" );
+
+ __BEGIN__;
+
+ int i, s_count, s_dims, d_count, d_dims;
+ CvMat _src, _dst, _ones;
+ CvMat* ones = 0;
+
+ if( !CV_IS_MAT(src) )
+ CV_ERROR( !src ? CV_StsNullPtr : CV_StsBadArg,
+ "The input parameter is not a valid matrix" );
+
+ if( !CV_IS_MAT(dst) )
+ CV_ERROR( !dst ? CV_StsNullPtr : CV_StsBadArg,
+ "The output parameter is not a valid matrix" );
+
+ if( src == dst || src->data.ptr == dst->data.ptr )
+ {
+ if( src != dst && (!CV_ARE_TYPES_EQ(src, dst) || !CV_ARE_SIZES_EQ(src,dst)) )
+ CV_ERROR( CV_StsBadArg, "Invalid inplace operation" );
+ EXIT;
+ }
+
+ if( src->rows > src->cols )
+ {
+ if( !((src->cols > 1) ^ (CV_MAT_CN(src->type) > 1)) )
+ CV_ERROR( CV_StsBadSize, "Either the number of channels or columns or rows must be =1" );
+
+ s_dims = CV_MAT_CN(src->type)*src->cols;
+ s_count = src->rows;
+ }
+ else
+ {
+ if( !((src->rows > 1) ^ (CV_MAT_CN(src->type) > 1)) )
+ CV_ERROR( CV_StsBadSize, "Either the number of channels or columns or rows must be =1" );
+
+ s_dims = CV_MAT_CN(src->type)*src->rows;
+ s_count = src->cols;
+ }
+
+ if( src->rows == 1 || src->cols == 1 )
+ src = cvReshape( src, &_src, 1, s_count );
+
+ if( dst->rows > dst->cols )
+ {
+ if( !((dst->cols > 1) ^ (CV_MAT_CN(dst->type) > 1)) )
+ CV_ERROR( CV_StsBadSize,
+ "Either the number of channels or columns or rows in the input matrix must be =1" );
+
+ d_dims = CV_MAT_CN(dst->type)*dst->cols;
+ d_count = dst->rows;
+ }
+ else
+ {
+ if( !((dst->rows > 1) ^ (CV_MAT_CN(dst->type) > 1)) )
+ CV_ERROR( CV_StsBadSize,
+ "Either the number of channels or columns or rows in the output matrix must be =1" );
+
+ d_dims = CV_MAT_CN(dst->type)*dst->rows;
+ d_count = dst->cols;
+ }
+
+ if( dst->rows == 1 || dst->cols == 1 )
+ dst = cvReshape( dst, &_dst, 1, d_count );
+
+ if( s_count != d_count )
+ CV_ERROR( CV_StsUnmatchedSizes, "Both matrices must have the same number of points" );
+
+ if( CV_MAT_DEPTH(src->type) < CV_32F || CV_MAT_DEPTH(dst->type) < CV_32F )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Both matrices must be floating-point (single or double precision)" );
+
+ if( s_dims < 2 || s_dims > 4 || d_dims < 2 || d_dims > 4 )
+ CV_ERROR( CV_StsOutOfRange,
+ "Both input and output point dimensionality must be 2, 3 or 4" );
+
+ if( s_dims < d_dims - 1 || s_dims > d_dims + 1 )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The dimensionalities of input and output point sets differ too much" );
+
+ if( s_dims == d_dims - 1 )
+ {
+ if( d_count == dst->rows )
+ {
+ ones = cvGetSubRect( dst, &_ones, cvRect( s_dims, 0, 1, d_count ));
+ dst = cvGetSubRect( dst, &_dst, cvRect( 0, 0, s_dims, d_count ));
+ }
+ else
+ {
+ ones = cvGetSubRect( dst, &_ones, cvRect( 0, s_dims, d_count, 1 ));
+ dst = cvGetSubRect( dst, &_dst, cvRect( 0, 0, d_count, s_dims ));
+ }
+ }
+
+ if( s_dims <= d_dims )
+ {
+ if( src->rows == dst->rows && src->cols == dst->cols )
+ {
+ if( CV_ARE_TYPES_EQ( src, dst ) )
+ cvCopy( src, dst );
+ else
+ cvConvert( src, dst );
+ }
+ else
+ {
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ {
+ CV_CALL( temp = cvCreateMat( src->rows, src->cols, dst->type ));
+ cvConvert( src, temp );
+ src = temp;
+ }
+ cvTranspose( src, dst );
+ }
+
+ if( ones )
+ cvSet( ones, cvRealScalar(1.) );
+ }
+ else
+ {
+ int s_plane_stride, s_stride, d_plane_stride, d_stride, elem_size;
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ {
+ CV_CALL( temp = cvCreateMat( src->rows, src->cols, dst->type ));
+ cvConvert( src, temp );
+ src = temp;
+ }
+
+ elem_size = CV_ELEM_SIZE(src->type);
+
+ if( s_count == src->cols )
+ s_plane_stride = src->step / elem_size, s_stride = 1;
+ else
+ s_stride = src->step / elem_size, s_plane_stride = 1;
+
+ if( d_count == dst->cols )
+ d_plane_stride = dst->step / elem_size, d_stride = 1;
+ else
+ d_stride = dst->step / elem_size, d_plane_stride = 1;
+
+ CV_CALL( denom = cvCreateMat( 1, d_count, dst->type ));
+
+ if( CV_MAT_DEPTH(dst->type) == CV_32F )
+ {
+ const float* xs = src->data.fl;
+ const float* ys = xs + s_plane_stride;
+ const float* zs = 0;
+ const float* ws = xs + (s_dims - 1)*s_plane_stride;
+
+ float* iw = denom->data.fl;
+
+ float* xd = dst->data.fl;
+ float* yd = xd + d_plane_stride;
+ float* zd = 0;
+
+ if( d_dims == 3 )
+ {
+ zs = ys + s_plane_stride;
+ zd = yd + d_plane_stride;
+ }
+
+ for( i = 0; i < d_count; i++, ws += s_stride )
+ {
+ float t = *ws;
+ iw[i] = t ? t : 1.f;
+ }
+
+ cvDiv( 0, denom, denom );
+
+ if( d_dims == 3 )
+ for( i = 0; i < d_count; i++ )
+ {
+ float w = iw[i];
+ float x = *xs * w, y = *ys * w, z = *zs * w;
+ xs += s_stride; ys += s_stride; zs += s_stride;
+ *xd = x; *yd = y; *zd = z;
+ xd += d_stride; yd += d_stride; zd += d_stride;
+ }
+ else
+ for( i = 0; i < d_count; i++ )
+ {
+ float w = iw[i];
+ float x = *xs * w, y = *ys * w;
+ xs += s_stride; ys += s_stride;
+ *xd = x; *yd = y;
+ xd += d_stride; yd += d_stride;
+ }
+ }
+ else
+ {
+ const double* xs = src->data.db;
+ const double* ys = xs + s_plane_stride;
+ const double* zs = 0;
+ const double* ws = xs + (s_dims - 1)*s_plane_stride;
+
+ double* iw = denom->data.db;
+
+ double* xd = dst->data.db;
+ double* yd = xd + d_plane_stride;
+ double* zd = 0;
+
+ if( d_dims == 3 )
+ {
+ zs = ys + s_plane_stride;
+ zd = yd + d_plane_stride;
+ }
+
+ for( i = 0; i < d_count; i++, ws += s_stride )
+ {
+ double t = *ws;
+ iw[i] = t ? t : 1.;
+ }
+
+ cvDiv( 0, denom, denom );
+
+ if( d_dims == 3 )
+ for( i = 0; i < d_count; i++ )
+ {
+ double w = iw[i];
+ double x = *xs * w, y = *ys * w, z = *zs * w;
+ xs += s_stride; ys += s_stride; zs += s_stride;
+ *xd = x; *yd = y; *zd = z;
+ xd += d_stride; yd += d_stride; zd += d_stride;
+ }
+ else
+ for( i = 0; i < d_count; i++ )
+ {
+ double w = iw[i];
+ double x = *xs * w, y = *ys * w;
+ xs += s_stride; ys += s_stride;
+ *xd = x; *yd = y;
+ xd += d_stride; yd += d_stride;
+ }
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &denom );
+ cvReleaseMat( &temp );
+}
+
+/* End of file. */
diff --git a/cv/src/cvgeometry.cpp b/cv/src/cvgeometry.cpp
new file mode 100644
index 0000000..1f1c0d1
--- /dev/null
+++ b/cv/src/cvgeometry.cpp
@@ -0,0 +1,593 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+
+CV_IMPL CvRect
+cvMaxRect( const CvRect* rect1, const CvRect* rect2 )
+{
+ if( rect1 && rect2 )
+ {
+ CvRect max_rect;
+ int a, b;
+
+ max_rect.x = a = rect1->x;
+ b = rect2->x;
+ if( max_rect.x > b )
+ max_rect.x = b;
+
+ max_rect.width = a += rect1->width;
+ b += rect2->width;
+
+ if( max_rect.width < b )
+ max_rect.width = b;
+ max_rect.width -= max_rect.x;
+
+ max_rect.y = a = rect1->y;
+ b = rect2->y;
+ if( max_rect.y > b )
+ max_rect.y = b;
+
+ max_rect.height = a += rect1->height;
+ b += rect2->height;
+
+ if( max_rect.height < b )
+ max_rect.height = b;
+ max_rect.height -= max_rect.y;
+ return max_rect;
+ }
+ else if( rect1 )
+ return *rect1;
+ else if( rect2 )
+ return *rect2;
+ else
+ return cvRect(0,0,0,0);
+}
+
+
+CV_IMPL void
+cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] )
+{
+ CV_FUNCNAME( "cvBoxPoints" );
+
+ __BEGIN__;
+
+ double angle = box.angle*CV_PI/180.;
+ float a = (float)cos(angle)*0.5f;
+ float b = (float)sin(angle)*0.5f;
+
+ if( !pt )
+ CV_ERROR( CV_StsNullPtr, "NULL vertex array pointer" );
+
+ pt[0].x = box.center.x - a*box.size.height - b*box.size.width;
+ pt[0].y = box.center.y + b*box.size.height - a*box.size.width;
+ pt[1].x = box.center.x + a*box.size.height - b*box.size.width;
+ pt[1].y = box.center.y - b*box.size.height - a*box.size.width;
+ pt[2].x = 2*box.center.x - pt[0].x;
+ pt[2].y = 2*box.center.y - pt[0].y;
+ pt[3].x = 2*box.center.x - pt[1].x;
+ pt[3].y = 2*box.center.y - pt[1].y;
+
+ __END__;
+}
+
+
+int
+icvIntersectLines( double x1, double dx1, double y1, double dy1,
+ double x2, double dx2, double y2, double dy2, double *t2 )
+{
+ double d = dx1 * dy2 - dx2 * dy1;
+ int result = -1;
+
+ if( d != 0 )
+ {
+ *t2 = ((x2 - x1) * dy1 - (y2 - y1) * dx1) / d;
+ result = 0;
+ }
+ return result;
+}
+
+
+void
+icvCreateCenterNormalLine( CvSubdiv2DEdge edge, double *_a, double *_b, double *_c )
+{
+ CvPoint2D32f org = cvSubdiv2DEdgeOrg( edge )->pt;
+ CvPoint2D32f dst = cvSubdiv2DEdgeDst( edge )->pt;
+
+ double a = dst.x - org.x;
+ double b = dst.y - org.y;
+ double c = -(a * (dst.x + org.x) + b * (dst.y + org.y));
+
+ *_a = a + a;
+ *_b = b + b;
+ *_c = c;
+}
+
+
+void
+icvIntersectLines3( double *a0, double *b0, double *c0,
+ double *a1, double *b1, double *c1, CvPoint2D32f * point )
+{
+ double det = a0[0] * b1[0] - a1[0] * b0[0];
+
+ if( det != 0 )
+ {
+ det = 1. / det;
+ point->x = (float) ((b0[0] * c1[0] - b1[0] * c0[0]) * det);
+ point->y = (float) ((a1[0] * c0[0] - a0[0] * c1[0]) * det);
+ }
+ else
+ {
+ point->x = point->y = FLT_MAX;
+ }
+}
+
+
+CV_IMPL double
+cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist )
+{
+ double result = 0;
+ CV_FUNCNAME( "cvCheckPointPolygon" );
+
+ __BEGIN__;
+
+ CvSeqBlock block;
+ CvContour header;
+ CvSeq* contour = (CvSeq*)_contour;
+ CvSeqReader reader;
+ int i, total, counter = 0;
+ int is_float;
+ double min_dist_num = FLT_MAX, min_dist_denom = 1;
+ CvPoint ip = {0,0};
+
+ if( !CV_IS_SEQ(contour) )
+ {
+ CV_CALL( contour = cvPointSeqFromMat( CV_SEQ_KIND_CURVE + CV_SEQ_FLAG_CLOSED,
+ _contour, &header, &block ));
+ }
+ else if( CV_IS_SEQ_POLYGON(contour) )
+ {
+ if( contour->header_size == sizeof(CvContour) && !measure_dist )
+ {
+ CvRect r = ((CvContour*)contour)->rect;
+ if( pt.x < r.x || pt.y < r.y ||
+ pt.x >= r.x + r.width || pt.y >= r.y + r.height )
+ return -100;
+ }
+ }
+ else if( CV_IS_SEQ_CHAIN(contour) )
+ {
+ CV_ERROR( CV_StsBadArg,
+ "Chains are not supported. Convert them to polygonal representation using cvApproxChains()" );
+ }
+ else
+ CV_ERROR( CV_StsBadArg, "Input contour is neither a valid sequence nor a matrix" );
+
+ total = contour->total;
+ is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2;
+ cvStartReadSeq( contour, &reader, -1 );
+
+ if( !is_float && !measure_dist && (ip.x = cvRound(pt.x)) == pt.x && (ip.y = cvRound(pt.y)) == pt.y )
+ {
+ // the fastest "pure integer" branch
+ CvPoint v0, v;
+ CV_READ_SEQ_ELEM( v, reader );
+
+ for( i = 0; i < total; i++ )
+ {
+ int dist;
+ v0 = v;
+ CV_READ_SEQ_ELEM( v, reader );
+
+ if( (v0.y <= ip.y && v.y <= ip.y) ||
+ (v0.y > ip.y && v.y > ip.y) ||
+ (v0.x < ip.x && v.x < ip.x) )
+ {
+ if( ip.y == v.y && (ip.x == v.x || (ip.y == v0.y &&
+ ((v0.x <= ip.x && ip.x <= v.x) || (v.x <= ip.x && ip.x <= v0.x)))) )
+ EXIT;
+ continue;
+ }
+
+ dist = (ip.y - v0.y)*(v.x - v0.x) - (ip.x - v0.x)*(v.y - v0.y);
+ if( dist == 0 )
+ EXIT;
+ if( v.y < v0.y )
+ dist = -dist;
+ counter += dist > 0;
+ }
+
+ result = counter % 2 == 0 ? -100 : 100;
+ }
+ else
+ {
+ CvPoint2D32f v0, v;
+ CvPoint iv;
+
+ if( is_float )
+ {
+ CV_READ_SEQ_ELEM( v, reader );
+ }
+ else
+ {
+ CV_READ_SEQ_ELEM( iv, reader );
+ v = cvPointTo32f( iv );
+ }
+
+ if( !measure_dist )
+ {
+ for( i = 0; i < total; i++ )
+ {
+ double dist;
+ v0 = v;
+ if( is_float )
+ {
+ CV_READ_SEQ_ELEM( v, reader );
+ }
+ else
+ {
+ CV_READ_SEQ_ELEM( iv, reader );
+ v = cvPointTo32f( iv );
+ }
+
+ if( (v0.y <= pt.y && v.y <= pt.y) ||
+ (v0.y > pt.y && v.y > pt.y) ||
+ (v0.x < pt.x && v.x < pt.x) )
+ {
+ if( pt.y == v.y && (pt.x == v.x || (pt.y == v0.y &&
+ ((v0.x <= pt.x && pt.x <= v.x) || (v.x <= pt.x && pt.x <= v0.x)))) )
+ EXIT;
+ continue;
+ }
+
+ dist = (double)(pt.y - v0.y)*(v.x - v0.x) - (double)(pt.x - v0.x)*(v.y - v0.y);
+ if( dist == 0 )
+ EXIT;
+ if( v.y < v0.y )
+ dist = -dist;
+ counter += dist > 0;
+ }
+
+ result = counter % 2 == 0 ? -100 : 100;
+ }
+ else
+ {
+ for( i = 0; i < total; i++ )
+ {
+ double dx, dy, dx1, dy1, dx2, dy2, dist_num, dist_denom = 1;
+
+ v0 = v;
+ if( is_float )
+ {
+ CV_READ_SEQ_ELEM( v, reader );
+ }
+ else
+ {
+ CV_READ_SEQ_ELEM( iv, reader );
+ v = cvPointTo32f( iv );
+ }
+
+ dx = v.x - v0.x; dy = v.y - v0.y;
+ dx1 = pt.x - v0.x; dy1 = pt.y - v0.y;
+ dx2 = pt.x - v.x; dy2 = pt.y - v.y;
+
+ if( dx1*dx + dy1*dy <= 0 )
+ dist_num = dx1*dx1 + dy1*dy1;
+ else if( dx2*dx + dy2*dy >= 0 )
+ dist_num = dx2*dx2 + dy2*dy2;
+ else
+ {
+ dist_num = (dy1*dx - dx1*dy);
+ dist_num *= dist_num;
+ dist_denom = dx*dx + dy*dy;
+ }
+
+ if( dist_num*min_dist_denom < min_dist_num*dist_denom )
+ {
+ min_dist_num = dist_num;
+ min_dist_denom = dist_denom;
+ if( min_dist_num == 0 )
+ break;
+ }
+
+ if( (v0.y <= pt.y && v.y <= pt.y) ||
+ (v0.y > pt.y && v.y > pt.y) ||
+ (v0.x < pt.x && v.x < pt.x) )
+ continue;
+
+ dist_num = dy1*dx - dx1*dy;
+ if( dy < 0 )
+ dist_num = -dist_num;
+ counter += dist_num > 0;
+ }
+
+ result = sqrt(min_dist_num/min_dist_denom);
+ if( counter % 2 == 0 )
+ result = -result;
+ }
+ }
+
+ __END__;
+
+ return result;
+}
+
+
+CV_IMPL void
+cvRQDecomp3x3( const CvMat *matrixM, CvMat *matrixR, CvMat *matrixQ,
+ CvMat *matrixQx, CvMat *matrixQy, CvMat *matrixQz,
+ CvPoint3D64f *eulerAngles)
+{
+ CV_FUNCNAME("cvRQDecomp3x3");
+ __BEGIN__;
+
+ double _M[3][3], _R[3][3], _Q[3][3];
+ CvMat M = cvMat(3, 3, CV_64F, _M);
+ CvMat R = cvMat(3, 3, CV_64F, _R);
+ CvMat Q = cvMat(3, 3, CV_64F, _Q);
+ double z, c, s;
+
+ /* Validate parameters. */
+ CV_ASSERT( CV_IS_MAT(matrixM) && CV_IS_MAT(matrixR) && CV_IS_MAT(matrixQ) &&
+ matrixM->cols == 3 && matrixM->rows == 3 &&
+ CV_ARE_SIZES_EQ(matrixM, matrixR) && CV_ARE_SIZES_EQ(matrixM, matrixQ));
+
+ cvConvert(matrixM, &M);
+
+ {
+ /* Find Givens rotation Q_x for x axis (left multiplication). */
+ /*
+ ( 1 0 0 )
+ Qx = ( 0 c s ), c = m33/sqrt(m32^2 + m33^2), s = m32/sqrt(m32^2 + m33^2)
+ ( 0 -s c )
+ */
+ s = _M[2][1];
+ c = _M[2][2];
+ z = 1./sqrt(c * c + s * s + DBL_EPSILON);
+ c *= z;
+ s *= z;
+
+ double _Qx[3][3] = { {1, 0, 0}, {0, c, s}, {0, -s, c} };
+ CvMat Qx = cvMat(3, 3, CV_64F, _Qx);
+
+ cvMatMul(&M, &Qx, &R);
+ assert(fabs(_R[2][1]) < FLT_EPSILON);
+ _R[2][1] = 0;
+
+ /* Find Givens rotation for y axis. */
+ /*
+ ( c 0 s )
+ Qy = ( 0 1 0 ), c = m33/sqrt(m31^2 + m33^2), s = m31/sqrt(m31^2 + m33^2)
+ (-s 0 c )
+ */
+ s = _R[2][0];
+ c = _R[2][2];
+ z = 1./sqrt(c * c + s * s + DBL_EPSILON);
+ c *= z;
+ s *= z;
+
+ double _Qy[3][3] = { {c, 0, s}, {0, 1, 0}, {-s, 0, c} };
+ CvMat Qy = cvMat(3, 3, CV_64F, _Qy);
+ cvMatMul(&R, &Qy, &M);
+
+ assert(fabs(_M[2][0]) < FLT_EPSILON);
+ _M[2][0] = 0;
+
+ /* Find Givens rotation for z axis. */
+ /*
+ ( c s 0 )
+ Qz = (-s c 0 ), c = m22/sqrt(m21^2 + m22^2), s = m21/sqrt(m21^2 + m22^2)
+ ( 0 0 1 )
+ */
+
+ s = _M[1][0];
+ c = _M[1][1];
+ z = 1./sqrt(c * c + s * s + DBL_EPSILON);
+ c *= z;
+ s *= z;
+
+ double _Qz[3][3] = { {c, s, 0}, {-s, c, 0}, {0, 0, 1} };
+ CvMat Qz = cvMat(3, 3, CV_64F, _Qz);
+
+ cvMatMul(&M, &Qz, &R);
+ assert(fabs(_R[1][0]) < FLT_EPSILON);
+ _R[1][0] = 0;
+
+ // Solve the decomposition ambiguity.
+ // Diagonal entries of R, except the last one, shall be positive.
+ // Further rotate R by 180 degree if necessary
+ if( _R[0][0] < 0 )
+ {
+ if( _R[1][1] < 0 )
+ {
+ // rotate around z for 180 degree, i.e. a rotation matrix of
+ // [-1, 0, 0],
+ // [ 0, -1, 0],
+ // [ 0, 0, 1]
+ _R[0][0] *= -1;
+ _R[0][1] *= -1;
+ _R[1][1] *= -1;
+
+ _Qz[0][0] *= -1;
+ _Qz[0][1] *= -1;
+ _Qz[1][0] *= -1;
+ _Qz[1][1] *= -1;
+ }
+ else
+ {
+ // rotate around y for 180 degree, i.e. a rotation matrix of
+ // [-1, 0, 0],
+ // [ 0, 1, 0],
+ // [ 0, 0, -1]
+ _R[0][0] *= -1;
+ _R[0][2] *= -1;
+ _R[1][2] *= -1;
+ _R[2][2] *= -1;
+
+ cvTranspose( &Qz, &Qz );
+
+ _Qy[0][0] *= -1;
+ _Qy[0][2] *= -1;
+ _Qy[2][0] *= -1;
+ _Qy[2][2] *= -1;
+ }
+ }
+ else if( _R[1][1] < 0 )
+ {
+ // ??? for some reason, we never get here ???
+
+ // rotate around x for 180 degree, i.e. a rotation matrix of
+ // [ 1, 0, 0],
+ // [ 0, -1, 0],
+ // [ 0, 0, -1]
+ _R[0][1] *= -1;
+ _R[0][2] *= -1;
+ _R[1][1] *= -1;
+ _R[1][2] *= -1;
+ _R[2][2] *= -1;
+
+ cvTranspose( &Qz, &Qz );
+ cvTranspose( &Qy, &Qy );
+
+ _Qx[1][1] *= -1;
+ _Qx[1][2] *= -1;
+ _Qx[2][1] *= -1;
+ _Qx[2][2] *= -1;
+ }
+
+ // calculate the euler angle
+ if( eulerAngles )
+ {
+ eulerAngles->x = acos(_Qx[1][1]) * (_Qx[1][2] >= 0 ? 1 : -1) * (180.0 / CV_PI);
+ eulerAngles->y = acos(_Qy[0][0]) * (_Qy[0][2] >= 0 ? 1 : -1) * (180.0 / CV_PI);
+ eulerAngles->z = acos(_Qz[0][0]) * (_Qz[0][1] >= 0 ? 1 : -1) * (180.0 / CV_PI);
+ }
+
+ /* Calulate orthogonal matrix. */
+ /*
+ Q = QzT * QyT * QxT
+ */
+ cvGEMM( &Qz, &Qy, 1, 0, 0, &M, CV_GEMM_A_T + CV_GEMM_B_T );
+ cvGEMM( &M, &Qx, 1, 0, 0, &Q, CV_GEMM_B_T );
+
+ /* Save R and Q matrices. */
+ cvConvert( &R, matrixR );
+ cvConvert( &Q, matrixQ );
+
+ if( matrixQx )
+ cvConvert(&Qx, matrixQx);
+ if( matrixQy )
+ cvConvert(&Qy, matrixQy);
+ if( matrixQz )
+ cvConvert(&Qz, matrixQz);
+ }
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvDecomposeProjectionMatrix( const CvMat *projMatr, CvMat *calibMatr,
+ CvMat *rotMatr, CvMat *posVect,
+ CvMat *rotMatrX, CvMat *rotMatrY,
+ CvMat *rotMatrZ, CvPoint3D64f *eulerAngles)
+{
+ CvMat *tmpProjMatr = 0;
+ CvMat *tmpMatrixD = 0;
+ CvMat *tmpMatrixV = 0;
+ CvMat *tmpMatrixM = 0;
+
+ CV_FUNCNAME("cvDecomposeProjectionMatrix");
+ __BEGIN__;
+
+ /* Validate parameters. */
+ if(projMatr == 0 || calibMatr == 0 || rotMatr == 0 || posVect == 0)
+ CV_ERROR(CV_StsNullPtr, "Some of parameters is a NULL pointer!");
+
+ if(!CV_IS_MAT(projMatr) || !CV_IS_MAT(calibMatr) || !CV_IS_MAT(rotMatr) || !CV_IS_MAT(posVect))
+ CV_ERROR(CV_StsUnsupportedFormat, "Input parameters must be a matrices!");
+
+ if(projMatr->cols != 4 || projMatr->rows != 3)
+ CV_ERROR(CV_StsUnmatchedSizes, "Size of projection matrix must be 3x4!");
+
+ if(calibMatr->cols != 3 || calibMatr->rows != 3 || rotMatr->cols != 3 || rotMatr->rows != 3)
+ CV_ERROR(CV_StsUnmatchedSizes, "Size of calibration and rotation matrices must be 3x3!");
+
+ if(posVect->cols != 1 || posVect->rows != 4)
+ CV_ERROR(CV_StsUnmatchedSizes, "Size of position vector must be 4x1!");
+
+ CV_CALL(tmpProjMatr = cvCreateMat(4, 4, CV_64F));
+ CV_CALL(tmpMatrixD = cvCreateMat(4, 4, CV_64F));
+ CV_CALL(tmpMatrixV = cvCreateMat(4, 4, CV_64F));
+ CV_CALL(tmpMatrixM = cvCreateMat(3, 3, CV_64F));
+
+ /* Compute position vector. */
+
+ cvSetZero(tmpProjMatr); // Add zero row to make matrix square.
+ int i, k;
+ for(i = 0; i < 3; i++)
+ for(k = 0; k < 4; k++)
+ cvmSet(tmpProjMatr, i, k, cvmGet(projMatr, i, k));
+
+ CV_CALL(cvSVD(tmpProjMatr, tmpMatrixD, NULL, tmpMatrixV, CV_SVD_MODIFY_A + CV_SVD_V_T));
+
+ /* Save position vector. */
+
+ for(i = 0; i < 4; i++)
+ cvmSet(posVect, i, 0, cvmGet(tmpMatrixV, 3, i)); // Solution is last row of V.
+
+ /* Compute calibration and rotation matrices via RQ decomposition. */
+
+ cvGetCols(projMatr, tmpMatrixM, 0, 3); // M is first square matrix of P.
+
+ assert(cvDet(tmpMatrixM) != 0.0); // So far only finite cameras could be decomposed, so M has to be nonsingular [det(M) != 0].
+
+ CV_CALL(cvRQDecomp3x3(tmpMatrixM, calibMatr, rotMatr, rotMatrX, rotMatrY, rotMatrZ, eulerAngles));
+
+ __END__;
+
+ cvReleaseMat(&tmpProjMatr);
+ cvReleaseMat(&tmpMatrixD);
+ cvReleaseMat(&tmpMatrixV);
+ cvReleaseMat(&tmpMatrixM);
+}
+
+/* End of file. */
diff --git a/cv/src/cvhaar.cpp b/cv/src/cvhaar.cpp
new file mode 100644
index 0000000..06fa5cd
--- /dev/null
+++ b/cv/src/cvhaar.cpp
@@ -0,0 +1,2328 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/* Haar features calculation */
+
+#include "_cv.h"
+#include <stdio.h>
+
+/* these settings affect the quality of detection: change with care */
+#define CV_ADJUST_FEATURES 1
+#define CV_ADJUST_WEIGHTS 0
+
+typedef int sumtype;
+typedef double sqsumtype;
+
+typedef struct CvHidHaarFeature
+{
+ struct
+ {
+ sumtype *p0, *p1, *p2, *p3;
+ float weight;
+ }
+ rect[CV_HAAR_FEATURE_MAX];
+}
+CvHidHaarFeature;
+
+
+typedef struct CvHidHaarTreeNode
+{
+ CvHidHaarFeature feature;
+ float threshold;
+ int left;
+ int right;
+}
+CvHidHaarTreeNode;
+
+
+typedef struct CvHidHaarClassifier
+{
+ int count;
+ //CvHaarFeature* orig_feature;
+ CvHidHaarTreeNode* node;
+ float* alpha;
+}
+CvHidHaarClassifier;
+
+
+typedef struct CvHidHaarStageClassifier
+{
+ int count;
+ float threshold;
+ CvHidHaarClassifier* classifier;
+ int two_rects;
+
+ struct CvHidHaarStageClassifier* next;
+ struct CvHidHaarStageClassifier* child;
+ struct CvHidHaarStageClassifier* parent;
+}
+CvHidHaarStageClassifier;
+
+
+struct CvHidHaarClassifierCascade
+{
+ int count;
+ int is_stump_based;
+ int has_tilted_features;
+ int is_tree;
+ double inv_window_area;
+ CvMat sum, sqsum, tilted;
+ CvHidHaarStageClassifier* stage_classifier;
+ sqsumtype *pq0, *pq1, *pq2, *pq3;
+ sumtype *p0, *p1, *p2, *p3;
+
+ void** ipp_stages;
+};
+
+
+/* IPP functions for object detection */
+icvHaarClassifierInitAlloc_32f_t icvHaarClassifierInitAlloc_32f_p = 0;
+icvHaarClassifierFree_32f_t icvHaarClassifierFree_32f_p = 0;
+icvApplyHaarClassifier_32f_C1R_t icvApplyHaarClassifier_32f_C1R_p = 0;
+icvRectStdDev_32f_C1R_t icvRectStdDev_32f_C1R_p = 0;
+
+const int icv_object_win_border = 1;
+const float icv_stage_threshold_bias = 0.0001f;
+
+static CvHaarClassifierCascade*
+icvCreateHaarClassifierCascade( int stage_count )
+{
+ CvHaarClassifierCascade* cascade = 0;
+
+ CV_FUNCNAME( "icvCreateHaarClassifierCascade" );
+
+ __BEGIN__;
+
+ int block_size = sizeof(*cascade) + stage_count*sizeof(*cascade->stage_classifier);
+
+ if( stage_count <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "Number of stages should be positive" );
+
+ CV_CALL( cascade = (CvHaarClassifierCascade*)cvAlloc( block_size ));
+ memset( cascade, 0, block_size );
+
+ cascade->stage_classifier = (CvHaarStageClassifier*)(cascade + 1);
+ cascade->flags = CV_HAAR_MAGIC_VAL;
+ cascade->count = stage_count;
+
+ __END__;
+
+ return cascade;
+}
+
+static void
+icvReleaseHidHaarClassifierCascade( CvHidHaarClassifierCascade** _cascade )
+{
+ if( _cascade && *_cascade )
+ {
+ CvHidHaarClassifierCascade* cascade = *_cascade;
+ if( cascade->ipp_stages && icvHaarClassifierFree_32f_p )
+ {
+ int i;
+ for( i = 0; i < cascade->count; i++ )
+ {
+ if( cascade->ipp_stages[i] )
+ icvHaarClassifierFree_32f_p( cascade->ipp_stages[i] );
+ }
+ }
+ cvFree( &cascade->ipp_stages );
+ cvFree( _cascade );
+ }
+}
+
+/* create more efficient internal representation of haar classifier cascade */
+static CvHidHaarClassifierCascade*
+icvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade )
+{
+ CvRect* ipp_features = 0;
+ float *ipp_weights = 0, *ipp_thresholds = 0, *ipp_val1 = 0, *ipp_val2 = 0;
+ int* ipp_counts = 0;
+
+ CvHidHaarClassifierCascade* out = 0;
+
+ CV_FUNCNAME( "icvCreateHidHaarClassifierCascade" );
+
+ __BEGIN__;
+
+ int i, j, k, l;
+ int datasize;
+ int total_classifiers = 0;
+ int total_nodes = 0;
+ char errorstr[100];
+ CvHidHaarClassifier* haar_classifier_ptr;
+ CvHidHaarTreeNode* haar_node_ptr;
+ CvSize orig_window_size;
+ int has_tilted_features = 0;
+ int max_count = 0;
+
+ if( !CV_IS_HAAR_CLASSIFIER(cascade) )
+ CV_ERROR( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier pointer" );
+
+ if( cascade->hid_cascade )
+ CV_ERROR( CV_StsError, "hid_cascade has been already created" );
+
+ if( !cascade->stage_classifier )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( cascade->count <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "Negative number of cascade stages" );
+
+ orig_window_size = cascade->orig_window_size;
+
+ /* check input structure correctness and calculate total memory size needed for
+ internal representation of the classifier cascade */
+ for( i = 0; i < cascade->count; i++ )
+ {
+ CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
+
+ if( !stage_classifier->classifier ||
+ stage_classifier->count <= 0 )
+ {
+ sprintf( errorstr, "header of the stage classifier #%d is invalid "
+ "(has null pointers or non-positive classfier count)", i );
+ CV_ERROR( CV_StsError, errorstr );
+ }
+
+ max_count = MAX( max_count, stage_classifier->count );
+ total_classifiers += stage_classifier->count;
+
+ for( j = 0; j < stage_classifier->count; j++ )
+ {
+ CvHaarClassifier* classifier = stage_classifier->classifier + j;
+
+ total_nodes += classifier->count;
+ for( l = 0; l < classifier->count; l++ )
+ {
+ for( k = 0; k < CV_HAAR_FEATURE_MAX; k++ )
+ {
+ if( classifier->haar_feature[l].rect[k].r.width )
+ {
+ CvRect r = classifier->haar_feature[l].rect[k].r;
+ int tilted = classifier->haar_feature[l].tilted;
+ has_tilted_features |= tilted != 0;
+ if( r.width < 0 || r.height < 0 || r.y < 0 ||
+ r.x + r.width > orig_window_size.width
+ ||
+ (!tilted &&
+ (r.x < 0 || r.y + r.height > orig_window_size.height))
+ ||
+ (tilted && (r.x - r.height < 0 ||
+ r.y + r.width + r.height > orig_window_size.height)))
+ {
+ sprintf( errorstr, "rectangle #%d of the classifier #%d of "
+ "the stage classifier #%d is not inside "
+ "the reference (original) cascade window", k, j, i );
+ CV_ERROR( CV_StsNullPtr, errorstr );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // this is an upper boundary for the whole hidden cascade size
+ datasize = sizeof(CvHidHaarClassifierCascade) +
+ sizeof(CvHidHaarStageClassifier)*cascade->count +
+ sizeof(CvHidHaarClassifier) * total_classifiers +
+ sizeof(CvHidHaarTreeNode) * total_nodes +
+ sizeof(void*)*(total_nodes + total_classifiers);
+
+ CV_CALL( out = (CvHidHaarClassifierCascade*)cvAlloc( datasize ));
+ memset( out, 0, sizeof(*out) );
+
+ /* init header */
+ out->count = cascade->count;
+ out->stage_classifier = (CvHidHaarStageClassifier*)(out + 1);
+ haar_classifier_ptr = (CvHidHaarClassifier*)(out->stage_classifier + cascade->count);
+ haar_node_ptr = (CvHidHaarTreeNode*)(haar_classifier_ptr + total_classifiers);
+
+ out->is_stump_based = 1;
+ out->has_tilted_features = has_tilted_features;
+ out->is_tree = 0;
+
+ /* initialize internal representation */
+ for( i = 0; i < cascade->count; i++ )
+ {
+ CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
+ CvHidHaarStageClassifier* hid_stage_classifier = out->stage_classifier + i;
+
+ hid_stage_classifier->count = stage_classifier->count;
+ hid_stage_classifier->threshold = stage_classifier->threshold - icv_stage_threshold_bias;
+ hid_stage_classifier->classifier = haar_classifier_ptr;
+ hid_stage_classifier->two_rects = 1;
+ haar_classifier_ptr += stage_classifier->count;
+
+ hid_stage_classifier->parent = (stage_classifier->parent == -1)
+ ? NULL : out->stage_classifier + stage_classifier->parent;
+ hid_stage_classifier->next = (stage_classifier->next == -1)
+ ? NULL : out->stage_classifier + stage_classifier->next;
+ hid_stage_classifier->child = (stage_classifier->child == -1)
+ ? NULL : out->stage_classifier + stage_classifier->child;
+
+ out->is_tree |= hid_stage_classifier->next != NULL;
+
+ for( j = 0; j < stage_classifier->count; j++ )
+ {
+ CvHaarClassifier* classifier = stage_classifier->classifier + j;
+ CvHidHaarClassifier* hid_classifier = hid_stage_classifier->classifier + j;
+ int node_count = classifier->count;
+ float* alpha_ptr = (float*)(haar_node_ptr + node_count);
+
+ hid_classifier->count = node_count;
+ hid_classifier->node = haar_node_ptr;
+ hid_classifier->alpha = alpha_ptr;
+
+ for( l = 0; l < node_count; l++ )
+ {
+ CvHidHaarTreeNode* node = hid_classifier->node + l;
+ CvHaarFeature* feature = classifier->haar_feature + l;
+ memset( node, -1, sizeof(*node) );
+ node->threshold = classifier->threshold[l];
+ node->left = classifier->left[l];
+ node->right = classifier->right[l];
+
+ if( fabs(feature->rect[2].weight) < DBL_EPSILON ||
+ feature->rect[2].r.width == 0 ||
+ feature->rect[2].r.height == 0 )
+ memset( &(node->feature.rect[2]), 0, sizeof(node->feature.rect[2]) );
+ else
+ hid_stage_classifier->two_rects = 0;
+ }
+
+ memcpy( alpha_ptr, classifier->alpha, (node_count+1)*sizeof(alpha_ptr[0]));
+ haar_node_ptr =
+ (CvHidHaarTreeNode*)cvAlignPtr(alpha_ptr+node_count+1, sizeof(void*));
+
+ out->is_stump_based &= node_count == 1;
+ }
+ }
+
+ {
+ int can_use_ipp = icvHaarClassifierInitAlloc_32f_p != 0 &&
+ icvHaarClassifierFree_32f_p != 0 &&
+ icvApplyHaarClassifier_32f_C1R_p != 0 &&
+ icvRectStdDev_32f_C1R_p != 0 &&
+ !out->has_tilted_features && !out->is_tree && out->is_stump_based;
+
+ if( can_use_ipp )
+ {
+ int ipp_datasize = cascade->count*sizeof(out->ipp_stages[0]);
+ float ipp_weight_scale=(float)(1./((orig_window_size.width-icv_object_win_border*2)*
+ (orig_window_size.height-icv_object_win_border*2)));
+
+ CV_CALL( out->ipp_stages = (void**)cvAlloc( ipp_datasize ));
+ memset( out->ipp_stages, 0, ipp_datasize );
+
+ CV_CALL( ipp_features = (CvRect*)cvAlloc( max_count*3*sizeof(ipp_features[0]) ));
+ CV_CALL( ipp_weights = (float*)cvAlloc( max_count*3*sizeof(ipp_weights[0]) ));
+ CV_CALL( ipp_thresholds = (float*)cvAlloc( max_count*sizeof(ipp_thresholds[0]) ));
+ CV_CALL( ipp_val1 = (float*)cvAlloc( max_count*sizeof(ipp_val1[0]) ));
+ CV_CALL( ipp_val2 = (float*)cvAlloc( max_count*sizeof(ipp_val2[0]) ));
+ CV_CALL( ipp_counts = (int*)cvAlloc( max_count*sizeof(ipp_counts[0]) ));
+
+ for( i = 0; i < cascade->count; i++ )
+ {
+ CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
+ for( j = 0, k = 0; j < stage_classifier->count; j++ )
+ {
+ CvHaarClassifier* classifier = stage_classifier->classifier + j;
+ int rect_count = 2 + (classifier->haar_feature->rect[2].r.width != 0);
+
+ ipp_thresholds[j] = classifier->threshold[0];
+ ipp_val1[j] = classifier->alpha[0];
+ ipp_val2[j] = classifier->alpha[1];
+ ipp_counts[j] = rect_count;
+
+ for( l = 0; l < rect_count; l++, k++ )
+ {
+ ipp_features[k] = classifier->haar_feature->rect[l].r;
+ //ipp_features[k].y = orig_window_size.height - ipp_features[k].y - ipp_features[k].height;
+ ipp_weights[k] = classifier->haar_feature->rect[l].weight*ipp_weight_scale;
+ }
+ }
+
+ if( icvHaarClassifierInitAlloc_32f_p( &out->ipp_stages[i],
+ ipp_features, ipp_weights, ipp_thresholds,
+ ipp_val1, ipp_val2, ipp_counts, stage_classifier->count ) < 0 )
+ break;
+ }
+
+ if( i < cascade->count )
+ {
+ for( j = 0; j < i; j++ )
+ if( icvHaarClassifierFree_32f_p && out->ipp_stages[i] )
+ icvHaarClassifierFree_32f_p( out->ipp_stages[i] );
+ cvFree( &out->ipp_stages );
+ }
+ }
+ }
+
+ cascade->hid_cascade = out;
+ assert( (char*)haar_node_ptr - (char*)out <= datasize );
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ icvReleaseHidHaarClassifierCascade( &out );
+
+ cvFree( &ipp_features );
+ cvFree( &ipp_weights );
+ cvFree( &ipp_thresholds );
+ cvFree( &ipp_val1 );
+ cvFree( &ipp_val2 );
+ cvFree( &ipp_counts );
+
+ return out;
+}
+
+
+#define sum_elem_ptr(sum,row,col) \
+ ((sumtype*)CV_MAT_ELEM_PTR_FAST((sum),(row),(col),sizeof(sumtype)))
+
+#define sqsum_elem_ptr(sqsum,row,col) \
+ ((sqsumtype*)CV_MAT_ELEM_PTR_FAST((sqsum),(row),(col),sizeof(sqsumtype)))
+
+#define calc_sum(rect,offset) \
+ ((rect).p0[offset] - (rect).p1[offset] - (rect).p2[offset] + (rect).p3[offset])
+
+
+CV_IMPL void
+cvSetImagesForHaarClassifierCascade( CvHaarClassifierCascade* _cascade,
+ const CvArr* _sum,
+ const CvArr* _sqsum,
+ const CvArr* _tilted_sum,
+ double scale )
+{
+ CV_FUNCNAME("cvSetImagesForHaarClassifierCascade");
+
+ __BEGIN__;
+
+ CvMat sum_stub, *sum = (CvMat*)_sum;
+ CvMat sqsum_stub, *sqsum = (CvMat*)_sqsum;
+ CvMat tilted_stub, *tilted = (CvMat*)_tilted_sum;
+ CvHidHaarClassifierCascade* cascade;
+ int coi0 = 0, coi1 = 0;
+ int i;
+ CvRect equ_rect;
+ double weight_scale;
+
+ if( !CV_IS_HAAR_CLASSIFIER(_cascade) )
+ CV_ERROR( !_cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier pointer" );
+
+ if( scale <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "Scale must be positive" );
+
+ CV_CALL( sum = cvGetMat( sum, &sum_stub, &coi0 ));
+ CV_CALL( sqsum = cvGetMat( sqsum, &sqsum_stub, &coi1 ));
+
+ if( coi0 || coi1 )
+ CV_ERROR( CV_BadCOI, "COI is not supported" );
+
+ if( !CV_ARE_SIZES_EQ( sum, sqsum ))
+ CV_ERROR( CV_StsUnmatchedSizes, "All integral images must have the same size" );
+
+ if( CV_MAT_TYPE(sqsum->type) != CV_64FC1 ||
+ CV_MAT_TYPE(sum->type) != CV_32SC1 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Only (32s, 64f, 32s) combination of (sum,sqsum,tilted_sum) formats is allowed" );
+
+ if( !_cascade->hid_cascade )
+ CV_CALL( icvCreateHidHaarClassifierCascade(_cascade) );
+
+ cascade = _cascade->hid_cascade;
+
+ if( cascade->has_tilted_features )
+ {
+ CV_CALL( tilted = cvGetMat( tilted, &tilted_stub, &coi1 ));
+
+ if( CV_MAT_TYPE(tilted->type) != CV_32SC1 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Only (32s, 64f, 32s) combination of (sum,sqsum,tilted_sum) formats is allowed" );
+
+ if( sum->step != tilted->step )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Sum and tilted_sum must have the same stride (step, widthStep)" );
+
+ if( !CV_ARE_SIZES_EQ( sum, tilted ))
+ CV_ERROR( CV_StsUnmatchedSizes, "All integral images must have the same size" );
+ cascade->tilted = *tilted;
+ }
+
+ _cascade->scale = scale;
+ _cascade->real_window_size.width = cvRound( _cascade->orig_window_size.width * scale );
+ _cascade->real_window_size.height = cvRound( _cascade->orig_window_size.height * scale );
+
+ cascade->sum = *sum;
+ cascade->sqsum = *sqsum;
+
+ equ_rect.x = equ_rect.y = cvRound(scale);
+ equ_rect.width = cvRound((_cascade->orig_window_size.width-2)*scale);
+ equ_rect.height = cvRound((_cascade->orig_window_size.height-2)*scale);
+ weight_scale = 1./(equ_rect.width*equ_rect.height);
+ cascade->inv_window_area = weight_scale;
+
+ cascade->p0 = sum_elem_ptr(*sum, equ_rect.y, equ_rect.x);
+ cascade->p1 = sum_elem_ptr(*sum, equ_rect.y, equ_rect.x + equ_rect.width );
+ cascade->p2 = sum_elem_ptr(*sum, equ_rect.y + equ_rect.height, equ_rect.x );
+ cascade->p3 = sum_elem_ptr(*sum, equ_rect.y + equ_rect.height,
+ equ_rect.x + equ_rect.width );
+
+ cascade->pq0 = sqsum_elem_ptr(*sqsum, equ_rect.y, equ_rect.x);
+ cascade->pq1 = sqsum_elem_ptr(*sqsum, equ_rect.y, equ_rect.x + equ_rect.width );
+ cascade->pq2 = sqsum_elem_ptr(*sqsum, equ_rect.y + equ_rect.height, equ_rect.x );
+ cascade->pq3 = sqsum_elem_ptr(*sqsum, equ_rect.y + equ_rect.height,
+ equ_rect.x + equ_rect.width );
+
+ /* init pointers in haar features according to real window size and
+ given image pointers */
+ {
+#ifdef _OPENMP
+ int max_threads = cvGetNumThreads();
+ #pragma omp parallel for num_threads(max_threads) schedule(dynamic)
+#endif // _OPENMP
+ for( i = 0; i < _cascade->count; i++ )
+ {
+ int j, k, l;
+ for( j = 0; j < cascade->stage_classifier[i].count; j++ )
+ {
+ for( l = 0; l < cascade->stage_classifier[i].classifier[j].count; l++ )
+ {
+ CvHaarFeature* feature =
+ &_cascade->stage_classifier[i].classifier[j].haar_feature[l];
+ /* CvHidHaarClassifier* classifier =
+ cascade->stage_classifier[i].classifier + j; */
+ CvHidHaarFeature* hidfeature =
+ &cascade->stage_classifier[i].classifier[j].node[l].feature;
+ double sum0 = 0, area0 = 0;
+ CvRect r[3];
+#if CV_ADJUST_FEATURES
+ int base_w = -1, base_h = -1;
+ int new_base_w = 0, new_base_h = 0;
+ int kx, ky;
+ int flagx = 0, flagy = 0;
+ int x0 = 0, y0 = 0;
+#endif
+ int nr;
+
+ /* align blocks */
+ for( k = 0; k < CV_HAAR_FEATURE_MAX; k++ )
+ {
+ if( !hidfeature->rect[k].p0 )
+ break;
+#if CV_ADJUST_FEATURES
+ r[k] = feature->rect[k].r;
+ base_w = (int)CV_IMIN( (unsigned)base_w, (unsigned)(r[k].width-1) );
+ base_w = (int)CV_IMIN( (unsigned)base_w, (unsigned)(r[k].x - r[0].x-1) );
+ base_h = (int)CV_IMIN( (unsigned)base_h, (unsigned)(r[k].height-1) );
+ base_h = (int)CV_IMIN( (unsigned)base_h, (unsigned)(r[k].y - r[0].y-1) );
+#endif
+ }
+
+ nr = k;
+
+#if CV_ADJUST_FEATURES
+ base_w += 1;
+ base_h += 1;
+ kx = r[0].width / base_w;
+ ky = r[0].height / base_h;
+
+ if( kx <= 0 )
+ {
+ flagx = 1;
+ new_base_w = cvRound( r[0].width * scale ) / kx;
+ x0 = cvRound( r[0].x * scale );
+ }
+
+ if( ky <= 0 )
+ {
+ flagy = 1;
+ new_base_h = cvRound( r[0].height * scale ) / ky;
+ y0 = cvRound( r[0].y * scale );
+ }
+#endif
+
+ for( k = 0; k < nr; k++ )
+ {
+ CvRect tr;
+ double correction_ratio;
+
+#if CV_ADJUST_FEATURES
+ if( flagx )
+ {
+ tr.x = (r[k].x - r[0].x) * new_base_w / base_w + x0;
+ tr.width = r[k].width * new_base_w / base_w;
+ }
+ else
+#endif
+ {
+ tr.x = cvRound( r[k].x * scale );
+ tr.width = cvRound( r[k].width * scale );
+ }
+
+#if CV_ADJUST_FEATURES
+ if( flagy )
+ {
+ tr.y = (r[k].y - r[0].y) * new_base_h / base_h + y0;
+ tr.height = r[k].height * new_base_h / base_h;
+ }
+ else
+#endif
+ {
+ tr.y = cvRound( r[k].y * scale );
+ tr.height = cvRound( r[k].height * scale );
+ }
+
+#if CV_ADJUST_WEIGHTS
+ {
+ // RAINER START
+ const float orig_feature_size = (float)(feature->rect[k].r.width)*feature->rect[k].r.height;
+ const float orig_norm_size = (float)(_cascade->orig_window_size.width)*(_cascade->orig_window_size.height);
+ const float feature_size = float(tr.width*tr.height);
+ //const float normSize = float(equ_rect.width*equ_rect.height);
+ float target_ratio = orig_feature_size / orig_norm_size;
+ //float isRatio = featureSize / normSize;
+ //correctionRatio = targetRatio / isRatio / normSize;
+ correction_ratio = target_ratio / feature_size;
+ // RAINER END
+ }
+#else
+ correction_ratio = weight_scale * (!feature->tilted ? 1 : 0.5);
+#endif
+
+ if( !feature->tilted )
+ {
+ hidfeature->rect[k].p0 = sum_elem_ptr(*sum, tr.y, tr.x);
+ hidfeature->rect[k].p1 = sum_elem_ptr(*sum, tr.y, tr.x + tr.width);
+ hidfeature->rect[k].p2 = sum_elem_ptr(*sum, tr.y + tr.height, tr.x);
+ hidfeature->rect[k].p3 = sum_elem_ptr(*sum, tr.y + tr.height, tr.x + tr.width);
+ }
+ else
+ {
+ hidfeature->rect[k].p2 = sum_elem_ptr(*tilted, tr.y + tr.width, tr.x + tr.width);
+ hidfeature->rect[k].p3 = sum_elem_ptr(*tilted, tr.y + tr.width + tr.height,
+ tr.x + tr.width - tr.height);
+ hidfeature->rect[k].p0 = sum_elem_ptr(*tilted, tr.y, tr.x);
+ hidfeature->rect[k].p1 = sum_elem_ptr(*tilted, tr.y + tr.height, tr.x - tr.height);
+ }
+
+ hidfeature->rect[k].weight = (float)(feature->rect[k].weight * correction_ratio);
+
+ if( k == 0 )
+ area0 = tr.width * tr.height;
+ else
+ sum0 += hidfeature->rect[k].weight * tr.width * tr.height;
+ }
+
+ hidfeature->rect[0].weight = (float)(-sum0/area0);
+ } /* l */
+ } /* j */
+ }
+ }
+
+ __END__;
+}
+
+
+CV_INLINE
+double icvEvalHidHaarClassifier( CvHidHaarClassifier* classifier,
+ double variance_norm_factor,
+ size_t p_offset )
+{
+ int idx = 0;
+ do
+ {
+ CvHidHaarTreeNode* node = classifier->node + idx;
+ double t = node->threshold * variance_norm_factor;
+
+ double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
+ sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
+
+ if( node->feature.rect[2].p0 )
+ sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight;
+
+ idx = sum < t ? node->left : node->right;
+ }
+ while( idx > 0 );
+ return classifier->alpha[-idx];
+}
+
+
+CV_IMPL int
+cvRunHaarClassifierCascade( CvHaarClassifierCascade* _cascade,
+ CvPoint pt, int start_stage )
+{
+ int result = -1;
+ CV_FUNCNAME("cvRunHaarClassifierCascade");
+
+ __BEGIN__;
+
+ int p_offset, pq_offset;
+ int i, j;
+ double mean, variance_norm_factor;
+ CvHidHaarClassifierCascade* cascade;
+
+ if( !CV_IS_HAAR_CLASSIFIER(_cascade) )
+ CV_ERROR( !_cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid cascade pointer" );
+
+ cascade = _cascade->hid_cascade;
+ if( !cascade )
+ CV_ERROR( CV_StsNullPtr, "Hidden cascade has not been created.\n"
+ "Use cvSetImagesForHaarClassifierCascade" );
+
+ if( pt.x < 0 || pt.y < 0 ||
+ pt.x + _cascade->real_window_size.width >= cascade->sum.width-2 ||
+ pt.y + _cascade->real_window_size.height >= cascade->sum.height-2 )
+ EXIT;
+
+ p_offset = pt.y * (cascade->sum.step/sizeof(sumtype)) + pt.x;
+ pq_offset = pt.y * (cascade->sqsum.step/sizeof(sqsumtype)) + pt.x;
+ mean = calc_sum(*cascade,p_offset)*cascade->inv_window_area;
+ variance_norm_factor = cascade->pq0[pq_offset] - cascade->pq1[pq_offset] -
+ cascade->pq2[pq_offset] + cascade->pq3[pq_offset];
+ variance_norm_factor = variance_norm_factor*cascade->inv_window_area - mean*mean;
+ if( variance_norm_factor >= 0. )
+ variance_norm_factor = sqrt(variance_norm_factor);
+ else
+ variance_norm_factor = 1.;
+
+ if( cascade->is_tree )
+ {
+ CvHidHaarStageClassifier* ptr;
+ assert( start_stage == 0 );
+
+ result = 1;
+ ptr = cascade->stage_classifier;
+
+ while( ptr )
+ {
+ double stage_sum = 0;
+
+ for( j = 0; j < ptr->count; j++ )
+ {
+ stage_sum += icvEvalHidHaarClassifier( ptr->classifier + j,
+ variance_norm_factor, p_offset );
+ }
+
+ if( stage_sum >= ptr->threshold )
+ {
+ ptr = ptr->child;
+ }
+ else
+ {
+ while( ptr && ptr->next == NULL ) ptr = ptr->parent;
+ if( ptr == NULL )
+ {
+ result = 0;
+ EXIT;
+ }
+ ptr = ptr->next;
+ }
+ }
+ }
+ else if( cascade->is_stump_based )
+ {
+ for( i = start_stage; i < cascade->count; i++ )
+ {
+ double stage_sum = 0;
+
+ if( cascade->stage_classifier[i].two_rects )
+ {
+ for( j = 0; j < cascade->stage_classifier[i].count; j++ )
+ {
+ CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
+ CvHidHaarTreeNode* node = classifier->node;
+ double sum, t = node->threshold*variance_norm_factor, a, b;
+
+ sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
+ sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
+
+ a = classifier->alpha[0];
+ b = classifier->alpha[1];
+ stage_sum += sum < t ? a : b;
+ }
+ }
+ else
+ {
+ for( j = 0; j < cascade->stage_classifier[i].count; j++ )
+ {
+ CvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
+ CvHidHaarTreeNode* node = classifier->node;
+ double sum, t = node->threshold*variance_norm_factor, a, b;
+
+ sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
+ sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
+
+ if( node->feature.rect[2].p0 )
+ sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight;
+
+ a = classifier->alpha[0];
+ b = classifier->alpha[1];
+ stage_sum += sum < t ? a : b;
+ }
+ }
+
+ if( stage_sum < cascade->stage_classifier[i].threshold )
+ {
+ result = -i;
+ EXIT;
+ }
+ }
+ }
+ else
+ {
+ for( i = start_stage; i < cascade->count; i++ )
+ {
+ double stage_sum = 0;
+
+ for( j = 0; j < cascade->stage_classifier[i].count; j++ )
+ {
+ stage_sum += icvEvalHidHaarClassifier(
+ cascade->stage_classifier[i].classifier + j,
+ variance_norm_factor, p_offset );
+ }
+
+ if( stage_sum < cascade->stage_classifier[i].threshold )
+ {
+ result = -i;
+ EXIT;
+ }
+ }
+ }
+
+ result = 1;
+
+ __END__;
+
+ return result;
+}
+
+
+static int is_equal( const void* _r1, const void* _r2, void* )
+{
+ const CvRect* r1 = (const CvRect*)_r1;
+ const CvRect* r2 = (const CvRect*)_r2;
+ int distance = cvRound(r1->width*0.2);
+
+ return r2->x <= r1->x + distance &&
+ r2->x >= r1->x - distance &&
+ r2->y <= r1->y + distance &&
+ r2->y >= r1->y - distance &&
+ r2->width <= cvRound( r1->width * 1.2 ) &&
+ cvRound( r2->width * 1.2 ) >= r1->width;
+}
+
+
+#define VERY_ROUGH_SEARCH 0
+
+CV_IMPL CvSeq*
+cvHaarDetectObjects( const CvArr* _img,
+ CvHaarClassifierCascade* cascade,
+ CvMemStorage* storage, double scale_factor,
+ int min_neighbors, int flags, CvSize min_size )
+{
+ int split_stage = 2;
+
+ CvMat stub, *img = (CvMat*)_img;
+ CvMat *temp = 0, *sum = 0, *tilted = 0, *sqsum = 0, *norm_img = 0, *sumcanny = 0, *img_small = 0;
+ CvSeq* result_seq = 0;
+ CvMemStorage* temp_storage = 0;
+ CvAvgComp* comps = 0;
+ CvSeq* seq_thread[CV_MAX_THREADS] = {0};
+ int i, max_threads = 0;
+
+ CV_FUNCNAME( "cvHaarDetectObjects" );
+
+ __BEGIN__;
+
+ CvSeq *seq = 0, *seq2 = 0, *idx_seq = 0, *big_seq = 0;
+ CvAvgComp result_comp = {{0,0,0,0},0};
+ double factor;
+ int npass = 2, coi;
+ bool do_canny_pruning = (flags & CV_HAAR_DO_CANNY_PRUNING) != 0;
+ bool find_biggest_object = (flags & CV_HAAR_FIND_BIGGEST_OBJECT) != 0;
+ bool rough_search = (flags & CV_HAAR_DO_ROUGH_SEARCH) != 0;
+
+ if( !CV_IS_HAAR_CLASSIFIER(cascade) )
+ CV_ERROR( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier cascade" );
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "Null storage pointer" );
+
+ CV_CALL( img = cvGetMat( img, &stub, &coi ));
+ if( coi )
+ CV_ERROR( CV_BadCOI, "COI is not supported" );
+
+ if( CV_MAT_DEPTH(img->type) != CV_8U )
+ CV_ERROR( CV_StsUnsupportedFormat, "Only 8-bit images are supported" );
+
+ if( find_biggest_object )
+ flags &= ~CV_HAAR_SCALE_IMAGE;
+
+ CV_CALL( temp = cvCreateMat( img->rows, img->cols, CV_8UC1 ));
+ CV_CALL( sum = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 ));
+ CV_CALL( sqsum = cvCreateMat( img->rows + 1, img->cols + 1, CV_64FC1 ));
+ CV_CALL( temp_storage = cvCreateChildMemStorage( storage ));
+
+ if( !cascade->hid_cascade )
+ CV_CALL( icvCreateHidHaarClassifierCascade(cascade) );
+
+ if( cascade->hid_cascade->has_tilted_features )
+ tilted = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 );
+
+ seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvRect), temp_storage );
+ seq2 = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), temp_storage );
+ result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), storage );
+
+ max_threads = cvGetNumThreads();
+ if( max_threads > 1 )
+ for( i = 0; i < max_threads; i++ )
+ {
+ CvMemStorage* temp_storage_thread;
+ CV_CALL( temp_storage_thread = cvCreateMemStorage(0));
+ CV_CALL( seq_thread[i] = cvCreateSeq( 0, sizeof(CvSeq),
+ sizeof(CvRect), temp_storage_thread ));
+ }
+ else
+ seq_thread[0] = seq;
+
+ if( CV_MAT_CN(img->type) > 1 )
+ {
+ cvCvtColor( img, temp, CV_BGR2GRAY );
+ img = temp;
+ }
+
+ if( flags & CV_HAAR_FIND_BIGGEST_OBJECT )
+ flags &= ~(CV_HAAR_SCALE_IMAGE|CV_HAAR_DO_CANNY_PRUNING);
+
+ if( flags & CV_HAAR_SCALE_IMAGE )
+ {
+ CvSize win_size0 = cascade->orig_window_size;
+ int use_ipp = cascade->hid_cascade->ipp_stages != 0 &&
+ icvApplyHaarClassifier_32f_C1R_p != 0;
+
+ if( use_ipp )
+ CV_CALL( norm_img = cvCreateMat( img->rows, img->cols, CV_32FC1 ));
+ CV_CALL( img_small = cvCreateMat( img->rows + 1, img->cols + 1, CV_8UC1 ));
+
+ for( factor = 1; ; factor *= scale_factor )
+ {
+ int strip_count, strip_size;
+ int ystep = factor > 2. ? 1 : 2;
+ CvSize win_size = { cvRound(win_size0.width*factor),
+ cvRound(win_size0.height*factor) };
+ CvSize sz = { cvRound( img->cols/factor ), cvRound( img->rows/factor ) };
+ CvSize sz1 = { sz.width - win_size0.width, sz.height - win_size0.height };
+ CvRect equ_rect = { icv_object_win_border, icv_object_win_border,
+ win_size0.width - icv_object_win_border*2,
+ win_size0.height - icv_object_win_border*2 };
+ CvMat img1, sum1, sqsum1, norm1, tilted1, mask1;
+ CvMat* _tilted = 0;
+
+ if( sz1.width <= 0 || sz1.height <= 0 )
+ break;
+ if( win_size.width < min_size.width || win_size.height < min_size.height )
+ continue;
+
+ img1 = cvMat( sz.height, sz.width, CV_8UC1, img_small->data.ptr );
+ sum1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, sum->data.ptr );
+ sqsum1 = cvMat( sz.height+1, sz.width+1, CV_64FC1, sqsum->data.ptr );
+ if( tilted )
+ {
+ tilted1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, tilted->data.ptr );
+ _tilted = &tilted1;
+ }
+ norm1 = cvMat( sz1.height, sz1.width, CV_32FC1, norm_img ? norm_img->data.ptr : 0 );
+ mask1 = cvMat( sz1.height, sz1.width, CV_8UC1, temp->data.ptr );
+
+ cvResize( img, &img1, CV_INTER_LINEAR );
+ cvIntegral( &img1, &sum1, &sqsum1, _tilted );
+
+ if( max_threads > 1 )
+ {
+ strip_count = MAX(MIN(sz1.height/ystep, max_threads*3), 1);
+ strip_size = (sz1.height + strip_count - 1)/strip_count;
+ strip_size = (strip_size / ystep)*ystep;
+ }
+ else
+ {
+ strip_count = 1;
+ strip_size = sz1.height;
+ }
+
+ if( !use_ipp )
+ cvSetImagesForHaarClassifierCascade( cascade, &sum1, &sqsum1, 0, 1. );
+ else
+ {
+ for( i = 0; i <= sz.height; i++ )
+ {
+ const int* isum = (int*)(sum1.data.ptr + sum1.step*i);
+ float* fsum = (float*)isum;
+ const int FLT_DELTA = -(1 << 24);
+ int j;
+ for( j = 0; j <= sz.width; j++ )
+ fsum[j] = (float)(isum[j] + FLT_DELTA);
+ }
+ }
+
+ #ifdef _OPENMP
+ #pragma omp parallel for num_threads(max_threads) schedule(dynamic)
+ #endif
+ for( i = 0; i < strip_count; i++ )
+ {
+ int thread_id = cvGetThreadNum();
+ int positive = 0;
+ int y1 = i*strip_size, y2 = (i+1)*strip_size/* - ystep + 1*/;
+ CvSize ssz;
+ int x, y, j;
+ if( i == strip_count - 1 || y2 > sz1.height )
+ y2 = sz1.height;
+ ssz = cvSize(sz1.width, y2 - y1);
+
+ if( use_ipp )
+ {
+ icvRectStdDev_32f_C1R_p(
+ (float*)(sum1.data.ptr + y1*sum1.step), sum1.step,
+ (double*)(sqsum1.data.ptr + y1*sqsum1.step), sqsum1.step,
+ (float*)(norm1.data.ptr + y1*norm1.step), norm1.step, ssz, equ_rect );
+
+ positive = (ssz.width/ystep)*((ssz.height + ystep-1)/ystep);
+ memset( mask1.data.ptr + y1*mask1.step, ystep == 1, mask1.height*mask1.step);
+
+ if( ystep > 1 )
+ {
+ for( y = y1, positive = 0; y < y2; y += ystep )
+ for( x = 0; x < ssz.width; x += ystep )
+ mask1.data.ptr[mask1.step*y + x] = (uchar)1;
+ }
+
+ for( j = 0; j < cascade->count; j++ )
+ {
+ if( icvApplyHaarClassifier_32f_C1R_p(
+ (float*)(sum1.data.ptr + y1*sum1.step), sum1.step,
+ (float*)(norm1.data.ptr + y1*norm1.step), norm1.step,
+ mask1.data.ptr + y1*mask1.step, mask1.step, ssz, &positive,
+ cascade->hid_cascade->stage_classifier[j].threshold,
+ cascade->hid_cascade->ipp_stages[j]) < 0 )
+ {
+ positive = 0;
+ break;
+ }
+ if( positive <= 0 )
+ break;
+ }
+ }
+ else
+ {
+ for( y = y1, positive = 0; y < y2; y += ystep )
+ for( x = 0; x < ssz.width; x += ystep )
+ {
+ mask1.data.ptr[mask1.step*y + x] =
+ cvRunHaarClassifierCascade( cascade, cvPoint(x,y), 0 ) > 0;
+ positive += mask1.data.ptr[mask1.step*y + x];
+ }
+ }
+
+ if( positive > 0 )
+ {
+ for( y = y1; y < y2; y += ystep )
+ for( x = 0; x < ssz.width; x += ystep )
+ if( mask1.data.ptr[mask1.step*y + x] != 0 )
+ {
+ CvRect obj_rect = { cvRound(x*factor), cvRound(y*factor),
+ win_size.width, win_size.height };
+ cvSeqPush( seq_thread[thread_id], &obj_rect );
+ }
+ }
+ }
+
+ // gather the results
+ if( max_threads > 1 )
+ for( i = 0; i < max_threads; i++ )
+ {
+ CvSeq* s = seq_thread[i];
+ int j, total = s->total;
+ CvSeqBlock* b = s->first;
+ for( j = 0; j < total; j += b->count, b = b->next )
+ cvSeqPushMulti( seq, b->data, b->count );
+ }
+ }
+ }
+ else
+ {
+ int n_factors = 0;
+ CvRect scan_roi_rect = {0,0,0,0};
+ bool is_found = false, scan_roi = false;
+
+ cvIntegral( img, sum, sqsum, tilted );
+
+ if( do_canny_pruning )
+ {
+ sumcanny = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 );
+ cvCanny( img, temp, 0, 50, 3 );
+ cvIntegral( temp, sumcanny );
+ }
+
+ if( (unsigned)split_stage >= (unsigned)cascade->count ||
+ cascade->hid_cascade->is_tree )
+ {
+ split_stage = cascade->count;
+ npass = 1;
+ }
+
+ for( n_factors = 0, factor = 1;
+ factor*cascade->orig_window_size.width < img->cols - 10 &&
+ factor*cascade->orig_window_size.height < img->rows - 10;
+ n_factors++, factor *= scale_factor )
+ ;
+
+ if( find_biggest_object )
+ {
+ scale_factor = 1./scale_factor;
+ factor *= scale_factor;
+ big_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvRect), temp_storage );
+ }
+ else
+ factor = 1;
+
+ for( ; n_factors-- > 0 && !is_found; factor *= scale_factor )
+ {
+ const double ystep = MAX( 2, factor );
+ CvSize win_size = { cvRound( cascade->orig_window_size.width * factor ),
+ cvRound( cascade->orig_window_size.height * factor )};
+ CvRect equ_rect = { 0, 0, 0, 0 };
+ int *p0 = 0, *p1 = 0, *p2 = 0, *p3 = 0;
+ int *pq0 = 0, *pq1 = 0, *pq2 = 0, *pq3 = 0;
+ int pass, stage_offset = 0;
+ int start_x = 0, start_y = 0;
+ int end_x = cvRound((img->cols - win_size.width) / ystep);
+ int end_y = cvRound((img->rows - win_size.height) / ystep);
+
+ if( win_size.width < min_size.width || win_size.height < min_size.height )
+ {
+ if( find_biggest_object )
+ break;
+ continue;
+ }
+
+ cvSetImagesForHaarClassifierCascade( cascade, sum, sqsum, tilted, factor );
+ cvZero( temp );
+
+ if( do_canny_pruning )
+ {
+ equ_rect.x = cvRound(win_size.width*0.15);
+ equ_rect.y = cvRound(win_size.height*0.15);
+ equ_rect.width = cvRound(win_size.width*0.7);
+ equ_rect.height = cvRound(win_size.height*0.7);
+
+ p0 = (int*)(sumcanny->data.ptr + equ_rect.y*sumcanny->step) + equ_rect.x;
+ p1 = (int*)(sumcanny->data.ptr + equ_rect.y*sumcanny->step)
+ + equ_rect.x + equ_rect.width;
+ p2 = (int*)(sumcanny->data.ptr + (equ_rect.y + equ_rect.height)*sumcanny->step) + equ_rect.x;
+ p3 = (int*)(sumcanny->data.ptr + (equ_rect.y + equ_rect.height)*sumcanny->step)
+ + equ_rect.x + equ_rect.width;
+
+ pq0 = (int*)(sum->data.ptr + equ_rect.y*sum->step) + equ_rect.x;
+ pq1 = (int*)(sum->data.ptr + equ_rect.y*sum->step)
+ + equ_rect.x + equ_rect.width;
+ pq2 = (int*)(sum->data.ptr + (equ_rect.y + equ_rect.height)*sum->step) + equ_rect.x;
+ pq3 = (int*)(sum->data.ptr + (equ_rect.y + equ_rect.height)*sum->step)
+ + equ_rect.x + equ_rect.width;
+ }
+
+ if( scan_roi )
+ {
+ //adjust start_height and stop_height
+ start_y = cvRound(scan_roi_rect.y / ystep);
+ end_y = cvRound((scan_roi_rect.y + scan_roi_rect.height - win_size.height) / ystep);
+
+ start_x = cvRound(scan_roi_rect.x / ystep);
+ end_x = cvRound((scan_roi_rect.x + scan_roi_rect.width - win_size.width) / ystep);
+ }
+
+ cascade->hid_cascade->count = split_stage;
+
+ for( pass = 0; pass < npass; pass++ )
+ {
+ #ifdef _OPENMP
+ #pragma omp parallel for num_threads(max_threads) schedule(dynamic)
+ #endif
+ for( int _iy = start_y; _iy < end_y; _iy++ )
+ {
+ int thread_id = cvGetThreadNum();
+ int iy = cvRound(_iy*ystep);
+ int _ix, _xstep = 1;
+ uchar* mask_row = temp->data.ptr + temp->step * iy;
+
+ for( _ix = start_x; _ix < end_x; _ix += _xstep )
+ {
+ int ix = cvRound(_ix*ystep); // it really should be ystep
+
+ if( pass == 0 )
+ {
+ int result;
+ _xstep = 2;
+
+ if( do_canny_pruning )
+ {
+ int offset;
+ int s, sq;
+
+ offset = iy*(sum->step/sizeof(p0[0])) + ix;
+ s = p0[offset] - p1[offset] - p2[offset] + p3[offset];
+ sq = pq0[offset] - pq1[offset] - pq2[offset] + pq3[offset];
+ if( s < 100 || sq < 20 )
+ continue;
+ }
+
+ result = cvRunHaarClassifierCascade( cascade, cvPoint(ix,iy), 0 );
+ if( result > 0 )
+ {
+ if( pass < npass - 1 )
+ mask_row[ix] = 1;
+ else
+ {
+ CvRect rect = cvRect(ix,iy,win_size.width,win_size.height);
+ cvSeqPush( seq_thread[thread_id], &rect );
+ }
+ }
+ if( result < 0 )
+ _xstep = 1;
+ }
+ else if( mask_row[ix] )
+ {
+ int result = cvRunHaarClassifierCascade( cascade, cvPoint(ix,iy),
+ stage_offset );
+ if( result > 0 )
+ {
+ if( pass == npass - 1 )
+ {
+ CvRect rect = cvRect(ix,iy,win_size.width,win_size.height);
+ cvSeqPush( seq_thread[thread_id], &rect );
+ }
+ }
+ else
+ mask_row[ix] = 0;
+ }
+ }
+ }
+ stage_offset = cascade->hid_cascade->count;
+ cascade->hid_cascade->count = cascade->count;
+ }
+
+ // gather the results
+ if( max_threads > 1 )
+ for( i = 0; i < max_threads; i++ )
+ {
+ CvSeq* s = seq_thread[i];
+ int j, total = s->total;
+ CvSeqBlock* b = s->first;
+ for( j = 0; j < total; j += b->count, b = b->next )
+ cvSeqPushMulti( seq, b->data, b->count );
+ }
+
+ if( find_biggest_object )
+ {
+ CvSeq* bseq = min_neighbors > 0 ? big_seq : seq;
+
+ if( min_neighbors > 0 && !scan_roi )
+ {
+ // group retrieved rectangles in order to filter out noise
+ int ncomp = cvSeqPartition( seq, 0, &idx_seq, is_equal, 0 );
+ CV_CALL( comps = (CvAvgComp*)cvAlloc( (ncomp+1)*sizeof(comps[0])));
+ memset( comps, 0, (ncomp+1)*sizeof(comps[0]));
+
+ #if VERY_ROUGH_SEARCH
+ if( rough_search )
+ {
+ for( i = 0; i < seq->total; i++ )
+ {
+ CvRect r1 = *(CvRect*)cvGetSeqElem( seq, i );
+ int idx = *(int*)cvGetSeqElem( idx_seq, i );
+ assert( (unsigned)idx < (unsigned)ncomp );
+
+ comps[idx].neighbors++;
+ comps[idx].rect.x += r1.x;
+ comps[idx].rect.y += r1.y;
+ comps[idx].rect.width += r1.width;
+ comps[idx].rect.height += r1.height;
+ }
+
+ // calculate average bounding box
+ for( i = 0; i < ncomp; i++ )
+ {
+ int n = comps[i].neighbors;
+ if( n >= min_neighbors )
+ {
+ CvAvgComp comp;
+ comp.rect.x = (comps[i].rect.x*2 + n)/(2*n);
+ comp.rect.y = (comps[i].rect.y*2 + n)/(2*n);
+ comp.rect.width = (comps[i].rect.width*2 + n)/(2*n);
+ comp.rect.height = (comps[i].rect.height*2 + n)/(2*n);
+ comp.neighbors = n;
+ cvSeqPush( bseq, &comp );
+ }
+ }
+ }
+ else
+ #endif
+ {
+ for( i = 0 ; i <= ncomp; i++ )
+ comps[i].rect.x = comps[i].rect.y = INT_MAX;
+
+ // count number of neighbors
+ for( i = 0; i < seq->total; i++ )
+ {
+ CvRect r1 = *(CvRect*)cvGetSeqElem( seq, i );
+ int idx = *(int*)cvGetSeqElem( idx_seq, i );
+ assert( (unsigned)idx < (unsigned)ncomp );
+
+ comps[idx].neighbors++;
+
+ // rect.width and rect.height will store coordinate of right-bottom corner
+ comps[idx].rect.x = MIN(comps[idx].rect.x, r1.x);
+ comps[idx].rect.y = MIN(comps[idx].rect.y, r1.y);
+ comps[idx].rect.width = MAX(comps[idx].rect.width, r1.x+r1.width-1);
+ comps[idx].rect.height = MAX(comps[idx].rect.height, r1.y+r1.height-1);
+ }
+
+ // calculate enclosing box
+ for( i = 0; i < ncomp; i++ )
+ {
+ int n = comps[i].neighbors;
+ if( n >= min_neighbors )
+ {
+ CvAvgComp comp;
+ int t;
+ double min_scale = rough_search ? 0.6 : 0.4;
+ comp.rect.x = comps[i].rect.x;
+ comp.rect.y = comps[i].rect.y;
+ comp.rect.width = comps[i].rect.width - comps[i].rect.x + 1;
+ comp.rect.height = comps[i].rect.height - comps[i].rect.y + 1;
+
+ // update min_size
+ t = cvRound( comp.rect.width*min_scale );
+ min_size.width = MAX( min_size.width, t );
+
+ t = cvRound( comp.rect.height*min_scale );
+ min_size.height = MAX( min_size.height, t );
+
+ //expand the box by 20% because we could miss some neighbours
+ //see 'is_equal' function
+ #if 1
+ int offset = cvRound(comp.rect.width * 0.2);
+ int right = MIN( img->cols-1, comp.rect.x+comp.rect.width-1 + offset );
+ int bottom = MIN( img->rows-1, comp.rect.y+comp.rect.height-1 + offset);
+ comp.rect.x = MAX( comp.rect.x - offset, 0 );
+ comp.rect.y = MAX( comp.rect.y - offset, 0 );
+ comp.rect.width = right - comp.rect.x + 1;
+ comp.rect.height = bottom - comp.rect.y + 1;
+ #endif
+
+ comp.neighbors = n;
+ cvSeqPush( bseq, &comp );
+ }
+ }
+ }
+
+ cvFree( &comps );
+ }
+
+ // extract the biggest rect
+ if( bseq->total > 0 )
+ {
+ int max_area = 0;
+ for( i = 0; i < bseq->total; i++ )
+ {
+ CvAvgComp* comp = (CvAvgComp*)cvGetSeqElem( bseq, i );
+ int area = comp->rect.width * comp->rect.height;
+ if( max_area < area )
+ {
+ max_area = area;
+ result_comp.rect = comp->rect;
+ result_comp.neighbors = bseq == seq ? 1 : comp->neighbors;
+ }
+ }
+
+ //Prepare information for further scanning inside the biggest rectangle
+
+ #if VERY_ROUGH_SEARCH
+ // change scan ranges to roi in case of required
+ if( !rough_search && !scan_roi )
+ {
+ scan_roi = true;
+ scan_roi_rect = result_comp.rect;
+ cvClearSeq(bseq);
+ }
+ else if( rough_search )
+ is_found = true;
+ #else
+ if( !scan_roi )
+ {
+ scan_roi = true;
+ scan_roi_rect = result_comp.rect;
+ cvClearSeq(bseq);
+ }
+ #endif
+ }
+ }
+ }
+ }
+
+ if( min_neighbors == 0 && !find_biggest_object )
+ {
+ for( i = 0; i < seq->total; i++ )
+ {
+ CvRect* rect = (CvRect*)cvGetSeqElem( seq, i );
+ CvAvgComp comp;
+ comp.rect = *rect;
+ comp.neighbors = 1;
+ cvSeqPush( result_seq, &comp );
+ }
+ }
+
+ if( min_neighbors != 0
+#if VERY_ROUGH_SEARCH
+ && (!find_biggest_object || !rough_search)
+#endif
+ )
+ {
+ // group retrieved rectangles in order to filter out noise
+ int ncomp = cvSeqPartition( seq, 0, &idx_seq, is_equal, 0 );
+ CV_CALL( comps = (CvAvgComp*)cvAlloc( (ncomp+1)*sizeof(comps[0])));
+ memset( comps, 0, (ncomp+1)*sizeof(comps[0]));
+
+ // count number of neighbors
+ for( i = 0; i < seq->total; i++ )
+ {
+ CvRect r1 = *(CvRect*)cvGetSeqElem( seq, i );
+ int idx = *(int*)cvGetSeqElem( idx_seq, i );
+ assert( (unsigned)idx < (unsigned)ncomp );
+
+ comps[idx].neighbors++;
+
+ comps[idx].rect.x += r1.x;
+ comps[idx].rect.y += r1.y;
+ comps[idx].rect.width += r1.width;
+ comps[idx].rect.height += r1.height;
+ }
+
+ // calculate average bounding box
+ for( i = 0; i < ncomp; i++ )
+ {
+ int n = comps[i].neighbors;
+ if( n >= min_neighbors )
+ {
+ CvAvgComp comp;
+ comp.rect.x = (comps[i].rect.x*2 + n)/(2*n);
+ comp.rect.y = (comps[i].rect.y*2 + n)/(2*n);
+ comp.rect.width = (comps[i].rect.width*2 + n)/(2*n);
+ comp.rect.height = (comps[i].rect.height*2 + n)/(2*n);
+ comp.neighbors = comps[i].neighbors;
+
+ cvSeqPush( seq2, &comp );
+ }
+ }
+
+ if( !find_biggest_object )
+ {
+ // filter out small face rectangles inside large face rectangles
+ for( i = 0; i < seq2->total; i++ )
+ {
+ CvAvgComp r1 = *(CvAvgComp*)cvGetSeqElem( seq2, i );
+ int j, flag = 1;
+
+ for( j = 0; j < seq2->total; j++ )
+ {
+ CvAvgComp r2 = *(CvAvgComp*)cvGetSeqElem( seq2, j );
+ int distance = cvRound( r2.rect.width * 0.2 );
+
+ if( i != j &&
+ r1.rect.x >= r2.rect.x - distance &&
+ r1.rect.y >= r2.rect.y - distance &&
+ r1.rect.x + r1.rect.width <= r2.rect.x + r2.rect.width + distance &&
+ r1.rect.y + r1.rect.height <= r2.rect.y + r2.rect.height + distance &&
+ (r2.neighbors > MAX( 3, r1.neighbors ) || r1.neighbors < 3) )
+ {
+ flag = 0;
+ break;
+ }
+ }
+
+ if( flag )
+ cvSeqPush( result_seq, &r1 );
+ }
+ }
+ else
+ {
+ int max_area = 0;
+ for( i = 0; i < seq2->total; i++ )
+ {
+ CvAvgComp* comp = (CvAvgComp*)cvGetSeqElem( seq2, i );
+ int area = comp->rect.width * comp->rect.height;
+ if( max_area < area )
+ {
+ max_area = area;
+ result_comp = *comp;
+ }
+ }
+ }
+ }
+
+ if( find_biggest_object && result_comp.rect.width > 0 )
+ cvSeqPush( result_seq, &result_comp );
+
+ __END__;
+
+ if( max_threads > 1 )
+ for( i = 0; i < max_threads; i++ )
+ {
+ if( seq_thread[i] )
+ cvReleaseMemStorage( &seq_thread[i]->storage );
+ }
+
+ cvReleaseMemStorage( &temp_storage );
+ cvReleaseMat( &sum );
+ cvReleaseMat( &sqsum );
+ cvReleaseMat( &tilted );
+ cvReleaseMat( &temp );
+ cvReleaseMat( &sumcanny );
+ cvReleaseMat( &norm_img );
+ cvReleaseMat( &img_small );
+ cvFree( &comps );
+
+ return result_seq;
+}
+
+
+static CvHaarClassifierCascade*
+icvLoadCascadeCART( const char** input_cascade, int n, CvSize orig_window_size )
+{
+ int i;
+ CvHaarClassifierCascade* cascade = icvCreateHaarClassifierCascade(n);
+ cascade->orig_window_size = orig_window_size;
+
+ for( i = 0; i < n; i++ )
+ {
+ int j, count, l;
+ float threshold = 0;
+ const char* stage = input_cascade[i];
+ int dl = 0;
+
+ /* tree links */
+ int parent = -1;
+ int next = -1;
+
+ sscanf( stage, "%d%n", &count, &dl );
+ stage += dl;
+
+ assert( count > 0 );
+ cascade->stage_classifier[i].count = count;
+ cascade->stage_classifier[i].classifier =
+ (CvHaarClassifier*)cvAlloc( count*sizeof(cascade->stage_classifier[i].classifier[0]));
+
+ for( j = 0; j < count; j++ )
+ {
+ CvHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
+ int k, rects = 0;
+ char str[100];
+
+ sscanf( stage, "%d%n", &classifier->count, &dl );
+ stage += dl;
+
+ classifier->haar_feature = (CvHaarFeature*) cvAlloc(
+ classifier->count * ( sizeof( *classifier->haar_feature ) +
+ sizeof( *classifier->threshold ) +
+ sizeof( *classifier->left ) +
+ sizeof( *classifier->right ) ) +
+ (classifier->count + 1) * sizeof( *classifier->alpha ) );
+ classifier->threshold = (float*) (classifier->haar_feature+classifier->count);
+ classifier->left = (int*) (classifier->threshold + classifier->count);
+ classifier->right = (int*) (classifier->left + classifier->count);
+ classifier->alpha = (float*) (classifier->right + classifier->count);
+
+ for( l = 0; l < classifier->count; l++ )
+ {
+ sscanf( stage, "%d%n", &rects, &dl );
+ stage += dl;
+
+ assert( rects >= 2 && rects <= CV_HAAR_FEATURE_MAX );
+
+ for( k = 0; k < rects; k++ )
+ {
+ CvRect r;
+ int band = 0;
+ sscanf( stage, "%d%d%d%d%d%f%n",
+ &r.x, &r.y, &r.width, &r.height, &band,
+ &(classifier->haar_feature[l].rect[k].weight), &dl );
+ stage += dl;
+ classifier->haar_feature[l].rect[k].r = r;
+ }
+ sscanf( stage, "%s%n", str, &dl );
+ stage += dl;
+
+ classifier->haar_feature[l].tilted = strncmp( str, "tilted", 6 ) == 0;
+
+ for( k = rects; k < CV_HAAR_FEATURE_MAX; k++ )
+ {
+ memset( classifier->haar_feature[l].rect + k, 0,
+ sizeof(classifier->haar_feature[l].rect[k]) );
+ }
+
+ sscanf( stage, "%f%d%d%n", &(classifier->threshold[l]),
+ &(classifier->left[l]),
+ &(classifier->right[l]), &dl );
+ stage += dl;
+ }
+ for( l = 0; l <= classifier->count; l++ )
+ {
+ sscanf( stage, "%f%n", &(classifier->alpha[l]), &dl );
+ stage += dl;
+ }
+ }
+
+ sscanf( stage, "%f%n", &threshold, &dl );
+ stage += dl;
+
+ cascade->stage_classifier[i].threshold = threshold;
+
+ /* load tree links */
+ if( sscanf( stage, "%d%d%n", &parent, &next, &dl ) != 2 )
+ {
+ parent = i - 1;
+ next = -1;
+ }
+ stage += dl;
+
+ cascade->stage_classifier[i].parent = parent;
+ cascade->stage_classifier[i].next = next;
+ cascade->stage_classifier[i].child = -1;
+
+ if( parent != -1 && cascade->stage_classifier[parent].child == -1 )
+ {
+ cascade->stage_classifier[parent].child = i;
+ }
+ }
+
+ return cascade;
+}
+
+#ifndef _MAX_PATH
+#define _MAX_PATH 1024
+#endif
+
+CV_IMPL CvHaarClassifierCascade*
+cvLoadHaarClassifierCascade( const char* directory, CvSize orig_window_size )
+{
+ const char** input_cascade = 0;
+ CvHaarClassifierCascade *cascade = 0;
+
+ CV_FUNCNAME( "cvLoadHaarClassifierCascade" );
+
+ __BEGIN__;
+
+ int i, n;
+ const char* slash;
+ char name[_MAX_PATH];
+ int size = 0;
+ char* ptr = 0;
+
+ if( !directory )
+ CV_ERROR( CV_StsNullPtr, "Null path is passed" );
+
+ n = (int)strlen(directory)-1;
+ slash = directory[n] == '\\' || directory[n] == '/' ? "" : "/";
+
+ /* try to read the classifier from directory */
+ for( n = 0; ; n++ )
+ {
+ sprintf( name, "%s%s%d/AdaBoostCARTHaarClassifier.txt", directory, slash, n );
+ FILE* f = fopen( name, "rb" );
+ if( !f )
+ break;
+ fseek( f, 0, SEEK_END );
+ size += ftell( f ) + 1;
+ fclose(f);
+ }
+
+ if( n == 0 && slash[0] )
+ {
+ CV_CALL( cascade = (CvHaarClassifierCascade*)cvLoad( directory ));
+ EXIT;
+ }
+ else if( n == 0 )
+ CV_ERROR( CV_StsBadArg, "Invalid path" );
+
+ size += (n+1)*sizeof(char*);
+ CV_CALL( input_cascade = (const char**)cvAlloc( size ));
+ ptr = (char*)(input_cascade + n + 1);
+
+ for( i = 0; i < n; i++ )
+ {
+ sprintf( name, "%s/%d/AdaBoostCARTHaarClassifier.txt", directory, i );
+ FILE* f = fopen( name, "rb" );
+ if( !f )
+ CV_ERROR( CV_StsError, "" );
+ fseek( f, 0, SEEK_END );
+ size = ftell( f );
+ fseek( f, 0, SEEK_SET );
+ fread( ptr, 1, size, f );
+ fclose(f);
+ input_cascade[i] = ptr;
+ ptr += size;
+ *ptr++ = '\0';
+ }
+
+ input_cascade[n] = 0;
+ cascade = icvLoadCascadeCART( input_cascade, n, orig_window_size );
+
+ __END__;
+
+ if( input_cascade )
+ cvFree( &input_cascade );
+
+ if( cvGetErrStatus() < 0 )
+ cvReleaseHaarClassifierCascade( &cascade );
+
+ return cascade;
+}
+
+
+CV_IMPL void
+cvReleaseHaarClassifierCascade( CvHaarClassifierCascade** _cascade )
+{
+ if( _cascade && *_cascade )
+ {
+ int i, j;
+ CvHaarClassifierCascade* cascade = *_cascade;
+
+ for( i = 0; i < cascade->count; i++ )
+ {
+ for( j = 0; j < cascade->stage_classifier[i].count; j++ )
+ cvFree( &cascade->stage_classifier[i].classifier[j].haar_feature );
+ cvFree( &cascade->stage_classifier[i].classifier );
+ }
+ icvReleaseHidHaarClassifierCascade( &cascade->hid_cascade );
+ cvFree( _cascade );
+ }
+}
+
+
+/****************************************************************************************\
+* Persistence functions *
+\****************************************************************************************/
+
+/* field names */
+
+#define ICV_HAAR_SIZE_NAME "size"
+#define ICV_HAAR_STAGES_NAME "stages"
+#define ICV_HAAR_TREES_NAME "trees"
+#define ICV_HAAR_FEATURE_NAME "feature"
+#define ICV_HAAR_RECTS_NAME "rects"
+#define ICV_HAAR_TILTED_NAME "tilted"
+#define ICV_HAAR_THRESHOLD_NAME "threshold"
+#define ICV_HAAR_LEFT_NODE_NAME "left_node"
+#define ICV_HAAR_LEFT_VAL_NAME "left_val"
+#define ICV_HAAR_RIGHT_NODE_NAME "right_node"
+#define ICV_HAAR_RIGHT_VAL_NAME "right_val"
+#define ICV_HAAR_STAGE_THRESHOLD_NAME "stage_threshold"
+#define ICV_HAAR_PARENT_NAME "parent"
+#define ICV_HAAR_NEXT_NAME "next"
+
+static int
+icvIsHaarClassifier( const void* struct_ptr )
+{
+ return CV_IS_HAAR_CLASSIFIER( struct_ptr );
+}
+
+static void*
+icvReadHaarClassifier( CvFileStorage* fs, CvFileNode* node )
+{
+ CvHaarClassifierCascade* cascade = NULL;
+
+ CV_FUNCNAME( "cvReadHaarClassifier" );
+
+ __BEGIN__;
+
+ char buf[256];
+ CvFileNode* seq_fn = NULL; /* sequence */
+ CvFileNode* fn = NULL;
+ CvFileNode* stages_fn = NULL;
+ CvSeqReader stages_reader;
+ int n;
+ int i, j, k, l;
+ int parent, next;
+
+ CV_CALL( stages_fn = cvGetFileNodeByName( fs, node, ICV_HAAR_STAGES_NAME ) );
+ if( !stages_fn || !CV_NODE_IS_SEQ( stages_fn->tag) )
+ CV_ERROR( CV_StsError, "Invalid stages node" );
+
+ n = stages_fn->data.seq->total;
+ CV_CALL( cascade = icvCreateHaarClassifierCascade(n) );
+
+ /* read size */
+ CV_CALL( seq_fn = cvGetFileNodeByName( fs, node, ICV_HAAR_SIZE_NAME ) );
+ if( !seq_fn || !CV_NODE_IS_SEQ( seq_fn->tag ) || seq_fn->data.seq->total != 2 )
+ CV_ERROR( CV_StsError, "size node is not a valid sequence." );
+ CV_CALL( fn = (CvFileNode*) cvGetSeqElem( seq_fn->data.seq, 0 ) );
+ if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= 0 )
+ CV_ERROR( CV_StsError, "Invalid size node: width must be positive integer" );
+ cascade->orig_window_size.width = fn->data.i;
+ CV_CALL( fn = (CvFileNode*) cvGetSeqElem( seq_fn->data.seq, 1 ) );
+ if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= 0 )
+ CV_ERROR( CV_StsError, "Invalid size node: height must be positive integer" );
+ cascade->orig_window_size.height = fn->data.i;
+
+ CV_CALL( cvStartReadSeq( stages_fn->data.seq, &stages_reader ) );
+ for( i = 0; i < n; ++i )
+ {
+ CvFileNode* stage_fn;
+ CvFileNode* trees_fn;
+ CvSeqReader trees_reader;
+
+ stage_fn = (CvFileNode*) stages_reader.ptr;
+ if( !CV_NODE_IS_MAP( stage_fn->tag ) )
+ {
+ sprintf( buf, "Invalid stage %d", i );
+ CV_ERROR( CV_StsError, buf );
+ }
+
+ CV_CALL( trees_fn = cvGetFileNodeByName( fs, stage_fn, ICV_HAAR_TREES_NAME ) );
+ if( !trees_fn || !CV_NODE_IS_SEQ( trees_fn->tag )
+ || trees_fn->data.seq->total <= 0 )
+ {
+ sprintf( buf, "Trees node is not a valid sequence. (stage %d)", i );
+ CV_ERROR( CV_StsError, buf );
+ }
+
+ CV_CALL( cascade->stage_classifier[i].classifier =
+ (CvHaarClassifier*) cvAlloc( trees_fn->data.seq->total
+ * sizeof( cascade->stage_classifier[i].classifier[0] ) ) );
+ for( j = 0; j < trees_fn->data.seq->total; ++j )
+ {
+ cascade->stage_classifier[i].classifier[j].haar_feature = NULL;
+ }
+ cascade->stage_classifier[i].count = trees_fn->data.seq->total;
+
+ CV_CALL( cvStartReadSeq( trees_fn->data.seq, &trees_reader ) );
+ for( j = 0; j < trees_fn->data.seq->total; ++j )
+ {
+ CvFileNode* tree_fn;
+ CvSeqReader tree_reader;
+ CvHaarClassifier* classifier;
+ int last_idx;
+
+ classifier = &cascade->stage_classifier[i].classifier[j];
+ tree_fn = (CvFileNode*) trees_reader.ptr;
+ if( !CV_NODE_IS_SEQ( tree_fn->tag ) || tree_fn->data.seq->total <= 0 )
+ {
+ sprintf( buf, "Tree node is not a valid sequence."
+ " (stage %d, tree %d)", i, j );
+ CV_ERROR( CV_StsError, buf );
+ }
+
+ classifier->count = tree_fn->data.seq->total;
+ CV_CALL( classifier->haar_feature = (CvHaarFeature*) cvAlloc(
+ classifier->count * ( sizeof( *classifier->haar_feature ) +
+ sizeof( *classifier->threshold ) +
+ sizeof( *classifier->left ) +
+ sizeof( *classifier->right ) ) +
+ (classifier->count + 1) * sizeof( *classifier->alpha ) ) );
+ classifier->threshold = (float*) (classifier->haar_feature+classifier->count);
+ classifier->left = (int*) (classifier->threshold + classifier->count);
+ classifier->right = (int*) (classifier->left + classifier->count);
+ classifier->alpha = (float*) (classifier->right + classifier->count);
+
+ CV_CALL( cvStartReadSeq( tree_fn->data.seq, &tree_reader ) );
+ for( k = 0, last_idx = 0; k < tree_fn->data.seq->total; ++k )
+ {
+ CvFileNode* node_fn;
+ CvFileNode* feature_fn;
+ CvFileNode* rects_fn;
+ CvSeqReader rects_reader;
+
+ node_fn = (CvFileNode*) tree_reader.ptr;
+ if( !CV_NODE_IS_MAP( node_fn->tag ) )
+ {
+ sprintf( buf, "Tree node %d is not a valid map. (stage %d, tree %d)",
+ k, i, j );
+ CV_ERROR( CV_StsError, buf );
+ }
+ CV_CALL( feature_fn = cvGetFileNodeByName( fs, node_fn,
+ ICV_HAAR_FEATURE_NAME ) );
+ if( !feature_fn || !CV_NODE_IS_MAP( feature_fn->tag ) )
+ {
+ sprintf( buf, "Feature node is not a valid map. "
+ "(stage %d, tree %d, node %d)", i, j, k );
+ CV_ERROR( CV_StsError, buf );
+ }
+ CV_CALL( rects_fn = cvGetFileNodeByName( fs, feature_fn,
+ ICV_HAAR_RECTS_NAME ) );
+ if( !rects_fn || !CV_NODE_IS_SEQ( rects_fn->tag )
+ || rects_fn->data.seq->total < 1
+ || rects_fn->data.seq->total > CV_HAAR_FEATURE_MAX )
+ {
+ sprintf( buf, "Rects node is not a valid sequence. "
+ "(stage %d, tree %d, node %d)", i, j, k );
+ CV_ERROR( CV_StsError, buf );
+ }
+ CV_CALL( cvStartReadSeq( rects_fn->data.seq, &rects_reader ) );
+ for( l = 0; l < rects_fn->data.seq->total; ++l )
+ {
+ CvFileNode* rect_fn;
+ CvRect r;
+
+ rect_fn = (CvFileNode*) rects_reader.ptr;
+ if( !CV_NODE_IS_SEQ( rect_fn->tag ) || rect_fn->data.seq->total != 5 )
+ {
+ sprintf( buf, "Rect %d is not a valid sequence. "
+ "(stage %d, tree %d, node %d)", l, i, j, k );
+ CV_ERROR( CV_StsError, buf );
+ }
+
+ fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 0 );
+ if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i < 0 )
+ {
+ sprintf( buf, "x coordinate must be non-negative integer. "
+ "(stage %d, tree %d, node %d, rect %d)", i, j, k, l );
+ CV_ERROR( CV_StsError, buf );
+ }
+ r.x = fn->data.i;
+ fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 1 );
+ if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i < 0 )
+ {
+ sprintf( buf, "y coordinate must be non-negative integer. "
+ "(stage %d, tree %d, node %d, rect %d)", i, j, k, l );
+ CV_ERROR( CV_StsError, buf );
+ }
+ r.y = fn->data.i;
+ fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 2 );
+ if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= 0
+ || r.x + fn->data.i > cascade->orig_window_size.width )
+ {
+ sprintf( buf, "width must be positive integer and "
+ "(x + width) must not exceed window width. "
+ "(stage %d, tree %d, node %d, rect %d)", i, j, k, l );
+ CV_ERROR( CV_StsError, buf );
+ }
+ r.width = fn->data.i;
+ fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 3 );
+ if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= 0
+ || r.y + fn->data.i > cascade->orig_window_size.height )
+ {
+ sprintf( buf, "height must be positive integer and "
+ "(y + height) must not exceed window height. "
+ "(stage %d, tree %d, node %d, rect %d)", i, j, k, l );
+ CV_ERROR( CV_StsError, buf );
+ }
+ r.height = fn->data.i;
+ fn = CV_SEQ_ELEM( rect_fn->data.seq, CvFileNode, 4 );
+ if( !CV_NODE_IS_REAL( fn->tag ) )
+ {
+ sprintf( buf, "weight must be real number. "
+ "(stage %d, tree %d, node %d, rect %d)", i, j, k, l );
+ CV_ERROR( CV_StsError, buf );
+ }
+
+ classifier->haar_feature[k].rect[l].weight = (float) fn->data.f;
+ classifier->haar_feature[k].rect[l].r = r;
+
+ CV_NEXT_SEQ_ELEM( sizeof( *rect_fn ), rects_reader );
+ } /* for each rect */
+ for( l = rects_fn->data.seq->total; l < CV_HAAR_FEATURE_MAX; ++l )
+ {
+ classifier->haar_feature[k].rect[l].weight = 0;
+ classifier->haar_feature[k].rect[l].r = cvRect( 0, 0, 0, 0 );
+ }
+
+ CV_CALL( fn = cvGetFileNodeByName( fs, feature_fn, ICV_HAAR_TILTED_NAME));
+ if( !fn || !CV_NODE_IS_INT( fn->tag ) )
+ {
+ sprintf( buf, "tilted must be 0 or 1. "
+ "(stage %d, tree %d, node %d)", i, j, k );
+ CV_ERROR( CV_StsError, buf );
+ }
+ classifier->haar_feature[k].tilted = ( fn->data.i != 0 );
+ CV_CALL( fn = cvGetFileNodeByName( fs, node_fn, ICV_HAAR_THRESHOLD_NAME));
+ if( !fn || !CV_NODE_IS_REAL( fn->tag ) )
+ {
+ sprintf( buf, "threshold must be real number. "
+ "(stage %d, tree %d, node %d)", i, j, k );
+ CV_ERROR( CV_StsError, buf );
+ }
+ classifier->threshold[k] = (float) fn->data.f;
+ CV_CALL( fn = cvGetFileNodeByName( fs, node_fn, ICV_HAAR_LEFT_NODE_NAME));
+ if( fn )
+ {
+ if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= k
+ || fn->data.i >= tree_fn->data.seq->total )
+ {
+ sprintf( buf, "left node must be valid node number. "
+ "(stage %d, tree %d, node %d)", i, j, k );
+ CV_ERROR( CV_StsError, buf );
+ }
+ /* left node */
+ classifier->left[k] = fn->data.i;
+ }
+ else
+ {
+ CV_CALL( fn = cvGetFileNodeByName( fs, node_fn,
+ ICV_HAAR_LEFT_VAL_NAME ) );
+ if( !fn )
+ {
+ sprintf( buf, "left node or left value must be specified. "
+ "(stage %d, tree %d, node %d)", i, j, k );
+ CV_ERROR( CV_StsError, buf );
+ }
+ if( !CV_NODE_IS_REAL( fn->tag ) )
+ {
+ sprintf( buf, "left value must be real number. "
+ "(stage %d, tree %d, node %d)", i, j, k );
+ CV_ERROR( CV_StsError, buf );
+ }
+ /* left value */
+ if( last_idx >= classifier->count + 1 )
+ {
+ sprintf( buf, "Tree structure is broken: too many values. "
+ "(stage %d, tree %d, node %d)", i, j, k );
+ CV_ERROR( CV_StsError, buf );
+ }
+ classifier->left[k] = -last_idx;
+ classifier->alpha[last_idx++] = (float) fn->data.f;
+ }
+ CV_CALL( fn = cvGetFileNodeByName( fs, node_fn,ICV_HAAR_RIGHT_NODE_NAME));
+ if( fn )
+ {
+ if( !CV_NODE_IS_INT( fn->tag ) || fn->data.i <= k
+ || fn->data.i >= tree_fn->data.seq->total )
+ {
+ sprintf( buf, "right node must be valid node number. "
+ "(stage %d, tree %d, node %d)", i, j, k );
+ CV_ERROR( CV_StsError, buf );
+ }
+ /* right node */
+ classifier->right[k] = fn->data.i;
+ }
+ else
+ {
+ CV_CALL( fn = cvGetFileNodeByName( fs, node_fn,
+ ICV_HAAR_RIGHT_VAL_NAME ) );
+ if( !fn )
+ {
+ sprintf( buf, "right node or right value must be specified. "
+ "(stage %d, tree %d, node %d)", i, j, k );
+ CV_ERROR( CV_StsError, buf );
+ }
+ if( !CV_NODE_IS_REAL( fn->tag ) )
+ {
+ sprintf( buf, "right value must be real number. "
+ "(stage %d, tree %d, node %d)", i, j, k );
+ CV_ERROR( CV_StsError, buf );
+ }
+ /* right value */
+ if( last_idx >= classifier->count + 1 )
+ {
+ sprintf( buf, "Tree structure is broken: too many values. "
+ "(stage %d, tree %d, node %d)", i, j, k );
+ CV_ERROR( CV_StsError, buf );
+ }
+ classifier->right[k] = -last_idx;
+ classifier->alpha[last_idx++] = (float) fn->data.f;
+ }
+
+ CV_NEXT_SEQ_ELEM( sizeof( *node_fn ), tree_reader );
+ } /* for each node */
+ if( last_idx != classifier->count + 1 )
+ {
+ sprintf( buf, "Tree structure is broken: too few values. "
+ "(stage %d, tree %d)", i, j );
+ CV_ERROR( CV_StsError, buf );
+ }
+
+ CV_NEXT_SEQ_ELEM( sizeof( *tree_fn ), trees_reader );
+ } /* for each tree */
+
+ CV_CALL( fn = cvGetFileNodeByName( fs, stage_fn, ICV_HAAR_STAGE_THRESHOLD_NAME));
+ if( !fn || !CV_NODE_IS_REAL( fn->tag ) )
+ {
+ sprintf( buf, "stage threshold must be real number. (stage %d)", i );
+ CV_ERROR( CV_StsError, buf );
+ }
+ cascade->stage_classifier[i].threshold = (float) fn->data.f;
+
+ parent = i - 1;
+ next = -1;
+
+ CV_CALL( fn = cvGetFileNodeByName( fs, stage_fn, ICV_HAAR_PARENT_NAME ) );
+ if( !fn || !CV_NODE_IS_INT( fn->tag )
+ || fn->data.i < -1 || fn->data.i >= cascade->count )
+ {
+ sprintf( buf, "parent must be integer number. (stage %d)", i );
+ CV_ERROR( CV_StsError, buf );
+ }
+ parent = fn->data.i;
+ CV_CALL( fn = cvGetFileNodeByName( fs, stage_fn, ICV_HAAR_NEXT_NAME ) );
+ if( !fn || !CV_NODE_IS_INT( fn->tag )
+ || fn->data.i < -1 || fn->data.i >= cascade->count )
+ {
+ sprintf( buf, "next must be integer number. (stage %d)", i );
+ CV_ERROR( CV_StsError, buf );
+ }
+ next = fn->data.i;
+
+ cascade->stage_classifier[i].parent = parent;
+ cascade->stage_classifier[i].next = next;
+ cascade->stage_classifier[i].child = -1;
+
+ if( parent != -1 && cascade->stage_classifier[parent].child == -1 )
+ {
+ cascade->stage_classifier[parent].child = i;
+ }
+
+ CV_NEXT_SEQ_ELEM( sizeof( *stage_fn ), stages_reader );
+ } /* for each stage */
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ {
+ cvReleaseHaarClassifierCascade( &cascade );
+ cascade = NULL;
+ }
+
+ return cascade;
+}
+
+static void
+icvWriteHaarClassifier( CvFileStorage* fs, const char* name, const void* struct_ptr,
+ CvAttrList attributes )
+{
+ CV_FUNCNAME( "cvWriteHaarClassifier" );
+
+ __BEGIN__;
+
+ int i, j, k, l;
+ char buf[256];
+ const CvHaarClassifierCascade* cascade = (const CvHaarClassifierCascade*) struct_ptr;
+
+ /* TODO: parameters check */
+
+ CV_CALL( cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_HAAR, attributes ) );
+
+ CV_CALL( cvStartWriteStruct( fs, ICV_HAAR_SIZE_NAME, CV_NODE_SEQ | CV_NODE_FLOW ) );
+ CV_CALL( cvWriteInt( fs, NULL, cascade->orig_window_size.width ) );
+ CV_CALL( cvWriteInt( fs, NULL, cascade->orig_window_size.height ) );
+ CV_CALL( cvEndWriteStruct( fs ) ); /* size */
+
+ CV_CALL( cvStartWriteStruct( fs, ICV_HAAR_STAGES_NAME, CV_NODE_SEQ ) );
+ for( i = 0; i < cascade->count; ++i )
+ {
+ CV_CALL( cvStartWriteStruct( fs, NULL, CV_NODE_MAP ) );
+ sprintf( buf, "stage %d", i );
+ CV_CALL( cvWriteComment( fs, buf, 1 ) );
+
+ CV_CALL( cvStartWriteStruct( fs, ICV_HAAR_TREES_NAME, CV_NODE_SEQ ) );
+
+ for( j = 0; j < cascade->stage_classifier[i].count; ++j )
+ {
+ CvHaarClassifier* tree = &cascade->stage_classifier[i].classifier[j];
+
+ CV_CALL( cvStartWriteStruct( fs, NULL, CV_NODE_SEQ ) );
+ sprintf( buf, "tree %d", j );
+ CV_CALL( cvWriteComment( fs, buf, 1 ) );
+
+ for( k = 0; k < tree->count; ++k )
+ {
+ CvHaarFeature* feature = &tree->haar_feature[k];
+
+ CV_CALL( cvStartWriteStruct( fs, NULL, CV_NODE_MAP ) );
+ if( k )
+ {
+ sprintf( buf, "node %d", k );
+ }
+ else
+ {
+ sprintf( buf, "root node" );
+ }
+ CV_CALL( cvWriteComment( fs, buf, 1 ) );
+
+ CV_CALL( cvStartWriteStruct( fs, ICV_HAAR_FEATURE_NAME, CV_NODE_MAP ) );
+
+ CV_CALL( cvStartWriteStruct( fs, ICV_HAAR_RECTS_NAME, CV_NODE_SEQ ) );
+ for( l = 0; l < CV_HAAR_FEATURE_MAX && feature->rect[l].r.width != 0; ++l )
+ {
+ CV_CALL( cvStartWriteStruct( fs, NULL, CV_NODE_SEQ | CV_NODE_FLOW ) );
+ CV_CALL( cvWriteInt( fs, NULL, feature->rect[l].r.x ) );
+ CV_CALL( cvWriteInt( fs, NULL, feature->rect[l].r.y ) );
+ CV_CALL( cvWriteInt( fs, NULL, feature->rect[l].r.width ) );
+ CV_CALL( cvWriteInt( fs, NULL, feature->rect[l].r.height ) );
+ CV_CALL( cvWriteReal( fs, NULL, feature->rect[l].weight ) );
+ CV_CALL( cvEndWriteStruct( fs ) ); /* rect */
+ }
+ CV_CALL( cvEndWriteStruct( fs ) ); /* rects */
+ CV_CALL( cvWriteInt( fs, ICV_HAAR_TILTED_NAME, feature->tilted ) );
+ CV_CALL( cvEndWriteStruct( fs ) ); /* feature */
+
+ CV_CALL( cvWriteReal( fs, ICV_HAAR_THRESHOLD_NAME, tree->threshold[k]) );
+
+ if( tree->left[k] > 0 )
+ {
+ CV_CALL( cvWriteInt( fs, ICV_HAAR_LEFT_NODE_NAME, tree->left[k] ) );
+ }
+ else
+ {
+ CV_CALL( cvWriteReal( fs, ICV_HAAR_LEFT_VAL_NAME,
+ tree->alpha[-tree->left[k]] ) );
+ }
+
+ if( tree->right[k] > 0 )
+ {
+ CV_CALL( cvWriteInt( fs, ICV_HAAR_RIGHT_NODE_NAME, tree->right[k] ) );
+ }
+ else
+ {
+ CV_CALL( cvWriteReal( fs, ICV_HAAR_RIGHT_VAL_NAME,
+ tree->alpha[-tree->right[k]] ) );
+ }
+
+ CV_CALL( cvEndWriteStruct( fs ) ); /* split */
+ }
+
+ CV_CALL( cvEndWriteStruct( fs ) ); /* tree */
+ }
+
+ CV_CALL( cvEndWriteStruct( fs ) ); /* trees */
+
+ CV_CALL( cvWriteReal( fs, ICV_HAAR_STAGE_THRESHOLD_NAME,
+ cascade->stage_classifier[i].threshold) );
+
+ CV_CALL( cvWriteInt( fs, ICV_HAAR_PARENT_NAME,
+ cascade->stage_classifier[i].parent ) );
+ CV_CALL( cvWriteInt( fs, ICV_HAAR_NEXT_NAME,
+ cascade->stage_classifier[i].next ) );
+
+ CV_CALL( cvEndWriteStruct( fs ) ); /* stage */
+ } /* for each stage */
+
+ CV_CALL( cvEndWriteStruct( fs ) ); /* stages */
+ CV_CALL( cvEndWriteStruct( fs ) ); /* root */
+
+ __END__;
+}
+
+static void*
+icvCloneHaarClassifier( const void* struct_ptr )
+{
+ CvHaarClassifierCascade* cascade = NULL;
+
+ CV_FUNCNAME( "cvCloneHaarClassifier" );
+
+ __BEGIN__;
+
+ int i, j, k, n;
+ const CvHaarClassifierCascade* cascade_src =
+ (const CvHaarClassifierCascade*) struct_ptr;
+
+ n = cascade_src->count;
+ CV_CALL( cascade = icvCreateHaarClassifierCascade(n) );
+ cascade->orig_window_size = cascade_src->orig_window_size;
+
+ for( i = 0; i < n; ++i )
+ {
+ cascade->stage_classifier[i].parent = cascade_src->stage_classifier[i].parent;
+ cascade->stage_classifier[i].next = cascade_src->stage_classifier[i].next;
+ cascade->stage_classifier[i].child = cascade_src->stage_classifier[i].child;
+ cascade->stage_classifier[i].threshold = cascade_src->stage_classifier[i].threshold;
+
+ cascade->stage_classifier[i].count = 0;
+ CV_CALL( cascade->stage_classifier[i].classifier =
+ (CvHaarClassifier*) cvAlloc( cascade_src->stage_classifier[i].count
+ * sizeof( cascade->stage_classifier[i].classifier[0] ) ) );
+
+ cascade->stage_classifier[i].count = cascade_src->stage_classifier[i].count;
+
+ for( j = 0; j < cascade->stage_classifier[i].count; ++j )
+ {
+ cascade->stage_classifier[i].classifier[j].haar_feature = NULL;
+ }
+
+ for( j = 0; j < cascade->stage_classifier[i].count; ++j )
+ {
+ const CvHaarClassifier* classifier_src =
+ &cascade_src->stage_classifier[i].classifier[j];
+ CvHaarClassifier* classifier =
+ &cascade->stage_classifier[i].classifier[j];
+
+ classifier->count = classifier_src->count;
+ CV_CALL( classifier->haar_feature = (CvHaarFeature*) cvAlloc(
+ classifier->count * ( sizeof( *classifier->haar_feature ) +
+ sizeof( *classifier->threshold ) +
+ sizeof( *classifier->left ) +
+ sizeof( *classifier->right ) ) +
+ (classifier->count + 1) * sizeof( *classifier->alpha ) ) );
+ classifier->threshold = (float*) (classifier->haar_feature+classifier->count);
+ classifier->left = (int*) (classifier->threshold + classifier->count);
+ classifier->right = (int*) (classifier->left + classifier->count);
+ classifier->alpha = (float*) (classifier->right + classifier->count);
+ for( k = 0; k < classifier->count; ++k )
+ {
+ classifier->haar_feature[k] = classifier_src->haar_feature[k];
+ classifier->threshold[k] = classifier_src->threshold[k];
+ classifier->left[k] = classifier_src->left[k];
+ classifier->right[k] = classifier_src->right[k];
+ classifier->alpha[k] = classifier_src->alpha[k];
+ }
+ classifier->alpha[classifier->count] =
+ classifier_src->alpha[classifier->count];
+ }
+ }
+
+ __END__;
+
+ return cascade;
+}
+
+
+CvType haar_type( CV_TYPE_NAME_HAAR, icvIsHaarClassifier,
+ (CvReleaseFunc)cvReleaseHaarClassifierCascade,
+ icvReadHaarClassifier, icvWriteHaarClassifier,
+ icvCloneHaarClassifier );
+
+/* End of file. */
diff --git a/cv/src/cvhistogram.cpp b/cv/src/cvhistogram.cpp
new file mode 100644
index 0000000..cb9552b
--- /dev/null
+++ b/cv/src/cvhistogram.cpp
@@ -0,0 +1,2513 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+/* Creates new histogram */
+CvHistogram *
+cvCreateHist( int dims, int *sizes, CvHistType type, float** ranges, int uniform )
+{
+ CvHistogram *hist = 0;
+
+ CV_FUNCNAME( "cvCreateHist" );
+ __BEGIN__;
+
+ if( (unsigned)dims > CV_MAX_DIM )
+ CV_ERROR( CV_BadOrder, "Number of dimensions is out of range" );
+
+ if( !sizes )
+ CV_ERROR( CV_HeaderIsNull, "Null <sizes> pointer" );
+
+ CV_CALL( hist = (CvHistogram *)cvAlloc( sizeof( CvHistogram )));
+
+ hist->type = CV_HIST_MAGIC_VAL;
+ hist->thresh2 = 0;
+ hist->bins = 0;
+ if( type == CV_HIST_ARRAY )
+ {
+ CV_CALL( hist->bins = cvInitMatNDHeader( &hist->mat, dims, sizes,
+ CV_HIST_DEFAULT_TYPE ));
+ CV_CALL( cvCreateData( hist->bins ));
+ }
+ else if( type == CV_HIST_SPARSE )
+ {
+ CV_CALL( hist->bins = cvCreateSparseMat( dims, sizes, CV_HIST_DEFAULT_TYPE ));
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg, "Invalid histogram type" );
+ }
+
+ if( ranges )
+ CV_CALL( cvSetHistBinRanges( hist, ranges, uniform ));
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvReleaseHist( &hist );
+
+ return hist;
+}
+
+
+/* Creates histogram wrapping header for given array */
+CV_IMPL CvHistogram*
+cvMakeHistHeaderForArray( int dims, int *sizes, CvHistogram *hist,
+ float *data, float **ranges, int uniform )
+{
+ CvHistogram* result = 0;
+
+ CV_FUNCNAME( "cvMakeHistHeaderForArray" );
+
+ __BEGIN__;
+
+ if( !hist )
+ CV_ERROR( CV_StsNullPtr, "Null histogram header pointer" );
+
+ if( !data )
+ CV_ERROR( CV_StsNullPtr, "Null data pointer" );
+
+ hist->thresh2 = 0;
+ hist->type = CV_HIST_MAGIC_VAL;
+ CV_CALL( hist->bins = cvInitMatNDHeader( &hist->mat, dims, sizes,
+ CV_HIST_DEFAULT_TYPE, data ));
+
+ if( ranges )
+ {
+ if( !uniform )
+ CV_ERROR( CV_StsBadArg, "Only uniform bin ranges can be used here "
+ "(to avoid memory allocation)" );
+ CV_CALL( cvSetHistBinRanges( hist, ranges, uniform ));
+ }
+
+ result = hist;
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 && hist )
+ {
+ hist->type = 0;
+ hist->bins = 0;
+ }
+
+ return result;
+}
+
+
+CV_IMPL void
+cvReleaseHist( CvHistogram **hist )
+{
+ CV_FUNCNAME( "cvReleaseHist" );
+
+ __BEGIN__;
+
+ if( !hist )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( *hist )
+ {
+ CvHistogram* temp = *hist;
+
+ if( !CV_IS_HIST(temp))
+ CV_ERROR( CV_StsBadArg, "Invalid histogram header" );
+
+ *hist = 0;
+
+ if( CV_IS_SPARSE_HIST( temp ))
+ cvRelease( &temp->bins );
+ else
+ {
+ cvReleaseData( temp->bins );
+ temp->bins = 0;
+ }
+
+ if( temp->thresh2 )
+ cvFree( &temp->thresh2 );
+
+ cvFree( &temp );
+ }
+
+ __END__;
+}
+
+CV_IMPL void
+cvClearHist( CvHistogram *hist )
+{
+ CV_FUNCNAME( "cvClearHist" );
+
+ __BEGIN__;
+
+ if( !CV_IS_HIST(hist) )
+ CV_ERROR( CV_StsBadArg, "Invalid histogram header" );
+
+ cvZero( hist->bins );
+
+ __END__;
+}
+
+
+// Clears histogram bins that are below than threshold
+CV_IMPL void
+cvThreshHist( CvHistogram* hist, double thresh )
+{
+ CV_FUNCNAME( "cvThreshHist" );
+
+ __BEGIN__;
+
+ if( !CV_IS_HIST(hist) )
+ CV_ERROR( CV_StsBadArg, "Invalid histogram header" );
+
+ if( !CV_IS_SPARSE_MAT(hist->bins) )
+ {
+ CvMat mat;
+ CV_CALL( cvGetMat( hist->bins, &mat, 0, 1 ));
+ CV_CALL( cvThreshold( &mat, &mat, thresh, 0, CV_THRESH_TOZERO ));
+ }
+ else
+ {
+ CvSparseMat* mat = (CvSparseMat*)hist->bins;
+ CvSparseMatIterator iterator;
+ CvSparseNode *node;
+
+ for( node = cvInitSparseMatIterator( mat, &iterator );
+ node != 0; node = cvGetNextSparseNode( &iterator ))
+ {
+ float* val = (float*)CV_NODE_VAL( mat, node );
+ if( *val <= thresh )
+ *val = 0;
+ }
+ }
+
+ __END__;
+}
+
+
+// Normalizes histogram (make sum of the histogram bins == factor)
+CV_IMPL void
+cvNormalizeHist( CvHistogram* hist, double factor )
+{
+ double sum = 0;
+
+ CV_FUNCNAME( "cvNormalizeHist" );
+ __BEGIN__;
+
+ if( !CV_IS_HIST(hist) )
+ CV_ERROR( CV_StsBadArg, "Invalid histogram header" );
+
+ if( !CV_IS_SPARSE_HIST(hist) )
+ {
+ CvMat mat;
+ CV_CALL( cvGetMat( hist->bins, &mat, 0, 1 ));
+ CV_CALL( sum = cvSum( &mat ).val[0] );
+ if( fabs(sum) < DBL_EPSILON )
+ sum = 1;
+ CV_CALL( cvScale( &mat, &mat, factor/sum, 0 ));
+ }
+ else
+ {
+ CvSparseMat* mat = (CvSparseMat*)hist->bins;
+ CvSparseMatIterator iterator;
+ CvSparseNode *node;
+ float scale;
+
+ for( node = cvInitSparseMatIterator( mat, &iterator );
+ node != 0; node = cvGetNextSparseNode( &iterator ))
+ {
+ sum += *(float*)CV_NODE_VAL(mat,node);
+ }
+
+ if( fabs(sum) < DBL_EPSILON )
+ sum = 1;
+ scale = (float)(factor/sum);
+
+ for( node = cvInitSparseMatIterator( mat, &iterator );
+ node != 0; node = cvGetNextSparseNode( &iterator ))
+ {
+ *(float*)CV_NODE_VAL(mat,node) *= scale;
+ }
+ }
+
+ __END__;
+}
+
+
+// Retrieves histogram global min, max and their positions
+CV_IMPL void
+cvGetMinMaxHistValue( const CvHistogram* hist,
+ float *value_min, float* value_max,
+ int* idx_min, int* idx_max )
+{
+ double minVal, maxVal;
+
+ CV_FUNCNAME( "cvGetMinMaxHistValue" );
+
+ __BEGIN__;
+
+ int i, dims, size[CV_MAX_DIM];
+
+ if( !CV_IS_HIST(hist) )
+ CV_ERROR( CV_StsBadArg, "Invalid histogram header" );
+
+ dims = cvGetDims( hist->bins, size );
+
+ if( !CV_IS_SPARSE_HIST(hist) )
+ {
+ CvMat mat;
+ CvPoint minPt, maxPt;
+
+ CV_CALL( cvGetMat( hist->bins, &mat, 0, 1 ));
+ CV_CALL( cvMinMaxLoc( &mat, &minVal, &maxVal, &minPt, &maxPt ));
+
+ if( dims == 1 )
+ {
+ if( idx_min )
+ *idx_min = minPt.y + minPt.x;
+ if( idx_max )
+ *idx_max = maxPt.y + maxPt.x;
+ }
+ else if( dims == 2 )
+ {
+ if( idx_min )
+ idx_min[0] = minPt.y, idx_min[1] = minPt.x;
+ if( idx_max )
+ idx_max[0] = maxPt.y, idx_max[1] = maxPt.x;
+ }
+ else if( idx_min || idx_max )
+ {
+ int imin = minPt.y*mat.cols + minPt.x;
+ int imax = maxPt.y*mat.cols + maxPt.x;
+ int i;
+
+ for( i = dims - 1; i >= 0; i-- )
+ {
+ if( idx_min )
+ {
+ int t = imin / size[i];
+ idx_min[i] = imin - t*size[i];
+ imin = t;
+ }
+
+ if( idx_max )
+ {
+ int t = imax / size[i];
+ idx_max[i] = imax - t*size[i];
+ imax = t;
+ }
+ }
+ }
+ }
+ else
+ {
+ CvSparseMat* mat = (CvSparseMat*)hist->bins;
+ CvSparseMatIterator iterator;
+ CvSparseNode *node;
+ int minv = INT_MAX;
+ int maxv = INT_MIN;
+ CvSparseNode* minNode = 0;
+ CvSparseNode* maxNode = 0;
+ const int *_idx_min = 0, *_idx_max = 0;
+ Cv32suf m;
+
+ for( node = cvInitSparseMatIterator( mat, &iterator );
+ node != 0; node = cvGetNextSparseNode( &iterator ))
+ {
+ int value = *(int*)CV_NODE_VAL(mat,node);
+ value = CV_TOGGLE_FLT(value);
+ if( value < minv )
+ {
+ minv = value;
+ minNode = node;
+ }
+
+ if( value > maxv )
+ {
+ maxv = value;
+ maxNode = node;
+ }
+ }
+
+ if( minNode )
+ {
+ _idx_min = CV_NODE_IDX(mat,minNode);
+ _idx_max = CV_NODE_IDX(mat,maxNode);
+ m.i = CV_TOGGLE_FLT(minv); minVal = m.f;
+ m.i = CV_TOGGLE_FLT(maxv); maxVal = m.f;
+ }
+ else
+ {
+ minVal = maxVal = 0;
+ }
+
+ for( i = 0; i < dims; i++ )
+ {
+ if( idx_min )
+ idx_min[i] = _idx_min ? _idx_min[i] : -1;
+ if( idx_max )
+ idx_max[i] = _idx_max ? _idx_max[i] : -1;
+ }
+ }
+
+ if( value_min )
+ *value_min = (float)minVal;
+
+ if( value_max )
+ *value_max = (float)maxVal;
+
+ __END__;
+}
+
+
+// Compares two histograms using one of a few methods
+CV_IMPL double
+cvCompareHist( const CvHistogram* hist1,
+ const CvHistogram* hist2,
+ int method )
+{
+ double _result = -1;
+
+ CV_FUNCNAME( "cvCompareHist" );
+
+ __BEGIN__;
+
+ int i, dims1, dims2;
+ int size1[CV_MAX_DIM], size2[CV_MAX_DIM], total = 1;
+ double result = 0;
+
+ if( !CV_IS_HIST(hist1) || !CV_IS_HIST(hist2) )
+ CV_ERROR( CV_StsBadArg, "Invalid histogram header[s]" );
+
+ if( CV_IS_SPARSE_MAT(hist1->bins) != CV_IS_SPARSE_MAT(hist2->bins))
+ CV_ERROR(CV_StsUnmatchedFormats, "One of histograms is sparse and other is not");
+
+ CV_CALL( dims1 = cvGetDims( hist1->bins, size1 ));
+ CV_CALL( dims2 = cvGetDims( hist2->bins, size2 ));
+
+ if( dims1 != dims2 )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The histograms have different numbers of dimensions" );
+
+ for( i = 0; i < dims1; i++ )
+ {
+ if( size1[i] != size2[i] )
+ CV_ERROR( CV_StsUnmatchedSizes, "The histograms have different sizes" );
+ total *= size1[i];
+ }
+
+
+ if( !CV_IS_SPARSE_MAT(hist1->bins))
+ {
+ union { float* fl; uchar* ptr; } v;
+ float *ptr1, *ptr2;
+ v.fl = 0;
+ CV_CALL( cvGetRawData( hist1->bins, &v.ptr ));
+ ptr1 = v.fl;
+ CV_CALL( cvGetRawData( hist2->bins, &v.ptr ));
+ ptr2 = v.fl;
+
+ switch( method )
+ {
+ case CV_COMP_CHISQR:
+ for( i = 0; i < total; i++ )
+ {
+ double a = ptr1[i] - ptr2[i];
+ double b = ptr1[i] + ptr2[i];
+ if( fabs(b) > DBL_EPSILON )
+ result += a*a/b;
+ }
+ break;
+ case CV_COMP_CORREL:
+ {
+ double s1 = 0, s11 = 0;
+ double s2 = 0, s22 = 0;
+ double s12 = 0;
+ double num, denom2, scale = 1./total;
+
+ for( i = 0; i < total; i++ )
+ {
+ double a = ptr1[i];
+ double b = ptr2[i];
+
+ s12 += a*b;
+ s1 += a;
+ s11 += a*a;
+ s2 += b;
+ s22 += b*b;
+ }
+
+ num = s12 - s1*s2*scale;
+ denom2 = (s11 - s1*s1*scale)*(s22 - s2*s2*scale);
+ result = fabs(denom2) > DBL_EPSILON ? num/sqrt(denom2) : 1;
+ }
+ break;
+ case CV_COMP_INTERSECT:
+ for( i = 0; i < total; i++ )
+ {
+ float a = ptr1[i];
+ float b = ptr2[i];
+ if( a <= b )
+ result += a;
+ else
+ result += b;
+ }
+ break;
+ case CV_COMP_BHATTACHARYYA:
+ {
+ double s1 = 0, s2 = 0;
+ for( i = 0; i < total; i++ )
+ {
+ double a = ptr1[i];
+ double b = ptr2[i];
+ result += sqrt(a*b);
+ s1 += a;
+ s2 += b;
+ }
+ s1 *= s2;
+ s1 = fabs(s1) > FLT_EPSILON ? 1./sqrt(s1) : 1.;
+ result = 1. - result*s1;
+ result = sqrt(MAX(result,0.));
+ }
+ break;
+ default:
+ CV_ERROR( CV_StsBadArg, "Unknown comparison method" );
+ }
+ }
+ else
+ {
+ CvSparseMat* mat1 = (CvSparseMat*)(hist1->bins);
+ CvSparseMat* mat2 = (CvSparseMat*)(hist2->bins);
+ CvSparseMatIterator iterator;
+ CvSparseNode *node1, *node2;
+
+ if( mat1->heap->active_count > mat2->heap->active_count )
+ {
+ CvSparseMat* t;
+ CV_SWAP( mat1, mat2, t );
+ }
+
+ switch( method )
+ {
+ case CV_COMP_CHISQR:
+ for( node1 = cvInitSparseMatIterator( mat1, &iterator );
+ node1 != 0; node1 = cvGetNextSparseNode( &iterator ))
+ {
+ double v1 = *(float*)CV_NODE_VAL(mat1,node1);
+ uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1), 0, 0, &node1->hashval );
+ if( !node2_data )
+ result += v1;
+ else
+ {
+ double v2 = *(float*)node2_data;
+ double a = v1 - v2;
+ double b = v1 + v2;
+ if( fabs(b) > DBL_EPSILON )
+ result += a*a/b;
+ }
+ }
+
+ for( node2 = cvInitSparseMatIterator( mat2, &iterator );
+ node2 != 0; node2 = cvGetNextSparseNode( &iterator ))
+ {
+ double v2 = *(float*)CV_NODE_VAL(mat2,node2);
+ if( !cvPtrND( mat1, CV_NODE_IDX(mat2,node2), 0, 0, &node2->hashval ))
+ result += v2;
+ }
+ break;
+ case CV_COMP_CORREL:
+ {
+ double s1 = 0, s11 = 0;
+ double s2 = 0, s22 = 0;
+ double s12 = 0;
+ double num, denom2, scale = 1./total;
+
+ for( node1 = cvInitSparseMatIterator( mat1, &iterator );
+ node1 != 0; node1 = cvGetNextSparseNode( &iterator ))
+ {
+ double v1 = *(float*)CV_NODE_VAL(mat1,node1);
+ uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1),
+ 0, 0, &node1->hashval );
+ if( node2_data )
+ {
+ double v2 = *(float*)node2_data;
+ s12 += v1*v2;
+ }
+ s1 += v1;
+ s11 += v1*v1;
+ }
+
+ for( node2 = cvInitSparseMatIterator( mat2, &iterator );
+ node2 != 0; node2 = cvGetNextSparseNode( &iterator ))
+ {
+ double v2 = *(float*)CV_NODE_VAL(mat2,node2);
+ s2 += v2;
+ s22 += v2*v2;
+ }
+
+ num = s12 - s1*s2*scale;
+ denom2 = (s11 - s1*s1*scale)*(s22 - s2*s2*scale);
+ result = fabs(denom2) > DBL_EPSILON ? num/sqrt(denom2) : 1;
+ }
+ break;
+ case CV_COMP_INTERSECT:
+ {
+ for( node1 = cvInitSparseMatIterator( mat1, &iterator );
+ node1 != 0; node1 = cvGetNextSparseNode( &iterator ))
+ {
+ float v1 = *(float*)CV_NODE_VAL(mat1,node1);
+ uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1),
+ 0, 0, &node1->hashval );
+ if( node2_data )
+ {
+ float v2 = *(float*)node2_data;
+ if( v1 <= v2 )
+ result += v1;
+ else
+ result += v2;
+ }
+ }
+ }
+ break;
+ case CV_COMP_BHATTACHARYYA:
+ {
+ double s1 = 0, s2 = 0;
+
+ for( node1 = cvInitSparseMatIterator( mat1, &iterator );
+ node1 != 0; node1 = cvGetNextSparseNode( &iterator ))
+ {
+ double v1 = *(float*)CV_NODE_VAL(mat1,node1);
+ uchar* node2_data = cvPtrND( mat2, CV_NODE_IDX(mat1,node1),
+ 0, 0, &node1->hashval );
+ s1 += v1;
+ if( node2_data )
+ {
+ double v2 = *(float*)node2_data;
+ result += sqrt(v1 * v2);
+ }
+ }
+
+ for( node1 = cvInitSparseMatIterator( mat2, &iterator );
+ node1 != 0; node1 = cvGetNextSparseNode( &iterator ))
+ {
+ double v2 = *(float*)CV_NODE_VAL(mat2,node1);
+ s2 += v2;
+ }
+
+ s1 *= s2;
+ s1 = fabs(s1) > FLT_EPSILON ? 1./sqrt(s1) : 1.;
+ result = 1. - result*s1;
+ result = sqrt(MAX(result,0.));
+ }
+ break;
+ default:
+ CV_ERROR( CV_StsBadArg, "Unknown comparison method" );
+ }
+ }
+
+ _result = result;
+
+ __END__;
+
+ return _result;
+}
+
+// copies one histogram to another
+CV_IMPL void
+cvCopyHist( const CvHistogram* src, CvHistogram** _dst )
+{
+ CV_FUNCNAME( "cvCopyHist" );
+
+ __BEGIN__;
+
+ int eq = 0;
+ int is_sparse;
+ int i, dims1, dims2;
+ int size1[CV_MAX_DIM], size2[CV_MAX_DIM], total = 1;
+ float* ranges[CV_MAX_DIM];
+ float** thresh = 0;
+ CvHistogram* dst;
+
+ if( !_dst )
+ CV_ERROR( CV_StsNullPtr, "Destination double pointer is NULL" );
+
+ dst = *_dst;
+
+ if( !CV_IS_HIST(src) || (dst && !CV_IS_HIST(dst)) )
+ CV_ERROR( CV_StsBadArg, "Invalid histogram header[s]" );
+
+ is_sparse = CV_IS_SPARSE_MAT(src->bins);
+ CV_CALL( dims1 = cvGetDims( src->bins, size1 ));
+ for( i = 0; i < dims1; i++ )
+ total *= size1[i];
+
+ if( dst && is_sparse == CV_IS_SPARSE_MAT(dst->bins))
+ {
+ CV_CALL( dims2 = cvGetDims( dst->bins, size2 ));
+
+ if( dims1 == dims2 )
+ {
+ for( i = 0; i < dims1; i++ )
+ if( size1[i] != size2[i] )
+ break;
+ }
+
+ eq = i == dims1;
+ }
+
+ if( !eq )
+ {
+ cvReleaseHist( _dst );
+ CV_CALL( dst = cvCreateHist( dims1, size1,
+ !is_sparse ? CV_HIST_ARRAY : CV_HIST_SPARSE, 0, 0 ));
+ *_dst = dst;
+ }
+
+ if( CV_HIST_HAS_RANGES( src ))
+ {
+ if( CV_IS_UNIFORM_HIST( src ))
+ {
+ for( i = 0; i < dims1; i++ )
+ ranges[i] = (float*)src->thresh[i];
+ thresh = ranges;
+ }
+ else
+ thresh = src->thresh2;
+ CV_CALL( cvSetHistBinRanges( dst, thresh, CV_IS_UNIFORM_HIST(src)));
+ }
+
+ CV_CALL( cvCopy( src->bins, dst->bins ));
+
+ __END__;
+}
+
+
+// Sets a value range for every histogram bin
+CV_IMPL void
+cvSetHistBinRanges( CvHistogram* hist, float** ranges, int uniform )
+{
+ CV_FUNCNAME( "cvSetHistBinRanges" );
+
+ __BEGIN__;
+
+ int dims, size[CV_MAX_DIM], total = 0;
+ int i, j;
+
+ if( !ranges )
+ CV_ERROR( CV_StsNullPtr, "NULL ranges pointer" );
+
+ if( !CV_IS_HIST(hist) )
+ CV_ERROR( CV_StsBadArg, "Invalid histogram header" );
+
+ CV_CALL( dims = cvGetDims( hist->bins, size ));
+ for( i = 0; i < dims; i++ )
+ total += size[i]+1;
+
+ if( uniform )
+ {
+ for( i = 0; i < dims; i++ )
+ {
+ if( !ranges[i] )
+ CV_ERROR( CV_StsNullPtr, "One of <ranges> elements is NULL" );
+ hist->thresh[i][0] = ranges[i][0];
+ hist->thresh[i][1] = ranges[i][1];
+ }
+
+ hist->type |= CV_HIST_UNIFORM_FLAG + CV_HIST_RANGES_FLAG;
+ }
+ else
+ {
+ float* dim_ranges;
+
+ if( !hist->thresh2 )
+ {
+ CV_CALL( hist->thresh2 = (float**)cvAlloc(
+ dims*sizeof(hist->thresh2[0])+
+ total*sizeof(hist->thresh2[0][0])));
+ }
+ dim_ranges = (float*)(hist->thresh2 + dims);
+
+ for( i = 0; i < dims; i++ )
+ {
+ float val0 = -FLT_MAX;
+
+ if( !ranges[i] )
+ CV_ERROR( CV_StsNullPtr, "One of <ranges> elements is NULL" );
+
+ for( j = 0; j <= size[i]; j++ )
+ {
+ float val = ranges[i][j];
+ if( val <= val0 )
+ CV_ERROR(CV_StsOutOfRange, "Bin ranges should go in ascenting order");
+ val0 = dim_ranges[j] = val;
+ }
+
+ hist->thresh2[i] = dim_ranges;
+ dim_ranges += size[i] + 1;
+ }
+
+ hist->type |= CV_HIST_RANGES_FLAG;
+ hist->type &= ~CV_HIST_UNIFORM_FLAG;
+ }
+
+ __END__;
+}
+
+
+#define ICV_HIST_DUMMY_IDX (INT_MIN/3)
+
+static CvStatus
+icvCalcHistLookupTables8u( const CvHistogram* hist, int dims, int* size, int* tab )
+{
+ const int lo = 0, hi = 256;
+ int is_sparse = CV_IS_SPARSE_HIST( hist );
+ int have_range = CV_HIST_HAS_RANGES(hist);
+ int i, j;
+
+ if( !have_range || CV_IS_UNIFORM_HIST(hist))
+ {
+ for( i = 0; i < dims; i++ )
+ {
+ double a = have_range ? hist->thresh[i][0] : 0;
+ double b = have_range ? hist->thresh[i][1] : 256;
+ int sz = size[i];
+ double scale = sz/(b - a);
+ int step = 1;
+
+ if( !is_sparse )
+ step = ((CvMatND*)(hist->bins))->dim[i].step/sizeof(float);
+
+ for( j = lo; j < hi; j++ )
+ {
+ int idx = cvFloor((j - a)*scale);
+ if( (unsigned)idx < (unsigned)sz )
+ idx *= step;
+ else
+ idx = ICV_HIST_DUMMY_IDX;
+
+ tab[i*(hi - lo) + j - lo] = idx;
+ }
+ }
+ }
+ else
+ {
+ for( i = 0; i < dims; i++ )
+ {
+ double limit = hist->thresh2[i][0];
+ int idx = -1, write_idx = ICV_HIST_DUMMY_IDX, sz = size[i];
+ int step = 1;
+
+ if( !is_sparse )
+ step = ((CvMatND*)(hist->bins))->dim[i].step/sizeof(float);
+
+ if( limit > hi )
+ limit = hi;
+
+ j = lo;
+ for(;;)
+ {
+ for( ; j < limit; j++ )
+ tab[i*(hi - lo) + j - lo] = write_idx;
+
+ if( (unsigned)(++idx) < (unsigned)sz )
+ {
+ limit = hist->thresh2[i][idx+1];
+ if( limit > hi )
+ limit = hi;
+ write_idx = idx*step;
+ }
+ else
+ {
+ for( ; j < hi; j++ )
+ tab[i*(hi - lo) + j - lo] = ICV_HIST_DUMMY_IDX;
+ break;
+ }
+ }
+ }
+ }
+
+ return CV_OK;
+}
+
+
+/***************************** C A L C H I S T O G R A M *************************/
+
+// Calculates histogram for one or more 8u arrays
+static CvStatus CV_STDCALL
+ icvCalcHist_8u_C1R( uchar** img, int step, uchar* mask, int maskStep,
+ CvSize size, CvHistogram* hist )
+{
+ int* tab;
+ int is_sparse = CV_IS_SPARSE_HIST(hist);
+ int dims, histsize[CV_MAX_DIM];
+ int i, x;
+ CvStatus status;
+
+ dims = cvGetDims( hist->bins, histsize );
+
+ tab = (int*)cvStackAlloc( dims*256*sizeof(int));
+ status = icvCalcHistLookupTables8u( hist, dims, histsize, tab );
+
+ if( status < 0 )
+ return status;
+
+ if( !is_sparse )
+ {
+ int total = 1;
+ int* bins = ((CvMatND*)(hist->bins))->data.i;
+
+ for( i = 0; i < dims; i++ )
+ total *= histsize[i];
+
+ if( dims <= 3 && total >= -ICV_HIST_DUMMY_IDX )
+ return CV_BADSIZE_ERR; // too big histogram
+
+ switch( dims )
+ {
+ case 1:
+ {
+ int tab1d[256];
+ memset( tab1d, 0, sizeof(tab1d));
+
+ for( ; size.height--; img[0] += step )
+ {
+ uchar* ptr = img[0];
+ if( !mask )
+ {
+ for( x = 0; x <= size.width - 4; x += 4 )
+ {
+ int v0 = ptr[x];
+ int v1 = ptr[x+1];
+
+ tab1d[v0]++;
+ tab1d[v1]++;
+
+ v0 = ptr[x+2];
+ v1 = ptr[x+3];
+
+ tab1d[v0]++;
+ tab1d[v1]++;
+ }
+
+ for( ; x < size.width; x++ )
+ tab1d[ptr[x]]++;
+ }
+ else
+ {
+ for( x = 0; x < size.width; x++ )
+ if( mask[x] )
+ tab1d[ptr[x]]++;
+ mask += maskStep;
+ }
+ }
+
+ for( i = 0; i < 256; i++ )
+ {
+ int idx = tab[i];
+ if( idx >= 0 )
+ bins[idx] += tab1d[i];
+ }
+ }
+ break;
+ case 2:
+ for( ; size.height--; img[0] += step, img[1] += step )
+ {
+ uchar* ptr0 = img[0];
+ uchar* ptr1 = img[1];
+ if( !mask )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ int v0 = ptr0[x];
+ int v1 = ptr1[x];
+ int idx = tab[v0] + tab[256+v1];
+
+ if( idx >= 0 )
+ bins[idx]++;
+ }
+ }
+ else
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ if( mask[x] )
+ {
+ int v0 = ptr0[x];
+ int v1 = ptr1[x];
+
+ int idx = tab[v0] + tab[256+v1];
+
+ if( idx >= 0 )
+ bins[idx]++;
+ }
+ }
+ mask += maskStep;
+ }
+ }
+ break;
+ case 3:
+ for( ; size.height--; img[0] += step, img[1] += step, img[2] += step )
+ {
+ uchar* ptr0 = img[0];
+ uchar* ptr1 = img[1];
+ uchar* ptr2 = img[2];
+ if( !mask )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ int v0 = ptr0[x];
+ int v1 = ptr1[x];
+ int v2 = ptr2[x];
+ int idx = tab[v0] + tab[256+v1] + tab[512+v2];
+
+ if( idx >= 0 )
+ bins[idx]++;
+ }
+ }
+ else
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ if( mask[x] )
+ {
+ int v0 = ptr0[x];
+ int v1 = ptr1[x];
+ int v2 = ptr2[x];
+ int idx = tab[v0] + tab[256+v1] + tab[512+v2];
+
+ if( idx >= 0 )
+ bins[idx]++;
+ }
+ }
+ mask += maskStep;
+ }
+ }
+ break;
+ default:
+ for( ; size.height--; )
+ {
+ if( !mask )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ int* binptr = bins;
+ for( i = 0; i < dims; i++ )
+ {
+ int idx = tab[i*256 + img[i][x]];
+ if( idx < 0 )
+ break;
+ binptr += idx;
+ }
+ if( i == dims )
+ binptr[0]++;
+ }
+ }
+ else
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ if( mask[x] )
+ {
+ int* binptr = bins;
+ for( i = 0; i < dims; i++ )
+ {
+ int idx = tab[i*256 + img[i][x]];
+ if( idx < 0 )
+ break;
+ binptr += idx;
+ }
+ if( i == dims )
+ binptr[0]++;
+ }
+ }
+ mask += maskStep;
+ }
+
+ for( i = 0; i < dims; i++ )
+ img[i] += step;
+ }
+ }
+ }
+ else
+ {
+ CvSparseMat* mat = (CvSparseMat*)(hist->bins);
+ int node_idx[CV_MAX_DIM];
+
+ for( ; size.height--; )
+ {
+ if( !mask )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ for( i = 0; i < dims; i++ )
+ {
+ int idx = tab[i*256 + img[i][x]];
+ if( idx < 0 )
+ break;
+ node_idx[i] = idx;
+ }
+ if( i == dims )
+ {
+ int* bin = (int*)cvPtrND( mat, node_idx, 0, 1 );
+ bin[0]++;
+ }
+ }
+ }
+ else
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ if( mask[x] )
+ {
+ for( i = 0; i < dims; i++ )
+ {
+ int idx = tab[i*256 + img[i][x]];
+ if( idx < 0 )
+ break;
+ node_idx[i] = idx;
+ }
+ if( i == dims )
+ {
+ int* bin = (int*)cvPtrND( mat, node_idx, 0, 1, 0 );
+ bin[0]++;
+ }
+ }
+ }
+ mask += maskStep;
+ }
+
+ for( i = 0; i < dims; i++ )
+ img[i] += step;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+// Calculates histogram for one or more 32f arrays
+static CvStatus CV_STDCALL
+ icvCalcHist_32f_C1R( float** img, int step, uchar* mask, int maskStep,
+ CvSize size, CvHistogram* hist )
+{
+ int is_sparse = CV_IS_SPARSE_HIST(hist);
+ int uniform = CV_IS_UNIFORM_HIST(hist);
+ int dims, histsize[CV_MAX_DIM];
+ double uni_range[CV_MAX_DIM][2];
+ int i, x;
+
+ dims = cvGetDims( hist->bins, histsize );
+ step /= sizeof(img[0][0]);
+
+ if( uniform )
+ {
+ for( i = 0; i < dims; i++ )
+ {
+ double t = histsize[i]/((double)hist->thresh[i][1] - hist->thresh[i][0]);
+ uni_range[i][0] = t;
+ uni_range[i][1] = -t*hist->thresh[i][0];
+ }
+ }
+
+ if( !is_sparse )
+ {
+ CvMatND* mat = (CvMatND*)(hist->bins);
+ int* bins = mat->data.i;
+
+ if( uniform )
+ {
+ switch( dims )
+ {
+ case 1:
+ {
+ double a = uni_range[0][0], b = uni_range[0][1];
+ int sz = histsize[0];
+
+ for( ; size.height--; img[0] += step )
+ {
+ float* ptr = img[0];
+
+ if( !mask )
+ {
+ for( x = 0; x <= size.width - 4; x += 4 )
+ {
+ int v0 = cvFloor(ptr[x]*a + b);
+ int v1 = cvFloor(ptr[x+1]*a + b);
+
+ if( (unsigned)v0 < (unsigned)sz )
+ bins[v0]++;
+ if( (unsigned)v1 < (unsigned)sz )
+ bins[v1]++;
+
+ v0 = cvFloor(ptr[x+2]*a + b);
+ v1 = cvFloor(ptr[x+3]*a + b);
+
+ if( (unsigned)v0 < (unsigned)sz )
+ bins[v0]++;
+ if( (unsigned)v1 < (unsigned)sz )
+ bins[v1]++;
+ }
+
+ for( ; x < size.width; x++ )
+ {
+ int v0 = cvFloor(ptr[x]*a + b);
+ if( (unsigned)v0 < (unsigned)sz )
+ bins[v0]++;
+ }
+ }
+ else
+ {
+ for( x = 0; x < size.width; x++ )
+ if( mask[x] )
+ {
+ int v0 = cvFloor(ptr[x]*a + b);
+ if( (unsigned)v0 < (unsigned)sz )
+ bins[v0]++;
+ }
+ mask += maskStep;
+ }
+ }
+ }
+ break;
+ case 2:
+ {
+ double a0 = uni_range[0][0], b0 = uni_range[0][1];
+ double a1 = uni_range[1][0], b1 = uni_range[1][1];
+ int sz0 = histsize[0], sz1 = histsize[1];
+ int step0 = ((CvMatND*)(hist->bins))->dim[0].step/sizeof(float);
+
+ for( ; size.height--; img[0] += step, img[1] += step )
+ {
+ float* ptr0 = img[0];
+ float* ptr1 = img[1];
+
+ if( !mask )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ int v0 = cvFloor( ptr0[x]*a0 + b0 );
+ int v1 = cvFloor( ptr1[x]*a1 + b1 );
+
+ if( (unsigned)v0 < (unsigned)sz0 &&
+ (unsigned)v1 < (unsigned)sz1 )
+ bins[v0*step0 + v1]++;
+ }
+ }
+ else
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ if( mask[x] )
+ {
+ int v0 = cvFloor( ptr0[x]*a0 + b0 );
+ int v1 = cvFloor( ptr1[x]*a1 + b1 );
+
+ if( (unsigned)v0 < (unsigned)sz0 &&
+ (unsigned)v1 < (unsigned)sz1 )
+ bins[v0*step0 + v1]++;
+ }
+ }
+ mask += maskStep;
+ }
+ }
+ }
+ break;
+ default:
+ for( ; size.height--; )
+ {
+ if( !mask )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ int* binptr = bins;
+ for( i = 0; i < dims; i++ )
+ {
+ int idx = cvFloor((double)img[i][x]*uni_range[i][0]
+ + uni_range[i][1]);
+ if( (unsigned)idx >= (unsigned)histsize[i] )
+ break;
+ binptr += idx*(mat->dim[i].step/sizeof(float));
+ }
+ if( i == dims )
+ binptr[0]++;
+ }
+ }
+ else
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ if( mask[x] )
+ {
+ int* binptr = bins;
+ for( i = 0; i < dims; i++ )
+ {
+ int idx = cvFloor((double)img[i][x]*uni_range[i][0]
+ + uni_range[i][1]);
+ if( (unsigned)idx >= (unsigned)histsize[i] )
+ break;
+ binptr += idx*(mat->dim[i].step/sizeof(float));
+ }
+ if( i == dims )
+ binptr[0]++;
+ }
+ }
+ mask += maskStep;
+ }
+
+ for( i = 0; i < dims; i++ )
+ img[i] += step;
+ }
+ }
+ }
+ else
+ {
+ for( ; size.height--; )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ if( !mask || mask[x] )
+ {
+ int* binptr = bins;
+ for( i = 0; i < dims; i++ )
+ {
+ float v = img[i][x];
+ float* thresh = hist->thresh2[i];
+ int idx = -1, sz = histsize[i];
+
+ while( v >= thresh[idx+1] && ++idx < sz )
+ /* nop */;
+
+ if( (unsigned)idx >= (unsigned)sz )
+ break;
+
+ binptr += idx*(mat->dim[i].step/sizeof(float));
+ }
+ if( i == dims )
+ binptr[0]++;
+ }
+ }
+
+ for( i = 0; i < dims; i++ )
+ img[i] += step;
+ if( mask )
+ mask += maskStep;
+ }
+ }
+ }
+ else
+ {
+ CvSparseMat* mat = (CvSparseMat*)(hist->bins);
+ int node_idx[CV_MAX_DIM];
+
+ for( ; size.height--; )
+ {
+ if( uniform )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ if( !mask || mask[x] )
+ {
+ for( i = 0; i < dims; i++ )
+ {
+ int idx = cvFloor(img[i][x]*uni_range[i][0]
+ + uni_range[i][1]);
+ if( (unsigned)idx >= (unsigned)histsize[i] )
+ break;
+ node_idx[i] = idx;
+ }
+ if( i == dims )
+ {
+ int* bin = (int*)cvPtrND( mat, node_idx, 0, 1, 0 );
+ bin[0]++;
+ }
+ }
+ }
+ }
+ else
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ if( !mask || mask[x] )
+ {
+ for( i = 0; i < dims; i++ )
+ {
+ float v = img[i][x];
+ float* thresh = hist->thresh2[i];
+ int idx = -1, sz = histsize[i];
+
+ while( v >= thresh[idx+1] && ++idx < sz )
+ /* nop */;
+
+ if( (unsigned)idx >= (unsigned)sz )
+ break;
+
+ node_idx[i] = idx;
+ }
+ if( i == dims )
+ {
+ int* bin = (int*)cvPtrND( mat, node_idx, 0, 1, 0 );
+ bin[0]++;
+ }
+ }
+ }
+ }
+
+ for( i = 0; i < dims; i++ )
+ img[i] += step;
+
+ if( mask )
+ mask += maskStep;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+CV_IMPL void
+cvCalcArrHist( CvArr** img, CvHistogram* hist,
+ int do_not_clear, const CvArr* mask )
+{
+ CV_FUNCNAME( "cvCalcHist" );
+
+ __BEGIN__;
+
+ uchar* ptr[CV_MAX_DIM];
+ uchar* maskptr = 0;
+ int maskstep = 0, step = 0;
+ int i, dims;
+ int cont_flag = -1;
+ CvMat stub0, *mat0 = 0;
+ CvMatND dense;
+ CvSize size;
+
+ if( !CV_IS_HIST(hist))
+ CV_ERROR( CV_StsBadArg, "Bad histogram pointer" );
+
+ if( !img )
+ CV_ERROR( CV_StsNullPtr, "Null double array pointer" );
+
+ CV_CALL( dims = cvGetDims( hist->bins ));
+
+ for( i = 0; i < dims; i++ )
+ {
+ CvMat stub, *mat = (CvMat*)img[i];
+ CV_CALL( mat = cvGetMat( mat, i == 0 ? &stub0 : &stub, 0, 1 ));
+
+ if( CV_MAT_CN( mat->type ) != 1 )
+ CV_ERROR( CV_BadNumChannels, "Only 1-channel arrays are allowed here" );
+
+ if( i == 0 )
+ {
+ mat0 = mat;
+ step = mat0->step;
+ }
+ else
+ {
+ if( !CV_ARE_SIZES_EQ( mat0, mat ))
+ CV_ERROR( CV_StsUnmatchedSizes, "Not all the planes have equal sizes" );
+
+ if( mat0->step != mat->step )
+ CV_ERROR( CV_StsUnmatchedSizes, "Not all the planes have equal steps" );
+
+ if( !CV_ARE_TYPES_EQ( mat0, mat ))
+ CV_ERROR( CV_StsUnmatchedFormats, "Not all the planes have equal types" );
+ }
+
+ cont_flag &= mat->type;
+ ptr[i] = mat->data.ptr;
+ }
+
+ if( mask )
+ {
+ CvMat stub, *mat = (CvMat*)mask;
+ CV_CALL( mat = cvGetMat( mat, &stub, 0, 1 ));
+
+ if( !CV_IS_MASK_ARR(mat))
+ CV_ERROR( CV_StsBadMask, "Bad mask array" );
+
+ if( !CV_ARE_SIZES_EQ( mat0, mat ))
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Mask size does not match to other arrays\' size" );
+ maskptr = mat->data.ptr;
+ maskstep = mat->step;
+ cont_flag &= mat->type;
+ }
+
+ size = cvGetMatSize(mat0);
+ if( CV_IS_MAT_CONT( cont_flag ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ maskstep = step = CV_STUB_STEP;
+ }
+
+ if( !CV_IS_SPARSE_HIST(hist))
+ {
+ dense = *(CvMatND*)hist->bins;
+ dense.type = (dense.type & ~CV_MAT_TYPE_MASK) | CV_32SC1;
+ }
+
+ if( !do_not_clear )
+ {
+ CV_CALL( cvZero( hist->bins ));
+ }
+ else if( !CV_IS_SPARSE_HIST(hist))
+ {
+ CV_CALL( cvConvert( (CvMatND*)hist->bins, &dense ));
+ }
+ else
+ {
+ CvSparseMat* mat = (CvSparseMat*)(hist->bins);
+ CvSparseMatIterator iterator;
+ CvSparseNode* node;
+
+ for( node = cvInitSparseMatIterator( mat, &iterator );
+ node != 0; node = cvGetNextSparseNode( &iterator ))
+ {
+ Cv32suf* val = (Cv32suf*)CV_NODE_VAL( mat, node );
+ val->i = cvRound( val->f );
+ }
+ }
+
+ if( CV_MAT_DEPTH(mat0->type) > CV_8S && !CV_HIST_HAS_RANGES(hist))
+ CV_ERROR( CV_StsBadArg, "histogram ranges must be set (via cvSetHistBinRanges) "
+ "before calling the function" );
+
+ switch( CV_MAT_DEPTH(mat0->type) )
+ {
+ case CV_8U:
+ IPPI_CALL( icvCalcHist_8u_C1R( ptr, step, maskptr, maskstep, size, hist ));
+ break;
+ case CV_32F:
+ {
+ union { uchar** ptr; float** fl; } v;
+ v.ptr = ptr;
+ IPPI_CALL( icvCalcHist_32f_C1R( v.fl, step, maskptr, maskstep, size, hist ));
+ }
+ break;
+ default:
+ CV_ERROR( CV_StsUnsupportedFormat, "Unsupported array type" );
+ }
+
+ if( !CV_IS_SPARSE_HIST(hist))
+ {
+ CV_CALL( cvConvert( &dense, (CvMatND*)hist->bins ));
+ }
+ else
+ {
+ CvSparseMat* mat = (CvSparseMat*)(hist->bins);
+ CvSparseMatIterator iterator;
+ CvSparseNode* node;
+
+ for( node = cvInitSparseMatIterator( mat, &iterator );
+ node != 0; node = cvGetNextSparseNode( &iterator ))
+ {
+ Cv32suf* val = (Cv32suf*)CV_NODE_VAL( mat, node );
+ val->f = (float)val->i;
+ }
+ }
+
+ __END__;
+}
+
+
+/***************************** B A C K P R O J E C T *****************************/
+
+// Calculates back project for one or more 8u arrays
+static CvStatus CV_STDCALL
+ icvCalcBackProject_8u_C1R( uchar** img, int step, uchar* dst, int dstStep,
+ CvSize size, const CvHistogram* hist )
+{
+ const int small_hist_size = 1<<12;
+ int* tab = 0;
+ int is_sparse = CV_IS_SPARSE_HIST(hist);
+ int dims, histsize[CV_MAX_DIM];
+ int i, x;
+ CvStatus status;
+
+ dims = cvGetDims( hist->bins, histsize );
+
+ tab = (int*)cvStackAlloc( dims*256*sizeof(int));
+ status = icvCalcHistLookupTables8u( hist, dims, histsize, tab );
+ if( status < 0 )
+ return status;
+
+ if( !is_sparse )
+ {
+ int total = 1;
+ CvMatND* mat = (CvMatND*)(hist->bins);
+ float* bins = mat->data.fl;
+ uchar* buffer = 0;
+
+ for( i = 0; i < dims; i++ )
+ total *= histsize[i];
+
+ if( dims <= 3 && total >= -ICV_HIST_DUMMY_IDX )
+ return CV_BADSIZE_ERR; // too big histogram
+
+ if( dims > 1 && total <= small_hist_size && CV_IS_MAT_CONT(mat->type))
+ {
+ buffer = (uchar*)cvAlloc(total);
+ if( !buffer )
+ return CV_OUTOFMEM_ERR;
+ for( i = 0; i < total; i++ )
+ {
+ int v = cvRound(bins[i]);
+ buffer[i] = CV_CAST_8U(v);
+ }
+ }
+
+ switch( dims )
+ {
+ case 1:
+ {
+ uchar tab1d[256];
+ for( i = 0; i < 256; i++ )
+ {
+ int idx = tab[i];
+ if( idx >= 0 )
+ {
+ int v = cvRound(bins[idx]);
+ tab1d[i] = CV_CAST_8U(v);
+ }
+ else
+ tab1d[i] = 0;
+ }
+
+ for( ; size.height--; img[0] += step, dst += dstStep )
+ {
+ uchar* ptr = img[0];
+ for( x = 0; x <= size.width - 4; x += 4 )
+ {
+ uchar v0 = tab1d[ptr[x]];
+ uchar v1 = tab1d[ptr[x+1]];
+
+ dst[x] = v0;
+ dst[x+1] = v1;
+
+ v0 = tab1d[ptr[x+2]];
+ v1 = tab1d[ptr[x+3]];
+
+ dst[x+2] = v0;
+ dst[x+3] = v1;
+ }
+
+ for( ; x < size.width; x++ )
+ dst[x] = tab1d[ptr[x]];
+ }
+ }
+ break;
+ case 2:
+ for( ; size.height--; img[0] += step, img[1] += step, dst += dstStep )
+ {
+ uchar* ptr0 = img[0];
+ uchar* ptr1 = img[1];
+
+ if( buffer )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ int v0 = ptr0[x];
+ int v1 = ptr1[x];
+ int idx = tab[v0] + tab[256+v1];
+ int v = 0;
+
+ if( idx >= 0 )
+ v = buffer[idx];
+
+ dst[x] = (uchar)v;
+ }
+ }
+ else
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ int v0 = ptr0[x];
+ int v1 = ptr1[x];
+ int idx = tab[v0] + tab[256+v1];
+ int v = 0;
+
+ if( idx >= 0 )
+ {
+ v = cvRound(bins[idx]);
+ v = CV_CAST_8U(v);
+ }
+
+ dst[x] = (uchar)v;
+ }
+ }
+ }
+ break;
+ case 3:
+ for( ; size.height--; img[0] += step, img[1] += step,
+ img[2] += step, dst += dstStep )
+ {
+ uchar* ptr0 = img[0];
+ uchar* ptr1 = img[1];
+ uchar* ptr2 = img[2];
+
+ if( buffer )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ int v0 = ptr0[x];
+ int v1 = ptr1[x];
+ int v2 = ptr2[x];
+ int idx = tab[v0] + tab[256+v1] + tab[512+v2];
+ int v = 0;
+
+ if( idx >= 0 )
+ v = buffer[idx];
+
+ dst[x] = (uchar)v;
+ }
+ }
+ else
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ int v0 = ptr0[x];
+ int v1 = ptr1[x];
+ int v2 = ptr2[x];
+ int idx = tab[v0] + tab[256+v1] + tab[512+v2];
+ int v = 0;
+
+ if( idx >= 0 )
+ {
+ v = cvRound(bins[idx]);
+ v = CV_CAST_8U(v);
+ }
+ dst[x] = (uchar)v;
+ }
+ }
+ }
+ break;
+ default:
+ for( ; size.height--; dst += dstStep )
+ {
+ if( buffer )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ uchar* binptr = buffer;
+ int v = 0;
+
+ for( i = 0; i < dims; i++ )
+ {
+ int idx = tab[i*256 + img[i][x]];
+ if( idx < 0 )
+ break;
+ binptr += idx;
+ }
+
+ if( i == dims )
+ v = binptr[0];
+
+ dst[x] = (uchar)v;
+ }
+ }
+ else
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ float* binptr = bins;
+ int v = 0;
+
+ for( i = 0; i < dims; i++ )
+ {
+ int idx = tab[i*256 + img[i][x]];
+ if( idx < 0 )
+ break;
+ binptr += idx;
+ }
+
+ if( i == dims )
+ {
+ v = cvRound( binptr[0] );
+ v = CV_CAST_8U(v);
+ }
+
+ dst[x] = (uchar)v;
+ }
+ }
+
+ for( i = 0; i < dims; i++ )
+ img[i] += step;
+ }
+ }
+
+ cvFree( &buffer );
+ }
+ else
+ {
+ CvSparseMat* mat = (CvSparseMat*)(hist->bins);
+ int node_idx[CV_MAX_DIM];
+
+ for( ; size.height--; dst += dstStep )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ int v = 0;
+
+ for( i = 0; i < dims; i++ )
+ {
+ int idx = tab[i*256 + img[i][x]];
+ if( idx < 0 )
+ break;
+ node_idx[i] = idx;
+ }
+ if( i == dims )
+ {
+ float* bin = (float*)cvPtrND( mat, node_idx, 0, 1, 0 );
+ v = cvRound(bin[0]);
+ v = CV_CAST_8U(v);
+ }
+
+ dst[x] = (uchar)v;
+ }
+
+ for( i = 0; i < dims; i++ )
+ img[i] += step;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+// Calculates back project for one or more 32f arrays
+static CvStatus CV_STDCALL
+ icvCalcBackProject_32f_C1R( float** img, int step, float* dst, int dstStep,
+ CvSize size, const CvHistogram* hist )
+{
+ int is_sparse = CV_IS_SPARSE_HIST(hist);
+ int uniform = CV_IS_UNIFORM_HIST(hist);
+ int dims, histsize[CV_MAX_DIM];
+ double uni_range[CV_MAX_DIM][2];
+ int i, x;
+
+ dims = cvGetDims( hist->bins, histsize );
+ step /= sizeof(img[0][0]);
+ dstStep /= sizeof(dst[0]);
+
+ if( uniform )
+ {
+ for( i = 0; i < dims; i++ )
+ {
+ double t = ((double)histsize[i])/
+ ((double)hist->thresh[i][1] - hist->thresh[i][0]);
+ uni_range[i][0] = t;
+ uni_range[i][1] = -t*hist->thresh[i][0];
+ }
+ }
+
+ if( !is_sparse )
+ {
+ CvMatND* mat = (CvMatND*)(hist->bins);
+ float* bins = mat->data.fl;
+
+ if( uniform )
+ {
+ switch( dims )
+ {
+ case 1:
+ {
+ double a = uni_range[0][0], b = uni_range[0][1];
+ int sz = histsize[0];
+
+ for( ; size.height--; img[0] += step, dst += dstStep )
+ {
+ float* ptr = img[0];
+
+ for( x = 0; x <= size.width - 4; x += 4 )
+ {
+ int v0 = cvFloor(ptr[x]*a + b);
+ int v1 = cvFloor(ptr[x+1]*a + b);
+
+ if( (unsigned)v0 < (unsigned)sz )
+ dst[x] = bins[v0];
+ else
+ dst[x] = 0;
+
+ if( (unsigned)v1 < (unsigned)sz )
+ dst[x+1] = bins[v1];
+ else
+ dst[x+1] = 0;
+
+ v0 = cvFloor(ptr[x+2]*a + b);
+ v1 = cvFloor(ptr[x+3]*a + b);
+
+ if( (unsigned)v0 < (unsigned)sz )
+ dst[x+2] = bins[v0];
+ else
+ dst[x+2] = 0;
+
+ if( (unsigned)v1 < (unsigned)sz )
+ dst[x+3] = bins[v1];
+ else
+ dst[x+3] = 0;
+ }
+
+ for( ; x < size.width; x++ )
+ {
+ int v0 = cvFloor(ptr[x]*a + b);
+
+ if( (unsigned)v0 < (unsigned)sz )
+ dst[x] = bins[v0];
+ else
+ dst[x] = 0;
+ }
+ }
+ }
+ break;
+ case 2:
+ {
+ double a0 = uni_range[0][0], b0 = uni_range[0][1];
+ double a1 = uni_range[1][0], b1 = uni_range[1][1];
+ int sz0 = histsize[0], sz1 = histsize[1];
+ int step0 = ((CvMatND*)(hist->bins))->dim[0].step/sizeof(float);
+
+ for( ; size.height--; img[0] += step, img[1] += step, dst += dstStep )
+ {
+ float* ptr0 = img[0];
+ float* ptr1 = img[1];
+
+ for( x = 0; x < size.width; x++ )
+ {
+ int v0 = cvFloor( ptr0[x]*a0 + b0 );
+ int v1 = cvFloor( ptr1[x]*a1 + b1 );
+
+ if( (unsigned)v0 < (unsigned)sz0 &&
+ (unsigned)v1 < (unsigned)sz1 )
+ dst[x] = bins[v0*step0 + v1];
+ else
+ dst[x] = 0;
+ }
+ }
+ }
+ break;
+ default:
+ for( ; size.height--; dst += dstStep )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ float* binptr = bins;
+
+ for( i = 0; i < dims; i++ )
+ {
+ int idx = cvFloor(img[i][x]*uni_range[i][0]
+ + uni_range[i][1]);
+ if( (unsigned)idx >= (unsigned)histsize[i] )
+ break;
+ binptr += idx*(mat->dim[i].step/sizeof(float));
+ }
+ if( i == dims )
+ dst[x] = binptr[0];
+ else
+ dst[x] = 0;
+ }
+ }
+
+ for( i = 0; i < dims; i++ )
+ img[i] += step;
+ }
+ }
+ else
+ {
+ for( ; size.height--; dst += dstStep )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ float* binptr = bins;
+ for( i = 0; i < dims; i++ )
+ {
+ float v = img[i][x];
+ float* thresh = hist->thresh2[i];
+ int idx = -1, sz = histsize[i];
+
+ while( v >= thresh[idx+1] && ++idx < sz )
+ /* nop */;
+
+ if( (unsigned)idx >= (unsigned)sz )
+ break;
+
+ binptr += idx*(mat->dim[i].step/sizeof(float));
+ }
+ if( i == dims )
+ dst[x] = binptr[0];
+ else
+ dst[x] = 0;
+ }
+
+ for( i = 0; i < dims; i++ )
+ img[i] += step;
+ }
+ }
+ }
+ else
+ {
+ CvSparseMat* mat = (CvSparseMat*)(hist->bins);
+ int node_idx[CV_MAX_DIM];
+
+ for( ; size.height--; dst += dstStep )
+ {
+ if( uniform )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ for( i = 0; i < dims; i++ )
+ {
+ int idx = cvFloor(img[i][x]*uni_range[i][0]
+ + uni_range[i][1]);
+ if( (unsigned)idx >= (unsigned)histsize[i] )
+ break;
+ node_idx[i] = idx;
+ }
+ if( i == dims )
+ {
+ float* bin = (float*)cvPtrND( mat, node_idx, 0, 1, 0 );
+ dst[x] = bin[0];
+ }
+ else
+ dst[x] = 0;
+ }
+ }
+ else
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ for( i = 0; i < dims; i++ )
+ {
+ float v = img[i][x];
+ float* thresh = hist->thresh2[i];
+ int idx = -1, sz = histsize[i];
+
+ while( v >= thresh[idx+1] && ++idx < sz )
+ /* nop */;
+
+ if( (unsigned)idx >= (unsigned)sz )
+ break;
+
+ node_idx[i] = idx;
+ }
+ if( i == dims )
+ {
+ float* bin = (float*)cvPtrND( mat, node_idx, 0, 1, 0 );
+ dst[x] = bin[0];
+ }
+ else
+ dst[x] = 0;
+ }
+ }
+
+ for( i = 0; i < dims; i++ )
+ img[i] += step;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+CV_IMPL void
+cvCalcArrBackProject( CvArr** img, CvArr* dst, const CvHistogram* hist )
+{
+ CV_FUNCNAME( "cvCalcArrBackProject" );
+
+ __BEGIN__;
+
+ uchar* ptr[CV_MAX_DIM];
+ uchar* dstptr = 0;
+ int dststep = 0, step = 0;
+ int i, dims;
+ int cont_flag = -1;
+ CvMat stub0, *mat0 = 0;
+ CvSize size;
+
+ if( !CV_IS_HIST(hist))
+ CV_ERROR( CV_StsBadArg, "Bad histogram pointer" );
+
+ if( !img )
+ CV_ERROR( CV_StsNullPtr, "Null double array pointer" );
+
+ CV_CALL( dims = cvGetDims( hist->bins ));
+
+ for( i = 0; i <= dims; i++ )
+ {
+ CvMat stub, *mat = (CvMat*)(i < dims ? img[i] : dst);
+ CV_CALL( mat = cvGetMat( mat, i == 0 ? &stub0 : &stub, 0, 1 ));
+
+ if( CV_MAT_CN( mat->type ) != 1 )
+ CV_ERROR( CV_BadNumChannels, "Only 1-channel arrays are allowed here" );
+
+ if( i == 0 )
+ {
+ mat0 = mat;
+ step = mat0->step;
+ }
+ else
+ {
+ if( !CV_ARE_SIZES_EQ( mat0, mat ))
+ CV_ERROR( CV_StsUnmatchedSizes, "Not all the planes have equal sizes" );
+
+ if( mat0->step != mat->step )
+ CV_ERROR( CV_StsUnmatchedSizes, "Not all the planes have equal steps" );
+
+ if( !CV_ARE_TYPES_EQ( mat0, mat ))
+ CV_ERROR( CV_StsUnmatchedFormats, "Not all the planes have equal types" );
+ }
+
+ cont_flag &= mat->type;
+ if( i < dims )
+ ptr[i] = mat->data.ptr;
+ else
+ {
+ dstptr = mat->data.ptr;
+ dststep = mat->step;
+ }
+ }
+
+ size = cvGetMatSize(mat0);
+ if( CV_IS_MAT_CONT( cont_flag ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ dststep = step = CV_STUB_STEP;
+ }
+
+ if( CV_MAT_DEPTH(mat0->type) > CV_8S && !CV_HIST_HAS_RANGES(hist))
+ CV_ERROR( CV_StsBadArg, "histogram ranges must be set (via cvSetHistBinRanges) "
+ "before calling the function" );
+
+ switch( CV_MAT_DEPTH(mat0->type) )
+ {
+ case CV_8U:
+ IPPI_CALL( icvCalcBackProject_8u_C1R( ptr, step, dstptr, dststep, size, hist ));
+ break;
+ case CV_32F:
+ {
+ union { uchar** ptr; float** fl; } v;
+ v.ptr = ptr;
+ IPPI_CALL( icvCalcBackProject_32f_C1R( v.fl, step,
+ (float*)dstptr, dststep, size, hist ));
+ }
+ break;
+ default:
+ CV_ERROR( CV_StsUnsupportedFormat, "Unsupported array type" );
+ }
+
+ __END__;
+}
+
+
+////////////////////// B A C K P R O J E C T P A T C H /////////////////////////
+
+CV_IMPL void
+cvCalcArrBackProjectPatch( CvArr** arr, CvArr* dst, CvSize patch_size, CvHistogram* hist,
+ int method, double norm_factor )
+{
+ CvHistogram* model = 0;
+
+ CV_FUNCNAME( "cvCalcArrBackProjectPatch" );
+
+ __BEGIN__;
+
+ IplImage imgstub[CV_MAX_DIM], *img[CV_MAX_DIM];
+ IplROI roi;
+ CvMat dststub, *dstmat;
+ int i, dims;
+ int x, y;
+ CvSize size;
+
+ if( !CV_IS_HIST(hist))
+ CV_ERROR( CV_StsBadArg, "Bad histogram pointer" );
+
+ if( !arr )
+ CV_ERROR( CV_StsNullPtr, "Null double array pointer" );
+
+ if( norm_factor <= 0 )
+ CV_ERROR( CV_StsOutOfRange,
+ "Bad normalization factor (set it to 1.0 if unsure)" );
+
+ if( patch_size.width <= 0 || patch_size.height <= 0 )
+ CV_ERROR( CV_StsBadSize, "The patch width and height must be positive" );
+
+ CV_CALL( dims = cvGetDims( hist->bins ));
+ CV_CALL( cvCopyHist( hist, &model ));
+ CV_CALL( cvNormalizeHist( hist, norm_factor ));
+
+ for( i = 0; i < dims; i++ )
+ {
+ CvMat stub, *mat;
+ CV_CALL( mat = cvGetMat( arr[i], &stub, 0, 0 ));
+ CV_CALL( img[i] = cvGetImage( mat, &imgstub[i] ));
+ img[i]->roi = &roi;
+ }
+
+ CV_CALL( dstmat = cvGetMat( dst, &dststub, 0, 0 ));
+ if( CV_MAT_TYPE( dstmat->type ) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Resultant image must have 32fC1 type" );
+
+ if( dstmat->cols != img[0]->width - patch_size.width + 1 ||
+ dstmat->rows != img[0]->height - patch_size.height + 1 )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The output map must be (W-w+1 x H-h+1), "
+ "where the input images are (W x H) each and the patch is (w x h)" );
+
+ size = cvGetMatSize(dstmat);
+ roi.coi = 0;
+ roi.width = patch_size.width;
+ roi.height = patch_size.height;
+
+ for( y = 0; y < size.height; y++ )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ double result;
+
+ roi.xOffset = x;
+ roi.yOffset = y;
+
+ CV_CALL( cvCalcHist( img, model ));
+
+ CV_CALL( cvNormalizeHist( model, norm_factor ));
+ CV_CALL( result = cvCompareHist( model, hist, method ));
+ CV_MAT_ELEM( *dstmat, float, y, x ) = (float)result;
+ }
+ }
+
+ __END__;
+
+ cvReleaseHist( &model );
+}
+
+
+// Calculates Bayes probabilistic histograms
+CV_IMPL void
+cvCalcBayesianProb( CvHistogram** src, int count, CvHistogram** dst )
+{
+ CV_FUNCNAME( "cvCalcBayesianProb" );
+
+ __BEGIN__;
+
+ int i;
+
+ if( !src || !dst )
+ CV_ERROR( CV_StsNullPtr, "NULL histogram array pointer" );
+
+ if( count < 2 )
+ CV_ERROR( CV_StsOutOfRange, "Too small number of histograms" );
+
+ for( i = 0; i < count; i++ )
+ {
+ if( !CV_IS_HIST(src[i]) || !CV_IS_HIST(dst[i]) )
+ CV_ERROR( CV_StsBadArg, "Invalid histogram header" );
+
+ if( !CV_IS_MATND(src[i]->bins) || !CV_IS_MATND(dst[i]->bins) )
+ CV_ERROR( CV_StsBadArg, "The function supports dense histograms only" );
+ }
+
+ cvZero( dst[0]->bins );
+ // dst[0] = src[0] + ... + src[count-1]
+ for( i = 0; i < count; i++ )
+ CV_CALL( cvAdd( src[i]->bins, dst[0]->bins, dst[0]->bins ));
+
+ CV_CALL( cvDiv( 0, dst[0]->bins, dst[0]->bins ));
+
+ // dst[i] = src[i]*(1/dst[0])
+ for( i = count - 1; i >= 0; i-- )
+ CV_CALL( cvMul( src[i]->bins, dst[0]->bins, dst[i]->bins ));
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvCalcProbDensity( const CvHistogram* hist, const CvHistogram* hist_mask,
+ CvHistogram* hist_dens, double scale )
+{
+ CV_FUNCNAME( "cvCalcProbDensity" );
+
+ __BEGIN__;
+
+ if( scale <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "scale must be positive" );
+
+ if( !CV_IS_HIST(hist) || !CV_IS_HIST(hist_mask) || !CV_IS_HIST(hist_dens) )
+ CV_ERROR( CV_StsBadArg, "Invalid histogram pointer[s]" );
+
+ {
+ CvArr* arrs[] = { hist->bins, hist_mask->bins, hist_dens->bins };
+ CvMatND stubs[3];
+ CvNArrayIterator iterator;
+
+ CV_CALL( cvInitNArrayIterator( 3, arrs, 0, stubs, &iterator ));
+
+ if( CV_MAT_TYPE(iterator.hdr[0]->type) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "All histograms must have 32fC1 type" );
+
+ do
+ {
+ const float* srcdata = (const float*)(iterator.ptr[0]);
+ const float* maskdata = (const float*)(iterator.ptr[1]);
+ float* dstdata = (float*)(iterator.ptr[2]);
+ int i;
+
+ for( i = 0; i < iterator.size.width; i++ )
+ {
+ float s = srcdata[i];
+ float m = maskdata[i];
+ if( s > FLT_EPSILON )
+ if( m <= s )
+ dstdata[i] = (float)(m*scale/s);
+ else
+ dstdata[i] = (float)scale;
+ else
+ dstdata[i] = (float)0;
+ }
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+
+ __END__;
+}
+
+
+CV_IMPL void cvEqualizeHist( const CvArr* src, CvArr* dst )
+{
+ CvHistogram* hist = 0;
+ CvMat* lut = 0;
+
+ CV_FUNCNAME( "cvEqualizeHist" );
+
+ __BEGIN__;
+
+ int i, hist_sz = 256;
+ CvSize img_sz;
+ float scale;
+ float* h;
+ int sum = 0;
+ int type;
+
+ CV_CALL( type = cvGetElemType( src ));
+ if( type != CV_8UC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Only 8uC1 images are supported" );
+
+ CV_CALL( hist = cvCreateHist( 1, &hist_sz, CV_HIST_ARRAY ));
+ CV_CALL( lut = cvCreateMat( 1, 256, CV_8UC1 ));
+ CV_CALL( cvCalcArrHist( (CvArr**)&src, hist ));
+ CV_CALL( img_sz = cvGetSize( src ));
+ scale = 255.f/(img_sz.width*img_sz.height);
+ h = (float*)cvPtr1D( hist->bins, 0 );
+
+ for( i = 0; i < hist_sz; i++ )
+ {
+ sum += cvRound(h[i]);
+ lut->data.ptr[i] = (uchar)cvRound(sum*scale);
+ }
+
+ lut->data.ptr[0] = 0;
+ CV_CALL( cvLUT( src, dst, lut ));
+
+ __END__;
+
+ cvReleaseHist(&hist);
+ cvReleaseMat(&lut);
+}
+
+/* Implementation of RTTI and Generic Functions for CvHistogram */
+#define CV_TYPE_NAME_HIST "opencv-hist"
+
+static int icvIsHist( const void * ptr ){
+ return CV_IS_HIST( ((CvHistogram*)ptr) );
+}
+
+static CvHistogram * icvCloneHist( const CvHistogram * src ){
+ CvHistogram * dst=NULL;
+ cvCopyHist(src, &dst);
+ return dst;
+}
+
+static void *icvReadHist( CvFileStorage * fs, CvFileNode * node ){
+ CvHistogram * h = 0;
+ int is_uniform = 0;
+ int have_ranges = 0;
+
+ CV_FUNCNAME("icvReadHist");
+ __BEGIN__;
+
+ CV_CALL( h = (CvHistogram *) cvAlloc( sizeof(CvHistogram) ));
+
+ is_uniform = cvReadIntByName( fs, node, "is_uniform", 0 );
+ have_ranges = cvReadIntByName( fs, node, "have_ranges", 0);
+ h->type = CV_HIST_MAGIC_VAL |
+ (is_uniform ? CV_HIST_UNIFORM_FLAG : 0) |
+ (have_ranges ? CV_HIST_RANGES_FLAG : 0);
+
+ if(is_uniform){
+ // read histogram bins
+ CvMatND * mat = (CvMatND *) cvReadByName( fs, node, "mat" );
+ int sizes[CV_MAX_DIM];
+ int i;
+ if(!CV_IS_MATND(mat)){
+ CV_ERROR( CV_StsError, "Expected CvMatND");
+ }
+ for(i=0; i<mat->dims; i++){
+ sizes[i] = mat->dim[i].size;
+ }
+
+ cvInitMatNDHeader( &(h->mat), mat->dims, sizes, mat->type, mat->data.ptr );
+ h->bins = &(h->mat);
+
+ // take ownership of refcount pointer as well
+ h->mat.refcount = mat->refcount;
+
+ // increase refcount so freeing temp header doesn't free data
+ cvIncRefData( mat );
+
+ // free temporary header
+ cvReleaseMatND( &mat );
+ }
+ else{
+ h->bins = cvReadByName( fs, node, "bins" );
+ if(!CV_IS_SPARSE_MAT(h->bins)){
+ CV_ERROR( CV_StsError, "Unknown Histogram type");
+ }
+ }
+
+ // read thresholds
+ if(have_ranges){
+ int i;
+ int dims;
+ int size[CV_MAX_DIM];
+ int total = 0;
+ CvSeqReader reader;
+ CvFileNode * thresh_node;
+
+ CV_CALL( dims = cvGetDims( h->bins, size ));
+ for( i = 0; i < dims; i++ ){
+ total += size[i]+1;
+ }
+
+ thresh_node = cvGetFileNodeByName( fs, node, "thresh" );
+ if(!thresh_node){
+ CV_ERROR( CV_StsError, "'thresh' node is missing");
+ }
+ cvStartReadRawData( fs, thresh_node, &reader );
+
+ if(is_uniform){
+ for(i=0; i<dims; i++){
+ cvReadRawDataSlice( fs, &reader, 2, h->thresh[i], "f" );
+ }
+ h->thresh2 = NULL;
+ }
+ else{
+ float* dim_ranges;
+ CV_CALL( h->thresh2 = (float**)cvAlloc(
+ dims*sizeof(h->thresh2[0])+
+ total*sizeof(h->thresh2[0][0])));
+ dim_ranges = (float*)(h->thresh2 + dims);
+ for(i=0; i < dims; i++){
+ h->thresh2[i] = dim_ranges;
+ cvReadRawDataSlice( fs, &reader, size[i]+1, dim_ranges, "f" );
+ dim_ranges += size[i] + 1;
+ }
+ }
+
+ }
+
+ __END__;
+
+ return h;
+}
+
+static void icvWriteHist( CvFileStorage* fs, const char* name, const void* struct_ptr,
+ CvAttrList /*attributes*/ ){
+ const CvHistogram * hist = (const CvHistogram *) struct_ptr;
+ int sizes[CV_MAX_DIM];
+ int dims;
+ int i;
+ int is_uniform, have_ranges;
+
+ CV_FUNCNAME("icvWriteHist");
+ __BEGIN__;
+
+ cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_HIST );
+
+ is_uniform = (CV_IS_UNIFORM_HIST(hist) ? 1 : 0);
+ have_ranges = (hist->type & CV_HIST_RANGES_FLAG ? 1 : 0);
+
+ cvWriteInt( fs, "is_uniform", is_uniform );
+ cvWriteInt( fs, "have_ranges", have_ranges );
+ if(CV_IS_UNIFORM_HIST(hist)){
+ cvWrite( fs, "mat", &(hist->mat) );
+ }
+ else if(CV_IS_SPARSE_HIST(hist)){
+ cvWrite( fs, "bins", hist->bins );
+ }
+ else{
+ CV_ERROR( CV_StsError, "Unknown Histogram Type" );
+ }
+
+ // write thresholds
+ if(have_ranges){
+ dims = cvGetDims( hist->bins, sizes );
+ cvStartWriteStruct( fs, "thresh", CV_NODE_SEQ + CV_NODE_FLOW );
+ if(is_uniform){
+ for(i=0; i<dims; i++){
+ cvWriteRawData( fs, hist->thresh[i], 2, "f" );
+ }
+ }
+ else{
+ for(i=0; i<dims; i++){
+ cvWriteRawData( fs, hist->thresh2[i], sizes[i]+1, "f" );
+ }
+ }
+ cvEndWriteStruct( fs );
+ }
+
+ cvEndWriteStruct( fs );
+ __END__;
+}
+
+
+CvType hist_type( CV_TYPE_NAME_HIST, icvIsHist, (CvReleaseFunc)cvReleaseHist,
+ icvReadHist, icvWriteHist, (CvCloneFunc)icvCloneHist );
+
+/* End of file. */
+
diff --git a/cv/src/cvhough.cpp b/cv/src/cvhough.cpp
new file mode 100644
index 0000000..ea2d4f2
--- /dev/null
+++ b/cv/src/cvhough.cpp
@@ -0,0 +1,1161 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+#include "_cvlist.h"
+
+#define halfPi ((float)(CV_PI*0.5))
+#define Pi ((float)CV_PI)
+#define a0 0 /*-4.172325e-7f*/ /*(-(float)0x7)/((float)0x1000000); */
+#define a1 1.000025f /*((float)0x1922253)/((float)0x1000000)*2/Pi; */
+#define a2 -2.652905e-4f /*(-(float)0x2ae6)/((float)0x1000000)*4/(Pi*Pi); */
+#define a3 -0.165624f /*(-(float)0xa45511)/((float)0x1000000)*8/(Pi*Pi*Pi); */
+#define a4 -1.964532e-3f /*(-(float)0x30fd3)/((float)0x1000000)*16/(Pi*Pi*Pi*Pi); */
+#define a5 1.02575e-2f /*((float)0x191cac)/((float)0x1000000)*32/(Pi*Pi*Pi*Pi*Pi); */
+#define a6 -9.580378e-4f /*(-(float)0x3af27)/((float)0x1000000)*64/(Pi*Pi*Pi*Pi*Pi*Pi); */
+
+#define _sin(x) ((((((a6*(x) + a5)*(x) + a4)*(x) + a3)*(x) + a2)*(x) + a1)*(x) + a0)
+#define _cos(x) _sin(halfPi - (x))
+
+/****************************************************************************************\
+* Classical Hough Transform *
+\****************************************************************************************/
+
+typedef struct CvLinePolar
+{
+ float rho;
+ float angle;
+}
+CvLinePolar;
+
+/*=====================================================================================*/
+
+#define hough_cmp_gt(l1,l2) (aux[l1] > aux[l2])
+
+static CV_IMPLEMENT_QSORT_EX( icvHoughSortDescent32s, int, hough_cmp_gt, const int* )
+
+/*
+Here image is an input raster;
+step is it's step; size characterizes it's ROI;
+rho and theta are discretization steps (in pixels and radians correspondingly).
+threshold is the minimum number of pixels in the feature for it
+to be a candidate for line. lines is the output
+array of (rho, theta) pairs. linesMax is the buffer size (number of pairs).
+Functions return the actual number of found lines.
+*/
+static void
+icvHoughLinesStandard( const CvMat* img, float rho, float theta,
+ int threshold, CvSeq *lines, int linesMax )
+{
+ int *accum = 0;
+ int *sort_buf=0;
+ float *tabSin = 0;
+ float *tabCos = 0;
+
+ CV_FUNCNAME( "icvHoughLinesStandard" );
+
+ __BEGIN__;
+
+ const uchar* image;
+ int step, width, height;
+ int numangle, numrho;
+ int total = 0;
+ float ang;
+ int r, n;
+ int i, j;
+ float irho = 1 / rho;
+ double scale;
+
+ CV_ASSERT( CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1 );
+
+ image = img->data.ptr;
+ step = img->step;
+ width = img->cols;
+ height = img->rows;
+
+ numangle = cvRound(CV_PI / theta);
+ numrho = cvRound(((width + height) * 2 + 1) / rho);
+
+ CV_CALL( accum = (int*)cvAlloc( sizeof(accum[0]) * (numangle+2) * (numrho+2) ));
+ CV_CALL( sort_buf = (int*)cvAlloc( sizeof(accum[0]) * numangle * numrho ));
+ CV_CALL( tabSin = (float*)cvAlloc( sizeof(tabSin[0]) * numangle ));
+ CV_CALL( tabCos = (float*)cvAlloc( sizeof(tabCos[0]) * numangle ));
+ memset( accum, 0, sizeof(accum[0]) * (numangle+2) * (numrho+2) );
+
+ for( ang = 0, n = 0; n < numangle; ang += theta, n++ )
+ {
+ tabSin[n] = (float)(sin(ang) * irho);
+ tabCos[n] = (float)(cos(ang) * irho);
+ }
+
+ // stage 1. fill accumulator
+ for( i = 0; i < height; i++ )
+ for( j = 0; j < width; j++ )
+ {
+ if( image[i * step + j] != 0 )
+ for( n = 0; n < numangle; n++ )
+ {
+ r = cvRound( j * tabCos[n] + i * tabSin[n] );
+ r += (numrho - 1) / 2;
+ accum[(n+1) * (numrho+2) + r+1]++;
+ }
+ }
+
+ // stage 2. find local maximums
+ for( r = 0; r < numrho; r++ )
+ for( n = 0; n < numangle; n++ )
+ {
+ int base = (n+1) * (numrho+2) + r+1;
+ if( accum[base] > threshold &&
+ accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] &&
+ accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2] )
+ sort_buf[total++] = base;
+ }
+
+ // stage 3. sort the detected lines by accumulator value
+ icvHoughSortDescent32s( sort_buf, total, accum );
+
+ // stage 4. store the first min(total,linesMax) lines to the output buffer
+ linesMax = MIN(linesMax, total);
+ scale = 1./(numrho+2);
+ for( i = 0; i < linesMax; i++ )
+ {
+ CvLinePolar line;
+ int idx = sort_buf[i];
+ int n = cvFloor(idx*scale) - 1;
+ int r = idx - (n+1)*(numrho+2) - 1;
+ line.rho = (r - (numrho - 1)*0.5f) * rho;
+ line.angle = n * theta;
+ cvSeqPush( lines, &line );
+ }
+
+ __END__;
+
+ cvFree( &sort_buf );
+ cvFree( &tabSin );
+ cvFree( &tabCos );
+ cvFree( &accum );
+}
+
+
+/****************************************************************************************\
+* Multi-Scale variant of Classical Hough Transform *
+\****************************************************************************************/
+
+#if defined _MSC_VER && _MSC_VER >= 1200
+#pragma warning( disable: 4714 )
+#endif
+
+//DECLARE_AND_IMPLEMENT_LIST( _index, h_ );
+IMPLEMENT_LIST( _index, h_ )
+
+static void
+icvHoughLinesSDiv( const CvMat* img,
+ float rho, float theta, int threshold,
+ int srn, int stn,
+ CvSeq* lines, int linesMax )
+{
+ uchar *caccum = 0;
+ uchar *buffer = 0;
+ float *sinTable = 0;
+ int *x = 0;
+ int *y = 0;
+ _CVLIST *list = 0;
+
+ CV_FUNCNAME( "icvHoughLinesSDiv" );
+
+ __BEGIN__;
+
+#define _POINT(row, column)\
+ (image_src[(row)*step+(column)])
+
+ uchar *mcaccum = 0;
+ int rn, tn; /* number of rho and theta discrete values */
+ int index, i;
+ int ri, ti, ti1, ti0;
+ int row, col;
+ float r, t; /* Current rho and theta */
+ float rv; /* Some temporary rho value */
+ float irho;
+ float itheta;
+ float srho, stheta;
+ float isrho, istheta;
+
+ const uchar* image_src;
+ int w, h, step;
+ int fn = 0;
+ float xc, yc;
+
+ const float d2r = (float)(Pi / 180);
+ int sfn = srn * stn;
+ int fi;
+ int count;
+ int cmax = 0;
+
+ CVPOS pos;
+ _index *pindex;
+ _index vi;
+
+ CV_ASSERT( CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1 );
+ CV_ASSERT( linesMax > 0 && rho > 0 && theta > 0 );
+
+ threshold = MIN( threshold, 255 );
+
+ image_src = img->data.ptr;
+ step = img->step;
+ w = img->cols;
+ h = img->rows;
+
+ irho = 1 / rho;
+ itheta = 1 / theta;
+ srho = rho / srn;
+ stheta = theta / stn;
+ isrho = 1 / srho;
+ istheta = 1 / stheta;
+
+ rn = cvFloor( sqrt( (double)w * w + (double)h * h ) * irho );
+ tn = cvFloor( 2 * Pi * itheta );
+
+ list = h_create_list__index( linesMax < 1000 ? linesMax : 1000 );
+ vi.value = threshold;
+ vi.rho = -1;
+ h_add_head__index( list, &vi );
+
+ /* Precalculating sin */
+ CV_CALL( sinTable = (float*)cvAlloc( 5 * tn * stn * sizeof( float )));
+
+ for( index = 0; index < 5 * tn * stn; index++ )
+ {
+ sinTable[index] = (float)cos( stheta * index * 0.2f );
+ }
+
+ CV_CALL( caccum = (uchar*)cvAlloc( rn * tn * sizeof( caccum[0] )));
+ memset( caccum, 0, rn * tn * sizeof( caccum[0] ));
+
+ /* Counting all feature pixels */
+ for( row = 0; row < h; row++ )
+ for( col = 0; col < w; col++ )
+ fn += _POINT( row, col ) != 0;
+
+ CV_CALL( x = (int*)cvAlloc( fn * sizeof(x[0])));
+ CV_CALL( y = (int*)cvAlloc( fn * sizeof(y[0])));
+
+ /* Full Hough Transform (it's accumulator update part) */
+ fi = 0;
+ for( row = 0; row < h; row++ )
+ {
+ for( col = 0; col < w; col++ )
+ {
+ if( _POINT( row, col ))
+ {
+ int halftn;
+ float r0;
+ float scale_factor;
+ int iprev = -1;
+ float phi, phi1;
+ float theta_it; /* Value of theta for iterating */
+
+ /* Remember the feature point */
+ x[fi] = col;
+ y[fi] = row;
+ fi++;
+
+ yc = (float) row + 0.5f;
+ xc = (float) col + 0.5f;
+
+ /* Update the accumulator */
+ t = (float) fabs( cvFastArctan( yc, xc ) * d2r );
+ r = (float) sqrt( (double)xc * xc + (double)yc * yc );
+ r0 = r * irho;
+ ti0 = cvFloor( (t + Pi / 2) * itheta );
+
+ caccum[ti0]++;
+
+ theta_it = rho / r;
+ theta_it = theta_it < theta ? theta_it : theta;
+ scale_factor = theta_it * itheta;
+ halftn = cvFloor( Pi / theta_it );
+ for( ti1 = 1, phi = theta_it - halfPi, phi1 = (theta_it + t) * itheta;
+ ti1 < halftn; ti1++, phi += theta_it, phi1 += scale_factor )
+ {
+ rv = r0 * _cos( phi );
+ i = cvFloor( rv ) * tn;
+ i += cvFloor( phi1 );
+ assert( i >= 0 );
+ assert( i < rn * tn );
+ caccum[i] = (uchar) (caccum[i] + ((i ^ iprev) != 0));
+ iprev = i;
+ if( cmax < caccum[i] )
+ cmax = caccum[i];
+ }
+ }
+ }
+ }
+
+ /* Starting additional analysis */
+ count = 0;
+ for( ri = 0; ri < rn; ri++ )
+ {
+ for( ti = 0; ti < tn; ti++ )
+ {
+ if( caccum[ri * tn + ti > threshold] )
+ {
+ count++;
+ }
+ }
+ }
+
+ if( count * 100 > rn * tn )
+ {
+ icvHoughLinesStandard( img, rho, theta, threshold, lines, linesMax );
+ EXIT;
+ }
+
+ CV_CALL( buffer = (uchar *) cvAlloc(srn * stn + 2));
+ mcaccum = buffer + 1;
+
+ count = 0;
+ for( ri = 0; ri < rn; ri++ )
+ {
+ for( ti = 0; ti < tn; ti++ )
+ {
+ if( caccum[ri * tn + ti] > threshold )
+ {
+ count++;
+ memset( mcaccum, 0, sfn * sizeof( uchar ));
+
+ for( index = 0; index < fn; index++ )
+ {
+ int ti2;
+ float r0;
+
+ yc = (float) y[index] + 0.5f;
+ xc = (float) x[index] + 0.5f;
+
+ /* Update the accumulator */
+ t = (float) fabs( cvFastArctan( yc, xc ) * d2r );
+ r = (float) sqrt( (double)xc * xc + (double)yc * yc ) * isrho;
+ ti0 = cvFloor( (t + Pi * 0.5f) * istheta );
+ ti2 = (ti * stn - ti0) * 5;
+ r0 = (float) ri *srn;
+
+ for( ti1 = 0 /*, phi = ti*theta - Pi/2 - t */ ; ti1 < stn; ti1++, ti2 += 5
+ /*phi += stheta */ )
+ {
+ /*rv = r*_cos(phi) - r0; */
+ rv = r * sinTable[(int) (abs( ti2 ))] - r0;
+ i = cvFloor( rv ) * stn + ti1;
+
+ i = CV_IMAX( i, -1 );
+ i = CV_IMIN( i, sfn );
+ mcaccum[i]++;
+ assert( i >= -1 );
+ assert( i <= sfn );
+ }
+ }
+
+ /* Find peaks in maccum... */
+ for( index = 0; index < sfn; index++ )
+ {
+ i = 0;
+ pos = h_get_tail_pos__index( list );
+ if( h_get_prev__index( &pos )->value < mcaccum[index] )
+ {
+ vi.value = mcaccum[index];
+ vi.rho = index / stn * srho + ri * rho;
+ vi.theta = index % stn * stheta + ti * theta - halfPi;
+ while( h_is_pos__index( pos ))
+ {
+ if( h_get__index( pos )->value > mcaccum[index] )
+ {
+ h_insert_after__index( list, pos, &vi );
+ if( h_get_count__index( list ) > linesMax )
+ {
+ h_remove_tail__index( list );
+ }
+ break;
+ }
+ h_get_prev__index( &pos );
+ }
+ if( !h_is_pos__index( pos ))
+ {
+ h_add_head__index( list, &vi );
+ if( h_get_count__index( list ) > linesMax )
+ {
+ h_remove_tail__index( list );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ pos = h_get_head_pos__index( list );
+ if( h_get_count__index( list ) == 1 )
+ {
+ if( h_get__index( pos )->rho < 0 )
+ {
+ h_clear_list__index( list );
+ }
+ }
+ else
+ {
+ while( h_is_pos__index( pos ))
+ {
+ CvLinePolar line;
+ pindex = h_get__index( pos );
+ if( pindex->rho < 0 )
+ {
+ /* This should be the last element... */
+ h_get_next__index( &pos );
+ assert( !h_is_pos__index( pos ));
+ break;
+ }
+ line.rho = pindex->rho;
+ line.angle = pindex->theta;
+ cvSeqPush( lines, &line );
+
+ if( lines->total >= linesMax )
+ EXIT;
+ h_get_next__index( &pos );
+ }
+ }
+
+ __END__;
+
+ h_destroy_list__index( list );
+ cvFree( &sinTable );
+ cvFree( &x );
+ cvFree( &y );
+ cvFree( &caccum );
+ cvFree( &buffer );
+}
+
+
+/****************************************************************************************\
+* Probabilistic Hough Transform *
+\****************************************************************************************/
+
+#if defined WIN64 && defined EM64T && _MSC_VER == 1400 && !defined CV_ICC
+#pragma optimize("",off)
+#endif
+
+static void
+icvHoughLinesProbabalistic( CvMat* image,
+ float rho, float theta, int threshold,
+ int lineLength, int lineGap,
+ CvSeq *lines, int linesMax )
+{
+ CvMat* accum = 0;
+ CvMat* mask = 0;
+ CvMat* trigtab = 0;
+ CvMemStorage* storage = 0;
+
+ CV_FUNCNAME( "icvHoughLinesProbalistic" );
+
+ __BEGIN__;
+
+ CvSeq* seq;
+ CvSeqWriter writer;
+ int width, height;
+ int numangle, numrho;
+ float ang;
+ int r, n, count;
+ CvPoint pt;
+ float irho = 1 / rho;
+ CvRNG rng = cvRNG(-1);
+ const float* ttab;
+ uchar* mdata0;
+
+ CV_ASSERT( CV_IS_MAT(image) && CV_MAT_TYPE(image->type) == CV_8UC1 );
+
+ width = image->cols;
+ height = image->rows;
+
+ numangle = cvRound(CV_PI / theta);
+ numrho = cvRound(((width + height) * 2 + 1) / rho);
+
+ CV_CALL( accum = cvCreateMat( numangle, numrho, CV_32SC1 ));
+ CV_CALL( mask = cvCreateMat( height, width, CV_8UC1 ));
+ CV_CALL( trigtab = cvCreateMat( 1, numangle, CV_32FC2 ));
+ cvZero( accum );
+
+ CV_CALL( storage = cvCreateMemStorage(0) );
+
+ for( ang = 0, n = 0; n < numangle; ang += theta, n++ )
+ {
+ trigtab->data.fl[n*2] = (float)(cos(ang) * irho);
+ trigtab->data.fl[n*2+1] = (float)(sin(ang) * irho);
+ }
+ ttab = trigtab->data.fl;
+ mdata0 = mask->data.ptr;
+
+ CV_CALL( cvStartWriteSeq( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), storage, &writer ));
+
+ // stage 1. collect non-zero image points
+ for( pt.y = 0, count = 0; pt.y < height; pt.y++ )
+ {
+ const uchar* data = image->data.ptr + pt.y*image->step;
+ uchar* mdata = mdata0 + pt.y*width;
+ for( pt.x = 0; pt.x < width; pt.x++ )
+ {
+ if( data[pt.x] )
+ {
+ mdata[pt.x] = (uchar)1;
+ CV_WRITE_SEQ_ELEM( pt, writer );
+ }
+ else
+ mdata[pt.x] = 0;
+ }
+ }
+
+ seq = cvEndWriteSeq( &writer );
+ count = seq->total;
+
+ // stage 2. process all the points in random order
+ for( ; count > 0; count-- )
+ {
+ // choose random point out of the remaining ones
+ int idx = cvRandInt(&rng) % count;
+ int max_val = threshold-1, max_n = 0;
+ CvPoint* pt = (CvPoint*)cvGetSeqElem( seq, idx );
+ CvPoint line_end[2] = {{0,0}, {0,0}};
+ float a, b;
+ int* adata = accum->data.i;
+ int i, j, k, x0, y0, dx0, dy0, xflag;
+ int good_line;
+ const int shift = 16;
+
+ i = pt->y;
+ j = pt->x;
+
+ // "remove" it by overriding it with the last element
+ *pt = *(CvPoint*)cvGetSeqElem( seq, count-1 );
+
+ // check if it has been excluded already (i.e. belongs to some other line)
+ if( !mdata0[i*width + j] )
+ continue;
+
+ // update accumulator, find the most probable line
+ for( n = 0; n < numangle; n++, adata += numrho )
+ {
+ r = cvRound( j * ttab[n*2] + i * ttab[n*2+1] );
+ r += (numrho - 1) / 2;
+ int val = ++adata[r];
+ if( max_val < val )
+ {
+ max_val = val;
+ max_n = n;
+ }
+ }
+
+ // if it is too "weak" candidate, continue with another point
+ if( max_val < threshold )
+ continue;
+
+ // from the current point walk in each direction
+ // along the found line and extract the line segment
+ a = -ttab[max_n*2+1];
+ b = ttab[max_n*2];
+ x0 = j;
+ y0 = i;
+ if( fabs(a) > fabs(b) )
+ {
+ xflag = 1;
+ dx0 = a > 0 ? 1 : -1;
+ dy0 = cvRound( b*(1 << shift)/fabs(a) );
+ y0 = (y0 << shift) + (1 << (shift-1));
+ }
+ else
+ {
+ xflag = 0;
+ dy0 = b > 0 ? 1 : -1;
+ dx0 = cvRound( a*(1 << shift)/fabs(b) );
+ x0 = (x0 << shift) + (1 << (shift-1));
+ }
+
+ for( k = 0; k < 2; k++ )
+ {
+ int gap = 0, x = x0, y = y0, dx = dx0, dy = dy0;
+
+ if( k > 0 )
+ dx = -dx, dy = -dy;
+
+ // walk along the line using fixed-point arithmetics,
+ // stop at the image border or in case of too big gap
+ for( ;; x += dx, y += dy )
+ {
+ uchar* mdata;
+ int i1, j1;
+
+ if( xflag )
+ {
+ j1 = x;
+ i1 = y >> shift;
+ }
+ else
+ {
+ j1 = x >> shift;
+ i1 = y;
+ }
+
+ if( j1 < 0 || j1 >= width || i1 < 0 || i1 >= height )
+ break;
+
+ mdata = mdata0 + i1*width + j1;
+
+ // for each non-zero point:
+ // update line end,
+ // clear the mask element
+ // reset the gap
+ if( *mdata )
+ {
+ gap = 0;
+ line_end[k].y = i1;
+ line_end[k].x = j1;
+ }
+ else if( ++gap > lineGap )
+ break;
+ }
+ }
+
+ good_line = abs(line_end[1].x - line_end[0].x) >= lineLength ||
+ abs(line_end[1].y - line_end[0].y) >= lineLength;
+
+ for( k = 0; k < 2; k++ )
+ {
+ int x = x0, y = y0, dx = dx0, dy = dy0;
+
+ if( k > 0 )
+ dx = -dx, dy = -dy;
+
+ // walk along the line using fixed-point arithmetics,
+ // stop at the image border or in case of too big gap
+ for( ;; x += dx, y += dy )
+ {
+ uchar* mdata;
+ int i1, j1;
+
+ if( xflag )
+ {
+ j1 = x;
+ i1 = y >> shift;
+ }
+ else
+ {
+ j1 = x >> shift;
+ i1 = y;
+ }
+
+ mdata = mdata0 + i1*width + j1;
+
+ // for each non-zero point:
+ // update line end,
+ // clear the mask element
+ // reset the gap
+ if( *mdata )
+ {
+ if( good_line )
+ {
+ adata = accum->data.i;
+ for( n = 0; n < numangle; n++, adata += numrho )
+ {
+ r = cvRound( j1 * ttab[n*2] + i1 * ttab[n*2+1] );
+ r += (numrho - 1) / 2;
+ adata[r]--;
+ }
+ }
+ *mdata = 0;
+ }
+
+ if( i1 == line_end[k].y && j1 == line_end[k].x )
+ break;
+ }
+ }
+
+ if( good_line )
+ {
+ CvRect lr = { line_end[0].x, line_end[0].y, line_end[1].x, line_end[1].y };
+ cvSeqPush( lines, &lr );
+ if( lines->total >= linesMax )
+ EXIT;
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &accum );
+ cvReleaseMat( &mask );
+ cvReleaseMat( &trigtab );
+ cvReleaseMemStorage( &storage );
+}
+
+
+#if defined WIN64 && defined EM64T && _MSC_VER == 1400 && !defined CV_ICC
+#pragma optimize("",on)
+#endif
+
+
+/* Wrapper function for standard hough transform */
+CV_IMPL CvSeq*
+cvHoughLines2( CvArr* src_image, void* lineStorage, int method,
+ double rho, double theta, int threshold,
+ double param1, double param2 )
+{
+ CvSeq* result = 0;
+
+ CV_FUNCNAME( "cvHoughLines" );
+
+ __BEGIN__;
+
+ CvMat stub, *img = (CvMat*)src_image;
+ CvMat* mat = 0;
+ CvSeq* lines = 0;
+ CvSeq lines_header;
+ CvSeqBlock lines_block;
+ int lineType, elemSize;
+ int linesMax = INT_MAX;
+ int iparam1, iparam2;
+
+ CV_CALL( img = cvGetMat( img, &stub ));
+
+ if( !CV_IS_MASK_ARR(img))
+ CV_ERROR( CV_StsBadArg, "The source image must be 8-bit, single-channel" );
+
+ if( !lineStorage )
+ CV_ERROR( CV_StsNullPtr, "NULL destination" );
+
+ if( rho <= 0 || theta <= 0 || threshold <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "rho, theta and threshold must be positive" );
+
+ if( method != CV_HOUGH_PROBABILISTIC )
+ {
+ lineType = CV_32FC2;
+ elemSize = sizeof(float)*2;
+ }
+ else
+ {
+ lineType = CV_32SC4;
+ elemSize = sizeof(int)*4;
+ }
+
+ if( CV_IS_STORAGE( lineStorage ))
+ {
+ CV_CALL( lines = cvCreateSeq( lineType, sizeof(CvSeq), elemSize, (CvMemStorage*)lineStorage ));
+ }
+ else if( CV_IS_MAT( lineStorage ))
+ {
+ mat = (CvMat*)lineStorage;
+
+ if( !CV_IS_MAT_CONT( mat->type ) || (mat->rows != 1 && mat->cols != 1) )
+ CV_ERROR( CV_StsBadArg,
+ "The destination matrix should be continuous and have a single row or a single column" );
+
+ if( CV_MAT_TYPE( mat->type ) != lineType )
+ CV_ERROR( CV_StsBadArg,
+ "The destination matrix data type is inappropriate, see the manual" );
+
+ CV_CALL( lines = cvMakeSeqHeaderForArray( lineType, sizeof(CvSeq), elemSize, mat->data.ptr,
+ mat->rows + mat->cols - 1, &lines_header, &lines_block ));
+ linesMax = lines->total;
+ CV_CALL( cvClearSeq( lines ));
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*" );
+ }
+
+ iparam1 = cvRound(param1);
+ iparam2 = cvRound(param2);
+
+ switch( method )
+ {
+ case CV_HOUGH_STANDARD:
+ CV_CALL( icvHoughLinesStandard( img, (float)rho,
+ (float)theta, threshold, lines, linesMax ));
+ break;
+ case CV_HOUGH_MULTI_SCALE:
+ CV_CALL( icvHoughLinesSDiv( img, (float)rho, (float)theta,
+ threshold, iparam1, iparam2, lines, linesMax ));
+ break;
+ case CV_HOUGH_PROBABILISTIC:
+ CV_CALL( icvHoughLinesProbabalistic( img, (float)rho, (float)theta,
+ threshold, iparam1, iparam2, lines, linesMax ));
+ break;
+ default:
+ CV_ERROR( CV_StsBadArg, "Unrecognized method id" );
+ }
+
+ if( mat )
+ {
+ if( mat->cols > mat->rows )
+ mat->cols = lines->total;
+ else
+ mat->rows = lines->total;
+ }
+ else
+ {
+ result = lines;
+ }
+
+ __END__;
+
+ return result;
+}
+
+
+/****************************************************************************************\
+* Circle Detection *
+\****************************************************************************************/
+
+static void
+icvHoughCirclesGradient( CvMat* img, float dp, float min_dist,
+ int min_radius, int max_radius,
+ int canny_threshold, int acc_threshold,
+ CvSeq* circles, int circles_max )
+{
+ const int SHIFT = 10, ONE = 1 << SHIFT, R_THRESH = 30;
+ CvMat *dx = 0, *dy = 0;
+ CvMat *edges = 0;
+ CvMat *accum = 0;
+ int* sort_buf = 0;
+ CvMat* dist_buf = 0;
+ CvMemStorage* storage = 0;
+
+ CV_FUNCNAME( "icvHoughCirclesGradient" );
+
+ __BEGIN__;
+
+ int x, y, i, j, center_count, nz_count;
+ int rows, cols, arows, acols;
+ int astep, *adata;
+ float* ddata;
+ CvSeq *nz, *centers;
+ float idp, dr;
+ CvSeqReader reader;
+
+ CV_CALL( edges = cvCreateMat( img->rows, img->cols, CV_8UC1 ));
+ CV_CALL( cvCanny( img, edges, MAX(canny_threshold/2,1), canny_threshold, 3 ));
+
+ CV_CALL( dx = cvCreateMat( img->rows, img->cols, CV_16SC1 ));
+ CV_CALL( dy = cvCreateMat( img->rows, img->cols, CV_16SC1 ));
+ CV_CALL( cvSobel( img, dx, 1, 0, 3 ));
+ CV_CALL( cvSobel( img, dy, 0, 1, 3 ));
+
+ if( dp < 1.f )
+ dp = 1.f;
+ idp = 1.f/dp;
+ CV_CALL( accum = cvCreateMat( cvCeil(img->rows*idp)+2, cvCeil(img->cols*idp)+2, CV_32SC1 ));
+ CV_CALL( cvZero(accum));
+
+ CV_CALL( storage = cvCreateMemStorage() );
+ CV_CALL( nz = cvCreateSeq( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), storage ));
+ CV_CALL( centers = cvCreateSeq( CV_32SC1, sizeof(CvSeq), sizeof(int), storage ));
+
+ rows = img->rows;
+ cols = img->cols;
+ arows = accum->rows - 2;
+ acols = accum->cols - 2;
+ adata = accum->data.i;
+ astep = accum->step/sizeof(adata[0]);
+
+ for( y = 0; y < rows; y++ )
+ {
+ const uchar* edges_row = edges->data.ptr + y*edges->step;
+ const short* dx_row = (const short*)(dx->data.ptr + y*dx->step);
+ const short* dy_row = (const short*)(dy->data.ptr + y*dy->step);
+
+ for( x = 0; x < cols; x++ )
+ {
+ float vx, vy;
+ int sx, sy, x0, y0, x1, y1, r, k;
+ CvPoint pt;
+
+ vx = dx_row[x];
+ vy = dy_row[x];
+
+ if( !edges_row[x] || (vx == 0 && vy == 0) )
+ continue;
+
+ if( fabs(vx) < fabs(vy) )
+ {
+ sx = cvRound(vx*ONE/fabs(vy));
+ sy = vy < 0 ? -ONE : ONE;
+ }
+ else
+ {
+ assert( vx != 0 );
+ sy = cvRound(vy*ONE/fabs(vx));
+ sx = vx < 0 ? -ONE : ONE;
+ }
+
+ x0 = cvRound((x*idp)*ONE) + ONE + (ONE/2);
+ y0 = cvRound((y*idp)*ONE) + ONE + (ONE/2);
+
+ for( k = 0; k < 2; k++ )
+ {
+ x0 += min_radius * sx;
+ y0 += min_radius * sy;
+
+ for( x1 = x0, y1 = y0, r = min_radius; r <= max_radius; x1 += sx, y1 += sy, r++ )
+ {
+ int x2 = x1 >> SHIFT, y2 = y1 >> SHIFT;
+ if( (unsigned)x2 >= (unsigned)acols ||
+ (unsigned)y2 >= (unsigned)arows )
+ break;
+ adata[y2*astep + x2]++;
+ }
+
+ x0 -= min_radius * sx;
+ y0 -= min_radius * sy;
+ sx = -sx; sy = -sy;
+ }
+
+ pt.x = x; pt.y = y;
+ cvSeqPush( nz, &pt );
+ }
+ }
+
+ nz_count = nz->total;
+ if( !nz_count )
+ EXIT;
+
+ for( y = 1; y < arows - 1; y++ )
+ {
+ for( x = 1; x < acols - 1; x++ )
+ {
+ int base = y*(acols+2) + x;
+ if( adata[base] > acc_threshold &&
+ adata[base] > adata[base-1] && adata[base] > adata[base+1] &&
+ adata[base] > adata[base-acols-2] && adata[base] > adata[base+acols+2] )
+ cvSeqPush(centers, &base);
+ }
+ }
+
+ center_count = centers->total;
+ if( !center_count )
+ EXIT;
+
+ CV_CALL( sort_buf = (int*)cvAlloc( MAX(center_count,nz_count)*sizeof(sort_buf[0]) ));
+ cvCvtSeqToArray( centers, sort_buf );
+
+ icvHoughSortDescent32s( sort_buf, center_count, adata );
+ cvClearSeq( centers );
+ cvSeqPushMulti( centers, sort_buf, center_count );
+
+ CV_CALL( dist_buf = cvCreateMat( 1, nz_count, CV_32FC1 ));
+ ddata = dist_buf->data.fl;
+
+ dr = dp;
+ min_dist = MAX( min_dist, dp );
+ min_dist *= min_dist;
+
+ for( i = 0; i < centers->total; i++ )
+ {
+ int ofs = *(int*)cvGetSeqElem( centers, i );
+ y = ofs/(acols+2) - 1;
+ x = ofs - (y+1)*(acols+2) - 1;
+ float cx = (float)(x*dp), cy = (float)(y*dp);
+ int start_idx = nz_count - 1;
+ float start_dist, dist_sum;
+ float r_best = 0, c[3];
+ int max_count = R_THRESH;
+
+ for( j = 0; j < circles->total; j++ )
+ {
+ float* c = (float*)cvGetSeqElem( circles, j );
+ if( (c[0] - cx)*(c[0] - cx) + (c[1] - cy)*(c[1] - cy) < min_dist )
+ break;
+ }
+
+ if( j < circles->total )
+ continue;
+
+ cvStartReadSeq( nz, &reader );
+ for( j = 0; j < nz_count; j++ )
+ {
+ CvPoint pt;
+ float _dx, _dy;
+ CV_READ_SEQ_ELEM( pt, reader );
+ _dx = cx - pt.x; _dy = cy - pt.y;
+ ddata[j] = _dx*_dx + _dy*_dy;
+ sort_buf[j] = j;
+ }
+
+ cvPow( dist_buf, dist_buf, 0.5 );
+ icvHoughSortDescent32s( sort_buf, nz_count, (int*)ddata );
+
+ dist_sum = start_dist = ddata[sort_buf[nz_count-1]];
+ for( j = nz_count - 2; j >= 0; j-- )
+ {
+ float d = ddata[sort_buf[j]];
+
+ if( d > max_radius )
+ break;
+
+ if( d - start_dist > dr )
+ {
+ float r_cur = ddata[sort_buf[(j + start_idx)/2]];
+ if( (start_idx - j)*r_best >= max_count*r_cur ||
+ (r_best < FLT_EPSILON && start_idx - j >= max_count) )
+ {
+ r_best = r_cur;
+ max_count = start_idx - j;
+ }
+ start_dist = d;
+ start_idx = j;
+ dist_sum = 0;
+ }
+ dist_sum += d;
+ }
+
+ if( max_count > R_THRESH )
+ {
+ c[0] = cx;
+ c[1] = cy;
+ c[2] = (float)r_best;
+ cvSeqPush( circles, c );
+ if( circles->total > circles_max )
+ EXIT;
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &dist_buf );
+ cvFree( &sort_buf );
+ cvReleaseMemStorage( &storage );
+ cvReleaseMat( &edges );
+ cvReleaseMat( &dx );
+ cvReleaseMat( &dy );
+ cvReleaseMat( &accum );
+}
+
+CV_IMPL CvSeq*
+cvHoughCircles( CvArr* src_image, void* circle_storage,
+ int method, double dp, double min_dist,
+ double param1, double param2,
+ int min_radius, int max_radius )
+{
+ CvSeq* result = 0;
+
+ CV_FUNCNAME( "cvHoughCircles" );
+
+ __BEGIN__;
+
+ CvMat stub, *img = (CvMat*)src_image;
+ CvMat* mat = 0;
+ CvSeq* circles = 0;
+ CvSeq circles_header;
+ CvSeqBlock circles_block;
+ int circles_max = INT_MAX;
+ int canny_threshold = cvRound(param1);
+ int acc_threshold = cvRound(param2);
+
+ CV_CALL( img = cvGetMat( img, &stub ));
+
+ if( !CV_IS_MASK_ARR(img))
+ CV_ERROR( CV_StsBadArg, "The source image must be 8-bit, single-channel" );
+
+ if( !circle_storage )
+ CV_ERROR( CV_StsNullPtr, "NULL destination" );
+
+ if( dp <= 0 || min_dist <= 0 || canny_threshold <= 0 || acc_threshold <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "dp, min_dist, canny_threshold and acc_threshold must be all positive numbers" );
+
+ min_radius = MAX( min_radius, 0 );
+ if( max_radius <= 0 )
+ max_radius = MAX( img->rows, img->cols );
+ else if( max_radius <= min_radius )
+ max_radius = min_radius + 2;
+
+ if( CV_IS_STORAGE( circle_storage ))
+ {
+ CV_CALL( circles = cvCreateSeq( CV_32FC3, sizeof(CvSeq),
+ sizeof(float)*3, (CvMemStorage*)circle_storage ));
+ }
+ else if( CV_IS_MAT( circle_storage ))
+ {
+ mat = (CvMat*)circle_storage;
+
+ if( !CV_IS_MAT_CONT( mat->type ) || (mat->rows != 1 && mat->cols != 1) ||
+ CV_MAT_TYPE(mat->type) != CV_32FC3 )
+ CV_ERROR( CV_StsBadArg,
+ "The destination matrix should be continuous and have a single row or a single column" );
+
+ CV_CALL( circles = cvMakeSeqHeaderForArray( CV_32FC3, sizeof(CvSeq), sizeof(float)*3,
+ mat->data.ptr, mat->rows + mat->cols - 1, &circles_header, &circles_block ));
+ circles_max = circles->total;
+ CV_CALL( cvClearSeq( circles ));
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*" );
+ }
+
+ switch( method )
+ {
+ case CV_HOUGH_GRADIENT:
+ CV_CALL( icvHoughCirclesGradient( img, (float)dp, (float)min_dist,
+ min_radius, max_radius, canny_threshold,
+ acc_threshold, circles, circles_max ));
+ break;
+ default:
+ CV_ERROR( CV_StsBadArg, "Unrecognized method id" );
+ }
+
+ if( mat )
+ {
+ if( mat->cols > mat->rows )
+ mat->cols = circles->total;
+ else
+ mat->rows = circles->total;
+ }
+ else
+ result = circles;
+
+ __END__;
+
+ return result;
+}
+
+/* End of file. */
diff --git a/cv/src/cvimgwarp.cpp b/cv/src/cvimgwarp.cpp
new file mode 100644
index 0000000..65c0d8f
--- /dev/null
+++ b/cv/src/cvimgwarp.cpp
@@ -0,0 +1,2272 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/* ////////////////////////////////////////////////////////////////////
+//
+// Geometrical transforms on images and matrices: rotation, zoom etc.
+//
+// */
+
+#include "_cv.h"
+
+
+/************** interpolation constants and tables ***************/
+
+#define ICV_WARP_MUL_ONE_8U(x) ((x) << ICV_WARP_SHIFT)
+#define ICV_WARP_DESCALE_8U(x) CV_DESCALE((x), ICV_WARP_SHIFT*2)
+#define ICV_WARP_CLIP_X(x) ((unsigned)(x) < (unsigned)ssize.width ? \
+ (x) : (x) < 0 ? 0 : ssize.width - 1)
+#define ICV_WARP_CLIP_Y(y) ((unsigned)(y) < (unsigned)ssize.height ? \
+ (y) : (y) < 0 ? 0 : ssize.height - 1)
+
+float icvLinearCoeffs[(ICV_LINEAR_TAB_SIZE+1)*2];
+
+void icvInitLinearCoeffTab()
+{
+ static int inittab = 0;
+ if( !inittab )
+ {
+ for( int i = 0; i <= ICV_LINEAR_TAB_SIZE; i++ )
+ {
+ float x = (float)i/ICV_LINEAR_TAB_SIZE;
+ icvLinearCoeffs[i*2] = x;
+ icvLinearCoeffs[i*2+1] = 1.f - x;
+ }
+
+ inittab = 1;
+ }
+}
+
+
+float icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE+1)*2];
+
+void icvInitCubicCoeffTab()
+{
+ static int inittab = 0;
+ if( !inittab )
+ {
+#if 0
+ // classical Mitchell-Netravali filter
+ const double B = 1./3;
+ const double C = 1./3;
+ const double p0 = (6 - 2*B)/6.;
+ const double p2 = (-18 + 12*B + 6*C)/6.;
+ const double p3 = (12 - 9*B - 6*C)/6.;
+ const double q0 = (8*B + 24*C)/6.;
+ const double q1 = (-12*B - 48*C)/6.;
+ const double q2 = (6*B + 30*C)/6.;
+ const double q3 = (-B - 6*C)/6.;
+
+ #define ICV_CUBIC_1(x) (((x)*p3 + p2)*(x)*(x) + p0)
+ #define ICV_CUBIC_2(x) ((((x)*q3 + q2)*(x) + q1)*(x) + q0)
+#else
+ // alternative "sharp" filter
+ const double A = -0.75;
+ #define ICV_CUBIC_1(x) (((A + 2)*(x) - (A + 3))*(x)*(x) + 1)
+ #define ICV_CUBIC_2(x) (((A*(x) - 5*A)*(x) + 8*A)*(x) - 4*A)
+#endif
+ for( int i = 0; i <= ICV_CUBIC_TAB_SIZE; i++ )
+ {
+ float x = (float)i/ICV_CUBIC_TAB_SIZE;
+ icvCubicCoeffs[i*2] = (float)ICV_CUBIC_1(x);
+ x += 1.f;
+ icvCubicCoeffs[i*2+1] = (float)ICV_CUBIC_2(x);
+ }
+
+ inittab = 1;
+ }
+}
+
+
+/****************************************************************************************\
+* Resize *
+\****************************************************************************************/
+
+static CvStatus CV_STDCALL
+icvResize_NN_8u_C1R( const uchar* src, int srcstep, CvSize ssize,
+ uchar* dst, int dststep, CvSize dsize, int pix_size )
+{
+ int* x_ofs = (int*)cvStackAlloc( dsize.width * sizeof(x_ofs[0]) );
+ int pix_size4 = pix_size / sizeof(int);
+ int x, y, t;
+
+ for( x = 0; x < dsize.width; x++ )
+ {
+ t = (ssize.width*x*2 + MIN(ssize.width, dsize.width) - 1)/(dsize.width*2);
+ t -= t >= ssize.width;
+ x_ofs[x] = t*pix_size;
+ }
+
+ for( y = 0; y < dsize.height; y++, dst += dststep )
+ {
+ const uchar* tsrc;
+ t = (ssize.height*y*2 + MIN(ssize.height, dsize.height) - 1)/(dsize.height*2);
+ t -= t >= ssize.height;
+ tsrc = src + srcstep*t;
+
+ switch( pix_size )
+ {
+ case 1:
+ for( x = 0; x <= dsize.width - 2; x += 2 )
+ {
+ uchar t0 = tsrc[x_ofs[x]];
+ uchar t1 = tsrc[x_ofs[x+1]];
+
+ dst[x] = t0;
+ dst[x+1] = t1;
+ }
+
+ for( ; x < dsize.width; x++ )
+ dst[x] = tsrc[x_ofs[x]];
+ break;
+ case 2:
+ for( x = 0; x < dsize.width; x++ )
+ *(ushort*)(dst + x*2) = *(ushort*)(tsrc + x_ofs[x]);
+ break;
+ case 3:
+ for( x = 0; x < dsize.width; x++ )
+ {
+ const uchar* _tsrc = tsrc + x_ofs[x];
+ dst[x*3] = _tsrc[0]; dst[x*3+1] = _tsrc[1]; dst[x*3+2] = _tsrc[2];
+ }
+ break;
+ case 4:
+ for( x = 0; x < dsize.width; x++ )
+ *(int*)(dst + x*4) = *(int*)(tsrc + x_ofs[x]);
+ break;
+ case 6:
+ for( x = 0; x < dsize.width; x++ )
+ {
+ const ushort* _tsrc = (const ushort*)(tsrc + x_ofs[x]);
+ ushort* _tdst = (ushort*)(dst + x*6);
+ _tdst[0] = _tsrc[0]; _tdst[1] = _tsrc[1]; _tdst[2] = _tsrc[2];
+ }
+ break;
+ default:
+ for( x = 0; x < dsize.width; x++ )
+ CV_MEMCPY_INT( dst + x*pix_size, tsrc + x_ofs[x], pix_size4 );
+ }
+ }
+
+ return CV_OK;
+}
+
+
+typedef struct CvResizeAlpha
+{
+ int idx;
+ union
+ {
+ float alpha;
+ int ialpha;
+ };
+}
+CvResizeAlpha;
+
+
+#define ICV_DEF_RESIZE_BILINEAR_FUNC( flavor, arrtype, worktype, alpha_field, \
+ mul_one_macro, descale_macro ) \
+static CvStatus CV_STDCALL \
+icvResize_Bilinear_##flavor##_CnR( const arrtype* src, int srcstep, CvSize ssize,\
+ arrtype* dst, int dststep, CvSize dsize, \
+ int cn, int xmax, \
+ const CvResizeAlpha* xofs, \
+ const CvResizeAlpha* yofs, \
+ worktype* buf0, worktype* buf1 ) \
+{ \
+ int prev_sy0 = -1, prev_sy1 = -1; \
+ int k, dx, dy; \
+ \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ dsize.width *= cn; \
+ xmax *= cn; \
+ \
+ for( dy = 0; dy < dsize.height; dy++, dst += dststep ) \
+ { \
+ worktype fy = yofs[dy].alpha_field, *swap_t; \
+ int sy0 = yofs[dy].idx, sy1 = sy0 + (fy > 0 && sy0 < ssize.height-1); \
+ \
+ if( sy0 == prev_sy0 && sy1 == prev_sy1 ) \
+ k = 2; \
+ else if( sy0 == prev_sy1 ) \
+ { \
+ CV_SWAP( buf0, buf1, swap_t ); \
+ k = 1; \
+ } \
+ else \
+ k = 0; \
+ \
+ for( ; k < 2; k++ ) \
+ { \
+ worktype* _buf = k == 0 ? buf0 : buf1; \
+ const arrtype* _src; \
+ int sy = k == 0 ? sy0 : sy1; \
+ if( k == 1 && sy1 == sy0 ) \
+ { \
+ memcpy( buf1, buf0, dsize.width*sizeof(buf0[0]) ); \
+ continue; \
+ } \
+ \
+ _src = src + sy*srcstep; \
+ for( dx = 0; dx < xmax; dx++ ) \
+ { \
+ int sx = xofs[dx].idx; \
+ worktype fx = xofs[dx].alpha_field; \
+ worktype t = _src[sx]; \
+ _buf[dx] = mul_one_macro(t) + fx*(_src[sx+cn] - t); \
+ } \
+ \
+ for( ; dx < dsize.width; dx++ ) \
+ _buf[dx] = mul_one_macro(_src[xofs[dx].idx]); \
+ } \
+ \
+ prev_sy0 = sy0; \
+ prev_sy1 = sy1; \
+ \
+ if( sy0 == sy1 ) \
+ for( dx = 0; dx < dsize.width; dx++ ) \
+ dst[dx] = (arrtype)descale_macro( mul_one_macro(buf0[dx])); \
+ else \
+ for( dx = 0; dx < dsize.width; dx++ ) \
+ dst[dx] = (arrtype)descale_macro( mul_one_macro(buf0[dx]) + \
+ fy*(buf1[dx] - buf0[dx])); \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+typedef struct CvDecimateAlpha
+{
+ int si, di;
+ float alpha;
+}
+CvDecimateAlpha;
+
+
+#define ICV_DEF_RESIZE_AREA_FAST_FUNC( flavor, arrtype, worktype, cast_macro ) \
+static CvStatus CV_STDCALL \
+icvResize_AreaFast_##flavor##_CnR( const arrtype* src, int srcstep, CvSize ssize,\
+ arrtype* dst, int dststep, CvSize dsize, int cn, \
+ const int* ofs, const int* xofs ) \
+{ \
+ int dy, dx, k = 0; \
+ int scale_x = ssize.width/dsize.width; \
+ int scale_y = ssize.height/dsize.height; \
+ int area = scale_x*scale_y; \
+ float scale = 1.f/(scale_x*scale_y); \
+ \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ dsize.width *= cn; \
+ \
+ for( dy = 0; dy < dsize.height; dy++, dst += dststep ) \
+ for( dx = 0; dx < dsize.width; dx++ ) \
+ { \
+ const arrtype* _src = src + dy*scale_y*srcstep + xofs[dx]; \
+ worktype sum = 0; \
+ \
+ for( k = 0; k <= area - 4; k += 4 ) \
+ sum += _src[ofs[k]] + _src[ofs[k+1]] + \
+ _src[ofs[k+2]] + _src[ofs[k+3]]; \
+ \
+ for( ; k < area; k++ ) \
+ sum += _src[ofs[k]]; \
+ \
+ dst[dx] = (arrtype)cast_macro( sum*scale ); \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_RESIZE_AREA_FUNC( flavor, arrtype, load_macro, cast_macro ) \
+static CvStatus CV_STDCALL \
+icvResize_Area_##flavor##_CnR( const arrtype* src, int srcstep, CvSize ssize, \
+ arrtype* dst, int dststep, CvSize dsize, \
+ int cn, const CvDecimateAlpha* xofs, \
+ int xofs_count, float* buf, float* sum ) \
+{ \
+ int k, sy, dx, cur_dy = 0; \
+ float scale_y = (float)ssize.height/dsize.height; \
+ \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ dsize.width *= cn; \
+ \
+ for( sy = 0; sy < ssize.height; sy++, src += srcstep ) \
+ { \
+ if( cn == 1 ) \
+ for( k = 0; k < xofs_count; k++ ) \
+ { \
+ int dxn = xofs[k].di; \
+ float alpha = xofs[k].alpha; \
+ buf[dxn] = buf[dxn] + load_macro(src[xofs[k].si])*alpha; \
+ } \
+ else if( cn == 2 ) \
+ for( k = 0; k < xofs_count; k++ ) \
+ { \
+ int sxn = xofs[k].si; \
+ int dxn = xofs[k].di; \
+ float alpha = xofs[k].alpha; \
+ float t0 = buf[dxn] + load_macro(src[sxn])*alpha; \
+ float t1 = buf[dxn+1] + load_macro(src[sxn+1])*alpha; \
+ buf[dxn] = t0; buf[dxn+1] = t1; \
+ } \
+ else if( cn == 3 ) \
+ for( k = 0; k < xofs_count; k++ ) \
+ { \
+ int sxn = xofs[k].si; \
+ int dxn = xofs[k].di; \
+ float alpha = xofs[k].alpha; \
+ float t0 = buf[dxn] + load_macro(src[sxn])*alpha; \
+ float t1 = buf[dxn+1] + load_macro(src[sxn+1])*alpha; \
+ float t2 = buf[dxn+2] + load_macro(src[sxn+2])*alpha; \
+ buf[dxn] = t0; buf[dxn+1] = t1; buf[dxn+2] = t2; \
+ } \
+ else \
+ for( k = 0; k < xofs_count; k++ ) \
+ { \
+ int sxn = xofs[k].si; \
+ int dxn = xofs[k].di; \
+ float alpha = xofs[k].alpha; \
+ float t0 = buf[dxn] + load_macro(src[sxn])*alpha; \
+ float t1 = buf[dxn+1] + load_macro(src[sxn+1])*alpha; \
+ buf[dxn] = t0; buf[dxn+1] = t1; \
+ t0 = buf[dxn+2] + load_macro(src[sxn+2])*alpha; \
+ t1 = buf[dxn+3] + load_macro(src[sxn+3])*alpha; \
+ buf[dxn+2] = t0; buf[dxn+3] = t1; \
+ } \
+ \
+ if( (cur_dy + 1)*scale_y <= sy + 1 || sy == ssize.height - 1 ) \
+ { \
+ float beta = sy + 1 - (cur_dy+1)*scale_y, beta1; \
+ beta = MAX( beta, 0 ); \
+ beta1 = 1 - beta; \
+ if( fabs(beta) < 1e-3 ) \
+ for( dx = 0; dx < dsize.width; dx++ ) \
+ { \
+ dst[dx] = (arrtype)cast_macro(sum[dx] + buf[dx]); \
+ sum[dx] = buf[dx] = 0; \
+ } \
+ else \
+ for( dx = 0; dx < dsize.width; dx++ ) \
+ { \
+ dst[dx] = (arrtype)cast_macro(sum[dx] + buf[dx]*beta1); \
+ sum[dx] = buf[dx]*beta; \
+ buf[dx] = 0; \
+ } \
+ dst += dststep; \
+ cur_dy++; \
+ } \
+ else \
+ for( dx = 0; dx < dsize.width; dx += 2 ) \
+ { \
+ float t0 = sum[dx] + buf[dx]; \
+ float t1 = sum[dx+1] + buf[dx+1]; \
+ sum[dx] = t0; sum[dx+1] = t1; \
+ buf[dx] = buf[dx+1] = 0; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_RESIZE_BICUBIC_FUNC( flavor, arrtype, worktype, load_macro, \
+ cast_macro1, cast_macro2 ) \
+static CvStatus CV_STDCALL \
+icvResize_Bicubic_##flavor##_CnR( const arrtype* src, int srcstep, CvSize ssize,\
+ arrtype* dst, int dststep, CvSize dsize, \
+ int cn, int xmin, int xmax, \
+ const CvResizeAlpha* xofs, float** buf ) \
+{ \
+ float scale_y = (float)ssize.height/dsize.height; \
+ int dx, dy, sx, sy, sy2, ify; \
+ int prev_sy2 = -2; \
+ \
+ xmin *= cn; xmax *= cn; \
+ dsize.width *= cn; \
+ ssize.width *= cn; \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( dy = 0; dy < dsize.height; dy++, dst += dststep ) \
+ { \
+ float w0, w1, w2, w3; \
+ float fy, x, sum; \
+ float *row, *row0, *row1, *row2, *row3; \
+ int k1, k = 4; \
+ \
+ fy = dy*scale_y; \
+ sy = cvFloor(fy); \
+ fy -= sy; \
+ ify = cvRound(fy*ICV_CUBIC_TAB_SIZE); \
+ sy2 = sy + 2; \
+ \
+ if( sy2 > prev_sy2 ) \
+ { \
+ int delta = prev_sy2 - sy + 2; \
+ for( k = 0; k < delta; k++ ) \
+ CV_SWAP( buf[k], buf[k+4-delta], row ); \
+ } \
+ \
+ for( sy += k - 1; k < 4; k++, sy++ ) \
+ { \
+ const arrtype* _src = src + sy*srcstep; \
+ \
+ row = buf[k]; \
+ if( sy < 0 ) \
+ continue; \
+ if( sy >= ssize.height ) \
+ { \
+ assert( k > 0 ); \
+ memcpy( row, buf[k-1], dsize.width*sizeof(row[0]) ); \
+ continue; \
+ } \
+ \
+ for( dx = 0; dx < xmin; dx++ ) \
+ { \
+ int ifx = xofs[dx].ialpha, sx0 = xofs[dx].idx; \
+ sx = sx0 + cn*2; \
+ while( sx >= ssize.width ) \
+ sx -= cn; \
+ x = load_macro(_src[sx]); \
+ sum = x*icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE - ifx)*2 + 1]; \
+ if( (unsigned)(sx = sx0 + cn) < (unsigned)ssize.width ) \
+ x = load_macro(_src[sx]); \
+ sum += x*icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE - ifx)*2]; \
+ if( (unsigned)(sx = sx0) < (unsigned)ssize.width ) \
+ x = load_macro(_src[sx]); \
+ sum += x*icvCubicCoeffs[ifx*2]; \
+ if( (unsigned)(sx = sx0 - cn) < (unsigned)ssize.width ) \
+ x = load_macro(_src[sx]); \
+ row[dx] = sum + x*icvCubicCoeffs[ifx*2 + 1]; \
+ } \
+ \
+ for( ; dx < xmax; dx++ ) \
+ { \
+ int ifx = xofs[dx].ialpha; \
+ int sx0 = xofs[dx].idx; \
+ row[dx] = _src[sx0 - cn]*icvCubicCoeffs[ifx*2 + 1] + \
+ _src[sx0]*icvCubicCoeffs[ifx*2] + \
+ _src[sx0 + cn]*icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE-ifx)*2] + \
+ _src[sx0 + cn*2]*icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE-ifx)*2+1];\
+ } \
+ \
+ for( ; dx < dsize.width; dx++ ) \
+ { \
+ int ifx = xofs[dx].ialpha, sx0 = xofs[dx].idx; \
+ x = load_macro(_src[sx0 - cn]); \
+ sum = x*icvCubicCoeffs[ifx*2 + 1]; \
+ if( (unsigned)(sx = sx0) < (unsigned)ssize.width ) \
+ x = load_macro(_src[sx]); \
+ sum += x*icvCubicCoeffs[ifx*2]; \
+ if( (unsigned)(sx = sx0 + cn) < (unsigned)ssize.width ) \
+ x = load_macro(_src[sx]); \
+ sum += x*icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE - ifx)*2]; \
+ if( (unsigned)(sx = sx0 + cn*2) < (unsigned)ssize.width ) \
+ x = load_macro(_src[sx]); \
+ row[dx] = sum + x*icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE-ifx)*2+1]; \
+ } \
+ \
+ if( sy == 0 ) \
+ for( k1 = 0; k1 < k; k1++ ) \
+ memcpy( buf[k1], row, dsize.width*sizeof(row[0])); \
+ } \
+ \
+ prev_sy2 = sy2; \
+ \
+ row0 = buf[0]; row1 = buf[1]; \
+ row2 = buf[2]; row3 = buf[3]; \
+ \
+ w0 = icvCubicCoeffs[ify*2+1]; \
+ w1 = icvCubicCoeffs[ify*2]; \
+ w2 = icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE - ify)*2]; \
+ w3 = icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE - ify)*2 + 1]; \
+ \
+ for( dx = 0; dx < dsize.width; dx++ ) \
+ { \
+ worktype val = cast_macro1( row0[dx]*w0 + row1[dx]*w1 + \
+ row2[dx]*w2 + row3[dx]*w3 ); \
+ dst[dx] = cast_macro2(val); \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_RESIZE_BILINEAR_FUNC( 8u, uchar, int, ialpha,
+ ICV_WARP_MUL_ONE_8U, ICV_WARP_DESCALE_8U )
+ICV_DEF_RESIZE_BILINEAR_FUNC( 16u, ushort, float, alpha, CV_NOP, cvRound )
+ICV_DEF_RESIZE_BILINEAR_FUNC( 32f, float, float, alpha, CV_NOP, CV_NOP )
+
+ICV_DEF_RESIZE_BICUBIC_FUNC( 8u, uchar, int, CV_8TO32F, cvRound, CV_CAST_8U )
+ICV_DEF_RESIZE_BICUBIC_FUNC( 16u, ushort, int, CV_NOP, cvRound, CV_CAST_16U )
+ICV_DEF_RESIZE_BICUBIC_FUNC( 32f, float, float, CV_NOP, CV_NOP, CV_NOP )
+
+ICV_DEF_RESIZE_AREA_FAST_FUNC( 8u, uchar, int, cvRound )
+ICV_DEF_RESIZE_AREA_FAST_FUNC( 16u, ushort, int, cvRound )
+ICV_DEF_RESIZE_AREA_FAST_FUNC( 32f, float, float, CV_NOP )
+
+ICV_DEF_RESIZE_AREA_FUNC( 8u, uchar, CV_8TO32F, cvRound )
+ICV_DEF_RESIZE_AREA_FUNC( 16u, ushort, CV_NOP, cvRound )
+ICV_DEF_RESIZE_AREA_FUNC( 32f, float, CV_NOP, CV_NOP )
+
+
+static void icvInitResizeTab( CvFuncTable* bilin_tab,
+ CvFuncTable* bicube_tab,
+ CvFuncTable* areafast_tab,
+ CvFuncTable* area_tab )
+{
+ bilin_tab->fn_2d[CV_8U] = (void*)icvResize_Bilinear_8u_CnR;
+ bilin_tab->fn_2d[CV_16U] = (void*)icvResize_Bilinear_16u_CnR;
+ bilin_tab->fn_2d[CV_32F] = (void*)icvResize_Bilinear_32f_CnR;
+
+ bicube_tab->fn_2d[CV_8U] = (void*)icvResize_Bicubic_8u_CnR;
+ bicube_tab->fn_2d[CV_16U] = (void*)icvResize_Bicubic_16u_CnR;
+ bicube_tab->fn_2d[CV_32F] = (void*)icvResize_Bicubic_32f_CnR;
+
+ areafast_tab->fn_2d[CV_8U] = (void*)icvResize_AreaFast_8u_CnR;
+ areafast_tab->fn_2d[CV_16U] = (void*)icvResize_AreaFast_16u_CnR;
+ areafast_tab->fn_2d[CV_32F] = (void*)icvResize_AreaFast_32f_CnR;
+
+ area_tab->fn_2d[CV_8U] = (void*)icvResize_Area_8u_CnR;
+ area_tab->fn_2d[CV_16U] = (void*)icvResize_Area_16u_CnR;
+ area_tab->fn_2d[CV_32F] = (void*)icvResize_Area_32f_CnR;
+}
+
+
+typedef CvStatus (CV_STDCALL * CvResizeBilinearFunc)
+ ( const void* src, int srcstep, CvSize ssize,
+ void* dst, int dststep, CvSize dsize,
+ int cn, int xmax, const CvResizeAlpha* xofs,
+ const CvResizeAlpha* yofs, float* buf0, float* buf1 );
+
+typedef CvStatus (CV_STDCALL * CvResizeBicubicFunc)
+ ( const void* src, int srcstep, CvSize ssize,
+ void* dst, int dststep, CvSize dsize,
+ int cn, int xmin, int xmax,
+ const CvResizeAlpha* xofs, float** buf );
+
+typedef CvStatus (CV_STDCALL * CvResizeAreaFastFunc)
+ ( const void* src, int srcstep, CvSize ssize,
+ void* dst, int dststep, CvSize dsize,
+ int cn, const int* ofs, const int *xofs );
+
+typedef CvStatus (CV_STDCALL * CvResizeAreaFunc)
+ ( const void* src, int srcstep, CvSize ssize,
+ void* dst, int dststep, CvSize dsize,
+ int cn, const CvDecimateAlpha* xofs,
+ int xofs_count, float* buf, float* sum );
+
+
+////////////////////////////////// IPP resize functions //////////////////////////////////
+
+icvResize_8u_C1R_t icvResize_8u_C1R_p = 0;
+icvResize_8u_C3R_t icvResize_8u_C3R_p = 0;
+icvResize_8u_C4R_t icvResize_8u_C4R_p = 0;
+icvResize_16u_C1R_t icvResize_16u_C1R_p = 0;
+icvResize_16u_C3R_t icvResize_16u_C3R_p = 0;
+icvResize_16u_C4R_t icvResize_16u_C4R_p = 0;
+icvResize_32f_C1R_t icvResize_32f_C1R_p = 0;
+icvResize_32f_C3R_t icvResize_32f_C3R_p = 0;
+icvResize_32f_C4R_t icvResize_32f_C4R_p = 0;
+
+typedef CvStatus (CV_STDCALL * CvResizeIPPFunc)
+( const void* src, CvSize srcsize, int srcstep, CvRect srcroi,
+ void* dst, int dststep, CvSize dstroi,
+ double xfactor, double yfactor, int interpolation );
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+CV_IMPL void
+cvResize( const CvArr* srcarr, CvArr* dstarr, int method )
+{
+ static CvFuncTable bilin_tab, bicube_tab, areafast_tab, area_tab;
+ static int inittab = 0;
+ void* temp_buf = 0;
+
+ CV_FUNCNAME( "cvResize" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize ssize, dsize;
+ float scale_x, scale_y;
+ int k, sx, sy, dx, dy;
+ int type, depth, cn;
+
+ CV_CALL( src = cvGetMat( srcarr, &srcstub ));
+ CV_CALL( dst = cvGetMat( dstarr, &dststub ));
+
+ if( CV_ARE_SIZES_EQ( src, dst ))
+ {
+ CV_CALL( cvCopy( src, dst ));
+ EXIT;
+ }
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( !inittab )
+ {
+ icvInitResizeTab( &bilin_tab, &bicube_tab, &areafast_tab, &area_tab );
+ inittab = 1;
+ }
+
+ ssize = cvGetMatSize( src );
+ dsize = cvGetMatSize( dst );
+ type = CV_MAT_TYPE(src->type);
+ depth = CV_MAT_DEPTH(type);
+ cn = CV_MAT_CN(type);
+ scale_x = (float)ssize.width/dsize.width;
+ scale_y = (float)ssize.height/dsize.height;
+
+ if( method == CV_INTER_CUBIC &&
+ (MIN(ssize.width, dsize.width) <= 4 ||
+ MIN(ssize.height, dsize.height) <= 4) )
+ method = CV_INTER_LINEAR;
+
+ if( icvResize_8u_C1R_p &&
+ MIN(ssize.width, dsize.width) > 4 &&
+ MIN(ssize.height, dsize.height) > 4 )
+ {
+ CvResizeIPPFunc ipp_func =
+ type == CV_8UC1 ? icvResize_8u_C1R_p :
+ type == CV_8UC3 ? icvResize_8u_C3R_p :
+ type == CV_8UC4 ? icvResize_8u_C4R_p :
+ type == CV_16UC1 ? icvResize_16u_C1R_p :
+ type == CV_16UC3 ? icvResize_16u_C3R_p :
+ type == CV_16UC4 ? icvResize_16u_C4R_p :
+ type == CV_32FC1 ? icvResize_32f_C1R_p :
+ type == CV_32FC3 ? icvResize_32f_C3R_p :
+ type == CV_32FC4 ? icvResize_32f_C4R_p : 0;
+ if( ipp_func && (CV_INTER_NN < method && method < CV_INTER_AREA))
+ {
+ int srcstep = src->step ? src->step : CV_STUB_STEP;
+ int dststep = dst->step ? dst->step : CV_STUB_STEP;
+ IPPI_CALL( ipp_func( src->data.ptr, ssize, srcstep,
+ cvRect(0,0,ssize.width,ssize.height),
+ dst->data.ptr, dststep, dsize,
+ (double)dsize.width/ssize.width,
+ (double)dsize.height/ssize.height, 1 << method ));
+ EXIT;
+ }
+ }
+
+ if( method == CV_INTER_NN )
+ {
+ IPPI_CALL( icvResize_NN_8u_C1R( src->data.ptr, src->step, ssize,
+ dst->data.ptr, dst->step, dsize,
+ CV_ELEM_SIZE(src->type)));
+ }
+ else if( method == CV_INTER_LINEAR || method == CV_INTER_AREA )
+ {
+ if( method == CV_INTER_AREA &&
+ ssize.width >= dsize.width && ssize.height >= dsize.height )
+ {
+ // "area" method for (scale_x > 1 & scale_y > 1)
+ int iscale_x = cvRound(scale_x);
+ int iscale_y = cvRound(scale_y);
+
+ if( fabs(scale_x - iscale_x) < DBL_EPSILON &&
+ fabs(scale_y - iscale_y) < DBL_EPSILON )
+ {
+ int area = iscale_x*iscale_y;
+ int srcstep = src->step / CV_ELEM_SIZE(depth);
+ int* ofs = (int*)cvStackAlloc( (area + dsize.width*cn)*sizeof(int) );
+ int* xofs = ofs + area;
+ CvResizeAreaFastFunc func = (CvResizeAreaFastFunc)areafast_tab.fn_2d[depth];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ for( sy = 0, k = 0; sy < iscale_y; sy++ )
+ for( sx = 0; sx < iscale_x; sx++ )
+ ofs[k++] = sy*srcstep + sx*cn;
+
+ for( dx = 0; dx < dsize.width; dx++ )
+ {
+ sx = dx*iscale_x*cn;
+ for( k = 0; k < cn; k++ )
+ xofs[dx*cn + k] = sx + k;
+ }
+
+ IPPI_CALL( func( src->data.ptr, src->step, ssize, dst->data.ptr,
+ dst->step, dsize, cn, ofs, xofs ));
+ }
+ else
+ {
+ int buf_len = dsize.width*cn + 4, buf_size, xofs_count = 0;
+ float scale = 1.f/(scale_x*scale_y);
+ float *buf, *sum;
+ CvDecimateAlpha* xofs;
+ CvResizeAreaFunc func = (CvResizeAreaFunc)area_tab.fn_2d[depth];
+
+ if( !func || cn > 4 )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ buf_size = buf_len*2*sizeof(float) + ssize.width*2*sizeof(CvDecimateAlpha);
+ if( buf_size < CV_MAX_LOCAL_SIZE )
+ buf = (float*)cvStackAlloc(buf_size);
+ else
+ CV_CALL( temp_buf = buf = (float*)cvAlloc(buf_size));
+ sum = buf + buf_len;
+ xofs = (CvDecimateAlpha*)(sum + buf_len);
+
+ for( dx = 0, k = 0; dx < dsize.width; dx++ )
+ {
+ float fsx1 = dx*scale_x, fsx2 = fsx1 + scale_x;
+ int sx1 = cvCeil(fsx1), sx2 = cvFloor(fsx2);
+
+ assert( (unsigned)sx1 < (unsigned)ssize.width );
+
+ if( sx1 > fsx1 )
+ {
+ assert( k < ssize.width*2 );
+ xofs[k].di = dx*cn;
+ xofs[k].si = (sx1-1)*cn;
+ xofs[k++].alpha = (sx1 - fsx1)*scale;
+ }
+
+ for( sx = sx1; sx < sx2; sx++ )
+ {
+ assert( k < ssize.width*2 );
+ xofs[k].di = dx*cn;
+ xofs[k].si = sx*cn;
+ xofs[k++].alpha = scale;
+ }
+
+ if( fsx2 - sx2 > 1e-3 )
+ {
+ assert( k < ssize.width*2 );
+ assert((unsigned)sx2 < (unsigned)ssize.width );
+ xofs[k].di = dx*cn;
+ xofs[k].si = sx2*cn;
+ xofs[k++].alpha = (fsx2 - sx2)*scale;
+ }
+ }
+
+ xofs_count = k;
+ memset( sum, 0, buf_len*sizeof(float) );
+ memset( buf, 0, buf_len*sizeof(float) );
+
+ IPPI_CALL( func( src->data.ptr, src->step, ssize, dst->data.ptr,
+ dst->step, dsize, cn, xofs, xofs_count, buf, sum ));
+ }
+ }
+ else // true "area" method for the cases (scale_x > 1 & scale_y < 1) and
+ // (scale_x < 1 & scale_y > 1) is not implemented.
+ // instead, it is emulated via some variant of bilinear interpolation.
+ {
+ float inv_scale_x = (float)dsize.width/ssize.width;
+ float inv_scale_y = (float)dsize.height/ssize.height;
+ int xmax = dsize.width, width = dsize.width*cn, buf_size;
+ float *buf0, *buf1;
+ CvResizeAlpha *xofs, *yofs;
+ int area_mode = method == CV_INTER_AREA;
+ float fx, fy;
+ CvResizeBilinearFunc func = (CvResizeBilinearFunc)bilin_tab.fn_2d[depth];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ buf_size = width*2*sizeof(float) + (width + dsize.height)*sizeof(CvResizeAlpha);
+ if( buf_size < CV_MAX_LOCAL_SIZE )
+ buf0 = (float*)cvStackAlloc(buf_size);
+ else
+ CV_CALL( temp_buf = buf0 = (float*)cvAlloc(buf_size));
+ buf1 = buf0 + width;
+ xofs = (CvResizeAlpha*)(buf1 + width);
+ yofs = xofs + width;
+
+ for( dx = 0; dx < dsize.width; dx++ )
+ {
+ if( !area_mode )
+ {
+ fx = (float)((dx+0.5)*scale_x - 0.5);
+ sx = cvFloor(fx);
+ fx -= sx;
+ }
+ else
+ {
+ sx = cvFloor(dx*scale_x);
+ fx = (dx+1) - (sx+1)*inv_scale_x;
+ fx = fx <= 0 ? 0.f : fx - cvFloor(fx);
+ }
+
+ if( sx < 0 )
+ fx = 0, sx = 0;
+
+ if( sx >= ssize.width-1 )
+ {
+ fx = 0, sx = ssize.width-1;
+ if( xmax >= dsize.width )
+ xmax = dx;
+ }
+
+ if( depth != CV_8U )
+ for( k = 0, sx *= cn; k < cn; k++ )
+ xofs[dx*cn + k].idx = sx + k, xofs[dx*cn + k].alpha = fx;
+ else
+ for( k = 0, sx *= cn; k < cn; k++ )
+ xofs[dx*cn + k].idx = sx + k,
+ xofs[dx*cn + k].ialpha = CV_FLT_TO_FIX(fx, ICV_WARP_SHIFT);
+ }
+
+ for( dy = 0; dy < dsize.height; dy++ )
+ {
+ if( !area_mode )
+ {
+ fy = (float)((dy+0.5)*scale_y - 0.5);
+ sy = cvFloor(fy);
+ fy -= sy;
+ if( sy < 0 )
+ sy = 0, fy = 0;
+ }
+ else
+ {
+ sy = cvFloor(dy*scale_y);
+ fy = (dy+1) - (sy+1)*inv_scale_y;
+ fy = fy <= 0 ? 0.f : fy - cvFloor(fy);
+ }
+
+ yofs[dy].idx = sy;
+ if( depth != CV_8U )
+ yofs[dy].alpha = fy;
+ else
+ yofs[dy].ialpha = CV_FLT_TO_FIX(fy, ICV_WARP_SHIFT);
+ }
+
+ IPPI_CALL( func( src->data.ptr, src->step, ssize, dst->data.ptr,
+ dst->step, dsize, cn, xmax, xofs, yofs, buf0, buf1 ));
+ }
+ }
+ else if( method == CV_INTER_CUBIC )
+ {
+ int width = dsize.width*cn, buf_size;
+ int xmin = dsize.width, xmax = -1;
+ CvResizeAlpha* xofs;
+ float* buf[4];
+ CvResizeBicubicFunc func = (CvResizeBicubicFunc)bicube_tab.fn_2d[depth];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ buf_size = width*(4*sizeof(float) + sizeof(xofs[0]));
+ if( buf_size < CV_MAX_LOCAL_SIZE )
+ buf[0] = (float*)cvStackAlloc(buf_size);
+ else
+ CV_CALL( temp_buf = buf[0] = (float*)cvAlloc(buf_size));
+
+ for( k = 1; k < 4; k++ )
+ buf[k] = buf[k-1] + width;
+ xofs = (CvResizeAlpha*)(buf[3] + width);
+
+ icvInitCubicCoeffTab();
+
+ for( dx = 0; dx < dsize.width; dx++ )
+ {
+ float fx = dx*scale_x;
+ sx = cvFloor(fx);
+ fx -= sx;
+ int ifx = cvRound(fx*ICV_CUBIC_TAB_SIZE);
+ if( sx-1 >= 0 && xmin > dx )
+ xmin = dx;
+ if( sx+2 < ssize.width )
+ xmax = dx + 1;
+
+ // at least one of 4 points should be within the image - to
+ // be able to set other points to the same value. see the loops
+ // for( dx = 0; dx < xmin; dx++ ) ... and for( ; dx < width; dx++ ) ...
+ if( sx < -2 )
+ sx = -2;
+ else if( sx > ssize.width )
+ sx = ssize.width;
+
+ for( k = 0; k < cn; k++ )
+ {
+ xofs[dx*cn + k].idx = sx*cn + k;
+ xofs[dx*cn + k].ialpha = ifx;
+ }
+ }
+
+ IPPI_CALL( func( src->data.ptr, src->step, ssize, dst->data.ptr,
+ dst->step, dsize, cn, xmin, xmax, xofs, buf ));
+ }
+ else
+ CV_ERROR( CV_StsBadFlag, "Unknown/unsupported interpolation method" );
+
+ __END__;
+
+ cvFree( &temp_buf );
+}
+
+
+/****************************************************************************************\
+* WarpAffine *
+\****************************************************************************************/
+
+#define ICV_DEF_WARP_AFFINE_BILINEAR_FUNC( flavor, arrtype, worktype, \
+ scale_alpha_macro, mul_one_macro, descale_macro, cast_macro ) \
+static CvStatus CV_STDCALL \
+icvWarpAffine_Bilinear_##flavor##_CnR( \
+ const arrtype* src, int step, CvSize ssize, \
+ arrtype* dst, int dststep, CvSize dsize, \
+ const double* matrix, int cn, \
+ const arrtype* fillval, const int* ofs ) \
+{ \
+ int x, y, k; \
+ double A12 = matrix[1], b1 = matrix[2]; \
+ double A22 = matrix[4], b2 = matrix[5]; \
+ \
+ step /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( y = 0; y < dsize.height; y++, dst += dststep ) \
+ { \
+ int xs = CV_FLT_TO_FIX( A12*y + b1, ICV_WARP_SHIFT ); \
+ int ys = CV_FLT_TO_FIX( A22*y + b2, ICV_WARP_SHIFT ); \
+ \
+ for( x = 0; x < dsize.width; x++ ) \
+ { \
+ int ixs = xs + ofs[x*2]; \
+ int iys = ys + ofs[x*2+1]; \
+ worktype a = scale_alpha_macro( ixs & ICV_WARP_MASK ); \
+ worktype b = scale_alpha_macro( iys & ICV_WARP_MASK ); \
+ worktype p0, p1; \
+ ixs >>= ICV_WARP_SHIFT; \
+ iys >>= ICV_WARP_SHIFT; \
+ \
+ if( (unsigned)ixs < (unsigned)(ssize.width - 1) && \
+ (unsigned)iys < (unsigned)(ssize.height - 1) ) \
+ { \
+ const arrtype* ptr = src + step*iys + ixs*cn; \
+ \
+ for( k = 0; k < cn; k++ ) \
+ { \
+ p0 = mul_one_macro(ptr[k]) + \
+ a * (ptr[k+cn] - ptr[k]); \
+ p1 = mul_one_macro(ptr[k+step]) + \
+ a * (ptr[k+cn+step] - ptr[k+step]); \
+ p0 = descale_macro(mul_one_macro(p0) + b*(p1 - p0)); \
+ dst[x*cn+k] = (arrtype)cast_macro(p0); \
+ } \
+ } \
+ else if( (unsigned)(ixs+1) < (unsigned)(ssize.width+1) && \
+ (unsigned)(iys+1) < (unsigned)(ssize.height+1)) \
+ { \
+ int x0 = ICV_WARP_CLIP_X( ixs ); \
+ int y0 = ICV_WARP_CLIP_Y( iys ); \
+ int x1 = ICV_WARP_CLIP_X( ixs + 1 ); \
+ int y1 = ICV_WARP_CLIP_Y( iys + 1 ); \
+ const arrtype* ptr0, *ptr1, *ptr2, *ptr3; \
+ \
+ ptr0 = src + y0*step + x0*cn; \
+ ptr1 = src + y0*step + x1*cn; \
+ ptr2 = src + y1*step + x0*cn; \
+ ptr3 = src + y1*step + x1*cn; \
+ \
+ for( k = 0; k < cn; k++ ) \
+ { \
+ p0 = mul_one_macro(ptr0[k]) + a * (ptr1[k] - ptr0[k]); \
+ p1 = mul_one_macro(ptr2[k]) + a * (ptr3[k] - ptr2[k]); \
+ p0 = descale_macro( mul_one_macro(p0) + b*(p1 - p0) ); \
+ dst[x*cn+k] = (arrtype)cast_macro(p0); \
+ } \
+ } \
+ else if( fillval ) \
+ for( k = 0; k < cn; k++ ) \
+ dst[x*cn+k] = fillval[k]; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_WARP_SCALE_ALPHA(x) ((x)*(1./(ICV_WARP_MASK+1)))
+
+ICV_DEF_WARP_AFFINE_BILINEAR_FUNC( 8u, uchar, int, CV_NOP, ICV_WARP_MUL_ONE_8U,
+ ICV_WARP_DESCALE_8U, CV_NOP )
+//ICV_DEF_WARP_AFFINE_BILINEAR_FUNC( 8u, uchar, double, ICV_WARP_SCALE_ALPHA, CV_NOP,
+// CV_NOP, ICV_WARP_CAST_8U )
+ICV_DEF_WARP_AFFINE_BILINEAR_FUNC( 16u, ushort, double, ICV_WARP_SCALE_ALPHA, CV_NOP,
+ CV_NOP, cvRound )
+ICV_DEF_WARP_AFFINE_BILINEAR_FUNC( 32f, float, double, ICV_WARP_SCALE_ALPHA, CV_NOP,
+ CV_NOP, CV_NOP )
+
+
+typedef CvStatus (CV_STDCALL * CvWarpAffineFunc)(
+ const void* src, int srcstep, CvSize ssize,
+ void* dst, int dststep, CvSize dsize,
+ const double* matrix, int cn,
+ const void* fillval, const int* ofs );
+
+static void icvInitWarpAffineTab( CvFuncTable* bilin_tab )
+{
+ bilin_tab->fn_2d[CV_8U] = (void*)icvWarpAffine_Bilinear_8u_CnR;
+ bilin_tab->fn_2d[CV_16U] = (void*)icvWarpAffine_Bilinear_16u_CnR;
+ bilin_tab->fn_2d[CV_32F] = (void*)icvWarpAffine_Bilinear_32f_CnR;
+}
+
+
+/////////////////////////////// IPP warpaffine functions /////////////////////////////////
+
+icvWarpAffineBack_8u_C1R_t icvWarpAffineBack_8u_C1R_p = 0;
+icvWarpAffineBack_8u_C3R_t icvWarpAffineBack_8u_C3R_p = 0;
+icvWarpAffineBack_8u_C4R_t icvWarpAffineBack_8u_C4R_p = 0;
+icvWarpAffineBack_32f_C1R_t icvWarpAffineBack_32f_C1R_p = 0;
+icvWarpAffineBack_32f_C3R_t icvWarpAffineBack_32f_C3R_p = 0;
+icvWarpAffineBack_32f_C4R_t icvWarpAffineBack_32f_C4R_p = 0;
+
+typedef CvStatus (CV_STDCALL * CvWarpAffineBackIPPFunc)
+( const void* src, CvSize srcsize, int srcstep, CvRect srcroi,
+ void* dst, int dststep, CvRect dstroi,
+ const double* coeffs, int interpolation );
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+CV_IMPL void
+cvWarpAffine( const CvArr* srcarr, CvArr* dstarr, const CvMat* matrix,
+ int flags, CvScalar fillval )
+{
+ static CvFuncTable bilin_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvWarpAffine" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ int k, type, depth, cn, *ofs = 0;
+ double src_matrix[6], dst_matrix[6];
+ double fillbuf[4];
+ int method = flags & 3;
+ CvMat srcAb = cvMat( 2, 3, CV_64F, src_matrix ),
+ dstAb = cvMat( 2, 3, CV_64F, dst_matrix ),
+ A, b, invA, invAb;
+ CvWarpAffineFunc func;
+ CvSize ssize, dsize;
+
+ if( !inittab )
+ {
+ icvInitWarpAffineTab( &bilin_tab );
+ inittab = 1;
+ }
+
+ CV_CALL( src = cvGetMat( srcarr, &srcstub ));
+ CV_CALL( dst = cvGetMat( dstarr, &dststub ));
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( !CV_IS_MAT(matrix) || CV_MAT_CN(matrix->type) != 1 ||
+ CV_MAT_DEPTH(matrix->type) < CV_32F || matrix->rows != 2 || matrix->cols != 3 )
+ CV_ERROR( CV_StsBadArg,
+ "Transformation matrix should be 2x3 floating-point single-channel matrix" );
+
+ if( flags & CV_WARP_INVERSE_MAP )
+ cvConvertScale( matrix, &dstAb );
+ else
+ {
+ // [R|t] -> [R^-1 | -(R^-1)*t]
+ cvConvertScale( matrix, &srcAb );
+ cvGetCols( &srcAb, &A, 0, 2 );
+ cvGetCol( &srcAb, &b, 2 );
+ cvGetCols( &dstAb, &invA, 0, 2 );
+ cvGetCol( &dstAb, &invAb, 2 );
+ cvInvert( &A, &invA, CV_SVD );
+ cvGEMM( &invA, &b, -1, 0, 0, &invAb );
+ }
+
+ type = CV_MAT_TYPE(src->type);
+ depth = CV_MAT_DEPTH(type);
+ cn = CV_MAT_CN(type);
+ if( cn > 4 )
+ CV_ERROR( CV_BadNumChannels, "" );
+
+ ssize = cvGetMatSize(src);
+ dsize = cvGetMatSize(dst);
+
+ if( icvWarpAffineBack_8u_C1R_p && MIN( ssize.width, dsize.width ) >= 4 &&
+ MIN( ssize.height, dsize.height ) >= 4 )
+ {
+ CvWarpAffineBackIPPFunc ipp_func =
+ type == CV_8UC1 ? icvWarpAffineBack_8u_C1R_p :
+ type == CV_8UC3 ? icvWarpAffineBack_8u_C3R_p :
+ type == CV_8UC4 ? icvWarpAffineBack_8u_C4R_p :
+ type == CV_32FC1 ? icvWarpAffineBack_32f_C1R_p :
+ type == CV_32FC3 ? icvWarpAffineBack_32f_C3R_p :
+ type == CV_32FC4 ? icvWarpAffineBack_32f_C4R_p : 0;
+
+ if( ipp_func && CV_INTER_NN <= method && method <= CV_INTER_AREA )
+ {
+ int srcstep = src->step ? src->step : CV_STUB_STEP;
+ int dststep = dst->step ? dst->step : CV_STUB_STEP;
+ CvRect srcroi = {0, 0, ssize.width, ssize.height};
+ CvRect dstroi = {0, 0, dsize.width, dsize.height};
+
+ // this is not the most efficient way to fill outliers
+ if( flags & CV_WARP_FILL_OUTLIERS )
+ cvSet( dst, fillval );
+
+ if( ipp_func( src->data.ptr, ssize, srcstep, srcroi,
+ dst->data.ptr, dststep, dstroi,
+ dstAb.data.db, 1 << method ) >= 0 )
+ EXIT;
+ }
+ }
+
+ cvScalarToRawData( &fillval, fillbuf, CV_MAT_TYPE(src->type), 0 );
+ ofs = (int*)cvStackAlloc( dst->cols*2*sizeof(ofs[0]) );
+ for( k = 0; k < dst->cols; k++ )
+ {
+ ofs[2*k] = CV_FLT_TO_FIX( dst_matrix[0]*k, ICV_WARP_SHIFT );
+ ofs[2*k+1] = CV_FLT_TO_FIX( dst_matrix[3]*k, ICV_WARP_SHIFT );
+ }
+
+ /*if( method == CV_INTER_LINEAR )*/
+ {
+ func = (CvWarpAffineFunc)bilin_tab.fn_2d[depth];
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src->data.ptr, src->step, ssize, dst->data.ptr,
+ dst->step, dsize, dst_matrix, cn,
+ flags & CV_WARP_FILL_OUTLIERS ? fillbuf : 0, ofs ));
+ }
+
+ __END__;
+}
+
+
+CV_IMPL CvMat*
+cv2DRotationMatrix( CvPoint2D32f center, double angle,
+ double scale, CvMat* matrix )
+{
+ CV_FUNCNAME( "cvGetRotationMatrix" );
+
+ __BEGIN__;
+
+ double m[2][3];
+ CvMat M = cvMat( 2, 3, CV_64FC1, m );
+ double alpha, beta;
+
+ if( !matrix )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ angle *= CV_PI/180;
+ alpha = cos(angle)*scale;
+ beta = sin(angle)*scale;
+
+ m[0][0] = alpha;
+ m[0][1] = beta;
+ m[0][2] = (1-alpha)*center.x - beta*center.y;
+ m[1][0] = -beta;
+ m[1][1] = alpha;
+ m[1][2] = beta*center.x + (1-alpha)*center.y;
+
+ cvConvert( &M, matrix );
+
+ __END__;
+
+ return matrix;
+}
+
+
+/****************************************************************************************\
+* WarpPerspective *
+\****************************************************************************************/
+
+#define ICV_DEF_WARP_PERSPECTIVE_BILINEAR_FUNC( flavor, arrtype, load_macro, cast_macro )\
+static CvStatus CV_STDCALL \
+icvWarpPerspective_Bilinear_##flavor##_CnR( \
+ const arrtype* src, int step, CvSize ssize, \
+ arrtype* dst, int dststep, CvSize dsize, \
+ const double* matrix, int cn, \
+ const arrtype* fillval ) \
+{ \
+ int x, y, k; \
+ float A11 = (float)matrix[0], A12 = (float)matrix[1], A13 = (float)matrix[2];\
+ float A21 = (float)matrix[3], A22 = (float)matrix[4], A23 = (float)matrix[5];\
+ float A31 = (float)matrix[6], A32 = (float)matrix[7], A33 = (float)matrix[8];\
+ \
+ step /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( y = 0; y < dsize.height; y++, dst += dststep ) \
+ { \
+ float xs0 = A12*y + A13; \
+ float ys0 = A22*y + A23; \
+ float ws = A32*y + A33; \
+ \
+ for( x = 0; x < dsize.width; x++, xs0 += A11, ys0 += A21, ws += A31 )\
+ { \
+ float inv_ws = 1.f/ws; \
+ float xs = xs0*inv_ws; \
+ float ys = ys0*inv_ws; \
+ int ixs = cvFloor(xs); \
+ int iys = cvFloor(ys); \
+ float a = xs - ixs; \
+ float b = ys - iys; \
+ float p0, p1; \
+ \
+ if( (unsigned)ixs < (unsigned)(ssize.width - 1) && \
+ (unsigned)iys < (unsigned)(ssize.height - 1) ) \
+ { \
+ const arrtype* ptr = src + step*iys + ixs*cn; \
+ \
+ for( k = 0; k < cn; k++ ) \
+ { \
+ p0 = load_macro(ptr[k]) + \
+ a * (load_macro(ptr[k+cn]) - load_macro(ptr[k])); \
+ p1 = load_macro(ptr[k+step]) + \
+ a * (load_macro(ptr[k+cn+step]) - \
+ load_macro(ptr[k+step])); \
+ dst[x*cn+k] = (arrtype)cast_macro(p0 + b*(p1 - p0)); \
+ } \
+ } \
+ else if( (unsigned)(ixs+1) < (unsigned)(ssize.width+1) && \
+ (unsigned)(iys+1) < (unsigned)(ssize.height+1)) \
+ { \
+ int x0 = ICV_WARP_CLIP_X( ixs ); \
+ int y0 = ICV_WARP_CLIP_Y( iys ); \
+ int x1 = ICV_WARP_CLIP_X( ixs + 1 ); \
+ int y1 = ICV_WARP_CLIP_Y( iys + 1 ); \
+ const arrtype* ptr0, *ptr1, *ptr2, *ptr3; \
+ \
+ ptr0 = src + y0*step + x0*cn; \
+ ptr1 = src + y0*step + x1*cn; \
+ ptr2 = src + y1*step + x0*cn; \
+ ptr3 = src + y1*step + x1*cn; \
+ \
+ for( k = 0; k < cn; k++ ) \
+ { \
+ p0 = load_macro(ptr0[k]) + \
+ a * (load_macro(ptr1[k]) - load_macro(ptr0[k])); \
+ p1 = load_macro(ptr2[k]) + \
+ a * (load_macro(ptr3[k]) - load_macro(ptr2[k])); \
+ dst[x*cn+k] = (arrtype)cast_macro(p0 + b*(p1 - p0)); \
+ } \
+ } \
+ else if( fillval ) \
+ for( k = 0; k < cn; k++ ) \
+ dst[x*cn+k] = fillval[k]; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_WARP_SCALE_ALPHA(x) ((x)*(1./(ICV_WARP_MASK+1)))
+
+ICV_DEF_WARP_PERSPECTIVE_BILINEAR_FUNC( 8u, uchar, CV_8TO32F, cvRound )
+ICV_DEF_WARP_PERSPECTIVE_BILINEAR_FUNC( 16u, ushort, CV_NOP, cvRound )
+ICV_DEF_WARP_PERSPECTIVE_BILINEAR_FUNC( 32f, float, CV_NOP, CV_NOP )
+
+typedef CvStatus (CV_STDCALL * CvWarpPerspectiveFunc)(
+ const void* src, int srcstep, CvSize ssize,
+ void* dst, int dststep, CvSize dsize,
+ const double* matrix, int cn, const void* fillval );
+
+static void icvInitWarpPerspectiveTab( CvFuncTable* bilin_tab )
+{
+ bilin_tab->fn_2d[CV_8U] = (void*)icvWarpPerspective_Bilinear_8u_CnR;
+ bilin_tab->fn_2d[CV_16U] = (void*)icvWarpPerspective_Bilinear_16u_CnR;
+ bilin_tab->fn_2d[CV_32F] = (void*)icvWarpPerspective_Bilinear_32f_CnR;
+}
+
+
+/////////////////////////// IPP warpperspective functions ////////////////////////////////
+
+icvWarpPerspectiveBack_8u_C1R_t icvWarpPerspectiveBack_8u_C1R_p = 0;
+icvWarpPerspectiveBack_8u_C3R_t icvWarpPerspectiveBack_8u_C3R_p = 0;
+icvWarpPerspectiveBack_8u_C4R_t icvWarpPerspectiveBack_8u_C4R_p = 0;
+icvWarpPerspectiveBack_32f_C1R_t icvWarpPerspectiveBack_32f_C1R_p = 0;
+icvWarpPerspectiveBack_32f_C3R_t icvWarpPerspectiveBack_32f_C3R_p = 0;
+icvWarpPerspectiveBack_32f_C4R_t icvWarpPerspectiveBack_32f_C4R_p = 0;
+
+icvWarpPerspective_8u_C1R_t icvWarpPerspective_8u_C1R_p = 0;
+icvWarpPerspective_8u_C3R_t icvWarpPerspective_8u_C3R_p = 0;
+icvWarpPerspective_8u_C4R_t icvWarpPerspective_8u_C4R_p = 0;
+icvWarpPerspective_32f_C1R_t icvWarpPerspective_32f_C1R_p = 0;
+icvWarpPerspective_32f_C3R_t icvWarpPerspective_32f_C3R_p = 0;
+icvWarpPerspective_32f_C4R_t icvWarpPerspective_32f_C4R_p = 0;
+
+typedef CvStatus (CV_STDCALL * CvWarpPerspectiveBackIPPFunc)
+( const void* src, CvSize srcsize, int srcstep, CvRect srcroi,
+ void* dst, int dststep, CvRect dstroi,
+ const double* coeffs, int interpolation );
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+CV_IMPL void
+cvWarpPerspective( const CvArr* srcarr, CvArr* dstarr,
+ const CvMat* matrix, int flags, CvScalar fillval )
+{
+ static CvFuncTable bilin_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvWarpPerspective" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ int type, depth, cn;
+ int method = flags & 3;
+ double src_matrix[9], dst_matrix[9];
+ double fillbuf[4];
+ CvMat A = cvMat( 3, 3, CV_64F, src_matrix ),
+ invA = cvMat( 3, 3, CV_64F, dst_matrix );
+ CvWarpPerspectiveFunc func;
+ CvSize ssize, dsize;
+
+ if( method == CV_INTER_NN || method == CV_INTER_AREA )
+ method = CV_INTER_LINEAR;
+
+ if( !inittab )
+ {
+ icvInitWarpPerspectiveTab( &bilin_tab );
+ inittab = 1;
+ }
+
+ CV_CALL( src = cvGetMat( srcarr, &srcstub ));
+ CV_CALL( dst = cvGetMat( dstarr, &dststub ));
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( !CV_IS_MAT(matrix) || CV_MAT_CN(matrix->type) != 1 ||
+ CV_MAT_DEPTH(matrix->type) < CV_32F || matrix->rows != 3 || matrix->cols != 3 )
+ CV_ERROR( CV_StsBadArg,
+ "Transformation matrix should be 3x3 floating-point single-channel matrix" );
+
+ if( flags & CV_WARP_INVERSE_MAP )
+ cvConvertScale( matrix, &invA );
+ else
+ {
+ cvConvertScale( matrix, &A );
+ cvInvert( &A, &invA, CV_SVD );
+ }
+
+ type = CV_MAT_TYPE(src->type);
+ depth = CV_MAT_DEPTH(type);
+ cn = CV_MAT_CN(type);
+ if( cn > 4 )
+ CV_ERROR( CV_BadNumChannels, "" );
+
+ ssize = cvGetMatSize(src);
+ dsize = cvGetMatSize(dst);
+
+ if( icvWarpPerspectiveBack_8u_C1R_p )
+ {
+ CvWarpPerspectiveBackIPPFunc ipp_func =
+ type == CV_8UC1 ? icvWarpPerspectiveBack_8u_C1R_p :
+ type == CV_8UC3 ? icvWarpPerspectiveBack_8u_C3R_p :
+ type == CV_8UC4 ? icvWarpPerspectiveBack_8u_C4R_p :
+ type == CV_32FC1 ? icvWarpPerspectiveBack_32f_C1R_p :
+ type == CV_32FC3 ? icvWarpPerspectiveBack_32f_C3R_p :
+ type == CV_32FC4 ? icvWarpPerspectiveBack_32f_C4R_p : 0;
+
+ if( ipp_func && CV_INTER_NN <= method && method <= CV_INTER_AREA &&
+ MIN(ssize.width,ssize.height) >= 4 && MIN(dsize.width,dsize.height) >= 4 )
+ {
+ int srcstep = src->step ? src->step : CV_STUB_STEP;
+ int dststep = dst->step ? dst->step : CV_STUB_STEP;
+ CvStatus status;
+ CvRect srcroi = {0, 0, ssize.width, ssize.height};
+ CvRect dstroi = {0, 0, dsize.width, dsize.height};
+
+ // this is not the most efficient way to fill outliers
+ if( flags & CV_WARP_FILL_OUTLIERS )
+ cvSet( dst, fillval );
+
+ status = ipp_func( src->data.ptr, ssize, srcstep, srcroi,
+ dst->data.ptr, dststep, dstroi,
+ invA.data.db, 1 << method );
+ if( status >= 0 )
+ EXIT;
+
+ ipp_func = type == CV_8UC1 ? icvWarpPerspective_8u_C1R_p :
+ type == CV_8UC3 ? icvWarpPerspective_8u_C3R_p :
+ type == CV_8UC4 ? icvWarpPerspective_8u_C4R_p :
+ type == CV_32FC1 ? icvWarpPerspective_32f_C1R_p :
+ type == CV_32FC3 ? icvWarpPerspective_32f_C3R_p :
+ type == CV_32FC4 ? icvWarpPerspective_32f_C4R_p : 0;
+
+ if( ipp_func )
+ {
+ if( flags & CV_WARP_INVERSE_MAP )
+ cvInvert( &invA, &A, CV_SVD );
+
+ status = ipp_func( src->data.ptr, ssize, srcstep, srcroi,
+ dst->data.ptr, dststep, dstroi,
+ A.data.db, 1 << method );
+ if( status >= 0 )
+ EXIT;
+ }
+ }
+ }
+
+ cvScalarToRawData( &fillval, fillbuf, CV_MAT_TYPE(src->type), 0 );
+
+ /*if( method == CV_INTER_LINEAR )*/
+ {
+ func = (CvWarpPerspectiveFunc)bilin_tab.fn_2d[depth];
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src->data.ptr, src->step, ssize, dst->data.ptr,
+ dst->step, dsize, dst_matrix, cn,
+ flags & CV_WARP_FILL_OUTLIERS ? fillbuf : 0 ));
+ }
+
+ __END__;
+}
+
+
+/* Calculates coefficients of perspective transformation
+ * which maps (xi,yi) to (ui,vi), (i=1,2,3,4):
+ *
+ * c00*xi + c01*yi + c02
+ * ui = ---------------------
+ * c20*xi + c21*yi + c22
+ *
+ * c10*xi + c11*yi + c12
+ * vi = ---------------------
+ * c20*xi + c21*yi + c22
+ *
+ * Coefficients are calculated by solving linear system:
+ * / x0 y0 1 0 0 0 -x0*u0 -y0*u0 \ /c00\ /u0\
+ * | x1 y1 1 0 0 0 -x1*u1 -y1*u1 | |c01| |u1|
+ * | x2 y2 1 0 0 0 -x2*u2 -y2*u2 | |c02| |u2|
+ * | x3 y3 1 0 0 0 -x3*u3 -y3*u3 |.|c10|=|u3|,
+ * | 0 0 0 x0 y0 1 -x0*v0 -y0*v0 | |c11| |v0|
+ * | 0 0 0 x1 y1 1 -x1*v1 -y1*v1 | |c12| |v1|
+ * | 0 0 0 x2 y2 1 -x2*v2 -y2*v2 | |c20| |v2|
+ * \ 0 0 0 x3 y3 1 -x3*v3 -y3*v3 / \c21/ \v3/
+ *
+ * where:
+ * cij - matrix coefficients, c22 = 1
+ */
+CV_IMPL CvMat*
+cvGetPerspectiveTransform( const CvPoint2D32f* src,
+ const CvPoint2D32f* dst,
+ CvMat* matrix )
+{
+ CV_FUNCNAME( "cvGetPerspectiveTransform" );
+
+ __BEGIN__;
+
+ double a[8][8];
+ double b[8], x[9];
+
+ CvMat A = cvMat( 8, 8, CV_64FC1, a );
+ CvMat B = cvMat( 8, 1, CV_64FC1, b );
+ CvMat X = cvMat( 8, 1, CV_64FC1, x );
+
+ int i;
+
+ if( !src || !dst || !matrix )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ for( i = 0; i < 4; ++i )
+ {
+ a[i][0] = a[i+4][3] = src[i].x;
+ a[i][1] = a[i+4][4] = src[i].y;
+ a[i][2] = a[i+4][5] = 1;
+ a[i][3] = a[i][4] = a[i][5] =
+ a[i+4][0] = a[i+4][1] = a[i+4][2] = 0;
+ a[i][6] = -src[i].x*dst[i].x;
+ a[i][7] = -src[i].y*dst[i].x;
+ a[i+4][6] = -src[i].x*dst[i].y;
+ a[i+4][7] = -src[i].y*dst[i].y;
+ b[i] = dst[i].x;
+ b[i+4] = dst[i].y;
+ }
+
+ cvSolve( &A, &B, &X, CV_SVD );
+ x[8] = 1;
+
+ X = cvMat( 3, 3, CV_64FC1, x );
+ cvConvert( &X, matrix );
+
+ __END__;
+
+ return matrix;
+}
+
+/* Calculates coefficients of affine transformation
+ * which maps (xi,yi) to (ui,vi), (i=1,2,3):
+ *
+ * ui = c00*xi + c01*yi + c02
+ *
+ * vi = c10*xi + c11*yi + c12
+ *
+ * Coefficients are calculated by solving linear system:
+ * / x0 y0 1 0 0 0 \ /c00\ /u0\
+ * | x1 y1 1 0 0 0 | |c01| |u1|
+ * | x2 y2 1 0 0 0 | |c02| |u2|
+ * | 0 0 0 x0 y0 1 | |c10| |v0|
+ * | 0 0 0 x1 y1 1 | |c11| |v1|
+ * \ 0 0 0 x2 y2 1 / |c12| |v2|
+ *
+ * where:
+ * cij - matrix coefficients
+ */
+CV_IMPL CvMat*
+cvGetAffineTransform( const CvPoint2D32f * src, const CvPoint2D32f * dst, CvMat * map_matrix )
+{
+ CV_FUNCNAME( "cvGetAffineTransform" );
+
+ __BEGIN__;
+
+ CvMat mA, mX, mB;
+ double A[6*6];
+ double B[6];
+ double x[6];
+ int i;
+
+ cvInitMatHeader(&mA, 6, 6, CV_64F, A);
+ cvInitMatHeader(&mB, 6, 1, CV_64F, B);
+ cvInitMatHeader(&mX, 6, 1, CV_64F, x);
+
+ if( !src || !dst || !map_matrix )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ for( i = 0; i < 3; i++ )
+ {
+ int j = i*12;
+ int k = i*12+6;
+ A[j] = A[k+3] = src[i].x;
+ A[j+1] = A[k+4] = src[i].y;
+ A[j+2] = A[k+5] = 1;
+ A[j+3] = A[j+4] = A[j+5] = 0;
+ A[k] = A[k+1] = A[k+2] = 0;
+ B[i*2] = dst[i].x;
+ B[i*2+1] = dst[i].y;
+ }
+ cvSolve(&mA, &mB, &mX);
+
+ mX = cvMat( 2, 3, CV_64FC1, x );
+ cvConvert( &mX, map_matrix );
+
+ __END__;
+ return map_matrix;
+}
+
+/****************************************************************************************\
+* Generic Geometric Transformation: Remap *
+\****************************************************************************************/
+
+#define ICV_DEF_REMAP_BILINEAR_FUNC( flavor, arrtype, load_macro, cast_macro ) \
+static CvStatus CV_STDCALL \
+icvRemap_Bilinear_##flavor##_CnR( const arrtype* src, int srcstep, CvSize ssize,\
+ arrtype* dst, int dststep, CvSize dsize, \
+ const float* mapx, int mxstep, \
+ const float* mapy, int mystep, \
+ int cn, const arrtype* fillval ) \
+{ \
+ int i, j, k; \
+ ssize.width--; \
+ ssize.height--; \
+ \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ mxstep /= sizeof(mapx[0]); \
+ mystep /= sizeof(mapy[0]); \
+ \
+ for( i = 0; i < dsize.height; i++, dst += dststep, \
+ mapx += mxstep, mapy += mystep ) \
+ { \
+ for( j = 0; j < dsize.width; j++ ) \
+ { \
+ float _x = mapx[j], _y = mapy[j]; \
+ int ix = cvFloor(_x), iy = cvFloor(_y); \
+ \
+ if( (unsigned)ix < (unsigned)ssize.width && \
+ (unsigned)iy < (unsigned)ssize.height ) \
+ { \
+ const arrtype* s = src + iy*srcstep + ix*cn; \
+ _x -= ix; _y -= iy; \
+ for( k = 0; k < cn; k++, s++ ) \
+ { \
+ float t0 = load_macro(s[0]), t1 = load_macro(s[srcstep]); \
+ t0 += _x*(load_macro(s[cn]) - t0); \
+ t1 += _x*(load_macro(s[srcstep + cn]) - t1); \
+ dst[j*cn + k] = (arrtype)cast_macro(t0 + _y*(t1 - t0)); \
+ } \
+ } \
+ else if( fillval ) \
+ for( k = 0; k < cn; k++ ) \
+ dst[j*cn + k] = fillval[k]; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_REMAP_BICUBIC_FUNC( flavor, arrtype, worktype, \
+ load_macro, cast_macro1, cast_macro2 ) \
+static CvStatus CV_STDCALL \
+icvRemap_Bicubic_##flavor##_CnR( const arrtype* src, int srcstep, CvSize ssize, \
+ arrtype* dst, int dststep, CvSize dsize, \
+ const float* mapx, int mxstep, \
+ const float* mapy, int mystep, \
+ int cn, const arrtype* fillval ) \
+{ \
+ int i, j, k; \
+ ssize.width = MAX( ssize.width - 3, 0 ); \
+ ssize.height = MAX( ssize.height - 3, 0 ); \
+ \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ mxstep /= sizeof(mapx[0]); \
+ mystep /= sizeof(mapy[0]); \
+ \
+ for( i = 0; i < dsize.height; i++, dst += dststep, \
+ mapx += mxstep, mapy += mystep ) \
+ { \
+ for( j = 0; j < dsize.width; j++ ) \
+ { \
+ int ix = cvRound(mapx[j]*(1 << ICV_WARP_SHIFT)); \
+ int iy = cvRound(mapy[j]*(1 << ICV_WARP_SHIFT)); \
+ int ifx = ix & ICV_WARP_MASK; \
+ int ify = iy & ICV_WARP_MASK; \
+ ix >>= ICV_WARP_SHIFT; \
+ iy >>= ICV_WARP_SHIFT; \
+ \
+ if( (unsigned)(ix-1) < (unsigned)ssize.width && \
+ (unsigned)(iy-1) < (unsigned)ssize.height ) \
+ { \
+ for( k = 0; k < cn; k++ ) \
+ { \
+ const arrtype* s = src + (iy-1)*srcstep + ix*cn + k; \
+ \
+ float t0 = load_macro(s[-cn])*icvCubicCoeffs[ifx*2 + 1] + \
+ load_macro(s[0])*icvCubicCoeffs[ifx*2] + \
+ load_macro(s[cn])*icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE-ifx)*2] +\
+ load_macro(s[cn*2])*icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE-ifx)*2+1];\
+ \
+ s += srcstep; \
+ \
+ float t1 = load_macro(s[-cn])*icvCubicCoeffs[ifx*2 + 1] + \
+ load_macro(s[0])*icvCubicCoeffs[ifx*2] + \
+ load_macro(s[cn])*icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE-ifx)*2] +\
+ load_macro(s[cn*2])*icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE-ifx)*2+1];\
+ \
+ s += srcstep; \
+ \
+ float t2 = load_macro(s[-cn])*icvCubicCoeffs[ifx*2 + 1] + \
+ load_macro(s[0])*icvCubicCoeffs[ifx*2] + \
+ load_macro(s[cn])*icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE-ifx)*2] +\
+ load_macro(s[cn*2])*icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE-ifx)*2+1];\
+ \
+ s += srcstep; \
+ \
+ float t3 = load_macro(s[-cn])*icvCubicCoeffs[ifx*2 + 1] + \
+ load_macro(s[0])*icvCubicCoeffs[ifx*2] + \
+ load_macro(s[cn])*icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE-ifx)*2] +\
+ load_macro(s[cn*2])*icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE-ifx)*2+1];\
+ \
+ worktype t = cast_macro1( t0*icvCubicCoeffs[ify*2 + 1] + \
+ t1*icvCubicCoeffs[ify*2] + \
+ t2*icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE-ify)*2] + \
+ t3*icvCubicCoeffs[(ICV_CUBIC_TAB_SIZE-ify)*2+1] );\
+ \
+ dst[j*cn + k] = cast_macro2(t); \
+ } \
+ } \
+ else if( fillval ) \
+ for( k = 0; k < cn; k++ ) \
+ dst[j*cn + k] = fillval[k]; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_REMAP_BILINEAR_FUNC( 8u, uchar, CV_8TO32F, cvRound )
+ICV_DEF_REMAP_BILINEAR_FUNC( 16u, ushort, CV_NOP, cvRound )
+ICV_DEF_REMAP_BILINEAR_FUNC( 32f, float, CV_NOP, CV_NOP )
+
+ICV_DEF_REMAP_BICUBIC_FUNC( 8u, uchar, int, CV_8TO32F, cvRound, CV_FAST_CAST_8U )
+ICV_DEF_REMAP_BICUBIC_FUNC( 16u, ushort, int, CV_NOP, cvRound, CV_CAST_16U )
+ICV_DEF_REMAP_BICUBIC_FUNC( 32f, float, float, CV_NOP, CV_NOP, CV_NOP )
+
+typedef CvStatus (CV_STDCALL * CvRemapFunc)(
+ const void* src, int srcstep, CvSize ssize,
+ void* dst, int dststep, CvSize dsize,
+ const float* mapx, int mxstep,
+ const float* mapy, int mystep,
+ int cn, const void* fillval );
+
+static void icvInitRemapTab( CvFuncTable* bilinear_tab, CvFuncTable* bicubic_tab )
+{
+ bilinear_tab->fn_2d[CV_8U] = (void*)icvRemap_Bilinear_8u_CnR;
+ bilinear_tab->fn_2d[CV_16U] = (void*)icvRemap_Bilinear_16u_CnR;
+ bilinear_tab->fn_2d[CV_32F] = (void*)icvRemap_Bilinear_32f_CnR;
+
+ bicubic_tab->fn_2d[CV_8U] = (void*)icvRemap_Bicubic_8u_CnR;
+ bicubic_tab->fn_2d[CV_16U] = (void*)icvRemap_Bicubic_16u_CnR;
+ bicubic_tab->fn_2d[CV_32F] = (void*)icvRemap_Bicubic_32f_CnR;
+}
+
+
+/******************** IPP remap functions *********************/
+
+typedef CvStatus (CV_STDCALL * CvRemapIPPFunc)(
+ const void* src, CvSize srcsize, int srcstep, CvRect srcroi,
+ const float* xmap, int xmapstep, const float* ymap, int ymapstep,
+ void* dst, int dststep, CvSize dstsize, int interpolation );
+
+icvRemap_8u_C1R_t icvRemap_8u_C1R_p = 0;
+icvRemap_8u_C3R_t icvRemap_8u_C3R_p = 0;
+icvRemap_8u_C4R_t icvRemap_8u_C4R_p = 0;
+
+icvRemap_32f_C1R_t icvRemap_32f_C1R_p = 0;
+icvRemap_32f_C3R_t icvRemap_32f_C3R_p = 0;
+icvRemap_32f_C4R_t icvRemap_32f_C4R_p = 0;
+
+/**************************************************************/
+
+#define CV_REMAP_SHIFT 5
+#define CV_REMAP_MASK ((1 << CV_REMAP_SHIFT) - 1)
+
+#if CV_SSE2 && defined(__GNUC__)
+#define align(x) __attribute__ ((aligned (x)))
+#elif CV_SSE2 && (defined(__ICL) || defined _MSC_VER && _MSC_VER >= 1300)
+#define align(x) __declspec(align(x))
+#else
+#define align(x)
+#endif
+
+static void icvRemapFixedPt_8u( const CvMat* src, CvMat* dst,
+ const CvMat* xymap, const CvMat* amap, const uchar* fillval )
+{
+ const int TABSZ = 1 << (CV_REMAP_SHIFT*2);
+ static ushort align(8) atab[TABSZ][4];
+ static int inittab = 0;
+
+ int x, y, cols = src->cols, rows = src->rows;
+ const uchar* sptr0 = src->data.ptr;
+ int sstep = src->step;
+ uchar fv0 = fillval[0], fv1 = fillval[1], fv2 = fillval[2], fv3 = fillval[3];
+ int cn = CV_MAT_CN(src->type);
+#if CV_SSE2
+ const uchar* sptr1 = sptr0 + sstep;
+ __m128i br = _mm_set1_epi32((cols-2) + ((rows-2)<<16));
+ __m128i xy2ofs = _mm_set1_epi32(1 + (sstep << 16));
+ __m128i z = _mm_setzero_si128();
+ int align(16) iofs0[4], iofs1[4];
+#endif
+
+ if( !inittab )
+ {
+ for( y = 0; y <= CV_REMAP_MASK; y++ )
+ for( x = 0; x <= CV_REMAP_MASK; x++ )
+ {
+ int k = (y << CV_REMAP_SHIFT) + x;
+ atab[k][0] = (ushort)((CV_REMAP_MASK+1 - y)*(CV_REMAP_MASK+1 - x));
+ atab[k][1] = (ushort)((CV_REMAP_MASK+1 - y)*x);
+ atab[k][2] = (ushort)(y*(CV_REMAP_MASK+1 - x));
+ atab[k][3] = (ushort)(y*x);
+ }
+ inittab = 1;
+ }
+
+ for( y = 0; y < rows; y++ )
+ {
+ const short* xy = (const short*)(xymap->data.ptr + xymap->step*y);
+ const ushort* alpha = (const ushort*)(amap->data.ptr + amap->step*y);
+ uchar* dptr = (uchar*)(dst->data.ptr + dst->step*y);
+ int x = 0;
+
+ if( cn == 1 )
+ {
+ #if CV_SSE2
+ for( ; x <= cols - 8; x += 8 )
+ {
+ __m128i xy0 = _mm_load_si128( (const __m128i*)(xy + x*2));
+ __m128i xy1 = _mm_load_si128( (const __m128i*)(xy + x*2 + 8));
+ // 0|0|0|0|... <= x0|y0|x1|y1|... < cols-1|rows-1|cols-1|rows-1|... ?
+ __m128i mask0 = _mm_cmpeq_epi32(_mm_or_si128(_mm_cmpgt_epi16(z, xy0),
+ _mm_cmpgt_epi16(xy0,br)), z);
+ __m128i mask1 = _mm_cmpeq_epi32(_mm_or_si128(_mm_cmpgt_epi16(z, xy1),
+ _mm_cmpgt_epi16(xy1,br)), z);
+ __m128i ofs0 = _mm_and_si128(_mm_madd_epi16( xy0, xy2ofs ), mask0 );
+ __m128i ofs1 = _mm_and_si128(_mm_madd_epi16( xy1, xy2ofs ), mask1 );
+ unsigned i0, i1;
+ __m128i v0, v1, v2, v3, a0, a1, b0, b1;
+ _mm_store_si128( (__m128i*)iofs0, ofs0 );
+ _mm_store_si128( (__m128i*)iofs1, ofs1 );
+ i0 = *(ushort*)(sptr0 + iofs0[0]) + (*(ushort*)(sptr0 + iofs0[1]) << 16);
+ i1 = *(ushort*)(sptr0 + iofs0[2]) + (*(ushort*)(sptr0 + iofs0[3]) << 16);
+ v0 = _mm_unpacklo_epi32(_mm_cvtsi32_si128(i0), _mm_cvtsi32_si128(i1));
+ i0 = *(ushort*)(sptr1 + iofs0[0]) + (*(ushort*)(sptr1 + iofs0[1]) << 16);
+ i1 = *(ushort*)(sptr1 + iofs0[2]) + (*(ushort*)(sptr1 + iofs0[3]) << 16);
+ v1 = _mm_unpacklo_epi32(_mm_cvtsi32_si128(i0), _mm_cvtsi32_si128(i1));
+ v0 = _mm_unpacklo_epi8(v0, z);
+ v1 = _mm_unpacklo_epi8(v1, z);
+
+ a0 = _mm_unpacklo_epi32(_mm_loadl_epi64((__m128i*)atab[alpha[x]]),
+ _mm_loadl_epi64((__m128i*)atab[alpha[x+1]]));
+ a1 = _mm_unpacklo_epi32(_mm_loadl_epi64((__m128i*)atab[alpha[x+2]]),
+ _mm_loadl_epi64((__m128i*)atab[alpha[x+3]]));
+ b0 = _mm_unpacklo_epi64(a0, a1);
+ b1 = _mm_unpackhi_epi64(a0, a1);
+ v0 = _mm_madd_epi16(v0, b0);
+ v1 = _mm_madd_epi16(v1, b1);
+ v0 = _mm_and_si128(_mm_add_epi32(v0, v1), mask0);
+
+ i0 = *(ushort*)(sptr0 + iofs1[0]) + (*(ushort*)(sptr0 + iofs1[1]) << 16);
+ i1 = *(ushort*)(sptr0 + iofs1[2]) + (*(ushort*)(sptr0 + iofs1[3]) << 16);
+ v2 = _mm_unpacklo_epi32(_mm_cvtsi32_si128(i0), _mm_cvtsi32_si128(i1));
+ i0 = *(ushort*)(sptr1 + iofs1[0]) + (*(ushort*)(sptr1 + iofs1[1]) << 16);
+ i1 = *(ushort*)(sptr1 + iofs1[2]) + (*(ushort*)(sptr1 + iofs1[3]) << 16);
+ v3 = _mm_unpacklo_epi32(_mm_cvtsi32_si128(i0), _mm_cvtsi32_si128(i1));
+ v2 = _mm_unpacklo_epi8(v2, z);
+ v3 = _mm_unpacklo_epi8(v3, z);
+
+ a0 = _mm_unpacklo_epi32(_mm_loadl_epi64((__m128i*)atab[alpha[x+4]]),
+ _mm_loadl_epi64((__m128i*)atab[alpha[x+5]]));
+ a1 = _mm_unpacklo_epi32(_mm_loadl_epi64((__m128i*)atab[alpha[x+6]]),
+ _mm_loadl_epi64((__m128i*)atab[alpha[x+7]]));
+ b0 = _mm_unpacklo_epi64(a0, a1);
+ b1 = _mm_unpackhi_epi64(a0, a1);
+ v2 = _mm_madd_epi16(v2, b0);
+ v3 = _mm_madd_epi16(v3, b1);
+ v2 = _mm_and_si128(_mm_add_epi32(v2, v3), mask1);
+
+ v0 = _mm_srai_epi32(v0, CV_REMAP_SHIFT*2);
+ v2 = _mm_srai_epi32(v2, CV_REMAP_SHIFT*2);
+ v0 = _mm_packus_epi16(_mm_packs_epi32(v0, v2), z);
+ _mm_storel_epi64( (__m128i*)(dptr + x), v0 );
+ }
+ #endif
+
+ for( ; x < cols; x++ )
+ {
+ int xi = xy[x*2], yi = xy[x*2+1];
+ if( (unsigned)yi >= (unsigned)(rows - 1) ||
+ (unsigned)xi >= (unsigned)(cols - 1))
+ {
+ dptr[x] = fv0;
+ }
+ else
+ {
+ const uchar* sptr = sptr0 + sstep*yi + xi;
+ const ushort* a = atab[alpha[x]];
+ dptr[x] = (uchar)((sptr[0]*a[0] + sptr[1]*a[1] + sptr[sstep]*a[2] +
+ sptr[sstep+1]*a[3])>>CV_REMAP_SHIFT*2);
+ }
+ }
+ }
+ else if( cn == 3 )
+ {
+ for( ; x < cols; x++ )
+ {
+ int xi = xy[x*2], yi = xy[x*2+1];
+ if( (unsigned)yi >= (unsigned)(rows - 1) ||
+ (unsigned)xi >= (unsigned)(cols - 1))
+ {
+ dptr[x*3] = fv0; dptr[x*3+1] = fv1; dptr[x*3+2] = fv2;
+ }
+ else
+ {
+ const uchar* sptr = sptr0 + sstep*yi + xi*3;
+ const ushort* a = atab[alpha[x]];
+ int v0, v1, v2;
+ v0 = (sptr[0]*a[0] + sptr[3]*a[1] +
+ sptr[sstep]*a[2] + sptr[sstep+3]*a[3])>>CV_REMAP_SHIFT*2;
+ v1 = (sptr[1]*a[0] + sptr[4]*a[1] +
+ sptr[sstep+1]*a[2] + sptr[sstep+4]*a[3])>>CV_REMAP_SHIFT*2;
+ v2 = (sptr[2]*a[0] + sptr[5]*a[1] +
+ sptr[sstep+2]*a[2] + sptr[sstep+5]*a[3])>>CV_REMAP_SHIFT*2;
+ dptr[x*3] = (uchar)v0; dptr[x*3+1] = (uchar)v1; dptr[x*3+2] = (uchar)v2;
+ }
+ }
+ }
+ else
+ {
+ assert( cn == 4 );
+ for( ; x < cols; x++ )
+ {
+ int xi = xy[x*2], yi = xy[x*2+1];
+ if( (unsigned)yi >= (unsigned)(rows - 1) ||
+ (unsigned)xi >= (unsigned)(cols - 1))
+ {
+ dptr[x*4] = fv0; dptr[x*4+1] = fv1;
+ dptr[x*4+2] = fv2; dptr[x*4+3] = fv3;
+ }
+ else
+ {
+ const uchar* sptr = sptr0 + sstep*yi + xi*3;
+ const ushort* a = atab[alpha[x]];
+ int v0, v1;
+ v0 = (sptr[0]*a[0] + sptr[4]*a[1] +
+ sptr[sstep]*a[2] + sptr[sstep+3]*a[3])>>CV_REMAP_SHIFT*2;
+ v1 = (sptr[1]*a[0] + sptr[5]*a[1] +
+ sptr[sstep+1]*a[2] + sptr[sstep+5]*a[3])>>CV_REMAP_SHIFT*2;
+ dptr[x*4] = (uchar)v0; dptr[x*4+1] = (uchar)v1;
+ v0 = (sptr[2]*a[0] + sptr[6]*a[1] +
+ sptr[sstep+2]*a[2] + sptr[sstep+6]*a[3])>>CV_REMAP_SHIFT*2;
+ v1 = (sptr[3]*a[0] + sptr[7]*a[1] +
+ sptr[sstep+3]*a[2] + sptr[sstep+7]*a[3])>>CV_REMAP_SHIFT*2;
+ dptr[x*4+2] = (uchar)v0; dptr[x*4+3] = (uchar)v1;
+ }
+ }
+ }
+ }
+}
+
+
+CV_IMPL void
+cvRemap( const CvArr* srcarr, CvArr* dstarr,
+ const CvArr* _mapx, const CvArr* _mapy,
+ int flags, CvScalar fillval )
+{
+ static CvFuncTable bilinear_tab;
+ static CvFuncTable bicubic_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvRemap" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvMat mxstub, *mapx = (CvMat*)_mapx;
+ CvMat mystub, *mapy = (CvMat*)_mapy;
+ int type, depth, cn;
+ bool fltremap;
+ int method = flags & 3;
+ double fillbuf[4];
+ CvSize ssize, dsize;
+
+ if( !inittab )
+ {
+ icvInitRemapTab( &bilinear_tab, &bicubic_tab );
+ icvInitLinearCoeffTab();
+ icvInitCubicCoeffTab();
+ inittab = 1;
+ }
+
+ CV_CALL( src = cvGetMat( srcarr, &srcstub ));
+ CV_CALL( dst = cvGetMat( dstarr, &dststub ));
+ CV_CALL( mapx = cvGetMat( mapx, &mxstub ));
+ CV_CALL( mapy = cvGetMat( mapy, &mystub ));
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( CV_MAT_TYPE(mapx->type) == CV_16SC1 && CV_MAT_TYPE(mapy->type) == CV_16SC2 )
+ {
+ CvMat* temp;
+ CV_SWAP(mapx, mapy, temp);
+ }
+
+ if( (CV_MAT_TYPE(mapx->type) != CV_32FC1 || CV_MAT_TYPE(mapy->type) != CV_32FC1) &&
+ (CV_MAT_TYPE(mapx->type) != CV_16SC2 || CV_MAT_TYPE(mapy->type) != CV_16SC1))
+ CV_ERROR( CV_StsUnmatchedFormats, "Either both map arrays must have 32fC1 type, "
+ "or one of them must be 16sC2 and the other one must be 16sC1" );
+
+ if( !CV_ARE_SIZES_EQ( mapx, mapy ) || !CV_ARE_SIZES_EQ( mapx, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Both map arrays and the destination array must have the same size" );
+
+ fltremap = CV_MAT_TYPE(mapx->type) == CV_32FC1;
+ type = CV_MAT_TYPE(src->type);
+ depth = CV_MAT_DEPTH(type);
+ cn = CV_MAT_CN(type);
+ if( cn > 4 )
+ CV_ERROR( CV_BadNumChannels, "" );
+
+ ssize = cvGetMatSize(src);
+ dsize = cvGetMatSize(dst);
+
+ cvScalarToRawData( &fillval, fillbuf, CV_MAT_TYPE(src->type), 0 );
+
+ if( !fltremap )
+ {
+ if( CV_MAT_TYPE(src->type) != CV_8UC1 && CV_MAT_TYPE(src->type) != CV_8UC3 &&
+ CV_MAT_TYPE(src->type) != CV_8UC4 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Only 8-bit input/output is supported by the fixed-point variant of cvRemap" );
+ icvRemapFixedPt_8u( src, dst, mapx, mapy, (uchar*)fillbuf );
+ EXIT;
+ }
+
+ if( icvRemap_8u_C1R_p )
+ {
+ CvRemapIPPFunc ipp_func =
+ type == CV_8UC1 ? icvRemap_8u_C1R_p :
+ type == CV_8UC3 ? icvRemap_8u_C3R_p :
+ type == CV_8UC4 ? icvRemap_8u_C4R_p :
+ type == CV_32FC1 ? icvRemap_32f_C1R_p :
+ type == CV_32FC3 ? icvRemap_32f_C3R_p :
+ type == CV_32FC4 ? icvRemap_32f_C4R_p : 0;
+
+ if( ipp_func )
+ {
+ int srcstep = src->step ? src->step : CV_STUB_STEP;
+ int dststep = dst->step ? dst->step : CV_STUB_STEP;
+ int mxstep = mapx->step ? mapx->step : CV_STUB_STEP;
+ int mystep = mapy->step ? mapy->step : CV_STUB_STEP;
+ CvStatus status;
+ CvRect srcroi = {0, 0, ssize.width, ssize.height};
+
+ // this is not the most efficient way to fill outliers
+ if( flags & CV_WARP_FILL_OUTLIERS )
+ cvSet( dst, fillval );
+
+ status = ipp_func( src->data.ptr, ssize, srcstep, srcroi,
+ mapx->data.fl, mxstep, mapy->data.fl, mystep,
+ dst->data.ptr, dststep, dsize,
+ 1 << (method == CV_INTER_NN || method == CV_INTER_LINEAR ||
+ method == CV_INTER_CUBIC ? method : CV_INTER_LINEAR) );
+ if( status >= 0 )
+ EXIT;
+ }
+ }
+
+ {
+ CvRemapFunc func = method == CV_INTER_CUBIC ?
+ (CvRemapFunc)bicubic_tab.fn_2d[depth] :
+ (CvRemapFunc)bilinear_tab.fn_2d[depth];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ func( src->data.ptr, src->step, ssize, dst->data.ptr, dst->step, dsize,
+ mapx->data.fl, mapx->step, mapy->data.fl, mapy->step,
+ cn, flags & CV_WARP_FILL_OUTLIERS ? fillbuf : 0 );
+ }
+
+ __END__;
+}
+
+CV_IMPL void
+cvConvertMaps( const CvArr* arrx, const CvArr* arry,
+ CvArr* arrxy, CvArr* arra )
+{
+ CV_FUNCNAME( "cvConvertMaps" );
+
+ __BEGIN__;
+
+ CvMat xstub, *mapx = cvGetMat( arrx, &xstub );
+ CvMat ystub, *mapy = cvGetMat( arry, &ystub );
+ CvMat xystub, *mapxy = cvGetMat( arrxy, &xystub );
+ CvMat astub, *mapa = cvGetMat( arra, &astub );
+ int x, y, cols = mapx->cols, rows = mapx->rows;
+
+ CV_ASSERT( CV_ARE_SIZES_EQ(mapx, mapy) && CV_ARE_TYPES_EQ(mapx, mapy) &&
+ CV_MAT_TYPE(mapx->type) == CV_32FC1 &&
+ CV_ARE_SIZES_EQ(mapxy, mapx) && CV_ARE_SIZES_EQ(mapxy, mapa) &&
+ CV_MAT_TYPE(mapxy->type) == CV_16SC2 &&
+ CV_MAT_TYPE(mapa->type) == CV_16SC1 );
+
+ for( y = 0; y < rows; y++ )
+ {
+ const float* xrow = (const float*)(mapx->data.ptr + mapx->step*y);
+ const float* yrow = (const float*)(mapy->data.ptr + mapy->step*y);
+ short* xy = (short*)(mapxy->data.ptr + mapxy->step*y);
+ short* alpha = (short*)(mapa->data.ptr + mapa->step*y);
+
+ for( x = 0; x < cols; x++ )
+ {
+ int xi = cvRound(xrow[x]*(1 << CV_REMAP_SHIFT));
+ int yi = cvRound(yrow[x]*(1 << CV_REMAP_SHIFT));
+ xy[x*2] = (short)(xi >> CV_REMAP_SHIFT);
+ xy[x*2+1] = (short)(yi >> CV_REMAP_SHIFT);
+ alpha[x] = (short)((xi & CV_REMAP_MASK) + ((yi & CV_REMAP_MASK)<<CV_REMAP_SHIFT));
+ }
+ }
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* Log-Polar Transform *
+\****************************************************************************************/
+
+/* now it is done via Remap; more correct implementation should use
+ some super-sampling technique outside of the "fovea" circle */
+CV_IMPL void
+cvLogPolar( const CvArr* srcarr, CvArr* dstarr,
+ CvPoint2D32f center, double M, int flags )
+{
+ CvMat* mapx = 0;
+ CvMat* mapy = 0;
+ double* exp_tab = 0;
+ float* buf = 0;
+
+ CV_FUNCNAME( "cvLogPolar" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize ssize, dsize;
+
+ CV_CALL( src = cvGetMat( srcarr, &srcstub ));
+ CV_CALL( dst = cvGetMat( dstarr, &dststub ));
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( M <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "M should be >0" );
+
+ ssize = cvGetMatSize(src);
+ dsize = cvGetMatSize(dst);
+
+ CV_CALL( mapx = cvCreateMat( dsize.height, dsize.width, CV_32F ));
+ CV_CALL( mapy = cvCreateMat( dsize.height, dsize.width, CV_32F ));
+
+ if( !(flags & CV_WARP_INVERSE_MAP) )
+ {
+ int phi, rho;
+
+ CV_CALL( exp_tab = (double*)cvAlloc( dsize.width*sizeof(exp_tab[0])) );
+
+ for( rho = 0; rho < dst->width; rho++ )
+ exp_tab[rho] = exp(rho/M);
+
+ for( phi = 0; phi < dsize.height; phi++ )
+ {
+ double cp = cos(phi*2*CV_PI/dsize.height);
+ double sp = sin(phi*2*CV_PI/dsize.height);
+ float* mx = (float*)(mapx->data.ptr + phi*mapx->step);
+ float* my = (float*)(mapy->data.ptr + phi*mapy->step);
+
+ for( rho = 0; rho < dsize.width; rho++ )
+ {
+ double r = exp_tab[rho];
+ double x = r*cp + center.x;
+ double y = r*sp + center.y;
+
+ mx[rho] = (float)x;
+ my[rho] = (float)y;
+ }
+ }
+ }
+ else
+ {
+ int x, y;
+ CvMat bufx, bufy, bufp, bufa;
+ double ascale = (ssize.width-1)/(2*CV_PI);
+
+ CV_CALL( buf = (float*)cvAlloc( 4*dsize.width*sizeof(buf[0]) ));
+
+ bufx = cvMat( 1, dsize.width, CV_32F, buf );
+ bufy = cvMat( 1, dsize.width, CV_32F, buf + dsize.width );
+ bufp = cvMat( 1, dsize.width, CV_32F, buf + dsize.width*2 );
+ bufa = cvMat( 1, dsize.width, CV_32F, buf + dsize.width*3 );
+
+ for( x = 0; x < dsize.width; x++ )
+ bufx.data.fl[x] = (float)x - center.x;
+
+ for( y = 0; y < dsize.height; y++ )
+ {
+ float* mx = (float*)(mapx->data.ptr + y*mapx->step);
+ float* my = (float*)(mapy->data.ptr + y*mapy->step);
+
+ for( x = 0; x < dsize.width; x++ )
+ bufy.data.fl[x] = (float)y - center.y;
+
+#if 1
+ cvCartToPolar( &bufx, &bufy, &bufp, &bufa );
+
+ for( x = 0; x < dsize.width; x++ )
+ bufp.data.fl[x] += 1.f;
+
+ cvLog( &bufp, &bufp );
+
+ for( x = 0; x < dsize.width; x++ )
+ {
+ double rho = bufp.data.fl[x]*M;
+ double phi = bufa.data.fl[x]*ascale;
+
+ mx[x] = (float)rho;
+ my[x] = (float)phi;
+ }
+#else
+ for( x = 0; x < dsize.width; x++ )
+ {
+ double xx = bufx.data.fl[x];
+ double yy = bufy.data.fl[x];
+
+ double p = log(sqrt(xx*xx + yy*yy) + 1.)*M;
+ double a = atan2(yy,xx);
+ if( a < 0 )
+ a = 2*CV_PI + a;
+ a *= ascale;
+
+ mx[x] = (float)p;
+ my[x] = (float)a;
+ }
+#endif
+ }
+ }
+
+ cvRemap( src, dst, mapx, mapy, flags, cvScalarAll(0) );
+
+ __END__;
+
+ cvFree( &exp_tab );
+ cvFree( &buf );
+ cvReleaseMat( &mapx );
+ cvReleaseMat( &mapy );
+}
+
+/* End of file. */
diff --git a/cv/src/cvinpaint.cpp b/cv/src/cvinpaint.cpp
new file mode 100644
index 0000000..fbf471c
--- /dev/null
+++ b/cv/src/cvinpaint.cpp
@@ -0,0 +1,821 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective icvers.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/* ////////////////////////////////////////////////////////////////////
+//
+// Geometrical transforms on images and matrices: rotation, zoom etc.
+//
+// */
+
+#include "_cv.h"
+
+#undef CV_MAT_ELEM_PTR_FAST
+#define CV_MAT_ELEM_PTR_FAST( mat, row, col, pix_size ) \
+ ((mat).data.ptr + (size_t)(mat).step*(row) + (pix_size)*(col))
+
+inline float
+min4( float a, float b, float c, float d )
+{
+ a = MIN(a,b);
+ c = MIN(c,d);
+ return MIN(a,c);
+}
+
+#define CV_MAT_3COLOR_ELEM(img,type,y,x,c) CV_MAT_ELEM(img,type,y,(x)*3+(c))
+#define KNOWN 0 //known outside narrow band
+#define BAND 1 //narrow band (known)
+#define INSIDE 2 //unknown
+#define CHANGE 3 //servise
+
+typedef struct CvHeapElem
+{
+ float T;
+ int i,j;
+ struct CvHeapElem* prev;
+ struct CvHeapElem* next;
+}
+CvHeapElem;
+
+
+class CvPriorityQueueFloat
+{
+protected:
+ CvHeapElem *mem,*empty,*head,*tail;
+ int num,in;
+
+public:
+ bool Init( const CvMat* f )
+ {
+ int i,j;
+ for( i = num = 0; i < f->rows; i++ )
+ {
+ for( j = 0; j < f->cols; j++ )
+ num += CV_MAT_ELEM(*f,uchar,i,j)!=0;
+ }
+ if (num<=0) return false;
+ mem = (CvHeapElem*)cvAlloc((num+2)*sizeof(CvHeapElem));
+ if (mem==NULL) return false;
+
+ head = mem;
+ head->i = head->j = -1;
+ head->prev = NULL;
+ head->next = mem+1;
+ head->T = -FLT_MAX;
+ empty = mem+1;
+ for (i=1; i<=num; i++) {
+ mem[i].prev = mem+i-1;
+ mem[i].next = mem+i+1;
+ mem[i].i = mem[i].i = -1;
+ mem[i].T = FLT_MAX;
+ }
+ tail = mem+i;
+ tail->i = tail->j = -1;
+ tail->prev = mem+i-1;
+ tail->next = NULL;
+ tail->T = FLT_MAX;
+ return true;
+ }
+
+ bool Add(const CvMat* f) {
+ int i,j;
+ for (i=0; i<f->rows; i++) {
+ for (j=0; j<f->cols; j++) {
+ if (CV_MAT_ELEM(*f,uchar,i,j)!=0) {
+ if (!Push(i,j,0)) return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ bool Push(int i, int j, float T) {
+ CvHeapElem *tmp=empty,*add=empty;
+ if (empty==tail) return false;
+ while (tmp->prev->T>T) tmp = tmp->prev;
+ if (tmp!=empty) {
+ add->prev->next = add->next;
+ add->next->prev = add->prev;
+ empty = add->next;
+ add->prev = tmp->prev;
+ add->next = tmp;
+ add->prev->next = add;
+ add->next->prev = add;
+ } else {
+ empty = empty->next;
+ }
+ add->i = i;
+ add->j = j;
+ add->T = T;
+ in++;
+ // printf("push i %3d j %3d T %12.4e in %4d\n",i,j,T,in);
+ return true;
+ }
+
+ bool Pop(int *i, int *j) {
+ CvHeapElem *tmp=head->next;
+ if (empty==tmp) return false;
+ *i = tmp->i;
+ *j = tmp->j;
+ tmp->prev->next = tmp->next;
+ tmp->next->prev = tmp->prev;
+ tmp->prev = empty->prev;
+ tmp->next = empty;
+ tmp->prev->next = tmp;
+ tmp->next->prev = tmp;
+ empty = tmp;
+ in--;
+ // printf("pop i %3d j %3d T %12.4e in %4d\n",tmp->i,tmp->j,tmp->T,in);
+ return true;
+ }
+
+ bool Pop(int *i, int *j, float *T) {
+ CvHeapElem *tmp=head->next;
+ if (empty==tmp) return false;
+ *i = tmp->i;
+ *j = tmp->j;
+ *T = tmp->T;
+ tmp->prev->next = tmp->next;
+ tmp->next->prev = tmp->prev;
+ tmp->prev = empty->prev;
+ tmp->next = empty;
+ tmp->prev->next = tmp;
+ tmp->next->prev = tmp;
+ empty = tmp;
+ in--;
+ // printf("pop i %3d j %3d T %12.4e in %4d\n",tmp->i,tmp->j,tmp->T,in);
+ return true;
+ }
+
+ CvPriorityQueueFloat(void) {
+ num=in=0;
+ mem=empty=head=tail=NULL;
+ }
+
+ ~CvPriorityQueueFloat(void)
+ {
+ cvFree( &mem );
+ }
+};
+
+inline float VectorScalMult(CvPoint2D32f v1,CvPoint2D32f v2) {
+ return v1.x*v2.x+v1.y*v2.y;
+}
+
+inline float VectorLength(CvPoint2D32f v1) {
+ return v1.x*v1.x+v1.y*v1.y;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+//HEAP::iterator Heap_Iterator;
+//HEAP Heap;
+
+float FastMarching_solve(int i1,int j1,int i2,int j2, const CvMat* f, const CvMat* t)
+{
+ double sol, a11, a22, m12;
+ a11=CV_MAT_ELEM(*t,float,i1,j1);
+ a22=CV_MAT_ELEM(*t,float,i2,j2);
+ m12=MIN(a11,a22);
+
+ if( CV_MAT_ELEM(*f,uchar,i1,j1) != INSIDE )
+ if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE )
+ if( fabs(a11-a22) >= 1.0 )
+ sol = 1+m12;
+ else
+ sol = (a11+a22+sqrt((double)(2-(a11-a22)*(a11-a22))))*0.5;
+ else
+ sol = 1+a11;
+ else if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE )
+ sol = 1+a22;
+ else
+ sol = 1+m12;
+
+ return (float)sol;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+
+static void
+icvCalcFMM(const CvMat *f, CvMat *t, CvPriorityQueueFloat *Heap, bool negate) {
+ int i, j, ii = 0, jj = 0, q;
+ float dist;
+
+ while (Heap->Pop(&ii,&jj)) {
+
+ unsigned known=(negate)?CHANGE:KNOWN;
+ CV_MAT_ELEM(*f,uchar,ii,jj) = (uchar)known;
+
+ for (q=0; q<4; q++) {
+ i=0; j=0;
+ if (q==0) {i=ii-1; j=jj;}
+ else if(q==1) {i=ii; j=jj-1;}
+ else if(q==2) {i=ii+1; j=jj;}
+ else {i=ii; j=jj+1;}
+ if ((i<=0)||(j<=0)||(i>f->rows)||(j>f->cols)) continue;
+
+ if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) {
+ dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
+ FastMarching_solve(i+1,j,i,j-1,f,t),
+ FastMarching_solve(i-1,j,i,j+1,f,t),
+ FastMarching_solve(i+1,j,i,j+1,f,t));
+ CV_MAT_ELEM(*t,float,i,j) = dist;
+ CV_MAT_ELEM(*f,uchar,i,j) = BAND;
+ Heap->Push(i,j,dist);
+ }
+ }
+ }
+
+ if (negate) {
+ for (i=0; i<f->rows; i++) {
+ for(j=0; j<f->cols; j++) {
+ if (CV_MAT_ELEM(*f,uchar,i,j) == CHANGE) {
+ CV_MAT_ELEM(*f,uchar,i,j) = KNOWN;
+ CV_MAT_ELEM(*t,float,i,j) = -CV_MAT_ELEM(*t,float,i,j);
+ }
+ }
+ }
+ }
+}
+
+
+static void
+icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap ) {
+ int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0;
+ float dist;
+
+ if (CV_MAT_CN(out->type)==3) {
+
+ while (Heap->Pop(&ii,&jj)) {
+
+ CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN;
+ for(q=0; q<4; q++) {
+ if (q==0) {i=ii-1; j=jj;}
+ else if(q==1) {i=ii; j=jj-1;}
+ else if(q==2) {i=ii+1; j=jj;}
+ else if(q==3) {i=ii; j=jj+1;}
+ if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue;
+
+ if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) {
+ dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
+ FastMarching_solve(i+1,j,i,j-1,f,t),
+ FastMarching_solve(i-1,j,i,j+1,f,t),
+ FastMarching_solve(i+1,j,i,j+1,f,t));
+ CV_MAT_ELEM(*t,float,i,j) = dist;
+
+ for (color=0; color<=2; color++) {
+ CvPoint2D32f gradI,gradT,r;
+ float Ia=0,Jx=0,Jy=0,s=1.0e-20f,w,dst,lev,dir,sat;
+
+ if (CV_MAT_ELEM(*f,uchar,i,j+1)!=INSIDE) {
+ if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) {
+ gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j-1)))*0.5f;
+ } else {
+ gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j)));
+ }
+ } else {
+ if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) {
+ gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i,j-1)));
+ } else {
+ gradT.x=0;
+ }
+ }
+ if (CV_MAT_ELEM(*f,uchar,i+1,j)!=INSIDE) {
+ if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) {
+ gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i-1,j)))*0.5f;
+ } else {
+ gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j)));
+ }
+ } else {
+ if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) {
+ gradT.y=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i-1,j)));
+ } else {
+ gradT.y=0;
+ }
+ }
+ for (k=i-range; k<=i+range; k++) {
+ int km=k-1+(k==1),kp=k-1-(k==t->rows-2);
+ for (l=j-range; l<=j+range; l++) {
+ int lm=l-1+(l==1),lp=l-1-(l==t->cols-2);
+ if (k>0&&l>0&&k<t->rows-1&&l<t->cols-1) {
+ if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&&
+ ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) {
+ r.y = (float)(i-k);
+ r.x = (float)(j-l);
+
+ dst = (float)(1./(VectorLength(r)*sqrt((double)VectorLength(r))));
+ lev = (float)(1./(1+fabs(CV_MAT_ELEM(*t,float,k,l)-CV_MAT_ELEM(*t,float,i,j))));
+
+ dir=VectorScalMult(r,gradT);
+ if (fabs(dir)<=0.01) dir=0.000001f;
+ w = (float)fabs(dst*lev*dir);
+
+ if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) {
+ if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
+ gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)))*2.0f;
+ } else {
+ gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)));
+ }
+ } else {
+ if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
+ gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)));
+ } else {
+ gradI.x=0;
+ }
+ }
+ if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) {
+ if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
+ gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)))*2.0f;
+ } else {
+ gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)));
+ }
+ } else {
+ if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
+ gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)));
+ } else {
+ gradI.y=0;
+ }
+ }
+ Ia += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color));
+ Jx -= (float)w * (float)(gradI.x*r.x);
+ Jy -= (float)w * (float)(gradI.y*r.y);
+ s += w;
+ }
+ }
+ }
+ }
+ sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f));
+ {
+ int isat = cvRound(sat);
+ CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = CV_CAST_8U(isat);
+ }
+ }
+
+ CV_MAT_ELEM(*f,uchar,i,j) = BAND;
+ Heap->Push(i,j,dist);
+ }
+ }
+ }
+
+ } else if (CV_MAT_CN(out->type)==1) {
+
+ while (Heap->Pop(&ii,&jj)) {
+
+ CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN;
+ for(q=0; q<4; q++) {
+ if (q==0) {i=ii-1; j=jj;}
+ else if(q==1) {i=ii; j=jj-1;}
+ else if(q==2) {i=ii+1; j=jj;}
+ else if(q==3) {i=ii; j=jj+1;}
+ if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue;
+
+ if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) {
+ dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
+ FastMarching_solve(i+1,j,i,j-1,f,t),
+ FastMarching_solve(i-1,j,i,j+1,f,t),
+ FastMarching_solve(i+1,j,i,j+1,f,t));
+ CV_MAT_ELEM(*t,float,i,j) = dist;
+
+ for (color=0; color<=0; color++) {
+ CvPoint2D32f gradI,gradT,r;
+ float Ia=0,Jx=0,Jy=0,s=1.0e-20f,w,dst,lev,dir,sat;
+
+ if (CV_MAT_ELEM(*f,uchar,i,j+1)!=INSIDE) {
+ if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) {
+ gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j-1)))*0.5f;
+ } else {
+ gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j)));
+ }
+ } else {
+ if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) {
+ gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i,j-1)));
+ } else {
+ gradT.x=0;
+ }
+ }
+ if (CV_MAT_ELEM(*f,uchar,i+1,j)!=INSIDE) {
+ if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) {
+ gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i-1,j)))*0.5f;
+ } else {
+ gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j)));
+ }
+ } else {
+ if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) {
+ gradT.y=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i-1,j)));
+ } else {
+ gradT.y=0;
+ }
+ }
+ for (k=i-range; k<=i+range; k++) {
+ int km=k-1+(k==1),kp=k-1-(k==t->rows-2);
+ for (l=j-range; l<=j+range; l++) {
+ int lm=l-1+(l==1),lp=l-1-(l==t->cols-2);
+ if (k>0&&l>0&&k<t->rows-1&&l<t->cols-1) {
+ if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&&
+ ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) {
+ r.y = (float)(i-k);
+ r.x = (float)(j-l);
+
+ dst = (float)(1./(VectorLength(r)*sqrt(VectorLength(r))));
+ lev = (float)(1./(1+fabs(CV_MAT_ELEM(*t,float,k,l)-CV_MAT_ELEM(*t,float,i,j))));
+
+ dir=VectorScalMult(r,gradT);
+ if (fabs(dir)<=0.01) dir=0.000001f;
+ w = (float)fabs(dst*lev*dir);
+
+ if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) {
+ if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
+ gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm-1)))*2.0f;
+ } else {
+ gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm)));
+ }
+ } else {
+ if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
+ gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp)-CV_MAT_ELEM(*out,uchar,km,lm-1)));
+ } else {
+ gradI.x=0;
+ }
+ }
+ if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) {
+ if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
+ gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)))*2.0f;
+ } else {
+ gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km,lm)));
+ }
+ } else {
+ if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
+ gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)));
+ } else {
+ gradI.y=0;
+ }
+ }
+ Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm));
+ Jx -= (float)w * (float)(gradI.x*r.x);
+ Jy -= (float)w * (float)(gradI.y*r.y);
+ s += w;
+ }
+ }
+ }
+ }
+ sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f));
+ {
+ int isat = cvRound(sat);
+ CV_MAT_ELEM(*out,uchar,i-1,j-1) = CV_CAST_8U(isat);
+ }
+ }
+
+ CV_MAT_ELEM(*f,uchar,i,j) = BAND;
+ Heap->Push(i,j,dist);
+ }
+ }
+ }
+ }
+}
+
+
+static void
+icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap) {
+ int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0;
+ float dist;
+
+ if (CV_MAT_CN(out->type)==3) {
+
+ while (Heap->Pop(&ii,&jj)) {
+
+ CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN;
+ for(q=0; q<4; q++) {
+ if (q==0) {i=ii-1; j=jj;}
+ else if(q==1) {i=ii; j=jj-1;}
+ else if(q==2) {i=ii+1; j=jj;}
+ else if(q==3) {i=ii; j=jj+1;}
+ if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue;
+
+ if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) {
+ dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
+ FastMarching_solve(i+1,j,i,j-1,f,t),
+ FastMarching_solve(i-1,j,i,j+1,f,t),
+ FastMarching_solve(i+1,j,i,j+1,f,t));
+ CV_MAT_ELEM(*t,float,i,j) = dist;
+
+ for (color=0; color<=2; color++) {
+ CvPoint2D32f gradI,r;
+ float Ia=0,s=1.0e-20f,w,dst,dir;
+
+ for (k=i-range; k<=i+range; k++) {
+ int km=k-1+(k==1),kp=k-1-(k==f->rows-2);
+ for (l=j-range; l<=j+range; l++) {
+ int lm=l-1+(l==1),lp=l-1-(l==f->cols-2);
+ if (k>0&&l>0&&k<f->rows-1&&l<f->cols-1) {
+ if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&&
+ ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) {
+ r.y=(float)(k-i);
+ r.x=(float)(l-j);
+
+ dst = 1/(VectorLength(r)*VectorLength(r)+1);
+
+ if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) {
+ if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
+ gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color))+
+ abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)));
+ } else {
+ gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)))*2.0f;
+ }
+ } else {
+ if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
+ gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)))*2.0f;
+ } else {
+ gradI.x=0;
+ }
+ }
+ if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) {
+ if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
+ gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))+
+ abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)));
+ } else {
+ gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)))*2.0f;
+ }
+ } else {
+ if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
+ gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)))*2.0f;
+ } else {
+ gradI.y=0;
+ }
+ }
+
+ gradI.x=-gradI.x;
+ dir=VectorScalMult(r,gradI);
+
+ if (fabs(dir)<=0.01) {
+ dir=0.000001f;
+ } else {
+ dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI)));
+ }
+ w = dst*dir;
+ Ia += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color));
+ s += w;
+ }
+ }
+ }
+ }
+ {
+ int out_val = cvRound((double)Ia/s);
+ CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = CV_CAST_8U(out_val);
+ }
+ }
+
+ CV_MAT_ELEM(*f,uchar,i,j) = BAND;
+ Heap->Push(i,j,dist);
+ }
+ }
+ }
+
+ } else if (CV_MAT_CN(out->type)==1) {
+
+ while (Heap->Pop(&ii,&jj)) {
+
+ CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN;
+ for(q=0; q<4; q++) {
+ if (q==0) {i=ii-1; j=jj;}
+ else if(q==1) {i=ii; j=jj-1;}
+ else if(q==2) {i=ii+1; j=jj;}
+ else if(q==3) {i=ii; j=jj+1;}
+ if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue;
+
+ if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) {
+ dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
+ FastMarching_solve(i+1,j,i,j-1,f,t),
+ FastMarching_solve(i-1,j,i,j+1,f,t),
+ FastMarching_solve(i+1,j,i,j+1,f,t));
+ CV_MAT_ELEM(*t,float,i,j) = dist;
+
+ {
+ CvPoint2D32f gradI,r;
+ float Ia=0,s=1.0e-20f,w,dst,dir;
+
+ for (k=i-range; k<=i+range; k++) {
+ int km=k-1+(k==1),kp=k-1-(k==t->rows-2);
+ for (l=j-range; l<=j+range; l++) {
+ int lm=l-1+(l==1),lp=l-1-(l==t->cols-2);
+ if (k>0&&l>0&&k<t->rows-1&&l<t->cols-1) {
+ if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&&
+ ((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) {
+ r.y=(float)(i-k);
+ r.x=(float)(j-l);
+
+ dst = 1/(VectorLength(r)*VectorLength(r)+1);
+
+ if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) {
+ if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
+ gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm))+
+ abs(CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)));
+ } else {
+ gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm)))*2.0f;
+ }
+ } else {
+ if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
+ gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)))*2.0f;
+ } else {
+ gradI.x=0;
+ }
+ }
+ if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) {
+ if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
+ gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm))+
+ abs(CV_MAT_ELEM(*out,uchar,km,lm)-CV_MAT_ELEM(*out,uchar,km,lm-1)));
+ } else {
+ gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm)))*2.0f;
+ }
+ } else {
+ if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
+ gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lm)-CV_MAT_ELEM(*out,uchar,km,lm-1)))*2.0f;
+ } else {
+ gradI.y=0;
+ }
+ }
+
+ gradI.x=-gradI.x;
+ dir=VectorScalMult(r,gradI);
+
+ if (fabs(dir)<=0.01) {
+ dir=0.000001f;
+ } else {
+ dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI)));
+ }
+ w = dst*dir;
+ Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm));
+ s += w;
+ }
+ }
+ }
+ }
+ {
+ int out_val = cvRound((double)Ia/s);
+ CV_MAT_ELEM(*out,uchar,i-1,j-1) = CV_CAST_8U(out_val);
+ }
+ }
+
+ CV_MAT_ELEM(*f,uchar,i,j) = BAND;
+ Heap->Push(i,j,dist);
+ }
+ }
+ }
+
+ }
+}
+
+#define SET_BORDER1_C1(image,type,value) {\
+ int i,j;\
+ for(j=0; j<image->cols; j++) {\
+ CV_MAT_ELEM(*image,type,0,j) = value;\
+ }\
+ for (i=1; i<image->rows-1; i++) {\
+ CV_MAT_ELEM(*image,type,i,0) = CV_MAT_ELEM(*image,type,i,image->cols-1) = value;\
+ }\
+ for(j=0; j<image->cols; j++) {\
+ CV_MAT_ELEM(*image,type,erows-1,j) = value;\
+ }\
+ }
+
+#define COPY_MASK_BORDER1_C1(src,dst,type) {\
+ int i,j;\
+ for (i=0; i<src->rows; i++) {\
+ for(j=0; j<src->cols; j++) {\
+ if (CV_MAT_ELEM(*src,type,i,j)!=0)\
+ CV_MAT_ELEM(*dst,type,i+1,j+1) = INSIDE;\
+ }\
+ }\
+ }
+
+
+CV_IMPL void
+cvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_img,
+ double inpaintRange, int flags )
+{
+ CvMat *mask = 0, *band = 0, *f = 0, *t = 0, *out = 0;
+ CvPriorityQueueFloat *Heap = 0, *Out = 0;
+ IplConvKernel *el_cross = 0, *el_range = 0;
+
+ CV_FUNCNAME( "cvInpaint" );
+
+ __BEGIN__;
+
+ CvMat input_hdr, mask_hdr, output_hdr;
+ CvMat* input_img, *inpaint_mask, *output_img;
+ int range=cvRound(inpaintRange);
+ int erows, ecols;
+
+ CV_CALL( input_img = cvGetMat( _input_img, &input_hdr ));
+ CV_CALL( inpaint_mask = cvGetMat( _inpaint_mask, &mask_hdr ));
+ CV_CALL( output_img = cvGetMat( _output_img, &output_hdr ));
+
+ if( !CV_ARE_SIZES_EQ(input_img,output_img) || !CV_ARE_SIZES_EQ(input_img,inpaint_mask))
+ CV_ERROR( CV_StsUnmatchedSizes, "All the input and output images must have the same size" );
+
+ if( (CV_MAT_TYPE(input_img->type) != CV_8UC1 &&
+ CV_MAT_TYPE(input_img->type) != CV_8UC3) ||
+ !CV_ARE_TYPES_EQ(input_img,output_img) )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Only 8-bit 1-channel and 3-channel input/output images are supported" );
+
+ if( CV_MAT_TYPE(inpaint_mask->type) != CV_8UC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "The mask must be 8-bit 1-channel image" );
+
+ range = MAX(range,1);
+ range = MIN(range,100);
+
+ ecols = input_img->cols + 2;
+ erows = input_img->rows + 2;
+
+ CV_CALL( f = cvCreateMat(erows, ecols, CV_8UC1));
+ CV_CALL( t = cvCreateMat(erows, ecols, CV_32FC1));
+ CV_CALL( band = cvCreateMat(erows, ecols, CV_8UC1));
+ CV_CALL( mask = cvCreateMat(erows, ecols, CV_8UC1));
+ CV_CALL( el_cross = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CROSS,NULL));
+
+ cvCopy( input_img, output_img );
+ cvSet(mask,cvScalar(KNOWN,0,0,0));
+ COPY_MASK_BORDER1_C1(inpaint_mask,mask,uchar);
+ SET_BORDER1_C1(mask,uchar,0);
+ cvSet(f,cvScalar(KNOWN,0,0,0));
+ cvSet(t,cvScalar(1.0e6f,0,0,0));
+ cvDilate(mask,band,el_cross,1); // image with narrow band
+ Heap=new CvPriorityQueueFloat;
+ if (!Heap->Init(band))
+ EXIT;
+ cvSub(band,mask,band,NULL);
+ SET_BORDER1_C1(band,uchar,0);
+ if (!Heap->Add(band))
+ EXIT;
+ cvSet(f,cvScalar(BAND,0,0,0),band);
+ cvSet(f,cvScalar(INSIDE,0,0,0),mask);
+ cvSet(t,cvScalar(0,0,0,0),band);
+
+ if( flags == CV_INPAINT_TELEA )
+ {
+ CV_CALL( out = cvCreateMat(erows, ecols, CV_8UC1));
+ CV_CALL( el_range = cvCreateStructuringElementEx(2*range+1,2*range+1,
+ range,range,CV_SHAPE_RECT,NULL));
+ cvDilate(mask,out,el_range,1);
+ cvSub(out,mask,out,NULL);
+ Out=new CvPriorityQueueFloat;
+ if (!Out->Init(out))
+ EXIT;
+ if (!Out->Add(band))
+ EXIT;
+ cvSub(out,band,out,NULL);
+ SET_BORDER1_C1(out,uchar,0);
+ icvCalcFMM(out,t,Out,true);
+ icvTeleaInpaintFMM(mask,t,output_img,range,Heap);
+ }
+ else
+ icvNSInpaintFMM(mask,t,output_img,range,Heap);
+
+ __END__;
+
+ delete Out;
+ delete Heap;
+ cvReleaseStructuringElement(&el_cross);
+ cvReleaseStructuringElement(&el_range);
+ cvReleaseMat(&out);
+ cvReleaseMat(&mask);
+ cvReleaseMat(&band);
+ cvReleaseMat(&t);
+ cvReleaseMat(&f);
+}
diff --git a/cv/src/cvkalman.cpp b/cv/src/cvkalman.cpp
new file mode 100644
index 0000000..c82214b
--- /dev/null
+++ b/cv/src/cvkalman.cpp
@@ -0,0 +1,241 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+
+CV_IMPL CvKalman*
+cvCreateKalman( int DP, int MP, int CP )
+{
+ CvKalman *kalman = 0;
+
+ CV_FUNCNAME( "cvCreateKalman" );
+
+ __BEGIN__;
+
+ if( DP <= 0 || MP <= 0 )
+ CV_ERROR( CV_StsOutOfRange,
+ "state and measurement vectors must have positive number of dimensions" );
+
+ if( CP < 0 )
+ CP = DP;
+
+ /* allocating memory for the structure */
+ CV_CALL( kalman = (CvKalman *)cvAlloc( sizeof( CvKalman )));
+ memset( kalman, 0, sizeof(*kalman));
+
+ kalman->DP = DP;
+ kalman->MP = MP;
+ kalman->CP = CP;
+
+ CV_CALL( kalman->state_pre = cvCreateMat( DP, 1, CV_32FC1 ));
+ cvZero( kalman->state_pre );
+
+ CV_CALL( kalman->state_post = cvCreateMat( DP, 1, CV_32FC1 ));
+ cvZero( kalman->state_post );
+
+ CV_CALL( kalman->transition_matrix = cvCreateMat( DP, DP, CV_32FC1 ));
+ cvSetIdentity( kalman->transition_matrix );
+
+ CV_CALL( kalman->process_noise_cov = cvCreateMat( DP, DP, CV_32FC1 ));
+ cvSetIdentity( kalman->process_noise_cov );
+
+ CV_CALL( kalman->measurement_matrix = cvCreateMat( MP, DP, CV_32FC1 ));
+ cvZero( kalman->measurement_matrix );
+
+ CV_CALL( kalman->measurement_noise_cov = cvCreateMat( MP, MP, CV_32FC1 ));
+ cvSetIdentity( kalman->measurement_noise_cov );
+
+ CV_CALL( kalman->error_cov_pre = cvCreateMat( DP, DP, CV_32FC1 ));
+
+ CV_CALL( kalman->error_cov_post = cvCreateMat( DP, DP, CV_32FC1 ));
+ cvZero( kalman->error_cov_post );
+
+ CV_CALL( kalman->gain = cvCreateMat( DP, MP, CV_32FC1 ));
+
+ if( CP > 0 )
+ {
+ CV_CALL( kalman->control_matrix = cvCreateMat( DP, CP, CV_32FC1 ));
+ cvZero( kalman->control_matrix );
+ }
+
+ CV_CALL( kalman->temp1 = cvCreateMat( DP, DP, CV_32FC1 ));
+ CV_CALL( kalman->temp2 = cvCreateMat( MP, DP, CV_32FC1 ));
+ CV_CALL( kalman->temp3 = cvCreateMat( MP, MP, CV_32FC1 ));
+ CV_CALL( kalman->temp4 = cvCreateMat( MP, DP, CV_32FC1 ));
+ CV_CALL( kalman->temp5 = cvCreateMat( MP, 1, CV_32FC1 ));
+
+#if 1
+ kalman->PosterState = kalman->state_pre->data.fl;
+ kalman->PriorState = kalman->state_post->data.fl;
+ kalman->DynamMatr = kalman->transition_matrix->data.fl;
+ kalman->MeasurementMatr = kalman->measurement_matrix->data.fl;
+ kalman->MNCovariance = kalman->measurement_noise_cov->data.fl;
+ kalman->PNCovariance = kalman->process_noise_cov->data.fl;
+ kalman->KalmGainMatr = kalman->gain->data.fl;
+ kalman->PriorErrorCovariance = kalman->error_cov_pre->data.fl;
+ kalman->PosterErrorCovariance = kalman->error_cov_post->data.fl;
+#endif
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvReleaseKalman( &kalman );
+
+ return kalman;
+}
+
+
+CV_IMPL void
+cvReleaseKalman( CvKalman** _kalman )
+{
+ CvKalman *kalman;
+
+ CV_FUNCNAME( "cvReleaseKalman" );
+ __BEGIN__;
+
+ if( !_kalman )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ kalman = *_kalman;
+
+ /* freeing the memory */
+ cvReleaseMat( &kalman->state_pre );
+ cvReleaseMat( &kalman->state_post );
+ cvReleaseMat( &kalman->transition_matrix );
+ cvReleaseMat( &kalman->control_matrix );
+ cvReleaseMat( &kalman->measurement_matrix );
+ cvReleaseMat( &kalman->process_noise_cov );
+ cvReleaseMat( &kalman->measurement_noise_cov );
+ cvReleaseMat( &kalman->error_cov_pre );
+ cvReleaseMat( &kalman->gain );
+ cvReleaseMat( &kalman->error_cov_post );
+ cvReleaseMat( &kalman->temp1 );
+ cvReleaseMat( &kalman->temp2 );
+ cvReleaseMat( &kalman->temp3 );
+ cvReleaseMat( &kalman->temp4 );
+ cvReleaseMat( &kalman->temp5 );
+
+ memset( kalman, 0, sizeof(*kalman));
+
+ /* deallocating the structure */
+ cvFree( _kalman );
+
+ __END__;
+}
+
+
+CV_IMPL const CvMat*
+cvKalmanPredict( CvKalman* kalman, const CvMat* control )
+{
+ CvMat* result = 0;
+
+ CV_FUNCNAME( "cvKalmanPredict" );
+
+ __BEGIN__;
+
+ if( !kalman )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ /* update the state */
+ /* x'(k) = A*x(k) */
+ CV_CALL( cvMatMulAdd( kalman->transition_matrix, kalman->state_post, 0, kalman->state_pre ));
+
+ if( control && kalman->CP > 0 )
+ /* x'(k) = x'(k) + B*u(k) */
+ CV_CALL( cvMatMulAdd( kalman->control_matrix, control, kalman->state_pre, kalman->state_pre ));
+
+ /* update error covariance matrices */
+ /* temp1 = A*P(k) */
+ CV_CALL( cvMatMulAdd( kalman->transition_matrix, kalman->error_cov_post, 0, kalman->temp1 ));
+
+ /* P'(k) = temp1*At + Q */
+ CV_CALL( cvGEMM( kalman->temp1, kalman->transition_matrix, 1, kalman->process_noise_cov, 1,
+ kalman->error_cov_pre, CV_GEMM_B_T ));
+
+ result = kalman->state_pre;
+
+ __END__;
+
+ return result;
+}
+
+
+CV_IMPL const CvMat*
+cvKalmanCorrect( CvKalman* kalman, const CvMat* measurement )
+{
+ CvMat* result = 0;
+
+ CV_FUNCNAME( "cvKalmanCorrect" );
+
+ __BEGIN__;
+
+ if( !kalman || !measurement )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ /* temp2 = H*P'(k) */
+ CV_CALL( cvMatMulAdd( kalman->measurement_matrix,
+ kalman->error_cov_pre, 0, kalman->temp2 ));
+ /* temp3 = temp2*Ht + R */
+ CV_CALL( cvGEMM( kalman->temp2, kalman->measurement_matrix, 1,
+ kalman->measurement_noise_cov, 1, kalman->temp3, CV_GEMM_B_T ));
+
+ /* temp4 = inv(temp3)*temp2 = Kt(k) */
+ CV_CALL( cvSolve( kalman->temp3, kalman->temp2, kalman->temp4, CV_SVD ));
+
+ /* K(k) */
+ CV_CALL( cvTranspose( kalman->temp4, kalman->gain ));
+
+ /* temp5 = z(k) - H*x'(k) */
+ CV_CALL( cvGEMM( kalman->measurement_matrix, kalman->state_pre, -1, measurement, 1, kalman->temp5 ));
+
+ /* x(k) = x'(k) + K(k)*temp5 */
+ CV_CALL( cvMatMulAdd( kalman->gain, kalman->temp5, kalman->state_pre, kalman->state_post ));
+
+ /* P(k) = P'(k) - K(k)*temp2 */
+ CV_CALL( cvGEMM( kalman->gain, kalman->temp2, -1, kalman->error_cov_pre, 1,
+ kalman->error_cov_post, 0 ));
+
+ result = kalman->state_post;
+
+ __END__;
+
+ return result;
+}
diff --git a/cv/src/cvkdtree.cpp b/cv/src/cvkdtree.cpp
new file mode 100644
index 0000000..7fd702d
--- /dev/null
+++ b/cv/src/cvkdtree.cpp
@@ -0,0 +1,283 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2008, Xavier Delacour, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+// 2008-05-13, Xavier Delacour <xavier.delacour@gmail.com>
+
+#include "_cv.h"
+
+#if !defined _MSC_VER || defined __ICL || _MSC_VER >= 1400
+#include "_cvkdtree.hpp"
+
+// * write up some docs
+
+// * removing __valuetype parameter from CvKDTree and using virtuals instead
+// * of void* data here could simplify things.
+
+struct CvFeatureTree {
+
+ template <class __scalartype, int __cvtype>
+ struct deref {
+ typedef __scalartype scalar_type;
+ typedef double accum_type;
+
+ CvMat* mat;
+ deref(CvMat* _mat) : mat(_mat) {
+ assert(CV_ELEM_SIZE1(__cvtype) == sizeof(__scalartype));
+ }
+ scalar_type operator() (int i, int j) const {
+ return *((scalar_type*)(mat->data.ptr + i * mat->step) + j);
+ }
+ };
+
+#define dispatch_cvtype(mat, c) \
+ switch (CV_MAT_DEPTH((mat)->type)) { \
+ case CV_32F: \
+ { typedef CvKDTree<int, deref<float, CV_32F> > tree_type; c; break; } \
+ case CV_64F: \
+ { typedef CvKDTree<int, deref<double, CV_64F> > tree_type; c; break; } \
+ default: assert(0); \
+ }
+
+ CvMat* mat;
+ void* data;
+
+ template <class __treetype>
+ void find_nn(CvMat* d, int k, int emax, CvMat* results, CvMat* dist) {
+ __treetype* tr = (__treetype*) data;
+ uchar* dptr = d->data.ptr;
+ uchar* resultsptr = results->data.ptr;
+ uchar* distptr = dist->data.ptr;
+ typename __treetype::bbf_nn_pqueue nn;
+
+ assert(d->cols == tr->dims());
+ assert(results->rows == d->rows);
+ assert(results->rows == dist->rows);
+ assert(results->cols == k);
+ assert(dist->cols == k);
+
+ for (int j = 0; j < d->rows; ++j) {
+ typename __treetype::scalar_type* dj = (typename __treetype::scalar_type*) dptr;
+
+ int* resultsj = (int*) resultsptr;
+ double* distj = (double*) distptr;
+ tr->find_nn_bbf(dj, k, emax, nn);
+
+ assert((int)nn.size() <= k);
+ for (unsigned int j = 0; j < nn.size(); ++j) {
+ *resultsj++ = *nn[j].p;
+ *distj++ = nn[j].dist;
+ }
+ std::fill(resultsj, resultsj + k - nn.size(), -1);
+ std::fill(distj, distj + k - nn.size(), 0);
+
+ dptr += d->step;
+ resultsptr += results->step;
+ distptr += dist->step;
+ }
+ }
+
+ template <class __treetype>
+ int find_ortho_range(CvMat* bounds_min, CvMat* bounds_max,
+ CvMat* results) {
+ int rn = results->rows * results->cols;
+ std::vector<int> inbounds;
+ dispatch_cvtype(mat, ((__treetype*)data)->
+ find_ortho_range((typename __treetype::scalar_type*)bounds_min->data.ptr,
+ (typename __treetype::scalar_type*)bounds_max->data.ptr,
+ inbounds));
+ std::copy(inbounds.begin(),
+ inbounds.begin() + std::min((int)inbounds.size(), rn),
+ (int*) results->data.ptr);
+ return inbounds.size();
+ }
+
+ CvFeatureTree(const CvFeatureTree& x);
+ CvFeatureTree& operator= (const CvFeatureTree& rhs);
+public:
+ CvFeatureTree(CvMat* _mat) : mat(_mat) {
+ // * a flag parameter should tell us whether
+ // * (a) user ensures *mat outlives *this and is unchanged,
+ // * (b) we take reference and user ensures mat is unchanged,
+ // * (c) we copy data, (d) we own and release data.
+
+ std::vector<int> tmp(mat->rows);
+ for (unsigned int j = 0; j < tmp.size(); ++j)
+ tmp[j] = j;
+
+ dispatch_cvtype(mat, data = new tree_type
+ (&tmp[0], &tmp[0] + tmp.size(), mat->cols,
+ tree_type::deref_type(mat)));
+ }
+ ~CvFeatureTree() {
+ dispatch_cvtype(mat, delete (tree_type*) data);
+ }
+
+ int dims() {
+ int d = 0;
+ dispatch_cvtype(mat, d = ((tree_type*) data)->dims());
+ return d;
+ }
+ int type() {
+ return mat->type;
+ }
+
+ void find_nn(CvMat* d, int k, int emax, CvMat* results, CvMat* dist) {
+ assert(CV_MAT_TYPE(d->type) == CV_MAT_TYPE(mat->type));
+ assert(CV_MAT_TYPE(dist->type) == CV_64FC1);
+ assert(CV_MAT_TYPE(results->type) == CV_32SC1);
+
+ dispatch_cvtype(mat, find_nn<tree_type>
+ (d, k, emax, results, dist));
+ }
+ int find_ortho_range(CvMat* bounds_min, CvMat* bounds_max,
+ CvMat* results) {
+ assert(CV_MAT_TYPE(bounds_min->type) == CV_MAT_TYPE(mat->type));
+ assert(CV_MAT_TYPE(bounds_min->type) == CV_MAT_TYPE(bounds_max->type));
+ assert(bounds_min->rows * bounds_min->cols == dims());
+ assert(bounds_max->rows * bounds_max->cols == dims());
+
+ int count = 0;
+ dispatch_cvtype(mat, count = find_ortho_range<tree_type>
+ (bounds_min, bounds_max,results));
+ return count;
+ }
+};
+
+
+
+CvFeatureTree* cvCreateFeatureTree(CvMat* desc) {
+ __BEGIN__;
+ CV_FUNCNAME("cvCreateFeatureTree");
+
+ if (CV_MAT_TYPE(desc->type) != CV_32FC1 &&
+ CV_MAT_TYPE(desc->type) != CV_64FC1)
+ CV_ERROR(CV_StsUnsupportedFormat, "descriptors must be either CV_32FC1 or CV_64FC1");
+
+ return new CvFeatureTree(desc);
+ __END__;
+
+ return 0;
+}
+
+void cvReleaseFeatureTree(CvFeatureTree* tr) {
+ delete tr;
+}
+
+// desc is m x d set of candidate points.
+// results is m x k set of row indices of matching points.
+// dist is m x k distance to matching points.
+void cvFindFeatures(CvFeatureTree* tr, CvMat* desc,
+ CvMat* results, CvMat* dist, int k, int emax) {
+ bool free_desc = false;
+ int dims = tr->dims();
+ int type = tr->type();
+
+ __BEGIN__;
+ CV_FUNCNAME("cvFindFeatures");
+
+ if (desc->cols != dims)
+ CV_ERROR(CV_StsUnmatchedSizes, "desc columns be equal feature dimensions");
+ if (results->rows != desc->rows && results->cols != k)
+ CV_ERROR(CV_StsUnmatchedSizes, "results and desc must be same height");
+ if (dist->rows != desc->rows && dist->cols != k)
+ CV_ERROR(CV_StsUnmatchedSizes, "dist and desc must be same height");
+ if (CV_MAT_TYPE(results->type) != CV_32SC1)
+ CV_ERROR(CV_StsUnsupportedFormat, "results must be CV_32SC1");
+ if (CV_MAT_TYPE(dist->type) != CV_64FC1)
+ CV_ERROR(CV_StsUnsupportedFormat, "dist must be CV_64FC1");
+
+ if (CV_MAT_TYPE(type) != CV_MAT_TYPE(desc->type)) {
+ CvMat* old_desc = desc;
+ desc = cvCreateMat(desc->rows, desc->cols, type);
+ cvConvert(old_desc, desc);
+ free_desc = true;
+ }
+
+ tr->find_nn(desc, k, emax, results, dist);
+
+ __END__;
+
+ if (free_desc)
+ cvReleaseMat(&desc);
+}
+
+int cvFindFeaturesBoxed(CvFeatureTree* tr,
+ CvMat* bounds_min, CvMat* bounds_max,
+ CvMat* results) {
+ int nr = -1;
+ bool free_bounds = false;
+ int dims = tr->dims();
+ int type = tr->type();
+
+ __BEGIN__;
+ CV_FUNCNAME("cvFindFeaturesBoxed");
+
+ if (bounds_min->cols * bounds_min->rows != dims ||
+ bounds_max->cols * bounds_max->rows != dims)
+ CV_ERROR(CV_StsUnmatchedSizes, "bounds_{min,max} must 1 x dims or dims x 1");
+ if (CV_MAT_TYPE(bounds_min->type) != CV_MAT_TYPE(bounds_max->type))
+ CV_ERROR(CV_StsUnmatchedFormats, "bounds_{min,max} must have same type");
+ if (CV_MAT_TYPE(results->type) != CV_32SC1)
+ CV_ERROR(CV_StsUnsupportedFormat, "results must be CV_32SC1");
+
+ if (CV_MAT_TYPE(bounds_min->type) != CV_MAT_TYPE(type)) {
+ free_bounds = true;
+
+ CvMat* old_bounds_min = bounds_min;
+ bounds_min = cvCreateMat(bounds_min->rows, bounds_min->cols, type);
+ cvConvert(old_bounds_min, bounds_min);
+
+ CvMat* old_bounds_max = bounds_max;
+ bounds_max = cvCreateMat(bounds_max->rows, bounds_max->cols, type);
+ cvConvert(old_bounds_max, bounds_max);
+ }
+
+ nr = tr->find_ortho_range(bounds_min, bounds_max, results);
+
+ __END__;
+ if (free_bounds) {
+ cvReleaseMat(&bounds_min);
+ cvReleaseMat(&bounds_max);
+ }
+
+ return nr;
+}
+#endif
diff --git a/cv/src/cvlinefit.cpp b/cv/src/cvlinefit.cpp
new file mode 100644
index 0000000..4095c80
--- /dev/null
+++ b/cv/src/cvlinefit.cpp
@@ -0,0 +1,727 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+static const double eps = 1e-6;
+
+static CvStatus
+icvFitLine2D_wods( CvPoint2D32f * points, int _count, float *weights, float *line )
+{
+ double x = 0, y = 0, x2 = 0, y2 = 0, xy = 0, w = 0;
+ double dx2, dy2, dxy;
+ int i;
+ int count = _count;
+ float t;
+
+ /* Calculating the average of x and y... */
+
+ if( weights == 0 )
+ {
+ for( i = 0; i < count; i += 1 )
+ {
+ x += points[i].x;
+ y += points[i].y;
+ x2 += points[i].x * points[i].x;
+ y2 += points[i].y * points[i].y;
+ xy += points[i].x * points[i].y;
+ }
+ w = (float) count;
+ }
+ else
+ {
+ for( i = 0; i < count; i += 1 )
+ {
+ x += weights[i] * points[i].x;
+ y += weights[i] * points[i].y;
+ x2 += weights[i] * points[i].x * points[i].x;
+ y2 += weights[i] * points[i].y * points[i].y;
+ xy += weights[i] * points[i].x * points[i].y;
+ w += weights[i];
+ }
+ }
+
+ x /= w;
+ y /= w;
+ x2 /= w;
+ y2 /= w;
+ xy /= w;
+
+ dx2 = x2 - x * x;
+ dy2 = y2 - y * y;
+ dxy = xy - x * y;
+
+ t = (float) atan2( 2 * dxy, dx2 - dy2 ) / 2;
+ line[0] = (float) cos( t );
+ line[1] = (float) sin( t );
+
+ line[2] = (float) x;
+ line[3] = (float) y;
+
+ return CV_NO_ERR;
+}
+
+static CvStatus
+icvFitLine3D_wods( CvPoint3D32f * points, int count, float *weights, float *line )
+{
+ int i;
+ float w0 = 0;
+ float x0 = 0, y0 = 0, z0 = 0;
+ float x2 = 0, y2 = 0, z2 = 0, xy = 0, yz = 0, xz = 0;
+ float dx2, dy2, dz2, dxy, dxz, dyz;
+ float *v;
+ float n;
+ float det[9], evc[9], evl[3];
+
+ memset( evl, 0, 3*sizeof(evl[0]));
+ memset( evc, 0, 9*sizeof(evl[0]));
+
+ if( weights )
+ {
+ for( i = 0; i < count; i++ )
+ {
+ float x = points[i].x;
+ float y = points[i].y;
+ float z = points[i].z;
+ float w = weights[i];
+
+
+ x2 += x * x * w;
+ xy += x * y * w;
+ xz += x * z * w;
+ y2 += y * y * w;
+ yz += y * z * w;
+ z2 += z * z * w;
+ x0 += x * w;
+ y0 += y * w;
+ z0 += z * w;
+ w0 += w;
+ }
+ }
+ else
+ {
+ for( i = 0; i < count; i++ )
+ {
+ float x = points[i].x;
+ float y = points[i].y;
+ float z = points[i].z;
+
+ x2 += x * x;
+ xy += x * y;
+ xz += x * z;
+ y2 += y * y;
+ yz += y * z;
+ z2 += z * z;
+ x0 += x;
+ y0 += y;
+ z0 += z;
+ }
+ w0 = (float) count;
+ }
+
+ x2 /= w0;
+ xy /= w0;
+ xz /= w0;
+ y2 /= w0;
+ yz /= w0;
+ z2 /= w0;
+
+ x0 /= w0;
+ y0 /= w0;
+ z0 /= w0;
+
+ dx2 = x2 - x0 * x0;
+ dxy = xy - x0 * y0;
+ dxz = xz - x0 * z0;
+ dy2 = y2 - y0 * y0;
+ dyz = yz - y0 * z0;
+ dz2 = z2 - z0 * z0;
+
+ det[0] = dz2 + dy2;
+ det[1] = -dxy;
+ det[2] = -dxz;
+ det[3] = det[1];
+ det[4] = dx2 + dz2;
+ det[5] = -dyz;
+ det[6] = det[2];
+ det[7] = det[5];
+ det[8] = dy2 + dx2;
+
+ /* Searching for a eigenvector of det corresponding to the minimal eigenvalue */
+#if 1
+ {
+ CvMat _det = cvMat( 3, 3, CV_32F, det );
+ CvMat _evc = cvMat( 3, 3, CV_32F, evc );
+ CvMat _evl = cvMat( 3, 1, CV_32F, evl );
+ cvEigenVV( &_det, &_evc, &_evl, 0 );
+ i = evl[0] < evl[1] ? (evl[0] < evl[2] ? 0 : 2) : (evl[1] < evl[2] ? 1 : 2);
+ }
+#else
+ {
+ CvMat _det = cvMat( 3, 3, CV_32F, det );
+ CvMat _evc = cvMat( 3, 3, CV_32F, evc );
+ CvMat _evl = cvMat( 1, 3, CV_32F, evl );
+
+ cvSVD( &_det, &_evl, &_evc, 0, CV_SVD_MODIFY_A+CV_SVD_U_T );
+ }
+ i = 2;
+#endif
+ v = &evc[i * 3];
+ n = (float) sqrt( (double)v[0] * v[0] + (double)v[1] * v[1] + (double)v[2] * v[2] );
+ n = (float)MAX(n, eps);
+ line[0] = v[0] / n;
+ line[1] = v[1] / n;
+ line[2] = v[2] / n;
+ line[3] = x0;
+ line[4] = y0;
+ line[5] = z0;
+
+ return CV_NO_ERR;
+}
+
+static double
+icvCalcDist2D( CvPoint2D32f * points, int count, float *_line, float *dist )
+{
+ int j;
+ float px = _line[2], py = _line[3];
+ float nx = _line[1], ny = -_line[0];
+ double sum_dist = 0.;
+
+ for( j = 0; j < count; j++ )
+ {
+ float x, y;
+
+ x = points[j].x - px;
+ y = points[j].y - py;
+
+ dist[j] = (float) fabs( nx * x + ny * y );
+ sum_dist += dist[j];
+ }
+
+ return sum_dist;
+}
+
+static double
+icvCalcDist3D( CvPoint3D32f * points, int count, float *_line, float *dist )
+{
+ int j;
+ float px = _line[3], py = _line[4], pz = _line[5];
+ float vx = _line[0], vy = _line[1], vz = _line[2];
+ double sum_dist = 0.;
+
+ for( j = 0; j < count; j++ )
+ {
+ float x, y, z;
+ double p1, p2, p3;
+
+ x = points[j].x - px;
+ y = points[j].y - py;
+ z = points[j].z - pz;
+
+ p1 = vy * z - vz * y;
+ p2 = vz * x - vx * z;
+ p3 = vx * y - vy * x;
+
+ dist[j] = (float) sqrt( p1*p1 + p2*p2 + p3*p3 );
+ sum_dist += dist[j];
+ }
+
+ return sum_dist;
+}
+
+static void
+icvWeightL1( float *d, int count, float *w )
+{
+ int i;
+
+ for( i = 0; i < count; i++ )
+ {
+ double t = fabs( (double) d[i] );
+ w[i] = (float)(1. / MAX(t, eps));
+ }
+}
+
+static void
+icvWeightL12( float *d, int count, float *w )
+{
+ int i;
+
+ for( i = 0; i < count; i++ )
+ {
+ w[i] = 1.0f / (float) sqrt( 1 + (double) (d[i] * d[i] * 0.5) );
+ }
+}
+
+
+static void
+icvWeightHuber( float *d, int count, float *w, float _c )
+{
+ int i;
+ const float c = _c <= 0 ? 1.345f : _c;
+
+ for( i = 0; i < count; i++ )
+ {
+ if( d[i] < c )
+ w[i] = 1.0f;
+ else
+ w[i] = c/d[i];
+ }
+}
+
+
+static void
+icvWeightFair( float *d, int count, float *w, float _c )
+{
+ int i;
+ const float c = _c == 0 ? 1 / 1.3998f : 1 / _c;
+
+ for( i = 0; i < count; i++ )
+ {
+ w[i] = 1 / (1 + d[i] * c);
+ }
+}
+
+static void
+icvWeightWelsch( float *d, int count, float *w, float _c )
+{
+ int i;
+ const float c = _c == 0 ? 1 / 2.9846f : 1 / _c;
+
+ for( i = 0; i < count; i++ )
+ {
+ w[i] = (float) exp( -d[i] * d[i] * c * c );
+ }
+}
+
+
+/* Takes an array of 2D points, type of distance (including user-defined
+distance specified by callbacks, fills the array of four floats with line
+parameters A, B, C, D, where (A, B) is the normalized direction vector,
+(C, D) is the point that belongs to the line. */
+
+static CvStatus icvFitLine2D( CvPoint2D32f * points, int count, int dist,
+ float _param, float reps, float aeps, float *line )
+{
+ double EPS = count*FLT_EPSILON;
+ void (*calc_weights) (float *, int, float *) = 0;
+ void (*calc_weights_param) (float *, int, float *, float) = 0;
+ float *w; /* weights */
+ float *r; /* square distances */
+ int i, j, k;
+ float _line[6], _lineprev[6];
+ float rdelta = reps != 0 ? reps : 1.0f;
+ float adelta = aeps != 0 ? aeps : 0.01f;
+ double min_err = DBL_MAX, err = 0;
+ CvRNG rng = cvRNG(-1);
+
+ memset( line, 0, 4*sizeof(line[0]) );
+
+ switch (dist)
+ {
+ case CV_DIST_L2:
+ return icvFitLine2D_wods( points, count, 0, line );
+
+ case CV_DIST_L1:
+ calc_weights = icvWeightL1;
+ break;
+
+ case CV_DIST_L12:
+ calc_weights = icvWeightL12;
+ break;
+
+ case CV_DIST_FAIR:
+ calc_weights_param = icvWeightFair;
+ break;
+
+ case CV_DIST_WELSCH:
+ calc_weights_param = icvWeightWelsch;
+ break;
+
+ case CV_DIST_HUBER:
+ calc_weights_param = icvWeightHuber;
+ break;
+
+ /*case CV_DIST_USER:
+ calc_weights = (void ( * )(float *, int, float *)) _PFP.fp;
+ break;*/
+
+ default:
+ return CV_BADFACTOR_ERR;
+ }
+
+ w = (float *) cvAlloc( count * sizeof( float ));
+ r = (float *) cvAlloc( count * sizeof( float ));
+
+ for( k = 0; k < 20; k++ )
+ {
+ int first = 1;
+ for( i = 0; i < count; i++ )
+ w[i] = 0.f;
+
+ for( i = 0; i < MIN(count,10); )
+ {
+ j = cvRandInt(&rng) % count;
+ if( w[j] < FLT_EPSILON )
+ {
+ w[j] = 1.f;
+ i++;
+ }
+ }
+
+ icvFitLine2D_wods( points, count, w, _line );
+ for( i = 0; i < 30; i++ )
+ {
+ double sum_w = 0;
+
+ if( first )
+ {
+ first = 0;
+ }
+ else
+ {
+ double t = _line[0] * _lineprev[0] + _line[1] * _lineprev[1];
+ t = MAX(t,-1.);
+ t = MIN(t,1.);
+ if( fabs(acos(t)) < adelta )
+ {
+ float x, y, d;
+
+ x = (float) fabs( _line[2] - _lineprev[2] );
+ y = (float) fabs( _line[3] - _lineprev[3] );
+
+ d = x > y ? x : y;
+ if( d < rdelta )
+ break;
+ }
+ }
+ /* calculate distances */
+ err = icvCalcDist2D( points, count, _line, r );
+ if( err < EPS )
+ break;
+
+ /* calculate weights */
+ if( calc_weights )
+ calc_weights( r, count, w );
+ else
+ calc_weights_param( r, count, w, _param );
+
+ for( j = 0; j < count; j++ )
+ sum_w += w[j];
+
+ if( fabs(sum_w) > FLT_EPSILON )
+ {
+ sum_w = 1./sum_w;
+ for( j = 0; j < count; j++ )
+ w[j] = (float)(w[j]*sum_w);
+ }
+ else
+ {
+ for( j = 0; j < count; j++ )
+ w[j] = 1.f;
+ }
+
+ /* save the line parameters */
+ memcpy( _lineprev, _line, 4 * sizeof( float ));
+
+ /* Run again... */
+ icvFitLine2D_wods( points, count, w, _line );
+ }
+
+ if( err < min_err )
+ {
+ min_err = err;
+ memcpy( line, _line, 4 * sizeof(line[0]));
+ if( err < EPS )
+ break;
+ }
+ }
+
+ cvFree( &w );
+ cvFree( &r );
+ return CV_OK;
+}
+
+
+/* Takes an array of 3D points, type of distance (including user-defined
+distance specified by callbacks, fills the array of four floats with line
+parameters A, B, C, D, E, F, where (A, B, C) is the normalized direction vector,
+(D, E, F) is the point that belongs to the line. */
+
+static CvStatus
+icvFitLine3D( CvPoint3D32f * points, int count, int dist,
+ float _param, float reps, float aeps, float *line )
+{
+ double EPS = count*FLT_EPSILON;
+ void (*calc_weights) (float *, int, float *) = 0;
+ void (*calc_weights_param) (float *, int, float *, float) = 0;
+ float *w; /* weights */
+ float *r; /* square distances */
+ int i, j, k;
+ float _line[6], _lineprev[6];
+ float rdelta = reps != 0 ? reps : 1.0f;
+ float adelta = aeps != 0 ? aeps : 0.01f;
+ double min_err = DBL_MAX, err = 0;
+ CvRNG rng = cvRNG(-1);
+
+ memset( line, 0, 6*sizeof(line[0]) );
+
+ switch (dist)
+ {
+ case CV_DIST_L2:
+ return icvFitLine3D_wods( points, count, 0, line );
+
+ case CV_DIST_L1:
+ calc_weights = icvWeightL1;
+ break;
+
+ case CV_DIST_L12:
+ calc_weights = icvWeightL12;
+ break;
+
+ case CV_DIST_FAIR:
+ calc_weights_param = icvWeightFair;
+ break;
+
+ case CV_DIST_WELSCH:
+ calc_weights_param = icvWeightWelsch;
+ break;
+
+ case CV_DIST_HUBER:
+ calc_weights_param = icvWeightHuber;
+ break;
+
+ /*case CV_DIST_USER:
+ _PFP.p = param;
+ calc_weights = (void ( * )(float *, int, float *)) _PFP.fp;
+ break;*/
+
+ default:
+ return CV_BADFACTOR_ERR;
+ }
+
+ w = (float *) cvAlloc( count * sizeof( float ));
+ r = (float *) cvAlloc( count * sizeof( float ));
+
+ for( k = 0; k < 20; k++ )
+ {
+ int first = 1;
+ for( i = 0; i < count; i++ )
+ w[i] = 0.f;
+
+ for( i = 0; i < MIN(count,10); )
+ {
+ j = cvRandInt(&rng) % count;
+ if( w[j] < FLT_EPSILON )
+ {
+ w[j] = 1.f;
+ i++;
+ }
+ }
+
+ icvFitLine3D_wods( points, count, w, _line );
+ for( i = 0; i < 30; i++ )
+ {
+ double sum_w = 0;
+
+ if( first )
+ {
+ first = 0;
+ }
+ else
+ {
+ double t = _line[0] * _lineprev[0] + _line[1] * _lineprev[1] + _line[2] * _lineprev[2];
+ t = MAX(t,-1.);
+ t = MIN(t,1.);
+ if( fabs(acos(t)) < adelta )
+ {
+ float x, y, z, ax, ay, az, dx, dy, dz, d;
+
+ x = _line[3] - _lineprev[3];
+ y = _line[4] - _lineprev[4];
+ z = _line[5] - _lineprev[5];
+ ax = _line[0] - _lineprev[0];
+ ay = _line[1] - _lineprev[1];
+ az = _line[2] - _lineprev[2];
+ dx = (float) fabs( y * az - z * ay );
+ dy = (float) fabs( z * ax - x * az );
+ dz = (float) fabs( x * ay - y * ax );
+
+ d = dx > dy ? (dx > dz ? dx : dz) : (dy > dz ? dy : dz);
+ if( d < rdelta )
+ break;
+ }
+ }
+ /* calculate distances */
+ if( icvCalcDist3D( points, count, _line, r ) < FLT_EPSILON*count )
+ break;
+
+ /* calculate weights */
+ if( calc_weights )
+ calc_weights( r, count, w );
+ else
+ calc_weights_param( r, count, w, _param );
+
+ for( j = 0; j < count; j++ )
+ sum_w += w[j];
+
+ if( fabs(sum_w) > FLT_EPSILON )
+ {
+ sum_w = 1./sum_w;
+ for( j = 0; j < count; j++ )
+ w[j] = (float)(w[j]*sum_w);
+ }
+ else
+ {
+ for( j = 0; j < count; j++ )
+ w[j] = 1.f;
+ }
+
+ /* save the line parameters */
+ memcpy( _lineprev, _line, 6 * sizeof( float ));
+
+ /* Run again... */
+ icvFitLine3D_wods( points, count, w, _line );
+ }
+
+ if( err < min_err )
+ {
+ min_err = err;
+ memcpy( line, _line, 6 * sizeof(line[0]));
+ if( err < EPS )
+ break;
+ }
+ }
+
+ // Return...
+ cvFree( &w );
+ cvFree( &r );
+ return CV_OK;
+}
+
+
+CV_IMPL void
+cvFitLine( const CvArr* array, int dist, double param,
+ double reps, double aeps, float *line )
+{
+ schar* buffer = 0;
+ CV_FUNCNAME( "cvFitLine" );
+
+ __BEGIN__;
+
+ schar* points = 0;
+ union { CvContour contour; CvSeq seq; } header;
+ CvSeqBlock block;
+ CvSeq* ptseq = (CvSeq*)array;
+ int type;
+
+ if( !line )
+ CV_ERROR( CV_StsNullPtr, "NULL pointer to line parameters" );
+
+ if( CV_IS_SEQ(ptseq) )
+ {
+ type = CV_SEQ_ELTYPE(ptseq);
+ if( ptseq->total == 0 )
+ CV_ERROR( CV_StsBadSize, "The sequence has no points" );
+ if( (type!=CV_32FC2 && type!=CV_32FC3 && type!=CV_32SC2 && type!=CV_32SC3) ||
+ CV_ELEM_SIZE(type) != ptseq->elem_size )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Input sequence must consist of 2d points or 3d points" );
+ }
+ else
+ {
+ CvMat* mat = (CvMat*)array;
+ type = CV_MAT_TYPE(mat->type);
+ if( !CV_IS_MAT(mat))
+ CV_ERROR( CV_StsBadArg, "Input array is not a sequence nor matrix" );
+
+ if( !CV_IS_MAT_CONT(mat->type) ||
+ (type!=CV_32FC2 && type!=CV_32FC3 && type!=CV_32SC2 && type!=CV_32SC3) ||
+ (mat->width != 1 && mat->height != 1))
+ CV_ERROR( CV_StsBadArg,
+ "Input array must be 1d continuous array of 2d or 3d points" );
+
+ CV_CALL( ptseq = cvMakeSeqHeaderForArray(
+ CV_SEQ_KIND_GENERIC|type, sizeof(CvContour), CV_ELEM_SIZE(type), mat->data.ptr,
+ mat->width + mat->height - 1, &header.seq, &block ));
+ }
+
+ if( reps < 0 || aeps < 0 )
+ CV_ERROR( CV_StsOutOfRange, "Both reps and aeps must be non-negative" );
+
+ if( CV_MAT_DEPTH(type) == CV_32F && ptseq->first->next == ptseq->first )
+ {
+ /* no need to copy data in this case */
+ points = ptseq->first->data;
+ }
+ else
+ {
+ CV_CALL( buffer = points = (schar*)cvAlloc( ptseq->total*CV_ELEM_SIZE(type) ));
+ CV_CALL( cvCvtSeqToArray( ptseq, points, CV_WHOLE_SEQ ));
+
+ if( CV_MAT_DEPTH(type) != CV_32F )
+ {
+ int i, total = ptseq->total*CV_MAT_CN(type);
+ assert( CV_MAT_DEPTH(type) == CV_32S );
+
+ for( i = 0; i < total; i++ )
+ ((float*)points)[i] = (float)((int*)points)[i];
+ }
+ }
+
+ if( dist == CV_DIST_USER )
+ CV_ERROR( CV_StsBadArg, "User-defined distance is not allowed" );
+
+ if( CV_MAT_CN(type) == 2 )
+ {
+ IPPI_CALL( icvFitLine2D( (CvPoint2D32f*)points, ptseq->total,
+ dist, (float)param, (float)reps, (float)aeps, line ));
+ }
+ else
+ {
+ IPPI_CALL( icvFitLine3D( (CvPoint3D32f*)points, ptseq->total,
+ dist, (float)param, (float)reps, (float)aeps, line ));
+ }
+
+ __END__;
+
+ cvFree( &buffer );
+}
+
+/* End of file. */
diff --git a/cv/src/cvlkpyramid.cpp b/cv/src/cvlkpyramid.cpp
new file mode 100644
index 0000000..f5ad42d
--- /dev/null
+++ b/cv/src/cvlkpyramid.cpp
@@ -0,0 +1,1394 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+#include <float.h>
+#include <stdio.h>
+
+static void
+intersect( CvPoint2D32f pt, CvSize win_size, CvSize imgSize,
+ CvPoint* min_pt, CvPoint* max_pt )
+{
+ CvPoint ipt;
+
+ ipt.x = cvFloor( pt.x );
+ ipt.y = cvFloor( pt.y );
+
+ ipt.x -= win_size.width;
+ ipt.y -= win_size.height;
+
+ win_size.width = win_size.width * 2 + 1;
+ win_size.height = win_size.height * 2 + 1;
+
+ min_pt->x = MAX( 0, -ipt.x );
+ min_pt->y = MAX( 0, -ipt.y );
+ max_pt->x = MIN( win_size.width, imgSize.width - ipt.x );
+ max_pt->y = MIN( win_size.height, imgSize.height - ipt.y );
+}
+
+
+static int icvMinimalPyramidSize( CvSize imgSize )
+{
+ return cvAlign(imgSize.width,8) * imgSize.height / 3;
+}
+
+
+static void
+icvInitPyramidalAlgorithm( const CvMat* imgA, const CvMat* imgB,
+ CvMat* pyrA, CvMat* pyrB,
+ int level, CvTermCriteria * criteria,
+ int max_iters, int flags,
+ uchar *** imgI, uchar *** imgJ,
+ int **step, CvSize** size,
+ double **scale, uchar ** buffer )
+{
+ CV_FUNCNAME( "icvInitPyramidalAlgorithm" );
+
+ __BEGIN__;
+
+ const int ALIGN = 8;
+ int pyrBytes, bufferBytes = 0, elem_size;
+ int level1 = level + 1;
+
+ int i;
+ CvSize imgSize, levelSize;
+
+ *buffer = 0;
+ *imgI = *imgJ = 0;
+ *step = 0;
+ *scale = 0;
+ *size = 0;
+
+ /* check input arguments */
+ if( ((flags & CV_LKFLOW_PYR_A_READY) != 0 && !pyrA) ||
+ ((flags & CV_LKFLOW_PYR_B_READY) != 0 && !pyrB) )
+ CV_ERROR( CV_StsNullPtr, "Some of the precomputed pyramids are missing" );
+
+ if( level < 0 )
+ CV_ERROR( CV_StsOutOfRange, "The number of pyramid layers is negative" );
+
+ switch( criteria->type )
+ {
+ case CV_TERMCRIT_ITER:
+ criteria->epsilon = 0.f;
+ break;
+ case CV_TERMCRIT_EPS:
+ criteria->max_iter = max_iters;
+ break;
+ case CV_TERMCRIT_ITER | CV_TERMCRIT_EPS:
+ break;
+ default:
+ assert( 0 );
+ CV_ERROR( CV_StsBadArg, "Invalid termination criteria" );
+ }
+
+ /* compare squared values */
+ criteria->epsilon *= criteria->epsilon;
+
+ /* set pointers and step for every level */
+ pyrBytes = 0;
+
+ imgSize = cvGetSize(imgA);
+ elem_size = CV_ELEM_SIZE(imgA->type);
+ levelSize = imgSize;
+
+ for( i = 1; i < level1; i++ )
+ {
+ levelSize.width = (levelSize.width + 1) >> 1;
+ levelSize.height = (levelSize.height + 1) >> 1;
+
+ int tstep = cvAlign(levelSize.width,ALIGN) * elem_size;
+ pyrBytes += tstep * levelSize.height;
+ }
+
+ assert( pyrBytes <= imgSize.width * imgSize.height * elem_size * 4 / 3 );
+
+ /* buffer_size = <size for patches> + <size for pyramids> */
+ bufferBytes = (int)((level1 >= 0) * ((pyrA->data.ptr == 0) +
+ (pyrB->data.ptr == 0)) * pyrBytes +
+ (sizeof(imgI[0][0]) * 2 + sizeof(step[0][0]) +
+ sizeof(size[0][0]) + sizeof(scale[0][0])) * level1);
+
+ CV_CALL( *buffer = (uchar *)cvAlloc( bufferBytes ));
+
+ *imgI = (uchar **) buffer[0];
+ *imgJ = *imgI + level1;
+ *step = (int *) (*imgJ + level1);
+ *scale = (double *) (*step + level1);
+ *size = (CvSize *)(*scale + level1);
+
+ imgI[0][0] = imgA->data.ptr;
+ imgJ[0][0] = imgB->data.ptr;
+ step[0][0] = imgA->step;
+ scale[0][0] = 1;
+ size[0][0] = imgSize;
+
+ if( level > 0 )
+ {
+ uchar *bufPtr = (uchar *) (*size + level1);
+ uchar *ptrA = pyrA->data.ptr;
+ uchar *ptrB = pyrB->data.ptr;
+
+ if( !ptrA )
+ {
+ ptrA = bufPtr;
+ bufPtr += pyrBytes;
+ }
+
+ if( !ptrB )
+ ptrB = bufPtr;
+
+ levelSize = imgSize;
+
+ /* build pyramids for both frames */
+ for( i = 1; i <= level; i++ )
+ {
+ int levelBytes;
+ CvMat prev_level, next_level;
+
+ levelSize.width = (levelSize.width + 1) >> 1;
+ levelSize.height = (levelSize.height + 1) >> 1;
+
+ size[0][i] = levelSize;
+ step[0][i] = cvAlign( levelSize.width, ALIGN ) * elem_size;
+ scale[0][i] = scale[0][i - 1] * 0.5;
+
+ levelBytes = step[0][i] * levelSize.height;
+ imgI[0][i] = (uchar *) ptrA;
+ ptrA += levelBytes;
+
+ if( !(flags & CV_LKFLOW_PYR_A_READY) )
+ {
+ prev_level = cvMat( size[0][i-1].height, size[0][i-1].width, CV_8UC1 );
+ next_level = cvMat( size[0][i].height, size[0][i].width, CV_8UC1 );
+ cvSetData( &prev_level, imgI[0][i-1], step[0][i-1] );
+ cvSetData( &next_level, imgI[0][i], step[0][i] );
+ cvPyrDown( &prev_level, &next_level );
+ }
+
+ imgJ[0][i] = (uchar *) ptrB;
+ ptrB += levelBytes;
+
+ if( !(flags & CV_LKFLOW_PYR_B_READY) )
+ {
+ prev_level = cvMat( size[0][i-1].height, size[0][i-1].width, CV_8UC1 );
+ next_level = cvMat( size[0][i].height, size[0][i].width, CV_8UC1 );
+ cvSetData( &prev_level, imgJ[0][i-1], step[0][i-1] );
+ cvSetData( &next_level, imgJ[0][i], step[0][i] );
+ cvPyrDown( &prev_level, &next_level );
+ }
+ }
+ }
+
+ __END__;
+}
+
+
+/* compute dI/dx and dI/dy */
+static void
+icvCalcIxIy_32f( const float* src, int src_step, float* dstX, float* dstY, int dst_step,
+ CvSize src_size, const float* smooth_k, float* buffer0 )
+{
+ int src_width = src_size.width, dst_width = src_size.width-2;
+ int x, height = src_size.height - 2;
+ float* buffer1 = buffer0 + src_width;
+
+ src_step /= sizeof(src[0]);
+ dst_step /= sizeof(dstX[0]);
+
+ for( ; height--; src += src_step, dstX += dst_step, dstY += dst_step )
+ {
+ const float* src2 = src + src_step;
+ const float* src3 = src + src_step*2;
+
+ for( x = 0; x < src_width; x++ )
+ {
+ float t0 = (src3[x] + src[x])*smooth_k[0] + src2[x]*smooth_k[1];
+ float t1 = src3[x] - src[x];
+ buffer0[x] = t0; buffer1[x] = t1;
+ }
+
+ for( x = 0; x < dst_width; x++ )
+ {
+ float t0 = buffer0[x+2] - buffer0[x];
+ float t1 = (buffer1[x] + buffer1[x+2])*smooth_k[0] + buffer1[x+1]*smooth_k[1];
+ dstX[x] = t0; dstY[x] = t1;
+ }
+ }
+}
+
+
+icvOpticalFlowPyrLKInitAlloc_8u_C1R_t icvOpticalFlowPyrLKInitAlloc_8u_C1R_p = 0;
+icvOpticalFlowPyrLKFree_8u_C1R_t icvOpticalFlowPyrLKFree_8u_C1R_p = 0;
+icvOpticalFlowPyrLK_8u_C1R_t icvOpticalFlowPyrLK_8u_C1R_p = 0;
+
+
+CV_IMPL void
+cvCalcOpticalFlowPyrLK( const void* arrA, const void* arrB,
+ void* pyrarrA, void* pyrarrB,
+ const CvPoint2D32f * featuresA,
+ CvPoint2D32f * featuresB,
+ int count, CvSize winSize, int level,
+ char *status, float *error,
+ CvTermCriteria criteria, int flags )
+{
+ uchar *pyrBuffer = 0;
+ uchar *buffer = 0;
+ float* _error = 0;
+ char* _status = 0;
+
+ void* ipp_optflow_state = 0;
+
+ CV_FUNCNAME( "cvCalcOpticalFlowPyrLK" );
+
+ __BEGIN__;
+
+ const int MAX_ITERS = 100;
+
+ CvMat stubA, *imgA = (CvMat*)arrA;
+ CvMat stubB, *imgB = (CvMat*)arrB;
+ CvMat pstubA, *pyrA = (CvMat*)pyrarrA;
+ CvMat pstubB, *pyrB = (CvMat*)pyrarrB;
+ CvSize imgSize;
+ static const float smoothKernel[] = { 0.09375, 0.3125, 0.09375 }; /* 3/32, 10/32, 3/32 */
+
+ int bufferBytes = 0;
+ uchar **imgI = 0;
+ uchar **imgJ = 0;
+ int *step = 0;
+ double *scale = 0;
+ CvSize* size = 0;
+
+ int threadCount = cvGetNumThreads();
+ float* _patchI[CV_MAX_THREADS];
+ float* _patchJ[CV_MAX_THREADS];
+ float* _Ix[CV_MAX_THREADS];
+ float* _Iy[CV_MAX_THREADS];
+
+ int i, l;
+
+ CvSize patchSize = cvSize( winSize.width * 2 + 1, winSize.height * 2 + 1 );
+ int patchLen = patchSize.width * patchSize.height;
+ int srcPatchLen = (patchSize.width + 2)*(patchSize.height + 2);
+
+ CV_CALL( imgA = cvGetMat( imgA, &stubA ));
+ CV_CALL( imgB = cvGetMat( imgB, &stubB ));
+
+ if( CV_MAT_TYPE( imgA->type ) != CV_8UC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( !CV_ARE_TYPES_EQ( imgA, imgB ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( !CV_ARE_SIZES_EQ( imgA, imgB ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( imgA->step != imgB->step )
+ CV_ERROR( CV_StsUnmatchedSizes, "imgA and imgB must have equal steps" );
+
+ imgSize = cvGetMatSize( imgA );
+
+ if( pyrA )
+ {
+ CV_CALL( pyrA = cvGetMat( pyrA, &pstubA ));
+
+ if( pyrA->step*pyrA->height < icvMinimalPyramidSize( imgSize ) )
+ CV_ERROR( CV_StsBadArg, "pyramid A has insufficient size" );
+ }
+ else
+ {
+ pyrA = &pstubA;
+ pyrA->data.ptr = 0;
+ }
+
+ if( pyrB )
+ {
+ CV_CALL( pyrB = cvGetMat( pyrB, &pstubB ));
+
+ if( pyrB->step*pyrB->height < icvMinimalPyramidSize( imgSize ) )
+ CV_ERROR( CV_StsBadArg, "pyramid B has insufficient size" );
+ }
+ else
+ {
+ pyrB = &pstubB;
+ pyrB->data.ptr = 0;
+ }
+
+ if( count == 0 )
+ EXIT;
+
+ if( !featuresA || !featuresB )
+ CV_ERROR( CV_StsNullPtr, "Some of arrays of point coordinates are missing" );
+
+ if( count < 0 )
+ CV_ERROR( CV_StsOutOfRange, "The number of tracked points is negative or zero" );
+
+ if( winSize.width <= 1 || winSize.height <= 1 )
+ CV_ERROR( CV_StsBadSize, "Invalid search window size" );
+
+ for( i = 0; i < threadCount; i++ )
+ _patchI[i] = _patchJ[i] = _Ix[i] = _Iy[i] = 0;
+
+ CV_CALL( icvInitPyramidalAlgorithm( imgA, imgB, pyrA, pyrB,
+ level, &criteria, MAX_ITERS, flags,
+ &imgI, &imgJ, &step, &size, &scale, &pyrBuffer ));
+
+ if( !status )
+ CV_CALL( status = _status = (char*)cvAlloc( count*sizeof(_status[0]) ));
+
+#if 0
+ if( icvOpticalFlowPyrLKInitAlloc_8u_C1R_p &&
+ icvOpticalFlowPyrLKFree_8u_C1R_p &&
+ icvOpticalFlowPyrLK_8u_C1R_p &&
+ winSize.width == winSize.height &&
+ icvOpticalFlowPyrLKInitAlloc_8u_C1R_p( &ipp_optflow_state, imgSize,
+ winSize.width*2+1, cvAlgHintAccurate ) >= 0 )
+ {
+ CvPyramid ipp_pyrA, ipp_pyrB;
+ static const double rate[] = { 1, 0.5, 0.25, 0.125, 0.0625, 0.03125, 0.015625, 0.0078125,
+ 0.00390625, 0.001953125, 0.0009765625, 0.00048828125, 0.000244140625,
+ 0.0001220703125 };
+ // initialize pyramid structures
+ assert( level < 14 );
+ ipp_pyrA.ptr = imgI;
+ ipp_pyrB.ptr = imgJ;
+ ipp_pyrA.sz = ipp_pyrB.sz = size;
+ ipp_pyrA.rate = ipp_pyrB.rate = (double*)rate;
+ ipp_pyrA.step = ipp_pyrB.step = step;
+ ipp_pyrA.state = ipp_pyrB.state = 0;
+ ipp_pyrA.level = ipp_pyrB.level = level;
+
+ if( !error )
+ CV_CALL( error = _error = (float*)cvAlloc( count*sizeof(_error[0]) ));
+
+ for( i = 0; i < count; i++ )
+ featuresB[i] = featuresA[i];
+
+ if( icvOpticalFlowPyrLK_8u_C1R_p( &ipp_pyrA, &ipp_pyrB,
+ (const float*)featuresA, (float*)featuresB, status, error, count,
+ winSize.width*2 + 1, level, criteria.max_iter,
+ (float)criteria.epsilon, ipp_optflow_state ) >= 0 )
+ {
+ for( i = 0; i < count; i++ )
+ status[i] = status[i] == 0;
+ EXIT;
+ }
+ }
+#endif
+
+ /* buffer_size = <size for patches> + <size for pyramids> */
+ bufferBytes = (srcPatchLen + patchLen * 3) * sizeof( _patchI[0][0] ) * threadCount;
+ CV_CALL( buffer = (uchar*)cvAlloc( bufferBytes ));
+
+ for( i = 0; i < threadCount; i++ )
+ {
+ _patchI[i] = i == 0 ? (float*)buffer : _Iy[i-1] + patchLen;
+ _patchJ[i] = _patchI[i] + srcPatchLen;
+ _Ix[i] = _patchJ[i] + patchLen;
+ _Iy[i] = _Ix[i] + patchLen;
+ }
+
+ memset( status, 1, count );
+ if( error )
+ memset( error, 0, count*sizeof(error[0]) );
+
+ if( !(flags & CV_LKFLOW_INITIAL_GUESSES) )
+ memcpy( featuresB, featuresA, count*sizeof(featuresA[0]));
+
+ /* do processing from top pyramid level (smallest image)
+ to the bottom (original image) */
+ for( l = level; l >= 0; l-- )
+ {
+ CvSize levelSize = size[l];
+ int levelStep = step[l];
+
+ {
+#ifdef _OPENMP
+ #pragma omp parallel for num_threads(threadCount) schedule(dynamic)
+#endif // _OPENMP
+ /* find flow for each given point */
+ for( i = 0; i < count; i++ )
+ {
+ CvPoint2D32f v;
+ CvPoint minI, maxI, minJ, maxJ;
+ CvSize isz, jsz;
+ int pt_status;
+ CvPoint2D32f u;
+ CvPoint prev_minJ = { -1, -1 }, prev_maxJ = { -1, -1 };
+ double Gxx = 0, Gxy = 0, Gyy = 0, D = 0, minEig = 0;
+ float prev_mx = 0, prev_my = 0;
+ int j, x, y;
+ int threadIdx = cvGetThreadNum();
+ float* patchI = _patchI[threadIdx];
+ float* patchJ = _patchJ[threadIdx];
+ float* Ix = _Ix[threadIdx];
+ float* Iy = _Iy[threadIdx];
+
+ v.x = featuresB[i].x;
+ v.y = featuresB[i].y;
+ if( l < level )
+ {
+ v.x += v.x;
+ v.y += v.y;
+ }
+ else
+ {
+ v.x = (float)(v.x * scale[l]);
+ v.y = (float)(v.y * scale[l]);
+ }
+
+ pt_status = status[i];
+ if( !pt_status )
+ continue;
+
+ minI = maxI = minJ = maxJ = cvPoint( 0, 0 );
+
+ u.x = (float) (featuresA[i].x * scale[l]);
+ u.y = (float) (featuresA[i].y * scale[l]);
+
+ intersect( u, winSize, levelSize, &minI, &maxI );
+ isz = jsz = cvSize(maxI.x - minI.x + 2, maxI.y - minI.y + 2);
+ u.x += (minI.x - (patchSize.width - maxI.x + 1))*0.5f;
+ u.y += (minI.y - (patchSize.height - maxI.y + 1))*0.5f;
+
+ if( isz.width < 3 || isz.height < 3 ||
+ icvGetRectSubPix_8u32f_C1R( imgI[l], levelStep, levelSize,
+ patchI, isz.width*sizeof(patchI[0]), isz, u ) < 0 )
+ {
+ /* point is outside the image. take the next */
+ status[i] = 0;
+ continue;
+ }
+
+ icvCalcIxIy_32f( patchI, isz.width*sizeof(patchI[0]), Ix, Iy,
+ (isz.width-2)*sizeof(patchI[0]), isz, smoothKernel, patchJ );
+
+ for( j = 0; j < criteria.max_iter; j++ )
+ {
+ double bx = 0, by = 0;
+ float mx, my;
+ CvPoint2D32f _v;
+
+ intersect( v, winSize, levelSize, &minJ, &maxJ );
+
+ minJ.x = MAX( minJ.x, minI.x );
+ minJ.y = MAX( minJ.y, minI.y );
+
+ maxJ.x = MIN( maxJ.x, maxI.x );
+ maxJ.y = MIN( maxJ.y, maxI.y );
+
+ jsz = cvSize(maxJ.x - minJ.x, maxJ.y - minJ.y);
+
+ _v.x = v.x + (minJ.x - (patchSize.width - maxJ.x + 1))*0.5f;
+ _v.y = v.y + (minJ.y - (patchSize.height - maxJ.y + 1))*0.5f;
+
+ if( jsz.width < 1 || jsz.height < 1 ||
+ icvGetRectSubPix_8u32f_C1R( imgJ[l], levelStep, levelSize, patchJ,
+ jsz.width*sizeof(patchJ[0]), jsz, _v ) < 0 )
+ {
+ /* point is outside image. take the next */
+ pt_status = 0;
+ break;
+ }
+
+ if( maxJ.x == prev_maxJ.x && maxJ.y == prev_maxJ.y &&
+ minJ.x == prev_minJ.x && minJ.y == prev_minJ.y )
+ {
+ for( y = 0; y < jsz.height; y++ )
+ {
+ const float* pi = patchI +
+ (y + minJ.y - minI.y + 1)*isz.width + minJ.x - minI.x + 1;
+ const float* pj = patchJ + y*jsz.width;
+ const float* ix = Ix +
+ (y + minJ.y - minI.y)*(isz.width-2) + minJ.x - minI.x;
+ const float* iy = Iy + (ix - Ix);
+
+ for( x = 0; x < jsz.width; x++ )
+ {
+ double t0 = pi[x] - pj[x];
+ bx += t0 * ix[x];
+ by += t0 * iy[x];
+ }
+ }
+ }
+ else
+ {
+ Gxx = Gyy = Gxy = 0;
+ for( y = 0; y < jsz.height; y++ )
+ {
+ const float* pi = patchI +
+ (y + minJ.y - minI.y + 1)*isz.width + minJ.x - minI.x + 1;
+ const float* pj = patchJ + y*jsz.width;
+ const float* ix = Ix +
+ (y + minJ.y - minI.y)*(isz.width-2) + minJ.x - minI.x;
+ const float* iy = Iy + (ix - Ix);
+
+ for( x = 0; x < jsz.width; x++ )
+ {
+ double t = pi[x] - pj[x];
+ bx += (double) (t * ix[x]);
+ by += (double) (t * iy[x]);
+ Gxx += ix[x] * ix[x];
+ Gxy += ix[x] * iy[x];
+ Gyy += iy[x] * iy[x];
+ }
+ }
+
+ D = Gxx * Gyy - Gxy * Gxy;
+ if( D < DBL_EPSILON )
+ {
+ pt_status = 0;
+ break;
+ }
+
+ // Adi Shavit - 2008.05
+ if( flags & CV_LKFLOW_GET_MIN_EIGENVALS )
+ minEig = (Gyy + Gxx - sqrt((Gxx-Gyy)*(Gxx-Gyy) + 4.*Gxy*Gxy))/(2*jsz.height*jsz.width);
+
+ D = 1. / D;
+
+ prev_minJ = minJ;
+ prev_maxJ = maxJ;
+ }
+
+ mx = (float) ((Gyy * bx - Gxy * by) * D);
+ my = (float) ((Gxx * by - Gxy * bx) * D);
+
+ v.x += mx;
+ v.y += my;
+
+ if( mx * mx + my * my < criteria.epsilon )
+ break;
+
+ if( j > 0 && fabs(mx + prev_mx) < 0.01 && fabs(my + prev_my) < 0.01 )
+ {
+ v.x -= mx*0.5f;
+ v.y -= my*0.5f;
+ break;
+ }
+ prev_mx = mx;
+ prev_my = my;
+ }
+
+ featuresB[i] = v;
+ status[i] = (char)pt_status;
+ if( l == 0 && error && pt_status )
+ {
+ /* calc error */
+ double err = 0;
+ if( flags & CV_LKFLOW_GET_MIN_EIGENVALS )
+ err = minEig;
+ else
+ {
+ for( y = 0; y < jsz.height; y++ )
+ {
+ const float* pi = patchI +
+ (y + minJ.y - minI.y + 1)*isz.width + minJ.x - minI.x + 1;
+ const float* pj = patchJ + y*jsz.width;
+
+ for( x = 0; x < jsz.width; x++ )
+ {
+ double t = pi[x] - pj[x];
+ err += t * t;
+ }
+ }
+ err = sqrt(err);
+ }
+ error[i] = (float)err;
+ }
+ } // end of point processing loop (i)
+ }
+ } // end of pyramid levels loop (l)
+
+ __END__;
+
+ if( ipp_optflow_state )
+ icvOpticalFlowPyrLKFree_8u_C1R_p( ipp_optflow_state );
+
+ cvFree( &pyrBuffer );
+ cvFree( &buffer );
+ cvFree( &_error );
+ cvFree( &_status );
+}
+
+
+/* Affine tracking algorithm */
+
+CV_IMPL void
+cvCalcAffineFlowPyrLK( const void* arrA, const void* arrB,
+ void* pyrarrA, void* pyrarrB,
+ const CvPoint2D32f * featuresA,
+ CvPoint2D32f * featuresB,
+ float *matrices, int count,
+ CvSize winSize, int level,
+ char *status, float *error,
+ CvTermCriteria criteria, int flags )
+{
+ const int MAX_ITERS = 100;
+
+ char* _status = 0;
+ uchar *buffer = 0;
+ uchar *pyr_buffer = 0;
+
+ CV_FUNCNAME( "cvCalcAffineFlowPyrLK" );
+
+ __BEGIN__;
+
+ CvMat stubA, *imgA = (CvMat*)arrA;
+ CvMat stubB, *imgB = (CvMat*)arrB;
+ CvMat pstubA, *pyrA = (CvMat*)pyrarrA;
+ CvMat pstubB, *pyrB = (CvMat*)pyrarrB;
+
+ static const float smoothKernel[] = { 0.09375, 0.3125, 0.09375 }; /* 3/32, 10/32, 3/32 */
+
+ int bufferBytes = 0;
+
+ uchar **imgI = 0;
+ uchar **imgJ = 0;
+ int *step = 0;
+ double *scale = 0;
+ CvSize* size = 0;
+
+ float *patchI;
+ float *patchJ;
+ float *Ix;
+ float *Iy;
+
+ int i, j, k, l;
+
+ CvSize patchSize = cvSize( winSize.width * 2 + 1, winSize.height * 2 + 1 );
+ int patchLen = patchSize.width * patchSize.height;
+ int patchStep = patchSize.width * sizeof( patchI[0] );
+
+ CvSize srcPatchSize = cvSize( patchSize.width + 2, patchSize.height + 2 );
+ int srcPatchLen = srcPatchSize.width * srcPatchSize.height;
+ int srcPatchStep = srcPatchSize.width * sizeof( patchI[0] );
+ CvSize imgSize;
+ float eps = (float)MIN(winSize.width, winSize.height);
+
+ CV_CALL( imgA = cvGetMat( imgA, &stubA ));
+ CV_CALL( imgB = cvGetMat( imgB, &stubB ));
+
+ if( CV_MAT_TYPE( imgA->type ) != CV_8UC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( !CV_ARE_TYPES_EQ( imgA, imgB ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( !CV_ARE_SIZES_EQ( imgA, imgB ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( imgA->step != imgB->step )
+ CV_ERROR( CV_StsUnmatchedSizes, "imgA and imgB must have equal steps" );
+
+ if( !matrices )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ imgSize = cvGetMatSize( imgA );
+
+ if( pyrA )
+ {
+ CV_CALL( pyrA = cvGetMat( pyrA, &pstubA ));
+
+ if( pyrA->step*pyrA->height < icvMinimalPyramidSize( imgSize ) )
+ CV_ERROR( CV_StsBadArg, "pyramid A has insufficient size" );
+ }
+ else
+ {
+ pyrA = &pstubA;
+ pyrA->data.ptr = 0;
+ }
+
+ if( pyrB )
+ {
+ CV_CALL( pyrB = cvGetMat( pyrB, &pstubB ));
+
+ if( pyrB->step*pyrB->height < icvMinimalPyramidSize( imgSize ) )
+ CV_ERROR( CV_StsBadArg, "pyramid B has insufficient size" );
+ }
+ else
+ {
+ pyrB = &pstubB;
+ pyrB->data.ptr = 0;
+ }
+
+ if( count == 0 )
+ EXIT;
+
+ /* check input arguments */
+ if( !featuresA || !featuresB || !matrices )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( winSize.width <= 1 || winSize.height <= 1 )
+ CV_ERROR( CV_StsOutOfRange, "the search window is too small" );
+
+ if( count < 0 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ CV_CALL( icvInitPyramidalAlgorithm( imgA, imgB,
+ pyrA, pyrB, level, &criteria, MAX_ITERS, flags,
+ &imgI, &imgJ, &step, &size, &scale, &pyr_buffer ));
+
+ /* buffer_size = <size for patches> + <size for pyramids> */
+ bufferBytes = (srcPatchLen + patchLen*3)*sizeof(patchI[0]) + (36*2 + 6)*sizeof(double);
+
+ CV_CALL( buffer = (uchar*)cvAlloc(bufferBytes));
+
+ if( !status )
+ CV_CALL( status = _status = (char*)cvAlloc(count) );
+
+ patchI = (float *) buffer;
+ patchJ = patchI + srcPatchLen;
+ Ix = patchJ + patchLen;
+ Iy = Ix + patchLen;
+
+ if( status )
+ memset( status, 1, count );
+
+ if( !(flags & CV_LKFLOW_INITIAL_GUESSES) )
+ {
+ memcpy( featuresB, featuresA, count * sizeof( featuresA[0] ));
+ for( i = 0; i < count * 4; i += 4 )
+ {
+ matrices[i] = matrices[i + 3] = 1.f;
+ matrices[i + 1] = matrices[i + 2] = 0.f;
+ }
+ }
+
+ for( i = 0; i < count; i++ )
+ {
+ featuresB[i].x = (float)(featuresB[i].x * scale[level] * 0.5);
+ featuresB[i].y = (float)(featuresB[i].y * scale[level] * 0.5);
+ }
+
+ /* do processing from top pyramid level (smallest image)
+ to the bottom (original image) */
+ for( l = level; l >= 0; l-- )
+ {
+ CvSize levelSize = size[l];
+ int levelStep = step[l];
+
+ /* find flow for each given point at the particular level */
+ for( i = 0; i < count; i++ )
+ {
+ CvPoint2D32f u;
+ float Av[6];
+ double G[36];
+ double meanI = 0, meanJ = 0;
+ int x, y;
+ int pt_status = status[i];
+ CvMat mat;
+
+ if( !pt_status )
+ continue;
+
+ Av[0] = matrices[i*4];
+ Av[1] = matrices[i*4+1];
+ Av[3] = matrices[i*4+2];
+ Av[4] = matrices[i*4+3];
+
+ Av[2] = featuresB[i].x += featuresB[i].x;
+ Av[5] = featuresB[i].y += featuresB[i].y;
+
+ u.x = (float) (featuresA[i].x * scale[l]);
+ u.y = (float) (featuresA[i].y * scale[l]);
+
+ if( u.x < -eps || u.x >= levelSize.width+eps ||
+ u.y < -eps || u.y >= levelSize.height+eps ||
+ icvGetRectSubPix_8u32f_C1R( imgI[l], levelStep,
+ levelSize, patchI, srcPatchStep, srcPatchSize, u ) < 0 )
+ {
+ /* point is outside the image. take the next */
+ if( l == 0 )
+ status[i] = 0;
+ continue;
+ }
+
+ icvCalcIxIy_32f( patchI, srcPatchStep, Ix, Iy,
+ (srcPatchSize.width-2)*sizeof(patchI[0]), srcPatchSize,
+ smoothKernel, patchJ );
+
+ /* repack patchI (remove borders) */
+ for( k = 0; k < patchSize.height; k++ )
+ memcpy( patchI + k * patchSize.width,
+ patchI + (k + 1) * srcPatchSize.width + 1, patchStep );
+
+ memset( G, 0, sizeof( G ));
+
+ /* calculate G matrix */
+ for( y = -winSize.height, k = 0; y <= winSize.height; y++ )
+ {
+ for( x = -winSize.width; x <= winSize.width; x++, k++ )
+ {
+ double ixix = ((double) Ix[k]) * Ix[k];
+ double ixiy = ((double) Ix[k]) * Iy[k];
+ double iyiy = ((double) Iy[k]) * Iy[k];
+
+ double xx, xy, yy;
+
+ G[0] += ixix;
+ G[1] += ixiy;
+ G[2] += x * ixix;
+ G[3] += y * ixix;
+ G[4] += x * ixiy;
+ G[5] += y * ixiy;
+
+ // G[6] == G[1]
+ G[7] += iyiy;
+ // G[8] == G[4]
+ // G[9] == G[5]
+ G[10] += x * iyiy;
+ G[11] += y * iyiy;
+
+ xx = x * x;
+ xy = x * y;
+ yy = y * y;
+
+ // G[12] == G[2]
+ // G[13] == G[8] == G[4]
+ G[14] += xx * ixix;
+ G[15] += xy * ixix;
+ G[16] += xx * ixiy;
+ G[17] += xy * ixiy;
+
+ // G[18] == G[3]
+ // G[19] == G[9]
+ // G[20] == G[15]
+ G[21] += yy * ixix;
+ // G[22] == G[17]
+ G[23] += yy * ixiy;
+
+ // G[24] == G[4]
+ // G[25] == G[10]
+ // G[26] == G[16]
+ // G[27] == G[22]
+ G[28] += xx * iyiy;
+ G[29] += xy * iyiy;
+
+ // G[30] == G[5]
+ // G[31] == G[11]
+ // G[32] == G[17]
+ // G[33] == G[23]
+ // G[34] == G[29]
+ G[35] += yy * iyiy;
+
+ meanI += patchI[k];
+ }
+ }
+
+ meanI /= patchSize.width*patchSize.height;
+
+ G[8] = G[4];
+ G[9] = G[5];
+ G[22] = G[17];
+
+ // fill part of G below its diagonal
+ for( y = 1; y < 6; y++ )
+ for( x = 0; x < y; x++ )
+ G[y * 6 + x] = G[x * 6 + y];
+
+ cvInitMatHeader( &mat, 6, 6, CV_64FC1, G );
+
+ if( cvInvert( &mat, &mat, CV_SVD ) < 1e-4 )
+ {
+ /* bad matrix. take the next point */
+ if( l == 0 )
+ status[i] = 0;
+ continue;
+ }
+
+ for( j = 0; j < criteria.max_iter; j++ )
+ {
+ double b[6] = {0,0,0,0,0,0}, eta[6];
+ double t0, t1, s = 0;
+
+ if( Av[2] < -eps || Av[2] >= levelSize.width+eps ||
+ Av[5] < -eps || Av[5] >= levelSize.height+eps ||
+ icvGetQuadrangleSubPix_8u32f_C1R( imgJ[l], levelStep,
+ levelSize, patchJ, patchStep, patchSize, Av ) < 0 )
+ {
+ pt_status = 0;
+ break;
+ }
+
+ for( y = -winSize.height, k = 0, meanJ = 0; y <= winSize.height; y++ )
+ for( x = -winSize.width; x <= winSize.width; x++, k++ )
+ meanJ += patchJ[k];
+
+ meanJ = meanJ / (patchSize.width * patchSize.height) - meanI;
+
+ for( y = -winSize.height, k = 0; y <= winSize.height; y++ )
+ {
+ for( x = -winSize.width; x <= winSize.width; x++, k++ )
+ {
+ double t = patchI[k] - patchJ[k] + meanJ;
+ double ixt = Ix[k] * t;
+ double iyt = Iy[k] * t;
+
+ s += t;
+
+ b[0] += ixt;
+ b[1] += iyt;
+ b[2] += x * ixt;
+ b[3] += y * ixt;
+ b[4] += x * iyt;
+ b[5] += y * iyt;
+ }
+ }
+
+ icvTransformVector_64d( G, b, eta, 6, 6 );
+
+ Av[2] = (float)(Av[2] + Av[0] * eta[0] + Av[1] * eta[1]);
+ Av[5] = (float)(Av[5] + Av[3] * eta[0] + Av[4] * eta[1]);
+
+ t0 = Av[0] * (1 + eta[2]) + Av[1] * eta[4];
+ t1 = Av[0] * eta[3] + Av[1] * (1 + eta[5]);
+ Av[0] = (float)t0;
+ Av[1] = (float)t1;
+
+ t0 = Av[3] * (1 + eta[2]) + Av[4] * eta[4];
+ t1 = Av[3] * eta[3] + Av[4] * (1 + eta[5]);
+ Av[3] = (float)t0;
+ Av[4] = (float)t1;
+
+ if( eta[0] * eta[0] + eta[1] * eta[1] < criteria.epsilon )
+ break;
+ }
+
+ if( pt_status != 0 || l == 0 )
+ {
+ status[i] = (char)pt_status;
+ featuresB[i].x = Av[2];
+ featuresB[i].y = Av[5];
+
+ matrices[i*4] = Av[0];
+ matrices[i*4+1] = Av[1];
+ matrices[i*4+2] = Av[3];
+ matrices[i*4+3] = Av[4];
+ }
+
+ if( pt_status && l == 0 && error )
+ {
+ /* calc error */
+ double err = 0;
+
+ for( y = 0, k = 0; y < patchSize.height; y++ )
+ {
+ for( x = 0; x < patchSize.width; x++, k++ )
+ {
+ double t = patchI[k] - patchJ[k] + meanJ;
+ err += t * t;
+ }
+ }
+ error[i] = (float)sqrt(err);
+ }
+ }
+ }
+
+ __END__;
+
+ cvFree( &pyr_buffer );
+ cvFree( &buffer );
+ cvFree( &_status );
+}
+
+
+
+static void
+icvGetRTMatrix( const CvPoint2D32f* a, const CvPoint2D32f* b,
+ int count, CvMat* M, int full_affine )
+{
+ if( full_affine )
+ {
+ double sa[36], sb[6];
+ CvMat A = cvMat( 6, 6, CV_64F, sa ), B = cvMat( 6, 1, CV_64F, sb );
+ CvMat MM = cvMat( 6, 1, CV_64F, M->data.db );
+
+ int i;
+
+ memset( sa, 0, sizeof(sa) );
+ memset( sb, 0, sizeof(sb) );
+
+ for( i = 0; i < count; i++ )
+ {
+ sa[0] += a[i].x*a[i].x;
+ sa[1] += a[i].y*a[i].x;
+ sa[2] += a[i].x;
+
+ sa[6] += a[i].x*a[i].y;
+ sa[7] += a[i].y*a[i].y;
+ sa[8] += a[i].y;
+
+ sa[12] += a[i].x;
+ sa[13] += a[i].y;
+ sa[14] += 1;
+
+ sb[0] += a[i].x*b[i].x;
+ sb[1] += a[i].y*b[i].x;
+ sb[2] += b[i].x;
+ sb[3] += a[i].x*b[i].y;
+ sb[4] += a[i].y*b[i].y;
+ sb[5] += b[i].y;
+ }
+
+ sa[21] = sa[0];
+ sa[22] = sa[1];
+ sa[23] = sa[2];
+ sa[27] = sa[6];
+ sa[28] = sa[7];
+ sa[29] = sa[8];
+ sa[33] = sa[12];
+ sa[34] = sa[13];
+ sa[35] = sa[14];
+
+ cvSolve( &A, &B, &MM, CV_SVD );
+ }
+ else
+ {
+ double sa[16], sb[4], m[4], *om = M->data.db;
+ CvMat A = cvMat( 4, 4, CV_64F, sa ), B = cvMat( 4, 1, CV_64F, sb );
+ CvMat MM = cvMat( 4, 1, CV_64F, m );
+
+ int i;
+
+ memset( sa, 0, sizeof(sa) );
+ memset( sb, 0, sizeof(sb) );
+
+ for( i = 0; i < count; i++ )
+ {
+ sa[0] += a[i].x*a[i].x + a[i].y*a[i].y;
+ sa[1] += 0;
+ sa[2] += a[i].x;
+ sa[3] += a[i].y;
+
+ sa[4] += 0;
+ sa[5] += a[i].x*a[i].x + a[i].y*a[i].y;
+ sa[6] += -a[i].y;
+ sa[7] += a[i].x;
+
+ sa[8] += a[i].x;
+ sa[9] += -a[i].y;
+ sa[10] += 1;
+ sa[11] += 0;
+
+ sa[12] += a[i].y;
+ sa[13] += a[i].x;
+ sa[14] += 0;
+ sa[15] += 1;
+
+ sb[0] += a[i].x*b[i].x + a[i].y*b[i].y;
+ sb[1] += a[i].x*b[i].y - a[i].y*b[i].x;
+ sb[2] += b[i].x;
+ sb[3] += b[i].y;
+ }
+
+ cvSolve( &A, &B, &MM, CV_SVD );
+
+ om[0] = om[4] = m[0];
+ om[1] = -m[1];
+ om[3] = m[1];
+ om[2] = m[2];
+ om[5] = m[3];
+ }
+}
+
+
+CV_IMPL int
+cvEstimateRigidTransform( const CvArr* _A, const CvArr* _B, CvMat* _M, int full_affine )
+{
+ int result = 0;
+
+ const int COUNT = 15;
+ const int WIDTH = 160, HEIGHT = 120;
+ const int RANSAC_MAX_ITERS = 100;
+ const int RANSAC_SIZE0 = 3;
+ const double MIN_TRIANGLE_SIDE = 20;
+ const double RANSAC_GOOD_RATIO = 0.5;
+
+ int allocated = 1;
+ CvMat *sA = 0, *sB = 0;
+ CvPoint2D32f *pA = 0, *pB = 0;
+ int* good_idx = 0;
+ char *status = 0;
+ CvMat* gray = 0;
+
+ CV_FUNCNAME( "cvEstimateRigidTransform" );
+
+ __BEGIN__;
+
+ CvMat stubA, *A;
+ CvMat stubB, *B;
+ CvSize sz0, sz1;
+ int cn, equal_sizes;
+ int i, j, k, k1;
+ int count_x, count_y, count;
+ double scale = 1;
+ CvRNG rng = cvRNG(-1);
+ double m[6]={0};
+ CvMat M = cvMat( 2, 3, CV_64F, m );
+ int good_count = 0;
+
+ CV_CALL( A = cvGetMat( _A, &stubA ));
+ CV_CALL( B = cvGetMat( _B, &stubB ));
+
+ if( !CV_IS_MAT(_M) )
+ CV_ERROR( _M ? CV_StsBadArg : CV_StsNullPtr, "Output parameter M is not a valid matrix" );
+
+ if( !CV_ARE_SIZES_EQ( A, B ) )
+ CV_ERROR( CV_StsUnmatchedSizes, "Both input images must have the same size" );
+
+ if( !CV_ARE_TYPES_EQ( A, B ) )
+ CV_ERROR( CV_StsUnmatchedFormats, "Both input images must have the same data type" );
+
+ if( CV_MAT_TYPE(A->type) == CV_8UC1 || CV_MAT_TYPE(A->type) == CV_8UC3 )
+ {
+ cn = CV_MAT_CN(A->type);
+ sz0 = cvGetSize(A);
+ sz1 = cvSize(WIDTH, HEIGHT);
+
+ scale = MAX( (double)sz1.width/sz0.width, (double)sz1.height/sz0.height );
+ scale = MIN( scale, 1. );
+ sz1.width = cvRound( sz0.width * scale );
+ sz1.height = cvRound( sz0.height * scale );
+
+ equal_sizes = sz1.width == sz0.width && sz1.height == sz0.height;
+
+ if( !equal_sizes || cn != 1 )
+ {
+ CV_CALL( sA = cvCreateMat( sz1.height, sz1.width, CV_8UC1 ));
+ CV_CALL( sB = cvCreateMat( sz1.height, sz1.width, CV_8UC1 ));
+
+ if( !equal_sizes && cn != 1 )
+ CV_CALL( gray = cvCreateMat( sz0.height, sz0.width, CV_8UC1 ));
+
+ if( gray )
+ {
+ cvCvtColor( A, gray, CV_BGR2GRAY );
+ cvResize( gray, sA, CV_INTER_AREA );
+ cvCvtColor( B, gray, CV_BGR2GRAY );
+ cvResize( gray, sB, CV_INTER_AREA );
+ }
+ else if( cn == 1 )
+ {
+ cvResize( gray, sA, CV_INTER_AREA );
+ cvResize( gray, sB, CV_INTER_AREA );
+ }
+ else
+ {
+ cvCvtColor( A, gray, CV_BGR2GRAY );
+ cvResize( gray, sA, CV_INTER_AREA );
+ cvCvtColor( B, gray, CV_BGR2GRAY );
+ }
+
+ cvReleaseMat( &gray );
+ A = sA;
+ B = sB;
+ }
+
+ count_y = COUNT;
+ count_x = cvRound((double)COUNT*sz1.width/sz1.height);
+ count = count_x * count_y;
+
+ CV_CALL( pA = (CvPoint2D32f*)cvAlloc( count*sizeof(pA[0]) ));
+ CV_CALL( pB = (CvPoint2D32f*)cvAlloc( count*sizeof(pB[0]) ));
+ CV_CALL( status = (char*)cvAlloc( count*sizeof(status[0]) ));
+
+ for( i = 0, k = 0; i < count_y; i++ )
+ for( j = 0; j < count_x; j++, k++ )
+ {
+ pA[k].x = (j+0.5f)*sz1.width/count_x;
+ pA[k].y = (i+0.5f)*sz1.height/count_y;
+ }
+
+ // find the corresponding points in B
+ cvCalcOpticalFlowPyrLK( A, B, 0, 0, pA, pB, count, cvSize(10,10), 3,
+ status, 0, cvTermCriteria(CV_TERMCRIT_ITER,40,0.1), 0 );
+
+ // repack the remained points
+ for( i = 0, k = 0; i < count; i++ )
+ if( status[i] )
+ {
+ if( i > k )
+ {
+ pA[k] = pA[i];
+ pB[k] = pB[i];
+ }
+ k++;
+ }
+
+ count = k;
+ }
+ else if( CV_MAT_TYPE(A->type) == CV_32FC2 || CV_MAT_TYPE(A->type) == CV_32SC2 )
+ {
+ count = A->cols*A->rows;
+
+ if( CV_IS_MAT_CONT(A->type & B->type) && CV_MAT_TYPE(A->type) == CV_32FC2 )
+ {
+ pA = (CvPoint2D32f*)A->data.ptr;
+ pB = (CvPoint2D32f*)B->data.ptr;
+ allocated = 0;
+ }
+ else
+ {
+ CvMat _pA, _pB;
+
+ CV_CALL( pA = (CvPoint2D32f*)cvAlloc( count*sizeof(pA[0]) ));
+ CV_CALL( pB = (CvPoint2D32f*)cvAlloc( count*sizeof(pB[0]) ));
+ _pA = cvMat( A->rows, A->cols, CV_32FC2, pA );
+ _pB = cvMat( B->rows, B->cols, CV_32FC2, pB );
+ cvConvert( A, &_pA );
+ cvConvert( B, &_pB );
+ }
+ }
+ else
+ CV_ERROR( CV_StsUnsupportedFormat, "Both input images must have either 8uC1 or 8uC3 type" );
+
+ CV_CALL( good_idx = (int*)cvAlloc( count*sizeof(good_idx[0]) ));
+
+ if( count < RANSAC_SIZE0 )
+ EXIT;
+
+ // RANSAC stuff:
+ // 1. find the consensus
+ for( k = 0; k < RANSAC_MAX_ITERS; k++ )
+ {
+ int idx[RANSAC_SIZE0];
+ CvPoint2D32f a[3];
+ CvPoint2D32f b[3];
+
+ memset( a, 0, sizeof(a) );
+ memset( b, 0, sizeof(b) );
+
+ // choose random 3 non-complanar points from A & B
+ for( i = 0; i < RANSAC_SIZE0; i++ )
+ {
+ for( k1 = 0; k1 < RANSAC_MAX_ITERS; k1++ )
+ {
+ idx[i] = cvRandInt(&rng) % count;
+
+ for( j = 0; j < i; j++ )
+ {
+ if( idx[j] == idx[i] )
+ break;
+ // check that the points are not very close one each other
+ if( fabs(pA[idx[i]].x - pA[idx[j]].x) +
+ fabs(pA[idx[i]].y - pA[idx[j]].y) < MIN_TRIANGLE_SIDE )
+ break;
+ if( fabs(pB[idx[i]].x - pB[idx[j]].x) +
+ fabs(pB[idx[i]].y - pB[idx[j]].y) < MIN_TRIANGLE_SIDE )
+ break;
+ }
+
+ if( j < i )
+ continue;
+
+ if( i+1 == RANSAC_SIZE0 )
+ {
+ // additional check for non-complanar vectors
+ a[0] = pA[idx[0]];
+ a[1] = pA[idx[1]];
+ a[2] = pA[idx[2]];
+
+ b[0] = pB[idx[0]];
+ b[1] = pB[idx[1]];
+ b[2] = pB[idx[2]];
+
+ if( fabs((a[1].x - a[0].x)*(a[2].y - a[0].y) - (a[1].y - a[0].y)*(a[2].x - a[0].x)) < 1 ||
+ fabs((b[1].x - b[0].x)*(b[2].y - b[0].y) - (b[1].y - b[0].y)*(b[2].x - b[0].x)) < 1 )
+ continue;
+ }
+ break;
+ }
+
+ if( k1 >= RANSAC_MAX_ITERS )
+ break;
+ }
+
+ if( i < RANSAC_SIZE0 )
+ continue;
+
+ // estimate the transformation using 3 points
+ icvGetRTMatrix( a, b, 3, &M, full_affine );
+
+ for( i = 0, good_count = 0; i < count; i++ )
+ {
+ if( fabs( m[0]*pA[i].x + m[1]*pA[i].y + m[2] - pB[i].x ) +
+ fabs( m[3]*pA[i].x + m[4]*pA[i].y + m[5] - pB[i].y ) < 8 )
+ good_idx[good_count++] = i;
+ }
+
+ if( good_count >= count*RANSAC_GOOD_RATIO )
+ break;
+ }
+
+ if( k >= RANSAC_MAX_ITERS )
+ EXIT;
+
+ if( good_count < count )
+ {
+ for( i = 0; i < good_count; i++ )
+ {
+ j = good_idx[i];
+ pA[i] = pA[j];
+ pB[i] = pB[j];
+ }
+ }
+
+ icvGetRTMatrix( pA, pB, good_count, &M, full_affine );
+ m[2] /= scale;
+ m[5] /= scale;
+ CV_CALL( cvConvert( &M, _M ));
+ result = 1;
+
+ __END__;
+
+ cvReleaseMat( &sA );
+ cvReleaseMat( &sB );
+ cvFree( &pA );
+ cvFree( &pB );
+ cvFree( &status );
+ cvFree( &good_idx );
+ cvReleaseMat( &gray );
+
+ return result;
+}
+
+
+/* End of file. */
diff --git a/cv/src/cvmatchcontours.cpp b/cv/src/cvmatchcontours.cpp
new file mode 100644
index 0000000..a4a6938
--- /dev/null
+++ b/cv/src/cvmatchcontours.cpp
@@ -0,0 +1,398 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvMatchContours
+// Purpose:
+// Calculates matching of the two contours
+// Context:
+// Parameters:
+// contour_1 - pointer to the first input contour object.
+// contour_2 - pointer to the second input contour object.
+// method - method for the matching calculation
+// (now CV_IPPI_CONTOURS_MATCH_I1, CV_CONTOURS_MATCH_I2 or
+// CV_CONTOURS_MATCH_I3 only )
+// rezult - output calculated measure
+//
+//F*/
+CV_IMPL double
+cvMatchShapes( const void* contour1, const void* contour2,
+ int method, double /*parameter*/ )
+{
+ CvMoments moments;
+ CvHuMoments huMoments;
+ double ma[7], mb[7];
+ int i, sma, smb;
+ double eps = 1.e-5;
+ double mmm;
+ double result = 0;
+
+ CV_FUNCNAME( "cvMatchShapes" );
+
+ __BEGIN__;
+
+ if( !contour1 || !contour2 )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+/* first moments calculation */
+ CV_CALL( cvMoments( contour1, &moments ));
+
+/* Hu moments calculation */
+ CV_CALL( cvGetHuMoments( &moments, &huMoments ));
+
+ ma[0] = huMoments.hu1;
+ ma[1] = huMoments.hu2;
+ ma[2] = huMoments.hu3;
+ ma[3] = huMoments.hu4;
+ ma[4] = huMoments.hu5;
+ ma[5] = huMoments.hu6;
+ ma[6] = huMoments.hu7;
+
+
+/* second moments calculation */
+ CV_CALL( cvMoments( contour2, &moments ));
+
+/* Hu moments calculation */
+ CV_CALL( cvGetHuMoments( &moments, &huMoments ));
+
+ mb[0] = huMoments.hu1;
+ mb[1] = huMoments.hu2;
+ mb[2] = huMoments.hu3;
+ mb[3] = huMoments.hu4;
+ mb[4] = huMoments.hu5;
+ mb[5] = huMoments.hu6;
+ mb[6] = huMoments.hu7;
+
+ switch (method)
+ {
+ case 1:
+ {
+ for( i = 0; i < 7; i++ )
+ {
+ double ama = fabs( ma[i] );
+ double amb = fabs( mb[i] );
+
+ if( ma[i] > 0 )
+ sma = 1;
+ else if( ma[i] < 0 )
+ sma = -1;
+ else
+ sma = 0;
+ if( mb[i] > 0 )
+ smb = 1;
+ else if( mb[i] < 0 )
+ smb = -1;
+ else
+ smb = 0;
+
+ if( ama > eps && amb > eps )
+ {
+ ama = 1. / (sma * log10( ama ));
+ amb = 1. / (smb * log10( amb ));
+ result += fabs( -ama + amb );
+ }
+ }
+ break;
+ }
+
+ case 2:
+ {
+ for( i = 0; i < 7; i++ )
+ {
+ double ama = fabs( ma[i] );
+ double amb = fabs( mb[i] );
+
+ if( ma[i] > 0 )
+ sma = 1;
+ else if( ma[i] < 0 )
+ sma = -1;
+ else
+ sma = 0;
+ if( mb[i] > 0 )
+ smb = 1;
+ else if( mb[i] < 0 )
+ smb = -1;
+ else
+ smb = 0;
+
+ if( ama > eps && amb > eps )
+ {
+ ama = sma * log10( ama );
+ amb = smb * log10( amb );
+ result += fabs( -ama + amb );
+ }
+ }
+ break;
+ }
+
+ case 3:
+ {
+ for( i = 0; i < 7; i++ )
+ {
+ double ama = fabs( ma[i] );
+ double amb = fabs( mb[i] );
+
+ if( ma[i] > 0 )
+ sma = 1;
+ else if( ma[i] < 0 )
+ sma = -1;
+ else
+ sma = 0;
+ if( mb[i] > 0 )
+ smb = 1;
+ else if( mb[i] < 0 )
+ smb = -1;
+ else
+ smb = 0;
+
+ if( ama > eps && amb > eps )
+ {
+ ama = sma * log10( ama );
+ amb = smb * log10( amb );
+ mmm = fabs( (ama - amb) / ama );
+ if( result < mmm )
+ result = mmm;
+ }
+ }
+ break;
+ }
+ default:
+ CV_ERROR_FROM_STATUS( CV_BADCOEF_ERR );
+ }
+
+ __END__;
+
+ return result;
+}
+
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvMatchContourTrees
+// Purpose:
+// Calculates matching of the two contour trees
+// Context:
+// Parameters:
+// tree1 - pointer to the first input contour tree object.
+// tree2 - pointer to the second input contour tree object.
+// method - method for the matching calculation
+// (now CV_CONTOUR_TREES_MATCH_I1 only )
+// threshold - threshold for the contour trees matching
+// result - output calculated measure
+//F*/
+CV_IMPL double
+cvMatchContourTrees( const CvContourTree* tree1, const CvContourTree* tree2,
+ int method, double threshold )
+{
+ _CvTrianAttr **ptr_p1 = 0, **ptr_p2 = 0; /*pointers to the pointer's buffer */
+ _CvTrianAttr **ptr_n1 = 0, **ptr_n2 = 0; /*pointers to the pointer's buffer */
+ _CvTrianAttr **ptr11, **ptr12, **ptr21, **ptr22;
+
+ int lpt1, lpt2, lpt, flag, flag_n, i, j, ibuf, ibuf1;
+ double match_v, d12, area1, area2, r11, r12, r21, r22, w1, w2;
+ double eps = 1.e-5;
+ char s1, s2;
+ _CvTrianAttr tree_1, tree_2; /*current vertex 1 and 2 tree */
+ CvSeqReader reader1, reader2;
+ double result = 0;
+
+ CV_FUNCNAME("cvMatchContourTrees");
+ __BEGIN__;
+
+ if( !tree1 || !tree2 )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( method != CV_CONTOUR_TREES_MATCH_I1 )
+ CV_ERROR( CV_StsBadArg, "Unknown/unsupported comparison method" );
+
+ if( !CV_IS_SEQ_POLYGON_TREE( tree1 ))
+ CV_ERROR( CV_StsBadArg, "The first argument is not a valid contour tree" );
+
+ if( !CV_IS_SEQ_POLYGON_TREE( tree2 ))
+ CV_ERROR( CV_StsBadArg, "The second argument is not a valid contour tree" );
+
+ lpt1 = tree1->total;
+ lpt2 = tree2->total;
+ lpt = lpt1 > lpt2 ? lpt1 : lpt2;
+
+ ptr_p1 = ptr_n1 = ptr_p2 = ptr_n2 = NULL;
+ CV_CALL( ptr_p1 = (_CvTrianAttr **) cvAlloc( lpt * sizeof( _CvTrianAttr * )));
+ CV_CALL( ptr_p2 = (_CvTrianAttr **) cvAlloc( lpt * sizeof( _CvTrianAttr * )));
+
+ CV_CALL( ptr_n1 = (_CvTrianAttr **) cvAlloc( lpt * sizeof( _CvTrianAttr * )));
+ CV_CALL( ptr_n2 = (_CvTrianAttr **) cvAlloc( lpt * sizeof( _CvTrianAttr * )));
+
+ cvStartReadSeq( (CvSeq *) tree1, &reader1, 0 );
+ cvStartReadSeq( (CvSeq *) tree2, &reader2, 0 );
+
+/*read the root of the first and second tree*/
+ CV_READ_SEQ_ELEM( tree_1, reader1 );
+ CV_READ_SEQ_ELEM( tree_2, reader2 );
+
+/*write to buffer pointers to root's childs vertexs*/
+ ptr_p1[0] = tree_1.next_v1;
+ ptr_p1[1] = tree_1.next_v2;
+ ptr_p2[0] = tree_2.next_v1;
+ ptr_p2[1] = tree_2.next_v2;
+ i = 2;
+ match_v = 0.;
+ area1 = tree_1.area;
+ area2 = tree_2.area;
+
+ if( area1 < eps || area2 < eps || lpt < 4 )
+ CV_ERROR( CV_StsBadSize, "" );
+
+ r11 = r12 = r21 = r22 = w1 = w2 = d12 = 0;
+ flag = 0;
+ s1 = s2 = 0;
+ do
+ {
+ if( flag == 0 )
+ {
+ ptr11 = ptr_p1;
+ ptr12 = ptr_n1;
+ ptr21 = ptr_p2;
+ ptr22 = ptr_n2;
+ flag = 1;
+ }
+ else
+ {
+ ptr11 = ptr_n1;
+ ptr12 = ptr_p1;
+ ptr21 = ptr_n2;
+ ptr22 = ptr_p2;
+ flag = 0;
+ }
+ ibuf = 0;
+ for( j = 0; j < i; j++ )
+ {
+ flag_n = 0;
+ if( ptr11[j] != NULL )
+ {
+ r11 = ptr11[j]->r1;
+ r12 = ptr11[j]->r2;
+ flag_n = 1;
+ w1 = ptr11[j]->area / area1;
+ s1 = ptr11[j]->sign;
+ }
+ else
+ {
+ r11 = r21 = 0;
+ }
+ if( ptr21[j] != NULL )
+ {
+ r21 = ptr21[j]->r1;
+ r22 = ptr21[j]->r2;
+ flag_n = 1;
+ w2 = ptr21[j]->area / area2;
+ s2 = ptr21[j]->sign;
+ }
+ else
+ {
+ r21 = r22 = 0;
+ }
+ if( flag_n != 0 )
+/* calculate node distance */
+ {
+ switch (method)
+ {
+ case 1:
+ {
+ double t0, t1;
+ if( s1 != s2 )
+ {
+ t0 = fabs( r11 * w1 + r21 * w2 );
+ t1 = fabs( r12 * w1 + r22 * w2 );
+ }
+ else
+ {
+ t0 = fabs( r11 * w1 - r21 * w2 );
+ t1 = fabs( r12 * w1 - r22 * w2 );
+ }
+ d12 = t0 + t1;
+ break;
+ }
+ }
+ match_v += d12;
+ ibuf1 = ibuf + 1;
+/*write to buffer the pointer to child vertexes*/
+ if( ptr11[j] != NULL )
+ {
+ ptr12[ibuf] = ptr11[j]->next_v1;
+ ptr12[ibuf1] = ptr11[j]->next_v2;
+ }
+ else
+ {
+ ptr12[ibuf] = NULL;
+ ptr12[ibuf1] = NULL;
+ }
+ if( ptr21[j] != NULL )
+ {
+ ptr22[ibuf] = ptr21[j]->next_v1;
+ ptr22[ibuf1] = ptr21[j]->next_v2;
+ }
+ else
+ {
+ ptr22[ibuf] = NULL;
+ ptr22[ibuf1] = NULL;
+ }
+ ibuf += 2;
+ }
+ }
+ i = ibuf;
+ }
+ while( i > 0 && match_v < threshold );
+
+ result = match_v;
+
+ __END__;
+
+ cvFree( &ptr_n2 );
+ cvFree( &ptr_n1 );
+ cvFree( &ptr_p2 );
+ cvFree( &ptr_p1 );
+
+ return result;
+}
+
+
+/* End of file. */
diff --git a/cv/src/cvmoments.cpp b/cv/src/cvmoments.cpp
new file mode 100644
index 0000000..fc66d31
--- /dev/null
+++ b/cv/src/cvmoments.cpp
@@ -0,0 +1,687 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+/* The function calculates center of gravity and central second order moments */
+static void
+icvCompleteMomentState( CvMoments* moments )
+{
+ double cx = 0, cy = 0;
+ double mu20, mu11, mu02;
+
+ assert( moments != 0 );
+ moments->inv_sqrt_m00 = 0;
+
+ if( fabs(moments->m00) > DBL_EPSILON )
+ {
+ double inv_m00 = 1. / moments->m00;
+ cx = moments->m10 * inv_m00;
+ cy = moments->m01 * inv_m00;
+ moments->inv_sqrt_m00 = sqrt( fabs(inv_m00) );
+ }
+
+ /* mu20 = m20 - m10*cx */
+ mu20 = moments->m20 - moments->m10 * cx;
+ /* mu11 = m11 - m10*cy */
+ mu11 = moments->m11 - moments->m10 * cy;
+ /* mu02 = m02 - m01*cy */
+ mu02 = moments->m02 - moments->m01 * cy;
+
+ moments->mu20 = mu20;
+ moments->mu11 = mu11;
+ moments->mu02 = mu02;
+
+ /* mu30 = m30 - cx*(3*mu20 + cx*m10) */
+ moments->mu30 = moments->m30 - cx * (3 * mu20 + cx * moments->m10);
+ mu11 += mu11;
+ /* mu21 = m21 - cx*(2*mu11 + cx*m01) - cy*mu20 */
+ moments->mu21 = moments->m21 - cx * (mu11 + cx * moments->m01) - cy * mu20;
+ /* mu12 = m12 - cy*(2*mu11 + cy*m10) - cx*mu02 */
+ moments->mu12 = moments->m12 - cy * (mu11 + cy * moments->m10) - cx * mu02;
+ /* mu03 = m03 - cy*(3*mu02 + cy*m01) */
+ moments->mu03 = moments->m03 - cy * (3 * mu02 + cy * moments->m01);
+}
+
+
+static void
+icvContourMoments( CvSeq* contour, CvMoments* moments )
+{
+ int is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2;
+
+ if( contour->total )
+ {
+ CvSeqReader reader;
+ double a00, a10, a01, a20, a11, a02, a30, a21, a12, a03;
+ double xi, yi, xi2, yi2, xi_1, yi_1, xi_12, yi_12, dxy, xii_1, yii_1;
+ int lpt = contour->total;
+
+ a00 = a10 = a01 = a20 = a11 = a02 = a30 = a21 = a12 = a03 = 0;
+
+ cvStartReadSeq( contour, &reader, 0 );
+
+ if( !is_float )
+ {
+ xi_1 = ((CvPoint*)(reader.ptr))->x;
+ yi_1 = ((CvPoint*)(reader.ptr))->y;
+ }
+ else
+ {
+ xi_1 = ((CvPoint2D32f*)(reader.ptr))->x;
+ yi_1 = ((CvPoint2D32f*)(reader.ptr))->y;
+ }
+ CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
+
+ xi_12 = xi_1 * xi_1;
+ yi_12 = yi_1 * yi_1;
+
+ while( lpt-- > 0 )
+ {
+ if( !is_float )
+ {
+ xi = ((CvPoint*)(reader.ptr))->x;
+ yi = ((CvPoint*)(reader.ptr))->y;
+ }
+ else
+ {
+ xi = ((CvPoint2D32f*)(reader.ptr))->x;
+ yi = ((CvPoint2D32f*)(reader.ptr))->y;
+ }
+ CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
+
+ xi2 = xi * xi;
+ yi2 = yi * yi;
+ dxy = xi_1 * yi - xi * yi_1;
+ xii_1 = xi_1 + xi;
+ yii_1 = yi_1 + yi;
+
+ a00 += dxy;
+ a10 += dxy * xii_1;
+ a01 += dxy * yii_1;
+ a20 += dxy * (xi_1 * xii_1 + xi2);
+ a11 += dxy * (xi_1 * (yii_1 + yi_1) + xi * (yii_1 + yi));
+ a02 += dxy * (yi_1 * yii_1 + yi2);
+ a30 += dxy * xii_1 * (xi_12 + xi2);
+ a03 += dxy * yii_1 * (yi_12 + yi2);
+ a21 +=
+ dxy * (xi_12 * (3 * yi_1 + yi) + 2 * xi * xi_1 * yii_1 +
+ xi2 * (yi_1 + 3 * yi));
+ a12 +=
+ dxy * (yi_12 * (3 * xi_1 + xi) + 2 * yi * yi_1 * xii_1 +
+ yi2 * (xi_1 + 3 * xi));
+
+ xi_1 = xi;
+ yi_1 = yi;
+ xi_12 = xi2;
+ yi_12 = yi2;
+ }
+
+ double db1_2, db1_6, db1_12, db1_24, db1_20, db1_60;
+
+ if( fabs(a00) > FLT_EPSILON )
+ {
+ if( a00 > 0 )
+ {
+ db1_2 = 0.5;
+ db1_6 = 0.16666666666666666666666666666667;
+ db1_12 = 0.083333333333333333333333333333333;
+ db1_24 = 0.041666666666666666666666666666667;
+ db1_20 = 0.05;
+ db1_60 = 0.016666666666666666666666666666667;
+ }
+ else
+ {
+ db1_2 = -0.5;
+ db1_6 = -0.16666666666666666666666666666667;
+ db1_12 = -0.083333333333333333333333333333333;
+ db1_24 = -0.041666666666666666666666666666667;
+ db1_20 = -0.05;
+ db1_60 = -0.016666666666666666666666666666667;
+ }
+
+ /* spatial moments */
+ moments->m00 = a00 * db1_2;
+ moments->m10 = a10 * db1_6;
+ moments->m01 = a01 * db1_6;
+ moments->m20 = a20 * db1_12;
+ moments->m11 = a11 * db1_24;
+ moments->m02 = a02 * db1_12;
+ moments->m30 = a30 * db1_20;
+ moments->m21 = a21 * db1_60;
+ moments->m12 = a12 * db1_60;
+ moments->m03 = a03 * db1_20;
+
+ icvCompleteMomentState( moments );
+ }
+ }
+}
+
+
+/* summarizes moment values for all tiles */
+static void
+icvAccumulateMoments( double *tiles, CvSize size, CvSize tile_size, CvMoments * moments )
+{
+ int x, y;
+
+ for( y = 0; y < size.height; y += tile_size.height )
+ {
+ for( x = 0; x < size.width; x += tile_size.width, tiles += 10 )
+ {
+ double dx = x, dy = y;
+ double dxm = dx * tiles[0], dym = dy * tiles[0];
+
+ /* + m00 ( = m00' ) */
+ moments->m00 += tiles[0];
+
+ /* + m10 ( = m10' + dx*m00' ) */
+ moments->m10 += tiles[1] + dxm;
+
+ /* + m01 ( = m01' + dy*m00' ) */
+ moments->m01 += tiles[2] + dym;
+
+ /* + m20 ( = m20' + 2*dx*m10' + dx*dx*m00' ) */
+ moments->m20 += tiles[3] + dx * (tiles[1] * 2 + dxm);
+
+ /* + m11 ( = m11' + dx*m01' + dy*m10' + dx*dy*m00' ) */
+ moments->m11 += tiles[4] + dx * (tiles[2] + dym) + dy * tiles[1];
+
+ /* + m02 ( = m02' + 2*dy*m01' + dy*dy*m00' ) */
+ moments->m02 += tiles[5] + dy * (tiles[2] * 2 + dym);
+
+ /* + m30 ( = m30' + 3*dx*m20' + 3*dx*dx*m10' + dx*dx*dx*m00' ) */
+ moments->m30 += tiles[6] + dx * (3. * tiles[3] + dx * (3. * tiles[1] + dxm));
+
+ /* + m21 (= m21' + dx*(2*m11' + 2*dy*m10' + dx*m01' + dx*dy*m00') + dy*m20') */
+ moments->m21 += tiles[7] + dx * (2 * (tiles[4] + dy * tiles[1]) +
+ dx * (tiles[2] + dym)) + dy * tiles[3];
+
+ /* + m12 (= m12' + dy*(2*m11' + 2*dx*m01' + dy*m10' + dx*dy*m00') + dx*m02') */
+ moments->m12 += tiles[8] + dy * (2 * (tiles[4] + dx * tiles[2]) +
+ dy * (tiles[1] + dxm)) + dx * tiles[5];
+
+ /* + m03 ( = m03' + 3*dy*m02' + 3*dy*dy*m01' + dy*dy*dy*m00' ) */
+ moments->m03 += tiles[9] + dy * (3. * tiles[5] + dy * (3. * tiles[2] + dym));
+ }
+ }
+
+ icvCompleteMomentState( moments );
+}
+
+
+/****************************************************************************************\
+* Spatial Moments *
+\****************************************************************************************/
+
+#define ICV_DEF_CALC_MOMENTS_IN_TILE( __op__, name, flavor, srctype, temptype, momtype ) \
+static CvStatus CV_STDCALL icv##name##_##flavor##_CnCR \
+( const srctype* img, int step, CvSize size, int cn, int coi, double *moments ) \
+{ \
+ int x, y, sx_init = (size.width & -4) * (size.width & -4), sy = 0; \
+ momtype mom[10]; \
+ \
+ assert( img && size.width && (size.width | size.height) >= 0 ); \
+ memset( mom, 0, 10 * sizeof( mom[0] )); \
+ \
+ if( coi ) \
+ img += coi - 1; \
+ step /= sizeof(img[0]); \
+ \
+ for( y = 0; y < size.height; sy += 2 * y + 1, y++, img += step ) \
+ { \
+ temptype x0 = 0; \
+ temptype x1 = 0; \
+ temptype x2 = 0; \
+ momtype x3 = 0; \
+ int sx = sx_init; \
+ const srctype* ptr = img; \
+ \
+ for( x = 0; x < size.width - 3; x += 4, ptr += cn*4 ) \
+ { \
+ temptype p0 = __op__(ptr[0]), p1 = __op__(ptr[cn]), \
+ p2 = __op__(ptr[2*cn]), p3 = __op__(ptr[3*cn]); \
+ temptype t = p1; \
+ temptype a, b, c; \
+ \
+ p0 += p1 + p2 + p3; /* p0 + p1 + p2 + p3 */ \
+ p1 += 2 * p2 + 3 * p3; /* p1 + p2*2 + p3*3 */ \
+ p2 = p1 + 2 * p2 + 6 * p3; /* p1 + p2*4 + p3*9 */ \
+ p3 = 2 * p2 - t + 9 * p3; /* p1 + p2*8 + p3*27 */ \
+ \
+ a = x * p0 + p1; /* x*p0 + (x+1)*p1 + (x+2)*p2 + (x+3)*p3 */ \
+ b = x * p1 + p2; /* (x+1)*p1 + 2*(x+2)*p2 + 3*(x+3)*p3 */ \
+ c = x * p2 + p3; /* (x+1)*p1 + 4*(x+2)*p2 + 9*(x+3)*p3 */ \
+ \
+ x0 += p0; \
+ x1 += a; \
+ a = a * x + b; /*(x^2)*p0+((x+1)^2)*p1+((x+2)^2)*p2+((x+3)^2)*p3 */ \
+ x2 += a; \
+ x3 += ((momtype)(a + b)) * x + c; /*x3 += (x^3)*p0+((x+1)^3)*p1 + */ \
+ /* ((x+2)^3)*p2+((x+3)^3)*p3 */ \
+ } \
+ \
+ /* process the rest */ \
+ for( ; x < size.width; sx += 2 * x + 1, x++, ptr += cn ) \
+ { \
+ temptype p = __op__(ptr[0]); \
+ temptype xp = x * p; \
+ \
+ x0 += p; \
+ x1 += xp; \
+ x2 += sx * p; \
+ x3 += ((momtype)sx) * xp; \
+ } \
+ \
+ { \
+ temptype py = y * x0; \
+ \
+ mom[9] += ((momtype)py) * sy; /* m03 */ \
+ mom[8] += ((momtype)x1) * sy; /* m12 */ \
+ mom[7] += ((momtype)x2) * y; /* m21 */ \
+ mom[6] += x3; /* m30 */ \
+ mom[5] += x0 * sy; /* m02 */ \
+ mom[4] += x1 * y; /* m11 */ \
+ mom[3] += x2; /* m20 */ \
+ mom[2] += py; /* m01 */ \
+ mom[1] += x1; /* m10 */ \
+ mom[0] += x0; /* m00 */ \
+ } \
+ } \
+ \
+ for( x = 0; x < 10; x++ ) \
+ moments[x] = (double)mom[x]; \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_CALC_MOMENTS_IN_TILE( CV_NOP, MomentsInTile, 8u, uchar, int, int )
+ICV_DEF_CALC_MOMENTS_IN_TILE( CV_NOP, MomentsInTile, 16u, ushort, int, int64 )
+ICV_DEF_CALC_MOMENTS_IN_TILE( CV_NOP, MomentsInTile, 16s, short, int, int64 )
+ICV_DEF_CALC_MOMENTS_IN_TILE( CV_NOP, MomentsInTile, 32f, float, double, double )
+ICV_DEF_CALC_MOMENTS_IN_TILE( CV_NOP, MomentsInTile, 64f, double, double, double )
+
+ICV_DEF_CALC_MOMENTS_IN_TILE( CV_NONZERO, MomentsInTileBin, 8u, uchar, int, int )
+ICV_DEF_CALC_MOMENTS_IN_TILE( CV_NONZERO, MomentsInTileBin, 16s, ushort, int, int )
+ICV_DEF_CALC_MOMENTS_IN_TILE( CV_NONZERO_FLT, MomentsInTileBin, 32f, int, int, int )
+ICV_DEF_CALC_MOMENTS_IN_TILE( CV_NONZERO_FLT, MomentsInTileBin, 64f, int64, double, double )
+
+#define icvMomentsInTile_8s_CnCR 0
+#define icvMomentsInTile_32s_CnCR 0
+#define icvMomentsInTileBin_8s_CnCR icvMomentsInTileBin_8u_CnCR
+#define icvMomentsInTileBin_16u_CnCR icvMomentsInTileBin_16s_CnCR
+#define icvMomentsInTileBin_32s_CnCR 0
+
+CV_DEF_INIT_FUNC_TAB_2D( MomentsInTile, CnCR )
+CV_DEF_INIT_FUNC_TAB_2D( MomentsInTileBin, CnCR )
+
+////////////////////////////////// IPP moment functions //////////////////////////////////
+
+icvMoments_8u_C1R_t icvMoments_8u_C1R_p = 0;
+icvMoments_32f_C1R_t icvMoments_32f_C1R_p = 0;
+icvMomentInitAlloc_64f_t icvMomentInitAlloc_64f_p = 0;
+icvMomentFree_64f_t icvMomentFree_64f_p = 0;
+icvGetSpatialMoment_64f_t icvGetSpatialMoment_64f_p = 0;
+
+typedef CvStatus (CV_STDCALL * CvMomentIPPFunc)
+ ( const void* img, int step, CvSize size, void* momentstate );
+
+CV_IMPL void
+cvMoments( const void* array, CvMoments* moments, int binary )
+{
+ static CvFuncTable mom_tab;
+ static CvFuncTable mombin_tab;
+ static int inittab = 0;
+ double* tiles = 0;
+ void* ippmomentstate = 0;
+
+ CV_FUNCNAME("cvMoments");
+
+ __BEGIN__;
+
+ int type = 0, depth, cn, pix_size;
+ int coi = 0;
+ int x, y, k, tile_num = 1;
+ CvSize size, tile_size = { 32, 32 };
+ CvMat stub, *mat = (CvMat*)array;
+ CvFunc2DnC_1A1P func = 0;
+ CvMomentIPPFunc ipp_func = 0;
+ CvContour contour_header;
+ CvSeq* contour = 0;
+ CvSeqBlock block;
+
+ if( CV_IS_SEQ( array ))
+ {
+ contour = (CvSeq*)array;
+ if( !CV_IS_SEQ_POLYGON( contour ))
+ CV_ERROR( CV_StsBadArg, "The passed sequence is not a valid contour" );
+ }
+
+ if( !inittab )
+ {
+ icvInitMomentsInTileCnCRTable( &mom_tab );
+ icvInitMomentsInTileBinCnCRTable( &mombin_tab );
+ inittab = 1;
+ }
+
+ if( !moments )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ memset( moments, 0, sizeof(*moments));
+
+ if( !contour )
+ {
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+ type = CV_MAT_TYPE( mat->type );
+
+ if( type == CV_32SC2 || type == CV_32FC2 )
+ {
+ CV_CALL( contour = cvPointSeqFromMat(
+ CV_SEQ_KIND_CURVE | CV_SEQ_FLAG_CLOSED,
+ mat, &contour_header, &block ));
+ }
+ }
+
+ if( contour )
+ {
+ icvContourMoments( contour, moments );
+ EXIT;
+ }
+
+ type = CV_MAT_TYPE( mat->type );
+ depth = CV_MAT_DEPTH( type );
+ cn = CV_MAT_CN( type );
+ pix_size = CV_ELEM_SIZE(type);
+ size = cvGetMatSize( mat );
+
+ if( cn > 1 && coi == 0 )
+ CV_ERROR( CV_StsBadArg, "Invalid image type" );
+
+ if( size.width <= 0 || size.height <= 0 )
+ {
+ EXIT;
+ }
+
+ if( type == CV_8UC1 )
+ ipp_func = (CvMomentIPPFunc)icvMoments_8u_C1R_p;
+ else if( type == CV_32FC1 )
+ ipp_func = (CvMomentIPPFunc)icvMoments_32f_C1R_p;
+
+ if( ipp_func && !binary )
+ {
+ int matstep = mat->step ? mat->step : CV_STUB_STEP;
+ IPPI_CALL( icvMomentInitAlloc_64f_p( &ippmomentstate, cvAlgHintAccurate ));
+ IPPI_CALL( ipp_func( mat->data.ptr, matstep, size, ippmomentstate ));
+ icvGetSpatialMoment_64f_p( ippmomentstate, 0, 0, 0, cvPoint(0,0), &moments->m00 );
+ icvGetSpatialMoment_64f_p( ippmomentstate, 1, 0, 0, cvPoint(0,0), &moments->m10 );
+ icvGetSpatialMoment_64f_p( ippmomentstate, 0, 1, 0, cvPoint(0,0), &moments->m01 );
+ icvGetSpatialMoment_64f_p( ippmomentstate, 2, 0, 0, cvPoint(0,0), &moments->m20 );
+ icvGetSpatialMoment_64f_p( ippmomentstate, 1, 1, 0, cvPoint(0,0), &moments->m11 );
+ icvGetSpatialMoment_64f_p( ippmomentstate, 0, 2, 0, cvPoint(0,0), &moments->m02 );
+ icvGetSpatialMoment_64f_p( ippmomentstate, 3, 0, 0, cvPoint(0,0), &moments->m30 );
+ icvGetSpatialMoment_64f_p( ippmomentstate, 2, 1, 0, cvPoint(0,0), &moments->m21 );
+ icvGetSpatialMoment_64f_p( ippmomentstate, 1, 2, 0, cvPoint(0,0), &moments->m12 );
+ icvGetSpatialMoment_64f_p( ippmomentstate, 0, 3, 0, cvPoint(0,0), &moments->m03 );
+ icvCompleteMomentState( moments );
+ EXIT;
+ }
+
+ func = (CvFunc2DnC_1A1P)(!binary ? mom_tab.fn_2d[depth] : mombin_tab.fn_2d[depth]);
+
+ if( !func )
+ CV_ERROR( CV_StsBadArg, cvUnsupportedFormat );
+
+ if( depth >= CV_32S && !binary )
+ tile_size = size;
+ else
+ tile_num = ((size.width + tile_size.width - 1)/tile_size.width)*
+ ((size.height + tile_size.height - 1)/tile_size.height);
+
+ CV_CALL( tiles = (double*)cvAlloc( tile_num*10*sizeof(double)));
+
+ for( y = 0, k = 0; y < size.height; y += tile_size.height )
+ {
+ CvSize cur_tile_size = tile_size;
+ if( y + cur_tile_size.height > size.height )
+ cur_tile_size.height = size.height - y;
+
+ for( x = 0; x < size.width; x += tile_size.width, k++ )
+ {
+ if( x + cur_tile_size.width > size.width )
+ cur_tile_size.width = size.width - x;
+
+ assert( k < tile_num );
+
+ IPPI_CALL( func( mat->data.ptr + y*mat->step + x*pix_size,
+ mat->step, cur_tile_size, cn, coi, tiles + k*10 ));
+ }
+ }
+
+ icvAccumulateMoments( tiles, size, tile_size, moments );
+
+ __END__;
+
+ if( ippmomentstate )
+ icvMomentFree_64f_p( ippmomentstate );
+
+ cvFree( &tiles );
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvGetHuMoments
+// Purpose: Returns Hu moments
+// Context:
+// Parameters:
+// mState - moment structure filled by one of the icvMoments[Binary]*** function
+// HuState - pointer to output structure containing seven Hu moments
+// Returns:
+// CV_NO_ERR if success or error code
+// Notes:
+//F*/
+CV_IMPL void
+cvGetHuMoments( CvMoments * mState, CvHuMoments * HuState )
+{
+ CV_FUNCNAME( "cvGetHuMoments" );
+
+ __BEGIN__;
+
+ if( !mState || !HuState )
+ CV_ERROR_FROM_STATUS( CV_NULLPTR_ERR );
+
+ {
+ double m00s = mState->inv_sqrt_m00, m00 = m00s * m00s, s2 = m00 * m00, s3 = s2 * m00s;
+
+ double nu20 = mState->mu20 * s2,
+ nu11 = mState->mu11 * s2,
+ nu02 = mState->mu02 * s2,
+ nu30 = mState->mu30 * s3,
+ nu21 = mState->mu21 * s3, nu12 = mState->mu12 * s3, nu03 = mState->mu03 * s3;
+
+ double t0 = nu30 + nu12;
+ double t1 = nu21 + nu03;
+
+ double q0 = t0 * t0, q1 = t1 * t1;
+
+ double n4 = 4 * nu11;
+ double s = nu20 + nu02;
+ double d = nu20 - nu02;
+
+ HuState->hu1 = s;
+ HuState->hu2 = d * d + n4 * nu11;
+ HuState->hu4 = q0 + q1;
+ HuState->hu6 = d * (q0 - q1) + n4 * t0 * t1;
+
+ t0 *= q0 - 3 * q1;
+ t1 *= 3 * q0 - q1;
+
+ q0 = nu30 - 3 * nu12;
+ q1 = 3 * nu21 - nu03;
+
+ HuState->hu3 = q0 * q0 + q1 * q1;
+ HuState->hu5 = q0 * t0 + q1 * t1;
+ HuState->hu7 = q1 * t0 - q0 * t1;
+ }
+
+ __END__;
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvGetSpatialMoment
+// Purpose: Returns spatial moment(x_order, y_order) which is determined as:
+// m(x_o,y_o) = sum (x ^ x_o)*(y ^ y_o)*I(x,y)
+// 0 <= x_o, y_o; x_o + y_o <= 3
+// Context:
+// Parameters:
+// mom - moment structure filled by one of the icvMoments[Binary]*** function
+// x_order - x order of the moment
+// y_order - y order of the moment
+// Returns:
+// moment value or large negative number (-DBL_MAX) if error
+// Notes:
+//F*/
+CV_IMPL double
+cvGetSpatialMoment( CvMoments * moments, int x_order, int y_order )
+{
+ int order = x_order + y_order;
+ double moment = -DBL_MAX;
+
+ CV_FUNCNAME( "cvGetSpatialMoment" );
+
+ __BEGIN__;
+
+ if( !moments )
+ CV_ERROR_FROM_STATUS( CV_NULLPTR_ERR );
+ if( (x_order | y_order) < 0 || order > 3 )
+ CV_ERROR_FROM_STATUS( CV_BADRANGE_ERR );
+
+ moment = (&(moments->m00))[order + (order >> 1) + (order > 2) * 2 + y_order];
+
+ __END__;
+
+ return moment;
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvGetCentralMoment
+// Purpose: Returns central moment(x_order, y_order) which is determined as:
+// mu(x_o,y_o) = sum ((x - xc)^ x_o)*((y - yc) ^ y_o)*I(x,y)
+// 0 <= x_o, y_o; x_o + y_o <= 3,
+// (xc, yc) = (m10/m00,m01/m00) - center of gravity
+// Context:
+// Parameters:
+// mom - moment structure filled by one of the icvMoments[Binary]*** function
+// x_order - x order of the moment
+// y_order - y order of the moment
+// Returns:
+// moment value or large negative number (-DBL_MAX) if error
+// Notes:
+//F*/
+CV_IMPL double
+cvGetCentralMoment( CvMoments * moments, int x_order, int y_order )
+{
+ int order = x_order + y_order;
+ double mu = 0;
+
+ CV_FUNCNAME( "cvGetCentralMoment" );
+
+ __BEGIN__;
+
+ if( !moments )
+ CV_ERROR_FROM_STATUS( CV_NULLPTR_ERR );
+ if( (x_order | y_order) < 0 || order > 3 )
+ CV_ERROR_FROM_STATUS( CV_BADRANGE_ERR );
+
+ if( order >= 2 )
+ {
+ mu = (&(moments->m00))[4 + order * 3 + y_order];
+ }
+ else if( order == 0 )
+ mu = moments->m00;
+
+ __END__;
+
+ return mu;
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvGetNormalizedCentralMoment
+// Purpose: Returns normalized central moment(x_order,y_order) which is determined as:
+// nu(x_o,y_o) = mu(x_o, y_o)/(m00 ^ (((x_o + y_o)/2) + 1))
+// 0 <= x_o, y_o; x_o + y_o <= 3,
+// (xc, yc) = (m10/m00,m01/m00) - center of gravity
+// Context:
+// Parameters:
+// mom - moment structure filled by one of the icvMoments[Binary]*** function
+// x_order - x order of the moment
+// y_order - y order of the moment
+// Returns:
+// moment value or large negative number (-DBL_MAX) if error
+// Notes:
+//F*/
+CV_IMPL double
+cvGetNormalizedCentralMoment( CvMoments * moments, int x_order, int y_order )
+{
+ int order = x_order + y_order;
+ double mu = 0;
+ double m00s, m00;
+
+ CV_FUNCNAME( "cvGetCentralNormalizedMoment" );
+
+ __BEGIN__;
+
+ mu = cvGetCentralMoment( moments, x_order, y_order );
+ CV_CHECK();
+
+ m00s = moments->inv_sqrt_m00;
+ m00 = m00s * m00s;
+
+ while( --order >= 0 )
+ m00 *= m00s;
+ mu *= m00;
+
+ __END__;
+
+ return mu;
+}
+
+
+/* End of file. */
diff --git a/cv/src/cvmorph.cpp b/cv/src/cvmorph.cpp
new file mode 100644
index 0000000..9a2899e
--- /dev/null
+++ b/cv/src/cvmorph.cpp
@@ -0,0 +1,1173 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+#include <limits.h>
+#include <stdio.h>
+
+#define IPCV_MORPHOLOGY_PTRS( morphtype, flavor ) \
+ icv##morphtype##Rect_##flavor##_C1R_t \
+ icv##morphtype##Rect_##flavor##_C1R_p = 0; \
+ icv##morphtype##Rect_GetBufSize_##flavor##_C1R_t \
+ icv##morphtype##Rect_GetBufSize_##flavor##_C1R_p = 0; \
+ icv##morphtype##Rect_##flavor##_C3R_t \
+ icv##morphtype##Rect_##flavor##_C3R_p = 0; \
+ icv##morphtype##Rect_GetBufSize_##flavor##_C3R_t \
+ icv##morphtype##Rect_GetBufSize_##flavor##_C3R_p = 0; \
+ icv##morphtype##Rect_##flavor##_C4R_t \
+ icv##morphtype##Rect_##flavor##_C4R_p = 0; \
+ icv##morphtype##Rect_GetBufSize_##flavor##_C4R_t \
+ icv##morphtype##Rect_GetBufSize_##flavor##_C4R_p = 0; \
+ \
+ icv##morphtype##_##flavor##_C1R_t \
+ icv##morphtype##_##flavor##_C1R_p = 0; \
+ icv##morphtype##_##flavor##_C3R_t \
+ icv##morphtype##_##flavor##_C3R_p = 0; \
+ icv##morphtype##_##flavor##_C4R_t \
+ icv##morphtype##_##flavor##_C4R_p = 0;
+
+#define IPCV_MORPHOLOGY_INITALLOC_PTRS( flavor ) \
+ icvMorphInitAlloc_##flavor##_C1R_t \
+ icvMorphInitAlloc_##flavor##_C1R_p = 0; \
+ icvMorphInitAlloc_##flavor##_C3R_t \
+ icvMorphInitAlloc_##flavor##_C3R_p = 0; \
+ icvMorphInitAlloc_##flavor##_C4R_t \
+ icvMorphInitAlloc_##flavor##_C4R_p = 0;
+
+IPCV_MORPHOLOGY_PTRS( Erode, 8u )
+IPCV_MORPHOLOGY_PTRS( Erode, 16u )
+IPCV_MORPHOLOGY_PTRS( Erode, 32f )
+IPCV_MORPHOLOGY_PTRS( Dilate, 8u )
+IPCV_MORPHOLOGY_PTRS( Dilate, 16u )
+IPCV_MORPHOLOGY_PTRS( Dilate, 32f )
+IPCV_MORPHOLOGY_INITALLOC_PTRS( 8u )
+IPCV_MORPHOLOGY_INITALLOC_PTRS( 16u )
+IPCV_MORPHOLOGY_INITALLOC_PTRS( 32f )
+
+icvMorphFree_t icvMorphFree_p = 0;
+
+/****************************************************************************************\
+ Basic Morphological Operations: Erosion & Dilation
+\****************************************************************************************/
+
+static void icvErodeRectRow_8u( const uchar* src, uchar* dst, void* params );
+static void icvErodeRectRow_16u( const ushort* src, ushort* dst, void* params );
+static void icvErodeRectRow_32f( const int* src, int* dst, void* params );
+static void icvDilateRectRow_8u( const uchar* src, uchar* dst, void* params );
+static void icvDilateRectRow_16u( const ushort* src, ushort* dst, void* params );
+static void icvDilateRectRow_32f( const int* src, int* dst, void* params );
+
+static void icvErodeRectCol_8u( const uchar** src, uchar* dst, int dst_step,
+ int count, void* params );
+static void icvErodeRectCol_16u( const ushort** src, ushort* dst, int dst_step,
+ int count, void* params );
+static void icvErodeRectCol_32f( const int** src, int* dst, int dst_step,
+ int count, void* params );
+static void icvDilateRectCol_8u( const uchar** src, uchar* dst, int dst_step,
+ int count, void* params );
+static void icvDilateRectCol_16u( const ushort** src, ushort* dst, int dst_step,
+ int count, void* params );
+static void icvDilateRectCol_32f( const int** src, int* dst, int dst_step,
+ int count, void* params );
+
+static void icvErodeAny_8u( const uchar** src, uchar* dst, int dst_step,
+ int count, void* params );
+static void icvErodeAny_16u( const ushort** src, ushort* dst, int dst_step,
+ int count, void* params );
+static void icvErodeAny_32f( const int** src, int* dst, int dst_step,
+ int count, void* params );
+static void icvDilateAny_8u( const uchar** src, uchar* dst, int dst_step,
+ int count, void* params );
+static void icvDilateAny_16u( const ushort** src, ushort* dst, int dst_step,
+ int count, void* params );
+static void icvDilateAny_32f( const int** src, int* dst, int dst_step,
+ int count, void* params );
+
+CvMorphology::CvMorphology()
+{
+ element = 0;
+ el_sparse = 0;
+}
+
+CvMorphology::CvMorphology( int _operation, int _max_width, int _src_dst_type,
+ int _element_shape, CvMat* _element,
+ CvSize _ksize, CvPoint _anchor,
+ int _border_mode, CvScalar _border_value )
+{
+ element = 0;
+ el_sparse = 0;
+ init( _operation, _max_width, _src_dst_type,
+ _element_shape, _element, _ksize, _anchor,
+ _border_mode, _border_value );
+}
+
+
+void CvMorphology::clear()
+{
+ cvReleaseMat( &element );
+ cvFree( &el_sparse );
+ CvBaseImageFilter::clear();
+}
+
+
+CvMorphology::~CvMorphology()
+{
+ clear();
+}
+
+
+void CvMorphology::init( int _operation, int _max_width, int _src_dst_type,
+ int _element_shape, CvMat* _element,
+ CvSize _ksize, CvPoint _anchor,
+ int _border_mode, CvScalar _border_value )
+{
+ CV_FUNCNAME( "CvMorphology::init" );
+
+ __BEGIN__;
+
+ int depth = CV_MAT_DEPTH(_src_dst_type);
+ int el_type = 0, nz = -1;
+
+ if( _operation != ERODE && _operation != DILATE )
+ CV_ERROR( CV_StsBadArg, "Unknown/unsupported morphological operation" );
+
+ if( _element_shape == CUSTOM )
+ {
+ if( !CV_IS_MAT(_element) )
+ CV_ERROR( CV_StsBadArg,
+ "structuring element should be valid matrix if CUSTOM element shape is specified" );
+
+ el_type = CV_MAT_TYPE(_element->type);
+ if( el_type != CV_8UC1 && el_type != CV_32SC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "the structuring element must have 8uC1 or 32sC1 type" );
+
+ _ksize = cvGetMatSize(_element);
+ CV_CALL( nz = cvCountNonZero(_element));
+ if( nz == _ksize.width*_ksize.height )
+ _element_shape = RECT;
+ }
+
+ operation = _operation;
+ el_shape = _element_shape;
+
+ CV_CALL( CvBaseImageFilter::init( _max_width, _src_dst_type, _src_dst_type,
+ _element_shape == RECT, _ksize, _anchor, _border_mode, _border_value ));
+
+ if( el_shape == RECT )
+ {
+ if( operation == ERODE )
+ {
+ if( depth == CV_8U )
+ x_func = (CvRowFilterFunc)icvErodeRectRow_8u,
+ y_func = (CvColumnFilterFunc)icvErodeRectCol_8u;
+ else if( depth == CV_16U )
+ x_func = (CvRowFilterFunc)icvErodeRectRow_16u,
+ y_func = (CvColumnFilterFunc)icvErodeRectCol_16u;
+ else if( depth == CV_32F )
+ x_func = (CvRowFilterFunc)icvErodeRectRow_32f,
+ y_func = (CvColumnFilterFunc)icvErodeRectCol_32f;
+ }
+ else
+ {
+ assert( operation == DILATE );
+ if( depth == CV_8U )
+ x_func = (CvRowFilterFunc)icvDilateRectRow_8u,
+ y_func = (CvColumnFilterFunc)icvDilateRectCol_8u;
+ else if( depth == CV_16U )
+ x_func = (CvRowFilterFunc)icvDilateRectRow_16u,
+ y_func = (CvColumnFilterFunc)icvDilateRectCol_16u;
+ else if( depth == CV_32F )
+ x_func = (CvRowFilterFunc)icvDilateRectRow_32f,
+ y_func = (CvColumnFilterFunc)icvDilateRectCol_32f;
+ }
+ }
+ else
+ {
+ int i, j, k = 0;
+ int cn = CV_MAT_CN(src_type);
+ CvPoint* nz_loc;
+
+ if( !(element && el_sparse &&
+ _ksize.width == element->cols && _ksize.height == element->rows) )
+ {
+ cvReleaseMat( &element );
+ cvFree( &el_sparse );
+ CV_CALL( element = cvCreateMat( _ksize.height, _ksize.width, CV_8UC1 ));
+ CV_CALL( el_sparse = (uchar*)cvAlloc(
+ ksize.width*ksize.height*(2*sizeof(int) + sizeof(uchar*))));
+ }
+
+ if( el_shape == CUSTOM )
+ {
+ CV_CALL( cvConvert( _element, element ));
+ }
+ else
+ {
+ CV_CALL( init_binary_element( element, el_shape, anchor ));
+ }
+
+ if( operation == ERODE )
+ {
+ if( depth == CV_8U )
+ y_func = (CvColumnFilterFunc)icvErodeAny_8u;
+ else if( depth == CV_16U )
+ y_func = (CvColumnFilterFunc)icvErodeAny_16u;
+ else if( depth == CV_32F )
+ y_func = (CvColumnFilterFunc)icvErodeAny_32f;
+ }
+ else
+ {
+ assert( operation == DILATE );
+ if( depth == CV_8U )
+ y_func = (CvColumnFilterFunc)icvDilateAny_8u;
+ else if( depth == CV_16U )
+ y_func = (CvColumnFilterFunc)icvDilateAny_16u;
+ else if( depth == CV_32F )
+ y_func = (CvColumnFilterFunc)icvDilateAny_32f;
+ }
+
+ nz_loc = (CvPoint*)el_sparse;
+
+ for( i = 0; i < ksize.height; i++ )
+ for( j = 0; j < ksize.width; j++ )
+ {
+ if( element->data.ptr[i*element->step+j] )
+ nz_loc[k++] = cvPoint(j*cn,i);
+ }
+ if( k == 0 )
+ nz_loc[k++] = cvPoint(anchor.x*cn,anchor.y);
+ el_sparse_count = k;
+ }
+
+ if( depth == CV_32F && border_mode == IPL_BORDER_CONSTANT )
+ {
+ int i, cn = CV_MAT_CN(src_type);
+ int* bt = (int*)border_tab;
+ for( i = 0; i < cn; i++ )
+ bt[i] = CV_TOGGLE_FLT(bt[i]);
+ }
+
+ __END__;
+}
+
+
+void CvMorphology::init( int _max_width, int _src_type, int _dst_type,
+ bool _is_separable, CvSize _ksize,
+ CvPoint _anchor, int _border_mode,
+ CvScalar _border_value )
+{
+ CvBaseImageFilter::init( _max_width, _src_type, _dst_type, _is_separable,
+ _ksize, _anchor, _border_mode, _border_value );
+}
+
+
+void CvMorphology::start_process( CvSlice x_range, int width )
+{
+ CvBaseImageFilter::start_process( x_range, width );
+ if( el_shape == RECT )
+ {
+ // cut the cyclic buffer off by 1 line if need, to make
+ // the vertical part of separable morphological filter
+ // always process 2 rows at once (except, may be,
+ // for the last one in a stripe).
+ int t = buf_max_count - max_ky*2;
+ if( t > 1 && t % 2 != 0 )
+ {
+ buf_max_count--;
+ buf_end -= buf_step;
+ }
+ }
+}
+
+
+int CvMorphology::fill_cyclic_buffer( const uchar* src, int src_step,
+ int y0, int y1, int y2 )
+{
+ int i, y = y0, bsz1 = border_tab_sz1, bsz = border_tab_sz;
+ int pix_size = CV_ELEM_SIZE(src_type);
+ int width_n = (prev_x_range.end_index - prev_x_range.start_index)*pix_size;
+
+ if( CV_MAT_DEPTH(src_type) != CV_32F )
+ return CvBaseImageFilter::fill_cyclic_buffer( src, src_step, y0, y1, y2 );
+
+ // fill the cyclic buffer
+ for( ; buf_count < buf_max_count && y < y2; buf_count++, y++, src += src_step )
+ {
+ uchar* trow = is_separable ? buf_end : buf_tail;
+
+ for( i = 0; i < width_n; i += sizeof(int) )
+ {
+ int t = *(int*)(src + i);
+ *(int*)(trow + i + bsz1) = CV_TOGGLE_FLT(t);
+ }
+
+ if( border_mode != IPL_BORDER_CONSTANT )
+ {
+ for( i = 0; i < bsz1; i++ )
+ {
+ int j = border_tab[i];
+ trow[i] = trow[j];
+ }
+ for( ; i < bsz; i++ )
+ {
+ int j = border_tab[i];
+ trow[i + width_n] = trow[j];
+ }
+ }
+ else
+ {
+ const uchar *bt = (uchar*)border_tab;
+ for( i = 0; i < bsz1; i++ )
+ trow[i] = bt[i];
+
+ for( ; i < bsz; i++ )
+ trow[i + width_n] = bt[i];
+ }
+
+ if( is_separable )
+ x_func( trow, buf_tail, this );
+
+ buf_tail += buf_step;
+ if( buf_tail >= buf_end )
+ buf_tail = buf_start;
+ }
+
+ return y - y0;
+}
+
+
+void CvMorphology::init_binary_element( CvMat* element, int element_shape, CvPoint anchor )
+{
+ CV_FUNCNAME( "CvMorphology::init_binary_element" );
+
+ __BEGIN__;
+
+ int type;
+ int i, j, cols, rows;
+ int r = 0, c = 0;
+ double inv_r2 = 0;
+
+ if( !CV_IS_MAT(element) )
+ CV_ERROR( CV_StsBadArg, "element must be valid matrix" );
+
+ type = CV_MAT_TYPE(element->type);
+ if( type != CV_8UC1 && type != CV_32SC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "element must have 8uC1 or 32sC1 type" );
+
+ if( anchor.x == -1 )
+ anchor.x = element->cols/2;
+
+ if( anchor.y == -1 )
+ anchor.y = element->rows/2;
+
+ if( (unsigned)anchor.x >= (unsigned)element->cols ||
+ (unsigned)anchor.y >= (unsigned)element->rows )
+ CV_ERROR( CV_StsOutOfRange, "anchor is outside of element" );
+
+ if( element_shape != RECT && element_shape != CROSS && element_shape != ELLIPSE )
+ CV_ERROR( CV_StsBadArg, "Unknown/unsupported element shape" );
+
+ rows = element->rows;
+ cols = element->cols;
+
+ if( rows == 1 || cols == 1 )
+ element_shape = RECT;
+
+ if( element_shape == ELLIPSE )
+ {
+ r = rows/2;
+ c = cols/2;
+ inv_r2 = r ? 1./((double)r*r) : 0;
+ }
+
+ for( i = 0; i < rows; i++ )
+ {
+ uchar* ptr = element->data.ptr + i*element->step;
+ int j1 = 0, j2 = 0, jx, t = 0;
+
+ if( element_shape == RECT || (element_shape == CROSS && i == anchor.y) )
+ j2 = cols;
+ else if( element_shape == CROSS )
+ j1 = anchor.x, j2 = j1 + 1;
+ else
+ {
+ int dy = i - r;
+ if( abs(dy) <= r )
+ {
+ int dx = cvRound(c*sqrt(((double)r*r - dy*dy)*inv_r2));
+ j1 = MAX( c - dx, 0 );
+ j2 = MIN( c + dx + 1, cols );
+ }
+ }
+
+ for( j = 0, jx = j1; j < cols; )
+ {
+ for( ; j < jx; j++ )
+ {
+ if( type == CV_8UC1 )
+ ptr[j] = (uchar)t;
+ else
+ ((int*)ptr)[j] = t;
+ }
+ if( jx == j2 )
+ jx = cols, t = 0;
+ else
+ jx = j2, t = 1;
+ }
+ }
+
+ __END__;
+}
+
+
+#define ICV_MORPH_RECT_ROW( name, flavor, arrtype, \
+ worktype, update_extr_macro ) \
+static void \
+icv##name##RectRow_##flavor( const arrtype* src, \
+ arrtype* dst, void* params ) \
+{ \
+ const CvMorphology* state = (const CvMorphology*)params;\
+ int ksize = state->get_kernel_size().width; \
+ int width = state->get_width(); \
+ int cn = CV_MAT_CN(state->get_src_type()); \
+ int i, j, k; \
+ \
+ width *= cn; ksize *= cn; \
+ \
+ if( ksize == cn ) \
+ { \
+ for( i = 0; i < width; i++ ) \
+ dst[i] = src[i]; \
+ return; \
+ } \
+ \
+ for( k = 0; k < cn; k++, src++, dst++ ) \
+ { \
+ for( i = 0; i <= width - cn*2; i += cn*2 ) \
+ { \
+ const arrtype* s = src + i; \
+ worktype m = s[cn], t; \
+ for( j = cn*2; j < ksize; j += cn ) \
+ { \
+ t = s[j]; update_extr_macro(m,t); \
+ } \
+ t = s[0]; update_extr_macro(t,m); \
+ dst[i] = (arrtype)t; \
+ t = s[j]; update_extr_macro(t,m); \
+ dst[i+cn] = (arrtype)t; \
+ } \
+ \
+ for( ; i < width; i += cn ) \
+ { \
+ const arrtype* s = src + i; \
+ worktype m = s[0], t; \
+ for( j = cn; j < ksize; j += cn ) \
+ { \
+ t = s[j]; update_extr_macro(m,t); \
+ } \
+ dst[i] = (arrtype)m; \
+ } \
+ } \
+}
+
+
+ICV_MORPH_RECT_ROW( Erode, 8u, uchar, int, CV_CALC_MIN_8U )
+ICV_MORPH_RECT_ROW( Dilate, 8u, uchar, int, CV_CALC_MAX_8U )
+ICV_MORPH_RECT_ROW( Erode, 16u, ushort, int, CV_CALC_MIN )
+ICV_MORPH_RECT_ROW( Dilate, 16u, ushort, int, CV_CALC_MAX )
+ICV_MORPH_RECT_ROW( Erode, 32f, int, int, CV_CALC_MIN )
+ICV_MORPH_RECT_ROW( Dilate, 32f, int, int, CV_CALC_MAX )
+
+
+#define ICV_MORPH_RECT_COL( name, flavor, arrtype, \
+ worktype, update_extr_macro, toggle_macro ) \
+static void \
+icv##name##RectCol_##flavor( const arrtype** src, \
+ arrtype* dst, int dst_step, int count, void* params ) \
+{ \
+ const CvMorphology* state = (const CvMorphology*)params;\
+ int ksize = state->get_kernel_size().height; \
+ int width = state->get_width(); \
+ int cn = CV_MAT_CN(state->get_src_type()); \
+ int i, k; \
+ \
+ width *= cn; \
+ dst_step /= sizeof(dst[0]); \
+ \
+ for( ; ksize > 1 && count > 1; count -= 2, \
+ dst += dst_step*2, src += 2 ) \
+ { \
+ for( i = 0; i <= width - 4; i += 4 ) \
+ { \
+ const arrtype* sptr = src[1] + i; \
+ worktype s0 = sptr[0], s1 = sptr[1], \
+ s2 = sptr[2], s3 = sptr[3], t0, t1; \
+ \
+ for( k = 2; k < ksize; k++ ) \
+ { \
+ sptr = src[k] + i; \
+ t0 = sptr[0]; t1 = sptr[1]; \
+ update_extr_macro(s0,t0); \
+ update_extr_macro(s1,t1); \
+ t0 = sptr[2]; t1 = sptr[3]; \
+ update_extr_macro(s2,t0); \
+ update_extr_macro(s3,t1); \
+ } \
+ \
+ sptr = src[0] + i; \
+ t0 = sptr[0]; t1 = sptr[1]; \
+ update_extr_macro(t0,s0); \
+ update_extr_macro(t1,s1); \
+ dst[i] = (arrtype)toggle_macro(t0); \
+ dst[i+1] = (arrtype)toggle_macro(t1); \
+ t0 = sptr[2]; t1 = sptr[3]; \
+ update_extr_macro(t0,s2); \
+ update_extr_macro(t1,s3); \
+ dst[i+2] = (arrtype)toggle_macro(t0); \
+ dst[i+3] = (arrtype)toggle_macro(t1); \
+ \
+ sptr = src[k] + i; \
+ t0 = sptr[0]; t1 = sptr[1]; \
+ update_extr_macro(t0,s0); \
+ update_extr_macro(t1,s1); \
+ dst[i+dst_step] = (arrtype)toggle_macro(t0); \
+ dst[i+dst_step+1] = (arrtype)toggle_macro(t1); \
+ t0 = sptr[2]; t1 = sptr[3]; \
+ update_extr_macro(t0,s2); \
+ update_extr_macro(t1,s3); \
+ dst[i+dst_step+2] = (arrtype)toggle_macro(t0); \
+ dst[i+dst_step+3] = (arrtype)toggle_macro(t1); \
+ } \
+ \
+ for( ; i < width; i++ ) \
+ { \
+ const arrtype* sptr = src[1] + i; \
+ worktype s0 = sptr[0], t0; \
+ \
+ for( k = 2; k < ksize; k++ ) \
+ { \
+ sptr = src[k] + i; t0 = sptr[0]; \
+ update_extr_macro(s0,t0); \
+ } \
+ \
+ sptr = src[0] + i; t0 = sptr[0]; \
+ update_extr_macro(t0,s0); \
+ dst[i] = (arrtype)toggle_macro(t0); \
+ \
+ sptr = src[k] + i; t0 = sptr[0]; \
+ update_extr_macro(t0,s0); \
+ dst[i+dst_step] = (arrtype)toggle_macro(t0); \
+ } \
+ } \
+ \
+ for( ; count > 0; count--, dst += dst_step, src++ ) \
+ { \
+ for( i = 0; i <= width - 4; i += 4 ) \
+ { \
+ const arrtype* sptr = src[0] + i; \
+ worktype s0 = sptr[0], s1 = sptr[1], \
+ s2 = sptr[2], s3 = sptr[3], t0, t1; \
+ \
+ for( k = 1; k < ksize; k++ ) \
+ { \
+ sptr = src[k] + i; \
+ t0 = sptr[0]; t1 = sptr[1]; \
+ update_extr_macro(s0,t0); \
+ update_extr_macro(s1,t1); \
+ t0 = sptr[2]; t1 = sptr[3]; \
+ update_extr_macro(s2,t0); \
+ update_extr_macro(s3,t1); \
+ } \
+ dst[i] = (arrtype)toggle_macro(s0); \
+ dst[i+1] = (arrtype)toggle_macro(s1); \
+ dst[i+2] = (arrtype)toggle_macro(s2); \
+ dst[i+3] = (arrtype)toggle_macro(s3); \
+ } \
+ \
+ for( ; i < width; i++ ) \
+ { \
+ const arrtype* sptr = src[0] + i; \
+ worktype s0 = sptr[0], t0; \
+ \
+ for( k = 1; k < ksize; k++ ) \
+ { \
+ sptr = src[k] + i; t0 = sptr[0]; \
+ update_extr_macro(s0,t0); \
+ } \
+ dst[i] = (arrtype)toggle_macro(s0); \
+ } \
+ } \
+}
+
+
+ICV_MORPH_RECT_COL( Erode, 8u, uchar, int, CV_CALC_MIN_8U, CV_NOP )
+ICV_MORPH_RECT_COL( Dilate, 8u, uchar, int, CV_CALC_MAX_8U, CV_NOP )
+ICV_MORPH_RECT_COL( Erode, 16u, ushort, int, CV_CALC_MIN, CV_NOP )
+ICV_MORPH_RECT_COL( Dilate, 16u, ushort, int, CV_CALC_MAX, CV_NOP )
+ICV_MORPH_RECT_COL( Erode, 32f, int, int, CV_CALC_MIN, CV_TOGGLE_FLT )
+ICV_MORPH_RECT_COL( Dilate, 32f, int, int, CV_CALC_MAX, CV_TOGGLE_FLT )
+
+
+#define ICV_MORPH_ANY( name, flavor, arrtype, worktype, \
+ update_extr_macro, toggle_macro ) \
+static void \
+icv##name##Any_##flavor( const arrtype** src, arrtype* dst, \
+ int dst_step, int count, void* params ) \
+{ \
+ CvMorphology* state = (CvMorphology*)params; \
+ int width = state->get_width(); \
+ int cn = CV_MAT_CN(state->get_src_type()); \
+ int i, k; \
+ CvPoint* el_sparse = (CvPoint*)state->get_element_sparse_buf();\
+ int el_count = state->get_element_sparse_count(); \
+ const arrtype** el_ptr = (const arrtype**)(el_sparse + el_count);\
+ const arrtype** el_end = el_ptr + el_count; \
+ \
+ width *= cn; \
+ dst_step /= sizeof(dst[0]); \
+ \
+ for( ; count > 0; count--, dst += dst_step, src++ ) \
+ { \
+ for( k = 0; k < el_count; k++ ) \
+ el_ptr[k] = src[el_sparse[k].y]+el_sparse[k].x; \
+ \
+ for( i = 0; i <= width - 4; i += 4 ) \
+ { \
+ const arrtype** psptr = el_ptr; \
+ const arrtype* sptr = *psptr++; \
+ worktype s0 = sptr[i], s1 = sptr[i+1], \
+ s2 = sptr[i+2], s3 = sptr[i+3], t; \
+ \
+ while( psptr != el_end ) \
+ { \
+ sptr = *psptr++; \
+ t = sptr[i]; \
+ update_extr_macro(s0,t); \
+ t = sptr[i+1]; \
+ update_extr_macro(s1,t); \
+ t = sptr[i+2]; \
+ update_extr_macro(s2,t); \
+ t = sptr[i+3]; \
+ update_extr_macro(s3,t); \
+ } \
+ \
+ dst[i] = (arrtype)toggle_macro(s0); \
+ dst[i+1] = (arrtype)toggle_macro(s1); \
+ dst[i+2] = (arrtype)toggle_macro(s2); \
+ dst[i+3] = (arrtype)toggle_macro(s3); \
+ } \
+ \
+ for( ; i < width; i++ ) \
+ { \
+ const arrtype* sptr = el_ptr[0] + i; \
+ worktype s0 = sptr[0], t0; \
+ \
+ for( k = 1; k < el_count; k++ ) \
+ { \
+ sptr = el_ptr[k] + i; \
+ t0 = sptr[0]; \
+ update_extr_macro(s0,t0); \
+ } \
+ \
+ dst[i] = (arrtype)toggle_macro(s0); \
+ } \
+ } \
+}
+
+ICV_MORPH_ANY( Erode, 8u, uchar, int, CV_CALC_MIN, CV_NOP )
+ICV_MORPH_ANY( Dilate, 8u, uchar, int, CV_CALC_MAX, CV_NOP )
+ICV_MORPH_ANY( Erode, 16u, ushort, int, CV_CALC_MIN, CV_NOP )
+ICV_MORPH_ANY( Dilate, 16u, ushort, int, CV_CALC_MAX, CV_NOP )
+ICV_MORPH_ANY( Erode, 32f, int, int, CV_CALC_MIN, CV_TOGGLE_FLT )
+ICV_MORPH_ANY( Dilate, 32f, int, int, CV_CALC_MAX, CV_TOGGLE_FLT )
+
+/////////////////////////////////// External Interface /////////////////////////////////////
+
+
+CV_IMPL IplConvKernel *
+cvCreateStructuringElementEx( int cols, int rows,
+ int anchorX, int anchorY,
+ int shape, int *values )
+{
+ IplConvKernel *element = 0;
+ int i, size = rows * cols;
+ int element_size = sizeof(*element) + size*sizeof(element->values[0]);
+
+ CV_FUNCNAME( "cvCreateStructuringElementEx" );
+
+ __BEGIN__;
+
+ if( !values && shape == CV_SHAPE_CUSTOM )
+ CV_ERROR_FROM_STATUS( CV_NULLPTR_ERR );
+
+ if( cols <= 0 || rows <= 0 ||
+ (unsigned) anchorX >= (unsigned) cols ||
+ (unsigned) anchorY >= (unsigned) rows )
+ CV_ERROR_FROM_STATUS( CV_BADSIZE_ERR );
+
+ CV_CALL( element = (IplConvKernel *)cvAlloc(element_size + 32));
+ if( !element )
+ CV_ERROR_FROM_STATUS( CV_OUTOFMEM_ERR );
+
+ element->nCols = cols;
+ element->nRows = rows;
+ element->anchorX = anchorX;
+ element->anchorY = anchorY;
+ element->nShiftR = shape < CV_SHAPE_ELLIPSE ? shape : CV_SHAPE_CUSTOM;
+ element->values = (int*)(element + 1);
+
+ if( shape == CV_SHAPE_CUSTOM )
+ {
+ if( !values )
+ CV_ERROR( CV_StsNullPtr, "Null pointer to the custom element mask" );
+ for( i = 0; i < size; i++ )
+ element->values[i] = values[i];
+ }
+ else
+ {
+ CvMat el_hdr = cvMat( rows, cols, CV_32SC1, element->values );
+ CV_CALL( CvMorphology::init_binary_element(&el_hdr,
+ shape, cvPoint(anchorX,anchorY)));
+ }
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvReleaseStructuringElement( &element );
+
+ return element;
+}
+
+
+CV_IMPL void
+cvReleaseStructuringElement( IplConvKernel ** element )
+{
+ CV_FUNCNAME( "cvReleaseStructuringElement" );
+
+ __BEGIN__;
+
+ if( !element )
+ CV_ERROR( CV_StsNullPtr, "" );
+ cvFree( element );
+
+ __END__;
+}
+
+
+typedef CvStatus (CV_STDCALL * CvMorphRectGetBufSizeFunc_IPP)
+ ( int width, CvSize el_size, int* bufsize );
+
+typedef CvStatus (CV_STDCALL * CvMorphRectFunc_IPP)
+ ( const void* src, int srcstep, void* dst, int dststep,
+ CvSize roi, CvSize el_size, CvPoint el_anchor, void* buffer );
+
+typedef CvStatus (CV_STDCALL * CvMorphCustomInitAllocFunc_IPP)
+ ( int width, const uchar* element, CvSize el_size,
+ CvPoint el_anchor, void** morphstate );
+
+typedef CvStatus (CV_STDCALL * CvMorphCustomFunc_IPP)
+ ( const void* src, int srcstep, void* dst, int dststep,
+ CvSize roi, int bordertype, void* morphstate );
+
+static void
+icvMorphOp( const void* srcarr, void* dstarr, IplConvKernel* element,
+ int iterations, int mop )
+{
+ CvMorphology morphology;
+ void* buffer = 0;
+ int local_alloc = 0;
+ void* morphstate = 0;
+ CvMat* temp = 0;
+
+ CV_FUNCNAME( "icvMorphOp" );
+
+ __BEGIN__;
+
+ int i, coi1 = 0, coi2 = 0;
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvMat el_hdr, *el = 0;
+ CvSize size, el_size;
+ CvPoint el_anchor;
+ int el_shape;
+ int type;
+ bool inplace;
+
+ if( !CV_IS_MAT(src) )
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
+
+ if( src != &srcstub )
+ {
+ srcstub = *src;
+ src = &srcstub;
+ }
+
+ if( dstarr == srcarr )
+ dst = src;
+ else
+ {
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+ }
+
+ if( dst != &dststub )
+ {
+ dststub = *dst;
+ dst = &dststub;
+ }
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ type = CV_MAT_TYPE( src->type );
+ size = cvGetMatSize( src );
+ inplace = src->data.ptr == dst->data.ptr;
+
+ if( iterations == 0 || (element && element->nCols == 1 && element->nRows == 1))
+ {
+ if( src->data.ptr != dst->data.ptr )
+ cvCopy( src, dst );
+ EXIT;
+ }
+
+ if( element )
+ {
+ el_size = cvSize( element->nCols, element->nRows );
+ el_anchor = cvPoint( element->anchorX, element->anchorY );
+ el_shape = (int)(element->nShiftR);
+ el_shape = el_shape < CV_SHAPE_CUSTOM ? el_shape : CV_SHAPE_CUSTOM;
+ }
+ else
+ {
+ el_size = cvSize(3,3);
+ el_anchor = cvPoint(1,1);
+ el_shape = CV_SHAPE_RECT;
+ }
+
+ if( el_shape == CV_SHAPE_RECT && iterations > 1 )
+ {
+ el_size.width = 1 + (el_size.width-1)*iterations;
+ el_size.height = 1 + (el_size.height-1)*iterations;
+ el_anchor.x *= iterations;
+ el_anchor.y *= iterations;
+ iterations = 1;
+ }
+
+ if( el_shape == CV_SHAPE_RECT && icvErodeRect_GetBufSize_8u_C1R_p )
+ {
+ CvMorphRectFunc_IPP rect_func = 0;
+ CvMorphRectGetBufSizeFunc_IPP rect_getbufsize_func = 0;
+
+ if( mop == 0 )
+ {
+ if( type == CV_8UC1 )
+ rect_getbufsize_func = icvErodeRect_GetBufSize_8u_C1R_p,
+ rect_func = icvErodeRect_8u_C1R_p;
+ else if( type == CV_8UC3 )
+ rect_getbufsize_func = icvErodeRect_GetBufSize_8u_C3R_p,
+ rect_func = icvErodeRect_8u_C3R_p;
+ else if( type == CV_8UC4 )
+ rect_getbufsize_func = icvErodeRect_GetBufSize_8u_C4R_p,
+ rect_func = icvErodeRect_8u_C4R_p;
+ else if( type == CV_16UC1 )
+ rect_getbufsize_func = icvErodeRect_GetBufSize_16u_C1R_p,
+ rect_func = icvErodeRect_16u_C1R_p;
+ else if( type == CV_16UC3 )
+ rect_getbufsize_func = icvErodeRect_GetBufSize_16u_C3R_p,
+ rect_func = icvErodeRect_16u_C3R_p;
+ else if( type == CV_16UC4 )
+ rect_getbufsize_func = icvErodeRect_GetBufSize_16u_C4R_p,
+ rect_func = icvErodeRect_16u_C4R_p;
+ else if( type == CV_32FC1 )
+ rect_getbufsize_func = icvErodeRect_GetBufSize_32f_C1R_p,
+ rect_func = icvErodeRect_32f_C1R_p;
+ else if( type == CV_32FC3 )
+ rect_getbufsize_func = icvErodeRect_GetBufSize_32f_C3R_p,
+ rect_func = icvErodeRect_32f_C3R_p;
+ else if( type == CV_32FC4 )
+ rect_getbufsize_func = icvErodeRect_GetBufSize_32f_C4R_p,
+ rect_func = icvErodeRect_32f_C4R_p;
+ }
+ else
+ {
+ if( type == CV_8UC1 )
+ rect_getbufsize_func = icvDilateRect_GetBufSize_8u_C1R_p,
+ rect_func = icvDilateRect_8u_C1R_p;
+ else if( type == CV_8UC3 )
+ rect_getbufsize_func = icvDilateRect_GetBufSize_8u_C3R_p,
+ rect_func = icvDilateRect_8u_C3R_p;
+ else if( type == CV_8UC4 )
+ rect_getbufsize_func = icvDilateRect_GetBufSize_8u_C4R_p,
+ rect_func = icvDilateRect_8u_C4R_p;
+ else if( type == CV_16UC1 )
+ rect_getbufsize_func = icvDilateRect_GetBufSize_16u_C1R_p,
+ rect_func = icvDilateRect_16u_C1R_p;
+ else if( type == CV_16UC3 )
+ rect_getbufsize_func = icvDilateRect_GetBufSize_16u_C3R_p,
+ rect_func = icvDilateRect_16u_C3R_p;
+ else if( type == CV_16UC4 )
+ rect_getbufsize_func = icvDilateRect_GetBufSize_16u_C4R_p,
+ rect_func = icvDilateRect_16u_C4R_p;
+ else if( type == CV_32FC1 )
+ rect_getbufsize_func = icvDilateRect_GetBufSize_32f_C1R_p,
+ rect_func = icvDilateRect_32f_C1R_p;
+ else if( type == CV_32FC3 )
+ rect_getbufsize_func = icvDilateRect_GetBufSize_32f_C3R_p,
+ rect_func = icvDilateRect_32f_C3R_p;
+ else if( type == CV_32FC4 )
+ rect_getbufsize_func = icvDilateRect_GetBufSize_32f_C4R_p,
+ rect_func = icvDilateRect_32f_C4R_p;
+ }
+
+ if( rect_getbufsize_func && rect_func )
+ {
+ int bufsize = 0;
+
+ CvStatus status = rect_getbufsize_func( size.width, el_size, &bufsize );
+ if( status >= 0 && bufsize > 0 )
+ {
+ if( bufsize < CV_MAX_LOCAL_SIZE )
+ {
+ buffer = cvStackAlloc( bufsize );
+ local_alloc = 1;
+ }
+ else
+ CV_CALL( buffer = cvAlloc( bufsize ));
+ }
+
+ if( status >= 0 )
+ {
+ int src_step, dst_step = dst->step ? dst->step : CV_STUB_STEP;
+
+ if( inplace )
+ {
+ CV_CALL( temp = cvCloneMat( dst ));
+ src = temp;
+ }
+ src_step = src->step ? src->step : CV_STUB_STEP;
+
+ status = rect_func( src->data.ptr, src_step, dst->data.ptr,
+ dst_step, size, el_size, el_anchor, buffer );
+ }
+
+ if( status >= 0 )
+ EXIT;
+ }
+ }
+ else if( el_shape == CV_SHAPE_CUSTOM && icvMorphInitAlloc_8u_C1R_p && icvMorphFree_p &&
+ src->data.ptr != dst->data.ptr )
+ {
+ CvMorphCustomFunc_IPP custom_func = 0;
+ CvMorphCustomInitAllocFunc_IPP custom_initalloc_func = 0;
+ const int bordertype = 1; // replication border
+
+ if( type == CV_8UC1 )
+ custom_initalloc_func = icvMorphInitAlloc_8u_C1R_p,
+ custom_func = mop == 0 ? icvErode_8u_C1R_p : icvDilate_8u_C1R_p;
+ else if( type == CV_8UC3 )
+ custom_initalloc_func = icvMorphInitAlloc_8u_C3R_p,
+ custom_func = mop == 0 ? icvErode_8u_C3R_p : icvDilate_8u_C3R_p;
+ else if( type == CV_8UC4 )
+ custom_initalloc_func = icvMorphInitAlloc_8u_C4R_p,
+ custom_func = mop == 0 ? icvErode_8u_C4R_p : icvDilate_8u_C4R_p;
+ else if( type == CV_16UC1 )
+ custom_initalloc_func = icvMorphInitAlloc_16u_C1R_p,
+ custom_func = mop == 0 ? icvErode_16u_C1R_p : icvDilate_16u_C1R_p;
+ else if( type == CV_16UC3 )
+ custom_initalloc_func = icvMorphInitAlloc_16u_C3R_p,
+ custom_func = mop == 0 ? icvErode_16u_C3R_p : icvDilate_16u_C3R_p;
+ else if( type == CV_16UC4 )
+ custom_initalloc_func = icvMorphInitAlloc_16u_C4R_p,
+ custom_func = mop == 0 ? icvErode_16u_C4R_p : icvDilate_16u_C4R_p;
+ else if( type == CV_32FC1 )
+ custom_initalloc_func = icvMorphInitAlloc_32f_C1R_p,
+ custom_func = mop == 0 ? icvErode_32f_C1R_p : icvDilate_32f_C1R_p;
+ else if( type == CV_32FC3 )
+ custom_initalloc_func = icvMorphInitAlloc_32f_C3R_p,
+ custom_func = mop == 0 ? icvErode_32f_C3R_p : icvDilate_32f_C3R_p;
+ else if( type == CV_32FC4 )
+ custom_initalloc_func = icvMorphInitAlloc_32f_C4R_p,
+ custom_func = mop == 0 ? icvErode_32f_C4R_p : icvDilate_32f_C4R_p;
+
+ if( custom_initalloc_func && custom_func )
+ {
+ uchar *src_ptr, *dst_ptr = dst->data.ptr;
+ int src_step, dst_step = dst->step ? dst->step : CV_STUB_STEP;
+ int el_len = el_size.width*el_size.height;
+ uchar* el_mask = (uchar*)cvStackAlloc( el_len );
+ CvStatus status;
+
+ for( i = 0; i < el_len; i++ )
+ el_mask[i] = (uchar)(element->values[i] != 0);
+
+ status = custom_initalloc_func( size.width, el_mask, el_size,
+ el_anchor, &morphstate );
+
+ if( status >= 0 && (inplace || iterations > 1) )
+ {
+ CV_CALL( temp = cvCloneMat( src ));
+ src = temp;
+ }
+
+ src_ptr = src->data.ptr;
+ src_step = src->step ? src->step : CV_STUB_STEP;
+
+ for( i = 0; i < iterations && status >= 0 && morphstate; i++ )
+ {
+ uchar* t_ptr;
+ int t_step;
+ status = custom_func( src_ptr, src_step, dst_ptr, dst_step,
+ size, bordertype, morphstate );
+ CV_SWAP( src_ptr, dst_ptr, t_ptr );
+ CV_SWAP( src_step, dst_step, t_step );
+ if( i == 0 && temp )
+ {
+ dst_ptr = temp->data.ptr;
+ dst_step = temp->step ? temp->step : CV_STUB_STEP;
+ }
+ }
+
+ if( status >= 0 )
+ {
+ if( iterations % 2 == 0 )
+ cvCopy( temp, dst );
+ EXIT;
+ }
+ }
+ }
+
+ if( el_shape != CV_SHAPE_RECT )
+ {
+ el_hdr = cvMat( element->nRows, element->nCols, CV_32SC1, element->values );
+ el = &el_hdr;
+ el_shape = CV_SHAPE_CUSTOM;
+ }
+
+ CV_CALL( morphology.init( mop, src->cols, src->type,
+ el_shape, el, el_size, el_anchor ));
+
+ for( i = 0; i < iterations; i++ )
+ {
+ CV_CALL( morphology.process( src, dst ));
+ src = dst;
+ }
+
+ __END__;
+
+ if( !local_alloc )
+ cvFree( &buffer );
+ if( morphstate )
+ icvMorphFree_p( morphstate );
+ cvReleaseMat( &temp );
+}
+
+
+CV_IMPL void
+cvErode( const void* src, void* dst, IplConvKernel* element, int iterations )
+{
+ icvMorphOp( src, dst, element, iterations, 0 );
+}
+
+
+CV_IMPL void
+cvDilate( const void* src, void* dst, IplConvKernel* element, int iterations )
+{
+ icvMorphOp( src, dst, element, iterations, 1 );
+}
+
+
+CV_IMPL void
+cvMorphologyEx( const void* src, void* dst,
+ void* temp, IplConvKernel* element, int op, int iterations )
+{
+ CV_FUNCNAME( "cvMorhologyEx" );
+
+ __BEGIN__;
+
+ if( (op == CV_MOP_GRADIENT ||
+ ((op == CV_MOP_TOPHAT || op == CV_MOP_BLACKHAT) && src == dst)) && temp == 0 )
+ CV_ERROR( CV_HeaderIsNull, "temp image required" );
+
+ if( temp == src || temp == dst )
+ CV_ERROR( CV_HeaderIsNull, "temp image is equal to src or dst" );
+
+ switch (op)
+ {
+ case CV_MOP_OPEN:
+ CV_CALL( cvErode( src, dst, element, iterations ));
+ CV_CALL( cvDilate( dst, dst, element, iterations ));
+ break;
+ case CV_MOP_CLOSE:
+ CV_CALL( cvDilate( src, dst, element, iterations ));
+ CV_CALL( cvErode( dst, dst, element, iterations ));
+ break;
+ case CV_MOP_GRADIENT:
+ CV_CALL( cvErode( src, temp, element, iterations ));
+ CV_CALL( cvDilate( src, dst, element, iterations ));
+ CV_CALL( cvSub( dst, temp, dst ));
+ break;
+ case CV_MOP_TOPHAT:
+ if( src != dst )
+ temp = dst;
+ CV_CALL( cvErode( src, temp, element, iterations ));
+ CV_CALL( cvDilate( temp, temp, element, iterations ));
+ CV_CALL( cvSub( src, temp, dst ));
+ break;
+ case CV_MOP_BLACKHAT:
+ if( src != dst )
+ temp = dst;
+ CV_CALL( cvDilate( src, temp, element, iterations ));
+ CV_CALL( cvErode( temp, temp, element, iterations ));
+ CV_CALL( cvSub( temp, src, dst ));
+ break;
+ default:
+ CV_ERROR( CV_StsBadArg, "unknown morphological operation" );
+ }
+
+ __END__;
+}
+
+/* End of file. */
diff --git a/cv/src/cvmotempl.cpp b/cv/src/cvmotempl.cpp
new file mode 100644
index 0000000..1792671
--- /dev/null
+++ b/cv/src/cvmotempl.cpp
@@ -0,0 +1,517 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+IPCVAPI_IMPL( CvStatus, icvUpdateMotionHistory_8u32f_C1IR,
+ (const uchar * silIm, int silStep, float *mhiIm, int mhiStep,
+ CvSize size, float timestamp, float mhi_duration),
+ (silIm, silStep, mhiIm, mhiStep, size, timestamp, mhi_duration) )
+{
+ int x, y;
+
+ /* function processes floating-point images using integer arithmetics */
+ Cv32suf v;
+ int ts, delbound;
+ int *mhi = (int *) mhiIm;
+
+ v.f = timestamp;
+ ts = v.i;
+
+ if( !silIm || !mhiIm )
+ return CV_NULLPTR_ERR;
+
+ if( size.height <= 0 || size.width <= 0 ||
+ silStep < size.width || mhiStep < size.width * CV_SIZEOF_FLOAT ||
+ (mhiStep & (CV_SIZEOF_FLOAT - 1)) != 0 )
+ return CV_BADSIZE_ERR;
+
+ if( mhi_duration < 0 )
+ return CV_BADFACTOR_ERR;
+
+ mhi_duration = timestamp - mhi_duration;
+
+ v.f = mhi_duration;
+ delbound = CV_TOGGLE_FLT( v.i );
+
+ mhiStep /= sizeof(mhi[0]);
+
+ if( mhiStep == size.width && silStep == size.width )
+ {
+ size.width *= size.height;
+ size.height = 1;
+ }
+
+ if( delbound > 0 )
+ for( y = 0; y < size.height; y++, silIm += silStep, mhi += mhiStep )
+ for( x = 0; x < size.width; x++ )
+ {
+ int val = mhi[x];
+
+ /* val = silIm[x] ? ts : val < delbound ? 0 : val; */
+ val &= (val < delbound) - 1;
+ val ^= (ts ^ val) & ((silIm[x] == 0) - 1);
+ mhi[x] = val;
+ }
+ else
+ for( y = 0; y < size.height; y++, silIm += silStep, mhi += mhiStep )
+ for( x = 0; x < size.width; x++ )
+ {
+ int val = mhi[x];
+
+ /* val = silIm[x] ? ts : val < delbound ? 0 : val; */
+ val &= (CV_TOGGLE_FLT( val ) < delbound) - 1;
+ val ^= (ts ^ val) & ((silIm[x] == 0) - 1);
+ mhi[x] = val;
+ }
+
+ return CV_OK;
+}
+
+
+/* motion templates */
+CV_IMPL void
+cvUpdateMotionHistory( const void* silhouette, void* mhimg,
+ double timestamp, double mhi_duration )
+{
+ CvSize size;
+ CvMat silhstub, *silh = (CvMat*)silhouette;
+ CvMat mhistub, *mhi = (CvMat*)mhimg;
+ int mhi_step, silh_step;
+
+ CV_FUNCNAME( "cvUpdateMHIByTime" );
+
+ __BEGIN__;
+
+ CV_CALL( silh = cvGetMat( silh, &silhstub ));
+ CV_CALL( mhi = cvGetMat( mhi, &mhistub ));
+
+ if( !CV_IS_MASK_ARR( silh ))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( CV_MAT_CN( mhi->type ) > 1 )
+ CV_ERROR( CV_BadNumChannels, "" );
+
+ if( CV_MAT_DEPTH( mhi->type ) != CV_32F )
+ CV_ERROR( CV_BadDepth, "" );
+
+ if( !CV_ARE_SIZES_EQ( mhi, silh ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ size = cvGetMatSize( mhi );
+
+ mhi_step = mhi->step;
+ silh_step = silh->step;
+
+ if( CV_IS_MAT_CONT( mhi->type & silh->type ))
+ {
+ size.width *= size.height;
+ mhi_step = silh_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+
+ IPPI_CALL( icvUpdateMotionHistory_8u32f_C1IR( (const uchar*)(silh->data.ptr), silh_step,
+ mhi->data.fl, mhi_step, size,
+ (float)timestamp, (float)mhi_duration ));
+ __END__;
+}
+
+
+CV_IMPL void
+cvCalcMotionGradient( const CvArr* mhiimg, CvArr* maskimg,
+ CvArr* orientation,
+ double delta1, double delta2,
+ int aperture_size )
+{
+ CvMat *dX_min = 0, *dY_max = 0;
+ IplConvKernel* el = 0;
+
+ CV_FUNCNAME( "cvCalcMotionGradient" );
+
+ __BEGIN__;
+
+ CvMat mhistub, *mhi = (CvMat*)mhiimg;
+ CvMat maskstub, *mask = (CvMat*)maskimg;
+ CvMat orientstub, *orient = (CvMat*)orientation;
+ CvMat dX_min_row, dY_max_row, orient_row, mask_row;
+ CvSize size;
+ int x, y;
+
+ float gradient_epsilon = 1e-4f * aperture_size * aperture_size;
+ float min_delta, max_delta;
+
+ CV_CALL( mhi = cvGetMat( mhi, &mhistub ));
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+ CV_CALL( orient = cvGetMat( orient, &orientstub ));
+
+ if( !CV_IS_MASK_ARR( mask ))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( aperture_size < 3 || aperture_size > 7 || (aperture_size & 1) == 0 )
+ CV_ERROR( CV_StsOutOfRange, "aperture_size must be 3, 5 or 7" );
+
+ if( delta1 <= 0 || delta2 <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "both delta's must be positive" );
+
+ if( CV_MAT_TYPE( mhi->type ) != CV_32FC1 || CV_MAT_TYPE( orient->type ) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "MHI and orientation must be single-channel floating-point images" );
+
+ if( !CV_ARE_SIZES_EQ( mhi, mask ) || !CV_ARE_SIZES_EQ( orient, mhi ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( orient->data.ptr == mhi->data.ptr )
+ CV_ERROR( CV_StsInplaceNotSupported, "orientation image must be different from MHI" );
+
+ if( delta1 > delta2 )
+ {
+ double t;
+ CV_SWAP( delta1, delta2, t );
+ }
+
+ size = cvGetMatSize( mhi );
+ min_delta = (float)delta1;
+ max_delta = (float)delta2;
+ CV_CALL( dX_min = cvCreateMat( mhi->rows, mhi->cols, CV_32F ));
+ CV_CALL( dY_max = cvCreateMat( mhi->rows, mhi->cols, CV_32F ));
+
+ /* calc Dx and Dy */
+ CV_CALL( cvSobel( mhi, dX_min, 1, 0, aperture_size ));
+ CV_CALL( cvSobel( mhi, dY_max, 0, 1, aperture_size ));
+ cvGetRow( dX_min, &dX_min_row, 0 );
+ cvGetRow( dY_max, &dY_max_row, 0 );
+ cvGetRow( orient, &orient_row, 0 );
+ cvGetRow( mask, &mask_row, 0 );
+
+ /* calc gradient */
+ for( y = 0; y < size.height; y++ )
+ {
+ dX_min_row.data.ptr = dX_min->data.ptr + y*dX_min->step;
+ dY_max_row.data.ptr = dY_max->data.ptr + y*dY_max->step;
+ orient_row.data.ptr = orient->data.ptr + y*orient->step;
+ mask_row.data.ptr = mask->data.ptr + y*mask->step;
+ cvCartToPolar( &dX_min_row, &dY_max_row, 0, &orient_row, 1 );
+
+ /* make orientation zero where the gradient is very small */
+ for( x = 0; x < size.width; x++ )
+ {
+ float dY = dY_max_row.data.fl[x];
+ float dX = dX_min_row.data.fl[x];
+
+ if( fabs(dX) < gradient_epsilon && fabs(dY) < gradient_epsilon )
+ {
+ mask_row.data.ptr[x] = 0;
+ orient_row.data.i[x] = 0;
+ }
+ else
+ mask_row.data.ptr[x] = 1;
+ }
+ }
+
+ CV_CALL( el = cvCreateStructuringElementEx( aperture_size, aperture_size,
+ aperture_size/2, aperture_size/2, CV_SHAPE_RECT ));
+ cvErode( mhi, dX_min, el );
+ cvDilate( mhi, dY_max, el );
+
+ /* mask off pixels which have little motion difference in their neighborhood */
+ for( y = 0; y < size.height; y++ )
+ {
+ dX_min_row.data.ptr = dX_min->data.ptr + y*dX_min->step;
+ dY_max_row.data.ptr = dY_max->data.ptr + y*dY_max->step;
+ mask_row.data.ptr = mask->data.ptr + y*mask->step;
+ orient_row.data.ptr = orient->data.ptr + y*orient->step;
+
+ for( x = 0; x < size.width; x++ )
+ {
+ float d0 = dY_max_row.data.fl[x] - dX_min_row.data.fl[x];
+
+ if( mask_row.data.ptr[x] == 0 || d0 < min_delta || max_delta < d0 )
+ {
+ mask_row.data.ptr[x] = 0;
+ orient_row.data.i[x] = 0;
+ }
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &dX_min );
+ cvReleaseMat( &dY_max );
+ cvReleaseStructuringElement( &el );
+}
+
+
+CV_IMPL double
+cvCalcGlobalOrientation( const void* orientation, const void* maskimg, const void* mhiimg,
+ double curr_mhi_timestamp, double mhi_duration )
+{
+ double angle = 0;
+ int hist_size = 12;
+ CvHistogram* hist = 0;
+
+ CV_FUNCNAME( "cvCalcGlobalOrientation" );
+
+ __BEGIN__;
+
+ CvMat mhistub, *mhi = (CvMat*)mhiimg;
+ CvMat maskstub, *mask = (CvMat*)maskimg;
+ CvMat orientstub, *orient = (CvMat*)orientation;
+ void* _orient;
+ float _ranges[] = { 0, 360 };
+ float* ranges = _ranges;
+ int base_orient;
+ double shift_orient = 0, shift_weight = 0, fbase_orient;
+ double a, b;
+ float delbound;
+ CvMat mhi_row, mask_row, orient_row;
+ int x, y, mhi_rows, mhi_cols;
+
+ CV_CALL( mhi = cvGetMat( mhi, &mhistub ));
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+ CV_CALL( orient = cvGetMat( orient, &orientstub ));
+
+ if( !CV_IS_MASK_ARR( mask ))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( CV_MAT_TYPE( mhi->type ) != CV_32FC1 || CV_MAT_TYPE( orient->type ) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "MHI and orientation must be single-channel floating-point images" );
+
+ if( !CV_ARE_SIZES_EQ( mhi, mask ) || !CV_ARE_SIZES_EQ( orient, mhi ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( mhi_duration <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "MHI duration must be positive" );
+
+ if( orient->data.ptr == mhi->data.ptr )
+ CV_ERROR( CV_StsInplaceNotSupported, "orientation image must be different from MHI" );
+
+ // calculate histogram of different orientation values
+ CV_CALL( hist = cvCreateHist( 1, &hist_size, CV_HIST_ARRAY, &ranges ));
+ _orient = orient;
+ cvCalcArrHist( &_orient, hist, 0, mask );
+
+ // find the maximum index (the dominant orientation)
+ cvGetMinMaxHistValue( hist, 0, 0, 0, &base_orient );
+ base_orient *= 360/hist_size;
+
+ // override timestamp with the maximum value in MHI
+ cvMinMaxLoc( mhi, 0, &curr_mhi_timestamp, 0, 0, mask );
+
+ // find the shift relative to the dominant orientation as weighted sum of relative angles
+ a = 254. / 255. / mhi_duration;
+ b = 1. - curr_mhi_timestamp * a;
+ fbase_orient = base_orient;
+ delbound = (float)(curr_mhi_timestamp - mhi_duration);
+ mhi_rows = mhi->rows;
+ mhi_cols = mhi->cols;
+
+ if( CV_IS_MAT_CONT( mhi->type & mask->type & orient->type ))
+ {
+ mhi_cols *= mhi_rows;
+ mhi_rows = 1;
+ }
+
+ cvGetRow( mhi, &mhi_row, 0 );
+ cvGetRow( mask, &mask_row, 0 );
+ cvGetRow( orient, &orient_row, 0 );
+
+ /*
+ a = 254/(255*dt)
+ b = 1 - t*a = 1 - 254*t/(255*dur) =
+ (255*dt - 254*t)/(255*dt) =
+ (dt - (t - dt)*254)/(255*dt);
+ --------------------------------------------------------
+ ax + b = 254*x/(255*dt) + (dt - (t - dt)*254)/(255*dt) =
+ (254*x + dt - (t - dt)*254)/(255*dt) =
+ ((x - (t - dt))*254 + dt)/(255*dt) =
+ (((x - (t - dt))/dt)*254 + 1)/255 = (((x - low_time)/dt)*254 + 1)/255
+ */
+ for( y = 0; y < mhi_rows; y++ )
+ {
+ mhi_row.data.ptr = mhi->data.ptr + mhi->step*y;
+ mask_row.data.ptr = mask->data.ptr + mask->step*y;
+ orient_row.data.ptr = orient->data.ptr + orient->step*y;
+
+ for( x = 0; x < mhi_cols; x++ )
+ if( mask_row.data.ptr[x] != 0 && mhi_row.data.fl[x] > delbound )
+ {
+ /*
+ orient in 0..360, base_orient in 0..360
+ -> (rel_angle = orient - base_orient) in -360..360.
+ rel_angle is translated to -180..180
+ */
+ double weight = mhi_row.data.fl[x] * a + b;
+ int rel_angle = cvRound( orient_row.data.fl[x] - fbase_orient );
+
+ rel_angle += (rel_angle < -180 ? 360 : 0);
+ rel_angle += (rel_angle > 180 ? -360 : 0);
+
+ if( abs(rel_angle) < 90 )
+ {
+ shift_orient += weight * rel_angle;
+ shift_weight += weight;
+ }
+ }
+ }
+
+ // add the dominant orientation and the relative shift
+ if( shift_weight == 0 )
+ shift_weight = 0.01;
+
+ base_orient = base_orient + cvRound( shift_orient / shift_weight );
+ base_orient -= (base_orient < 360 ? 0 : 360);
+ base_orient += (base_orient >= 0 ? 0 : 360);
+
+ angle = base_orient;
+
+ __END__;
+
+ cvReleaseHist( &hist );
+ return angle;
+}
+
+
+CV_IMPL CvSeq*
+cvSegmentMotion( const CvArr* mhiimg, CvArr* segmask, CvMemStorage* storage,
+ double timestamp, double seg_thresh )
+{
+ CvSeq* components = 0;
+ CvMat* mask8u = 0;
+
+ CV_FUNCNAME( "cvSegmentMotion" );
+
+ __BEGIN__;
+
+ CvMat mhistub, *mhi = (CvMat*)mhiimg;
+ CvMat maskstub, *mask = (CvMat*)segmask;
+ Cv32suf v, comp_idx;
+ int stub_val, ts;
+ int x, y;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "NULL memory storage" );
+
+ CV_CALL( mhi = cvGetMat( mhi, &mhistub ));
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+
+ if( CV_MAT_TYPE( mhi->type ) != CV_32FC1 || CV_MAT_TYPE( mask->type ) != CV_32FC1 )
+ CV_ERROR( CV_BadDepth, "Both MHI and the destination mask" );
+
+ if( !CV_ARE_SIZES_EQ( mhi, mask ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ CV_CALL( mask8u = cvCreateMat( mhi->rows + 2, mhi->cols + 2, CV_8UC1 ));
+ cvZero( mask8u );
+ cvZero( mask );
+ CV_CALL( components = cvCreateSeq( CV_SEQ_KIND_GENERIC, sizeof(CvSeq),
+ sizeof(CvConnectedComp), storage ));
+
+ v.f = (float)timestamp; ts = v.i;
+ v.f = FLT_MAX*0.1f; stub_val = v.i;
+ comp_idx.f = 1;
+
+ for( y = 0; y < mhi->rows; y++ )
+ {
+ int* mhi_row = (int*)(mhi->data.ptr + y*mhi->step);
+ for( x = 0; x < mhi->cols; x++ )
+ {
+ if( mhi_row[x] == 0 )
+ mhi_row[x] = stub_val;
+ }
+ }
+
+ for( y = 0; y < mhi->rows; y++ )
+ {
+ int* mhi_row = (int*)(mhi->data.ptr + y*mhi->step);
+ uchar* mask8u_row = mask8u->data.ptr + (y+1)*mask8u->step + 1;
+
+ for( x = 0; x < mhi->cols; x++ )
+ {
+ if( mhi_row[x] == ts && mask8u_row[x] == 0 )
+ {
+ CvConnectedComp comp;
+ int x1, y1;
+ CvScalar _seg_thresh = cvRealScalar(seg_thresh);
+ CvPoint seed = cvPoint(x,y);
+
+ CV_CALL( cvFloodFill( mhi, seed, cvRealScalar(0), _seg_thresh, _seg_thresh,
+ &comp, CV_FLOODFILL_MASK_ONLY + 2*256 + 4, mask8u ));
+
+ for( y1 = 0; y1 < comp.rect.height; y1++ )
+ {
+ int* mask_row1 = (int*)(mask->data.ptr +
+ (comp.rect.y + y1)*mask->step) + comp.rect.x;
+ uchar* mask8u_row1 = mask8u->data.ptr +
+ (comp.rect.y + y1+1)*mask8u->step + comp.rect.x+1;
+
+ for( x1 = 0; x1 < comp.rect.width; x1++ )
+ {
+ if( mask8u_row1[x1] > 1 )
+ {
+ mask8u_row1[x1] = 1;
+ mask_row1[x1] = comp_idx.i;
+ }
+ }
+ }
+ comp_idx.f++;
+ cvSeqPush( components, &comp );
+ }
+ }
+ }
+
+ for( y = 0; y < mhi->rows; y++ )
+ {
+ int* mhi_row = (int*)(mhi->data.ptr + y*mhi->step);
+ for( x = 0; x < mhi->cols; x++ )
+ {
+ if( mhi_row[x] == stub_val )
+ mhi_row[x] = 0;
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &mask8u );
+ return components;
+}
+
+/* End of file. */
diff --git a/cv/src/cvoptflowbm.cpp b/cv/src/cvoptflowbm.cpp
new file mode 100644
index 0000000..723e3aa
--- /dev/null
+++ b/cv/src/cvoptflowbm.cpp
@@ -0,0 +1,610 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+/*
+ Finds L1 norm between two blocks.
+*/
+static int
+icvCmpBlocksL1_8u_C1( const uchar * vec1, const uchar * vec2, int len )
+{
+ int i, sum = 0;
+
+ for( i = 0; i <= len - 4; i += 4 )
+ {
+ int t0 = abs(vec1[i] - vec2[i]);
+ int t1 = abs(vec1[i + 1] - vec2[i + 1]);
+ int t2 = abs(vec1[i + 2] - vec2[i + 2]);
+ int t3 = abs(vec1[i + 3] - vec2[i + 3]);
+
+ sum += t0 + t1 + t2 + t3;
+ }
+
+ for( ; i < len; i++ )
+ {
+ int t0 = abs(vec1[i] - vec2[i]);
+ sum += t0;
+ }
+
+ return sum;
+}
+
+
+static void
+icvCopyBM_8u_C1R( const uchar* src, int src_step,
+ uchar* dst, int dst_step, CvSize size )
+{
+ for( ; size.height--; src += src_step, dst += dst_step )
+ memcpy( dst, src, size.width );
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvCalcOpticalFlowBM_8u32fR
+// Purpose: calculate Optical flow for 2 images using block matching algorithm
+// Context:
+// Parameters:
+// imgA, // pointer to first frame ROI
+// imgB, // pointer to second frame ROI
+// imgStep, // full width of input images in bytes
+// imgSize, // size of the image
+// blockSize, // size of basic blocks which are compared
+// shiftSize, // coordinates increments.
+// maxRange, // size of the scanned neighborhood.
+// usePrevious, // flag of using previous velocity field
+// velocityX, // pointer to ROI of horizontal and
+// velocityY, // vertical components of optical flow
+// velStep); // full width of velocity frames in bytes
+// Returns: CV_OK or error code
+// Notes:
+//F*/
+#define SMALL_DIFF 2
+#define BIG_DIFF 128
+
+static CvStatus CV_STDCALL
+icvCalcOpticalFlowBM_8u32fR( uchar * imgA, uchar * imgB,
+ int imgStep, CvSize imgSize,
+ CvSize blockSize, CvSize shiftSize,
+ CvSize maxRange, int usePrev,
+ float *velocityX, float *velocityY,
+ int velStep )
+{
+ const float back = 1.f / (float) (1 << 16);
+
+ /* scanning scheme coordinates */
+
+ CvPoint *ss = 0;
+ int ss_count = 0;
+
+ int stand_accept_level = blockSize.height * blockSize.width * SMALL_DIFF;
+ int stand_escape_level = blockSize.height * blockSize.width * BIG_DIFF;
+
+ int i, j;
+
+ int *int_velocityX = (int *) velocityX;
+ int *int_velocityY = (int *) velocityY;
+
+ /* if image sizes can't be divided by block sizes then right blocks will */
+ /* have not full width - BorderWidth */
+ /* and bottom blocks will */
+ /* have not full height - BorderHeight */
+ int BorderWidth;
+ int BorderHeight;
+
+ int CurrentWidth;
+ int CurrentHeight;
+
+ int NumberBlocksX;
+ int NumberBlocksY;
+
+ int Y1 = 0;
+ int X1 = 0;
+
+ int DownStep = blockSize.height * imgStep;
+
+ uchar *blockA = 0;
+ uchar *blockB = 0;
+ uchar *blockZ = 0;
+ int blSize = blockSize.width * blockSize.height;
+ int bufferSize = cvAlign(blSize + 9,16);
+ int cmpSize = cvAlign(blSize,4);
+ int patch_ofs = blSize & -8;
+ int64 patch_mask = (((int64) 1) << (blSize - patch_ofs * 8)) - 1;
+
+ velStep /= sizeof(velocityX[0]);
+
+ if( patch_ofs == blSize )
+ patch_mask = (int64) - 1;
+
+/****************************************************************************************\
+* Checking bad arguments *
+\****************************************************************************************/
+ if( imgA == NULL )
+ return CV_NULLPTR_ERR;
+ if( imgB == NULL )
+ return CV_NULLPTR_ERR;
+
+/****************************************************************************************\
+* Allocate buffers *
+\****************************************************************************************/
+ blockA = (uchar *) cvAlloc( bufferSize * 3 );
+ if( !blockA )
+ return CV_OUTOFMEM_ERR;
+
+ blockB = blockA + bufferSize;
+ blockZ = blockB + bufferSize;
+
+ memset( blockZ, 0, bufferSize );
+
+ ss = (CvPoint *) cvAlloc( (2 * maxRange.width + 1) * (2 * maxRange.height + 1) *
+ sizeof( CvPoint ));
+ if( !ss )
+ {
+ cvFree( &blockA );
+ return CV_OUTOFMEM_ERR;
+ }
+
+/****************************************************************************************\
+* Calculate scanning scheme *
+\****************************************************************************************/
+ {
+ int X_shift_count = maxRange.width / shiftSize.width;
+ int Y_shift_count = maxRange.height / shiftSize.height;
+ int min_count = MIN( X_shift_count, Y_shift_count );
+
+ /* cycle by neighborhood rings */
+ /* scanning scheme is
+
+ . 9 10 11 12
+ . 8 1 2 13
+ . 7 * 3 14
+ . 6 5 4 15
+ 20 19 18 17 16
+ */
+
+ for( i = 0; i < min_count; i++ )
+ {
+ /* four cycles along sides */
+ int y = -(i + 1) * shiftSize.height;
+ int x = -(i + 1) * shiftSize.width;
+
+ /* upper side */
+ for( j = -i; j <= i + 1; j++, ss_count++ )
+ {
+ x += shiftSize.width;
+ ss[ss_count].x = x;
+ ss[ss_count].y = y;
+ }
+
+ /* right side */
+ for( j = -i; j <= i + 1; j++, ss_count++ )
+ {
+ y += shiftSize.height;
+ ss[ss_count].x = x;
+ ss[ss_count].y = y;
+ }
+
+ /* bottom side */
+ for( j = -i; j <= i + 1; j++, ss_count++ )
+ {
+ x -= shiftSize.width;
+ ss[ss_count].x = x;
+ ss[ss_count].y = y;
+ }
+
+ /* left side */
+ for( j = -i; j <= i + 1; j++, ss_count++ )
+ {
+ y -= shiftSize.height;
+ ss[ss_count].x = x;
+ ss[ss_count].y = y;
+ }
+ }
+
+ /* the rest part */
+ if( X_shift_count < Y_shift_count )
+ {
+ int xleft = -min_count * shiftSize.width;
+
+ /* cycle by neighbor rings */
+ for( i = min_count; i < Y_shift_count; i++ )
+ {
+ /* two cycles by x */
+ int y = -(i + 1) * shiftSize.height;
+ int x = xleft;
+
+ /* upper side */
+ for( j = -X_shift_count; j <= X_shift_count; j++, ss_count++ )
+ {
+ ss[ss_count].x = x;
+ ss[ss_count].y = y;
+ x += shiftSize.width;
+ }
+
+ x = xleft;
+ y = -y;
+ /* bottom side */
+ for( j = -X_shift_count; j <= X_shift_count; j++, ss_count++ )
+ {
+ ss[ss_count].x = x;
+ ss[ss_count].y = y;
+ x += shiftSize.width;
+ }
+ }
+ }
+ else if( X_shift_count > Y_shift_count )
+ {
+ int yupper = -min_count * shiftSize.height;
+
+ /* cycle by neighbor rings */
+ for( i = min_count; i < X_shift_count; i++ )
+ {
+ /* two cycles by y */
+ int x = -(i + 1) * shiftSize.width;
+ int y = yupper;
+
+ /* left side */
+ for( j = -Y_shift_count; j <= Y_shift_count; j++, ss_count++ )
+ {
+ ss[ss_count].x = x;
+ ss[ss_count].y = y;
+ y += shiftSize.height;
+ }
+
+ y = yupper;
+ x = -x;
+ /* right side */
+ for( j = -Y_shift_count; j <= Y_shift_count; j++, ss_count++ )
+ {
+ ss[ss_count].x = x;
+ ss[ss_count].y = y;
+ y += shiftSize.height;
+ }
+ }
+ }
+
+ }
+
+/****************************************************************************************\
+* Calculate some neeeded variables *
+\****************************************************************************************/
+ /* Calculate number of full blocks */
+ NumberBlocksX = (int) imgSize.width / blockSize.width;
+ NumberBlocksY = (int) imgSize.height / blockSize.height;
+
+ /* add 1 if not full border blocks exist */
+ BorderWidth = imgSize.width % blockSize.width;
+ if( BorderWidth )
+ NumberBlocksX++;
+ else
+ BorderWidth = blockSize.width;
+
+ BorderHeight = imgSize.height % blockSize.height;
+ if( BorderHeight )
+ NumberBlocksY++;
+ else
+ BorderHeight = blockSize.height;
+
+/****************************************************************************************\
+* Round input velocities integer searching area center position *
+\****************************************************************************************/
+ if( usePrev )
+ {
+ float *velxf = velocityX, *velyf = velocityY;
+ int* velx = (int*)velocityX, *vely = (int*)velocityY;
+
+ for( i = 0; i < NumberBlocksY; i++, velxf += velStep, velyf += velStep,
+ velx += velStep, vely += velStep )
+ {
+ for( j = 0; j < NumberBlocksX; j++ )
+ {
+ int vx = cvRound( velxf[j] ), vy = cvRound( velyf[j] );
+ velx[j] = vx; vely[j] = vy;
+ }
+ }
+ }
+/****************************************************************************************\
+* Main loop *
+\****************************************************************************************/
+ Y1 = 0;
+ for( i = 0; i < NumberBlocksY; i++ )
+ {
+ /* calculate height of current block */
+ CurrentHeight = (i == NumberBlocksY - 1) ? BorderHeight : blockSize.height;
+ X1 = 0;
+
+ for( j = 0; j < NumberBlocksX; j++ )
+ {
+ int accept_level;
+ int escape_level;
+
+ int blDist;
+
+ int VelocityX = 0;
+ int VelocityY = 0;
+
+ int offX = 0, offY = 0;
+
+ int CountDirection = 1;
+
+ int main_flag = i < NumberBlocksY - 1 && j < NumberBlocksX - 1;
+ CvSize CurSize;
+
+ /* calculate width of current block */
+ CurrentWidth = (j == NumberBlocksX - 1) ? BorderWidth : blockSize.width;
+
+ /* compute initial offset */
+ if( usePrev )
+ {
+ offX = int_velocityX[j];
+ offY = int_velocityY[j];
+ }
+
+ CurSize.width = CurrentWidth;
+ CurSize.height = CurrentHeight;
+
+ if( main_flag )
+ {
+ icvCopyBM_8u_C1R( imgA + X1, imgStep, blockA,
+ CurSize.width, CurSize );
+ icvCopyBM_8u_C1R( imgB + (Y1 + offY)*imgStep + (X1 + offX),
+ imgStep, blockB, CurSize.width, CurSize );
+
+ *((int64 *) (blockA + patch_ofs)) &= patch_mask;
+ *((int64 *) (blockB + patch_ofs)) &= patch_mask;
+ }
+ else
+ {
+ memset( blockA, 0, bufferSize );
+ memset( blockB, 0, bufferSize );
+
+ icvCopyBM_8u_C1R( imgA + X1, imgStep, blockA, blockSize.width, CurSize );
+ icvCopyBM_8u_C1R( imgB + (Y1 + offY) * imgStep + (X1 + offX), imgStep,
+ blockB, blockSize.width, CurSize );
+ }
+
+ if( !main_flag )
+ {
+ int tmp = CurSize.width * CurSize.height;
+
+ accept_level = tmp * SMALL_DIFF;
+ escape_level = tmp * BIG_DIFF;
+ }
+ else
+ {
+ accept_level = stand_accept_level;
+ escape_level = stand_escape_level;
+ }
+
+ blDist = icvCmpBlocksL1_8u_C1( blockA, blockB, cmpSize );
+
+ if( blDist > accept_level )
+ {
+ int k;
+ int VelX = 0;
+ int VelY = 0;
+
+ /* walk around basic block */
+
+ /* cycle for neighborhood */
+ for( k = 0; k < ss_count; k++ )
+ {
+ int tmpDist;
+
+ int Y2 = Y1 + offY + ss[k].y;
+ int X2 = X1 + offX + ss[k].x;
+
+ /* if we break upper border */
+ if( Y2 < 0 )
+ {
+ continue;
+ }
+ /* if we break bottom border */
+ if( Y2 + CurrentHeight >= imgSize.height )
+ {
+ continue;
+ }
+ /* if we break left border */
+ if( X2 < 0 )
+ {
+ continue;
+ }
+ /* if we break right border */
+ if( X2 + CurrentWidth >= imgSize.width )
+ {
+ continue;
+ }
+
+ if( main_flag )
+ {
+ icvCopyBM_8u_C1R( imgB + Y2 * imgStep + X2,
+ imgStep, blockB, CurSize.width, CurSize );
+
+ *((int64 *) (blockB + patch_ofs)) &= patch_mask;
+ }
+ else
+ {
+ memset( blockB, 0, bufferSize );
+ icvCopyBM_8u_C1R( imgB + Y1 * imgStep + X1, imgStep,
+ blockB, blockSize.width, CurSize );
+ }
+
+ tmpDist = icvCmpBlocksL1_8u_C1( blockA, blockB, cmpSize );
+
+ if( tmpDist < accept_level )
+ {
+ VelX = ss[k].x;
+ VelY = ss[k].y;
+ break; /*for */
+ }
+ else if( tmpDist < blDist )
+ {
+ blDist = tmpDist;
+ VelX = ss[k].x;
+ VelY = ss[k].y;
+ CountDirection = 1;
+ }
+ else if( tmpDist == blDist )
+ {
+ VelX += ss[k].x;
+ VelY += ss[k].y;
+ CountDirection++;
+ }
+ }
+ if( blDist > escape_level )
+ {
+ VelX = VelY = 0;
+ CountDirection = 1;
+ }
+ if( CountDirection > 1 )
+ {
+ int temp = CountDirection == 2 ? 1 << 15 : ((1 << 16) / CountDirection);
+
+ VelocityX = VelX * temp;
+ VelocityY = VelY * temp;
+ }
+ else
+ {
+ VelocityX = VelX << 16;
+ VelocityY = VelY << 16;
+ }
+ } /*if */
+
+ int_velocityX[j] = VelocityX + (offX << 16);
+ int_velocityY[j] = VelocityY + (offY << 16);
+
+ X1 += blockSize.width;
+
+ } /*for */
+ int_velocityX += velStep;
+ int_velocityY += velStep;
+
+ imgA += DownStep;
+ Y1 += blockSize.height;
+ } /*for */
+
+/****************************************************************************************\
+* Converting fixed point velocities to floating point *
+\****************************************************************************************/
+ {
+ float *velxf = velocityX, *velyf = velocityY;
+ int* velx = (int*)velocityX, *vely = (int*)velocityY;
+
+ for( i = 0; i < NumberBlocksY; i++, velxf += velStep, velyf += velStep,
+ velx += velStep, vely += velStep )
+ {
+ for( j = 0; j < NumberBlocksX; j++ )
+ {
+ float vx = (float)velx[j]*back, vy = (float)vely[j]*back;
+ velxf[j] = vx; velyf[j] = vy;
+ }
+ }
+ }
+
+ cvFree( &ss );
+ cvFree( &blockA );
+
+ return CV_OK;
+} /*cvCalcOpticalFlowBM_8u */
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvCalcOpticalFlowBM
+// Purpose: Optical flow implementation
+// Context:
+// Parameters:
+// srcA, srcB - source image
+// velx, vely - destination image
+// Returns:
+//
+// Notes:
+//F*/
+CV_IMPL void
+cvCalcOpticalFlowBM( const void* srcarrA, const void* srcarrB,
+ CvSize blockSize, CvSize shiftSize,
+ CvSize maxRange, int usePrevious,
+ void* velarrx, void* velarry )
+{
+ CV_FUNCNAME( "cvCalcOpticalFlowBM" );
+
+ __BEGIN__;
+
+ CvMat stubA, *srcA = (CvMat*)srcarrA;
+ CvMat stubB, *srcB = (CvMat*)srcarrB;
+ CvMat stubx, *velx = (CvMat*)velarrx;
+ CvMat stuby, *vely = (CvMat*)velarry;
+
+ CV_CALL( srcA = cvGetMat( srcA, &stubA ));
+ CV_CALL( srcB = cvGetMat( srcB, &stubB ));
+
+ CV_CALL( velx = cvGetMat( velx, &stubx ));
+ CV_CALL( vely = cvGetMat( vely, &stuby ));
+
+ if( !CV_ARE_TYPES_EQ( srcA, srcB ))
+ CV_ERROR( CV_StsUnmatchedFormats, "Source images have different formats" );
+
+ if( !CV_ARE_TYPES_EQ( velx, vely ))
+ CV_ERROR( CV_StsUnmatchedFormats, "Destination images have different formats" );
+
+ if( !CV_ARE_SIZES_EQ( srcA, srcB ) ||
+ !CV_ARE_SIZES_EQ( velx, vely ) ||
+ (unsigned)(velx->width*blockSize.width - srcA->width) >= (unsigned)blockSize.width ||
+ (unsigned)(velx->height*blockSize.height - srcA->height) >= (unsigned)blockSize.height )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( CV_MAT_TYPE( srcA->type ) != CV_8UC1 ||
+ CV_MAT_TYPE( velx->type ) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Source images must have 8uC1 type and "
+ "destination images must have 32fC1 type" );
+
+ if( srcA->step != srcB->step || velx->step != vely->step )
+ CV_ERROR( CV_BadStep, "two source or two destination images have different steps" );
+
+ IPPI_CALL( icvCalcOpticalFlowBM_8u32fR( (uchar*)srcA->data.ptr, (uchar*)srcB->data.ptr,
+ srcA->step, cvGetMatSize( srcA ), blockSize,
+ shiftSize, maxRange, usePrevious,
+ velx->data.fl, vely->data.fl, velx->step ));
+ __END__;
+}
+
+
+/* End of file. */
diff --git a/cv/src/cvoptflowhs.cpp b/cv/src/cvoptflowhs.cpp
new file mode 100644
index 0000000..77aa6f9
--- /dev/null
+++ b/cv/src/cvoptflowhs.cpp
@@ -0,0 +1,535 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+#define CONV( A, B, C) ( (float)( A + (B<<1) + C ) )
+
+typedef struct
+{
+ float xx;
+ float xy;
+ float yy;
+ float xt;
+ float yt;
+ float alpha; /* alpha = 1 / ( 1/lambda + xx + yy ) */
+}
+icvDerProductEx;
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvCalcOpticalFlowHS_8u32fR (Horn & Schunck method )
+// Purpose: calculate Optical flow for 2 images using Horn & Schunck algorithm
+// Context:
+// Parameters:
+// imgA - pointer to first frame ROI
+// imgB - pointer to second frame ROI
+// imgStep - width of single row of source images in bytes
+// imgSize - size of the source image ROI
+// usePrevious - use previous (input) velocity field.
+// velocityX - pointer to horizontal and
+// velocityY - vertical components of optical flow ROI
+// velStep - width of single row of velocity frames in bytes
+// lambda - Lagrangian multiplier
+// criteria - criteria of termination processmaximum number of iterations
+//
+// Returns: CV_OK - all ok
+// CV_OUTOFMEM_ERR - insufficient memory for function work
+// CV_NULLPTR_ERR - if one of input pointers is NULL
+// CV_BADSIZE_ERR - wrong input sizes interrelation
+//
+// Notes: 1.Optical flow to be computed for every pixel in ROI
+// 2.For calculating spatial derivatives we use 3x3 Sobel operator.
+// 3.We use the following border mode.
+// The last row or column is replicated for the border
+// ( IPL_BORDER_REPLICATE in IPL ).
+//
+//
+//F*/
+static CvStatus CV_STDCALL
+icvCalcOpticalFlowHS_8u32fR( uchar* imgA,
+ uchar* imgB,
+ int imgStep,
+ CvSize imgSize,
+ int usePrevious,
+ float* velocityX,
+ float* velocityY,
+ int velStep,
+ float lambda,
+ CvTermCriteria criteria )
+{
+ /* Loops indexes */
+ int i, j, k, address;
+
+ /* Buffers for Sobel calculations */
+ float *MemX[2];
+ float *MemY[2];
+
+ float ConvX, ConvY;
+ float GradX, GradY, GradT;
+
+ int imageWidth = imgSize.width;
+ int imageHeight = imgSize.height;
+
+ int ConvLine;
+ int LastLine;
+
+ int BufferSize;
+
+ float Ilambda = 1 / lambda;
+ int iter = 0;
+ int Stop;
+
+ /* buffers derivatives product */
+ icvDerProductEx *II;
+
+ float *VelBufX[2];
+ float *VelBufY[2];
+
+ /* variables for storing number of first pixel of image line */
+ int Line1;
+ int Line2;
+ int Line3;
+
+ int pixNumber;
+
+ /* auxiliary */
+ int NoMem = 0;
+
+ /* Checking bad arguments */
+ if( imgA == NULL )
+ return CV_NULLPTR_ERR;
+ if( imgB == NULL )
+ return CV_NULLPTR_ERR;
+
+ if( imgSize.width <= 0 )
+ return CV_BADSIZE_ERR;
+ if( imgSize.height <= 0 )
+ return CV_BADSIZE_ERR;
+ if( imgSize.width > imgStep )
+ return CV_BADSIZE_ERR;
+
+ if( (velStep & 3) != 0 )
+ return CV_BADSIZE_ERR;
+
+ velStep /= 4;
+
+ /****************************************************************************************/
+ /* Allocating memory for all buffers */
+ /****************************************************************************************/
+ for( k = 0; k < 2; k++ )
+ {
+ MemX[k] = (float *) cvAlloc( (imgSize.height) * sizeof( float ));
+
+ if( MemX[k] == NULL )
+ NoMem = 1;
+ MemY[k] = (float *) cvAlloc( (imgSize.width) * sizeof( float ));
+
+ if( MemY[k] == NULL )
+ NoMem = 1;
+
+ VelBufX[k] = (float *) cvAlloc( imageWidth * sizeof( float ));
+
+ if( VelBufX[k] == NULL )
+ NoMem = 1;
+ VelBufY[k] = (float *) cvAlloc( imageWidth * sizeof( float ));
+
+ if( VelBufY[k] == NULL )
+ NoMem = 1;
+ }
+
+ BufferSize = imageHeight * imageWidth;
+
+ II = (icvDerProductEx *) cvAlloc( BufferSize * sizeof( icvDerProductEx ));
+ if( (II == NULL) )
+ NoMem = 1;
+
+ if( NoMem )
+ {
+ for( k = 0; k < 2; k++ )
+ {
+ if( MemX[k] )
+ cvFree( &MemX[k] );
+
+ if( MemY[k] )
+ cvFree( &MemY[k] );
+
+ if( VelBufX[k] )
+ cvFree( &VelBufX[k] );
+
+ if( VelBufY[k] )
+ cvFree( &VelBufY[k] );
+ }
+ if( II )
+ cvFree( &II );
+ return CV_OUTOFMEM_ERR;
+ }
+/****************************************************************************************\
+* Calculate first line of memX and memY *
+\****************************************************************************************/
+ MemY[0][0] = MemY[1][0] = CONV( imgA[0], imgA[0], imgA[1] );
+ MemX[0][0] = MemX[1][0] = CONV( imgA[0], imgA[0], imgA[imgStep] );
+
+ for( j = 1; j < imageWidth - 1; j++ )
+ {
+ MemY[0][j] = MemY[1][j] = CONV( imgA[j - 1], imgA[j], imgA[j + 1] );
+ }
+
+ pixNumber = imgStep;
+ for( i = 1; i < imageHeight - 1; i++ )
+ {
+ MemX[0][i] = MemX[1][i] = CONV( imgA[pixNumber - imgStep],
+ imgA[pixNumber], imgA[pixNumber + imgStep] );
+ pixNumber += imgStep;
+ }
+
+ MemY[0][imageWidth - 1] =
+ MemY[1][imageWidth - 1] = CONV( imgA[imageWidth - 2],
+ imgA[imageWidth - 1], imgA[imageWidth - 1] );
+
+ MemX[0][imageHeight - 1] =
+ MemX[1][imageHeight - 1] = CONV( imgA[pixNumber - imgStep],
+ imgA[pixNumber], imgA[pixNumber] );
+
+
+/****************************************************************************************\
+* begin scan image, calc derivatives *
+\****************************************************************************************/
+
+ ConvLine = 0;
+ Line2 = -imgStep;
+ address = 0;
+ LastLine = imgStep * (imageHeight - 1);
+ while( ConvLine < imageHeight )
+ {
+ /*Here we calculate derivatives for line of image */
+ int memYline = (ConvLine + 1) & 1;
+
+ Line2 += imgStep;
+ Line1 = Line2 - ((Line2 == 0) ? 0 : imgStep);
+ Line3 = Line2 + ((Line2 == LastLine) ? 0 : imgStep);
+
+ /* Process first pixel */
+ ConvX = CONV( imgA[Line1 + 1], imgA[Line2 + 1], imgA[Line3 + 1] );
+ ConvY = CONV( imgA[Line3], imgA[Line3], imgA[Line3 + 1] );
+
+ GradY = (ConvY - MemY[memYline][0]) * 0.125f;
+ GradX = (ConvX - MemX[1][ConvLine]) * 0.125f;
+
+ MemY[memYline][0] = ConvY;
+ MemX[1][ConvLine] = ConvX;
+
+ GradT = (float) (imgB[Line2] - imgA[Line2]);
+
+ II[address].xx = GradX * GradX;
+ II[address].xy = GradX * GradY;
+ II[address].yy = GradY * GradY;
+ II[address].xt = GradX * GradT;
+ II[address].yt = GradY * GradT;
+
+ II[address].alpha = 1 / (Ilambda + II[address].xx + II[address].yy);
+ address++;
+
+ /* Process middle of line */
+ for( j = 1; j < imageWidth - 1; j++ )
+ {
+ ConvX = CONV( imgA[Line1 + j + 1], imgA[Line2 + j + 1], imgA[Line3 + j + 1] );
+ ConvY = CONV( imgA[Line3 + j - 1], imgA[Line3 + j], imgA[Line3 + j + 1] );
+
+ GradY = (ConvY - MemY[memYline][j]) * 0.125f;
+ GradX = (ConvX - MemX[(j - 1) & 1][ConvLine]) * 0.125f;
+
+ MemY[memYline][j] = ConvY;
+ MemX[(j - 1) & 1][ConvLine] = ConvX;
+
+ GradT = (float) (imgB[Line2 + j] - imgA[Line2 + j]);
+
+ II[address].xx = GradX * GradX;
+ II[address].xy = GradX * GradY;
+ II[address].yy = GradY * GradY;
+ II[address].xt = GradX * GradT;
+ II[address].yt = GradY * GradT;
+
+ II[address].alpha = 1 / (Ilambda + II[address].xx + II[address].yy);
+ address++;
+ }
+ /* Process last pixel of line */
+ ConvX = CONV( imgA[Line1 + imageWidth - 1], imgA[Line2 + imageWidth - 1],
+ imgA[Line3 + imageWidth - 1] );
+
+ ConvY = CONV( imgA[Line3 + imageWidth - 2], imgA[Line3 + imageWidth - 1],
+ imgA[Line3 + imageWidth - 1] );
+
+
+ GradY = (ConvY - MemY[memYline][imageWidth - 1]) * 0.125f;
+ GradX = (ConvX - MemX[(imageWidth - 2) & 1][ConvLine]) * 0.125f;
+
+ MemY[memYline][imageWidth - 1] = ConvY;
+
+ GradT = (float) (imgB[Line2 + imageWidth - 1] - imgA[Line2 + imageWidth - 1]);
+
+ II[address].xx = GradX * GradX;
+ II[address].xy = GradX * GradY;
+ II[address].yy = GradY * GradY;
+ II[address].xt = GradX * GradT;
+ II[address].yt = GradY * GradT;
+
+ II[address].alpha = 1 / (Ilambda + II[address].xx + II[address].yy);
+ address++;
+
+ ConvLine++;
+ }
+/****************************************************************************************\
+* Prepare initial approximation *
+\****************************************************************************************/
+ if( !usePrevious )
+ {
+ float *vx = velocityX;
+ float *vy = velocityY;
+
+ for( i = 0; i < imageHeight; i++ )
+ {
+ memset( vx, 0, imageWidth * sizeof( float ));
+ memset( vy, 0, imageWidth * sizeof( float ));
+
+ vx += velStep;
+ vy += velStep;
+ }
+ }
+/****************************************************************************************\
+* Perform iterations *
+\****************************************************************************************/
+ iter = 0;
+ Stop = 0;
+ LastLine = velStep * (imageHeight - 1);
+ while( !Stop )
+ {
+ float Eps = 0;
+ address = 0;
+
+ iter++;
+/****************************************************************************************\
+* begin scan velocity and update it *
+\****************************************************************************************/
+ Line2 = -velStep;
+ for( i = 0; i < imageHeight; i++ )
+ {
+ /* Here average velocity */
+
+ float averageX;
+ float averageY;
+ float tmp;
+
+ Line2 += velStep;
+ Line1 = Line2 - ((Line2 == 0) ? 0 : velStep);
+ Line3 = Line2 + ((Line2 == LastLine) ? 0 : velStep);
+ /* Process first pixel */
+ averageX = (velocityX[Line2] +
+ velocityX[Line2 + 1] + velocityX[Line1] + velocityX[Line3]) / 4;
+
+ averageY = (velocityY[Line2] +
+ velocityY[Line2 + 1] + velocityY[Line1] + velocityY[Line3]) / 4;
+
+ VelBufX[i & 1][0] = averageX -
+ (II[address].xx * averageX +
+ II[address].xy * averageY + II[address].xt) * II[address].alpha;
+
+ VelBufY[i & 1][0] = averageY -
+ (II[address].xy * averageX +
+ II[address].yy * averageY + II[address].yt) * II[address].alpha;
+
+ /* update Epsilon */
+ if( criteria.type & CV_TERMCRIT_EPS )
+ {
+ tmp = (float)fabs(velocityX[Line2] - VelBufX[i & 1][0]);
+ Eps = MAX( tmp, Eps );
+ tmp = (float)fabs(velocityY[Line2] - VelBufY[i & 1][0]);
+ Eps = MAX( tmp, Eps );
+ }
+ address++;
+ /* Process middle of line */
+ for( j = 1; j < imageWidth - 1; j++ )
+ {
+ averageX = (velocityX[Line2 + j - 1] +
+ velocityX[Line2 + j + 1] +
+ velocityX[Line1 + j] + velocityX[Line3 + j]) / 4;
+ averageY = (velocityY[Line2 + j - 1] +
+ velocityY[Line2 + j + 1] +
+ velocityY[Line1 + j] + velocityY[Line3 + j]) / 4;
+
+ VelBufX[i & 1][j] = averageX -
+ (II[address].xx * averageX +
+ II[address].xy * averageY + II[address].xt) * II[address].alpha;
+
+ VelBufY[i & 1][j] = averageY -
+ (II[address].xy * averageX +
+ II[address].yy * averageY + II[address].yt) * II[address].alpha;
+ /* update Epsilon */
+ if( criteria.type & CV_TERMCRIT_EPS )
+ {
+ tmp = (float)fabs(velocityX[Line2 + j] - VelBufX[i & 1][j]);
+ Eps = MAX( tmp, Eps );
+ tmp = (float)fabs(velocityY[Line2 + j] - VelBufY[i & 1][j]);
+ Eps = MAX( tmp, Eps );
+ }
+ address++;
+ }
+ /* Process last pixel of line */
+ averageX = (velocityX[Line2 + imageWidth - 2] +
+ velocityX[Line2 + imageWidth - 1] +
+ velocityX[Line1 + imageWidth - 1] +
+ velocityX[Line3 + imageWidth - 1]) / 4;
+
+ averageY = (velocityY[Line2 + imageWidth - 2] +
+ velocityY[Line2 + imageWidth - 1] +
+ velocityY[Line1 + imageWidth - 1] +
+ velocityY[Line3 + imageWidth - 1]) / 4;
+
+
+ VelBufX[i & 1][imageWidth - 1] = averageX -
+ (II[address].xx * averageX +
+ II[address].xy * averageY + II[address].xt) * II[address].alpha;
+
+ VelBufY[i & 1][imageWidth - 1] = averageY -
+ (II[address].xy * averageX +
+ II[address].yy * averageY + II[address].yt) * II[address].alpha;
+
+ /* update Epsilon */
+ if( criteria.type & CV_TERMCRIT_EPS )
+ {
+ tmp = (float)fabs(velocityX[Line2 + imageWidth - 1] -
+ VelBufX[i & 1][imageWidth - 1]);
+ Eps = MAX( tmp, Eps );
+ tmp = (float)fabs(velocityY[Line2 + imageWidth - 1] -
+ VelBufY[i & 1][imageWidth - 1]);
+ Eps = MAX( tmp, Eps );
+ }
+ address++;
+
+ /* store new velocity from old buffer to velocity frame */
+ if( i > 0 )
+ {
+ memcpy( &velocityX[Line1], VelBufX[(i - 1) & 1], imageWidth * sizeof( float ));
+ memcpy( &velocityY[Line1], VelBufY[(i - 1) & 1], imageWidth * sizeof( float ));
+ }
+ } /*for */
+ /* store new velocity from old buffer to velocity frame */
+ memcpy( &velocityX[imageWidth * (imageHeight - 1)],
+ VelBufX[(imageHeight - 1) & 1], imageWidth * sizeof( float ));
+
+ memcpy( &velocityY[imageWidth * (imageHeight - 1)],
+ VelBufY[(imageHeight - 1) & 1], imageWidth * sizeof( float ));
+
+ if( (criteria.type & CV_TERMCRIT_ITER) && (iter == criteria.max_iter) )
+ Stop = 1;
+ if( (criteria.type & CV_TERMCRIT_EPS) && (Eps < criteria.epsilon) )
+ Stop = 1;
+ }
+ /* Free memory */
+ for( k = 0; k < 2; k++ )
+ {
+ cvFree( &MemX[k] );
+ cvFree( &MemY[k] );
+ cvFree( &VelBufX[k] );
+ cvFree( &VelBufY[k] );
+ }
+ cvFree( &II );
+
+ return CV_OK;
+} /*icvCalcOpticalFlowHS_8u32fR*/
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvCalcOpticalFlowHS
+// Purpose: Optical flow implementation
+// Context:
+// Parameters:
+// srcA, srcB - source image
+// velx, vely - destination image
+// Returns:
+//
+// Notes:
+//F*/
+CV_IMPL void
+cvCalcOpticalFlowHS( const void* srcarrA, const void* srcarrB, int usePrevious,
+ void* velarrx, void* velarry,
+ double lambda, CvTermCriteria criteria )
+{
+ CV_FUNCNAME( "cvCalcOpticalFlowHS" );
+
+ __BEGIN__;
+
+ CvMat stubA, *srcA = (CvMat*)srcarrA;
+ CvMat stubB, *srcB = (CvMat*)srcarrB;
+ CvMat stubx, *velx = (CvMat*)velarrx;
+ CvMat stuby, *vely = (CvMat*)velarry;
+
+ CV_CALL( srcA = cvGetMat( srcA, &stubA ));
+ CV_CALL( srcB = cvGetMat( srcB, &stubB ));
+
+ CV_CALL( velx = cvGetMat( velx, &stubx ));
+ CV_CALL( vely = cvGetMat( vely, &stuby ));
+
+ if( !CV_ARE_TYPES_EQ( srcA, srcB ))
+ CV_ERROR( CV_StsUnmatchedFormats, "Source images have different formats" );
+
+ if( !CV_ARE_TYPES_EQ( velx, vely ))
+ CV_ERROR( CV_StsUnmatchedFormats, "Destination images have different formats" );
+
+ if( !CV_ARE_SIZES_EQ( srcA, srcB ) ||
+ !CV_ARE_SIZES_EQ( velx, vely ) ||
+ !CV_ARE_SIZES_EQ( srcA, velx ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( CV_MAT_TYPE( srcA->type ) != CV_8UC1 ||
+ CV_MAT_TYPE( velx->type ) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Source images must have 8uC1 type and "
+ "destination images must have 32fC1 type" );
+
+ if( srcA->step != srcB->step || velx->step != vely->step )
+ CV_ERROR( CV_BadStep, "source and destination images have different step" );
+
+ IPPI_CALL( icvCalcOpticalFlowHS_8u32fR( (uchar*)srcA->data.ptr, (uchar*)srcB->data.ptr,
+ srcA->step, cvGetMatSize( srcA ), usePrevious,
+ velx->data.fl, vely->data.fl,
+ velx->step, (float)lambda, criteria ));
+ __END__;
+}
+
+/* End of file. */
diff --git a/cv/src/cvoptflowlk.cpp b/cv/src/cvoptflowlk.cpp
new file mode 100644
index 0000000..065bfc8
--- /dev/null
+++ b/cv/src/cvoptflowlk.cpp
@@ -0,0 +1,611 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+typedef struct
+{
+ float xx;
+ float xy;
+ float yy;
+ float xt;
+ float yt;
+}
+icvDerProduct;
+
+
+#define CONV( A, B, C) ((float)( A + (B<<1) + C ))
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvCalcOpticalFlowLK_8u32fR ( Lucas & Kanade method )
+// Purpose: calculate Optical flow for 2 images using Lucas & Kanade algorithm
+// Context:
+// Parameters:
+// imgA, // pointer to first frame ROI
+// imgB, // pointer to second frame ROI
+// imgStep, // width of single row of source images in bytes
+// imgSize, // size of the source image ROI
+// winSize, // size of the averaging window used for grouping
+// velocityX, // pointer to horizontal and
+// velocityY, // vertical components of optical flow ROI
+// velStep // width of single row of velocity frames in bytes
+//
+// Returns: CV_OK - all ok
+// CV_OUTOFMEM_ERR - insufficient memory for function work
+// CV_NULLPTR_ERR - if one of input pointers is NULL
+// CV_BADSIZE_ERR - wrong input sizes interrelation
+//
+// Notes: 1.Optical flow to be computed for every pixel in ROI
+// 2.For calculating spatial derivatives we use 3x3 Sobel operator.
+// 3.We use the following border mode.
+// The last row or column is replicated for the border
+// ( IPL_BORDER_REPLICATE in IPL ).
+//
+//
+//F*/
+static CvStatus CV_STDCALL
+icvCalcOpticalFlowLK_8u32fR( uchar * imgA,
+ uchar * imgB,
+ int imgStep,
+ CvSize imgSize,
+ CvSize winSize,
+ float *velocityX,
+ float *velocityY, int velStep )
+{
+ /* Loops indexes */
+ int i, j, k;
+
+ /* Gaussian separable kernels */
+ float GaussX[16];
+ float GaussY[16];
+ float *KerX;
+ float *KerY;
+
+ /* Buffers for Sobel calculations */
+ float *MemX[2];
+ float *MemY[2];
+
+ float ConvX, ConvY;
+ float GradX, GradY, GradT;
+
+ int winWidth = winSize.width;
+ int winHeight = winSize.height;
+
+ int imageWidth = imgSize.width;
+ int imageHeight = imgSize.height;
+
+ int HorRadius = (winWidth - 1) >> 1;
+ int VerRadius = (winHeight - 1) >> 1;
+
+ int PixelLine;
+ int ConvLine;
+
+ int BufferAddress;
+
+ int BufferHeight = 0;
+ int BufferWidth;
+ int BufferSize;
+
+ /* buffers derivatives product */
+ icvDerProduct *II;
+
+ /* buffers for gaussian horisontal convolution */
+ icvDerProduct *WII;
+
+ /* variables for storing number of first pixel of image line */
+ int Line1;
+ int Line2;
+ int Line3;
+
+ /* we must have 2*2 linear system coeffs
+ | A1B2 B1 | {u} {C1} {0}
+ | | { } + { } = { }
+ | A2 A1B2 | {v} {C2} {0}
+ */
+ float A1B2, A2, B1, C1, C2;
+
+ int pixNumber;
+
+ /* auxiliary */
+ int NoMem = 0;
+
+ velStep /= sizeof(velocityX[0]);
+
+ /* Checking bad arguments */
+ if( imgA == NULL )
+ return CV_NULLPTR_ERR;
+ if( imgB == NULL )
+ return CV_NULLPTR_ERR;
+
+ if( imageHeight < winHeight )
+ return CV_BADSIZE_ERR;
+ if( imageWidth < winWidth )
+ return CV_BADSIZE_ERR;
+
+ if( winHeight >= 16 )
+ return CV_BADSIZE_ERR;
+ if( winWidth >= 16 )
+ return CV_BADSIZE_ERR;
+
+ if( !(winHeight & 1) )
+ return CV_BADSIZE_ERR;
+ if( !(winWidth & 1) )
+ return CV_BADSIZE_ERR;
+
+ BufferHeight = winHeight;
+ BufferWidth = imageWidth;
+
+ /****************************************************************************************/
+ /* Computing Gaussian coeffs */
+ /****************************************************************************************/
+ GaussX[0] = 1;
+ GaussY[0] = 1;
+ for( i = 1; i < winWidth; i++ )
+ {
+ GaussX[i] = 1;
+ for( j = i - 1; j > 0; j-- )
+ {
+ GaussX[j] += GaussX[j - 1];
+ }
+ }
+ for( i = 1; i < winHeight; i++ )
+ {
+ GaussY[i] = 1;
+ for( j = i - 1; j > 0; j-- )
+ {
+ GaussY[j] += GaussY[j - 1];
+ }
+ }
+ KerX = &GaussX[HorRadius];
+ KerY = &GaussY[VerRadius];
+
+ /****************************************************************************************/
+ /* Allocating memory for all buffers */
+ /****************************************************************************************/
+ for( k = 0; k < 2; k++ )
+ {
+ MemX[k] = (float *) cvAlloc( (imgSize.height) * sizeof( float ));
+
+ if( MemX[k] == NULL )
+ NoMem = 1;
+ MemY[k] = (float *) cvAlloc( (imgSize.width) * sizeof( float ));
+
+ if( MemY[k] == NULL )
+ NoMem = 1;
+ }
+
+ BufferSize = BufferHeight * BufferWidth;
+
+ II = (icvDerProduct *) cvAlloc( BufferSize * sizeof( icvDerProduct ));
+ WII = (icvDerProduct *) cvAlloc( BufferSize * sizeof( icvDerProduct ));
+
+
+ if( (II == NULL) || (WII == NULL) )
+ NoMem = 1;
+
+ if( NoMem )
+ {
+ for( k = 0; k < 2; k++ )
+ {
+ if( MemX[k] )
+ cvFree( &MemX[k] );
+
+ if( MemY[k] )
+ cvFree( &MemY[k] );
+ }
+ if( II )
+ cvFree( &II );
+ if( WII )
+ cvFree( &WII );
+
+ return CV_OUTOFMEM_ERR;
+ }
+
+ /****************************************************************************************/
+ /* Calculate first line of memX and memY */
+ /****************************************************************************************/
+ MemY[0][0] = MemY[1][0] = CONV( imgA[0], imgA[0], imgA[1] );
+ MemX[0][0] = MemX[1][0] = CONV( imgA[0], imgA[0], imgA[imgStep] );
+
+ for( j = 1; j < imageWidth - 1; j++ )
+ {
+ MemY[0][j] = MemY[1][j] = CONV( imgA[j - 1], imgA[j], imgA[j + 1] );
+ }
+
+ pixNumber = imgStep;
+ for( i = 1; i < imageHeight - 1; i++ )
+ {
+ MemX[0][i] = MemX[1][i] = CONV( imgA[pixNumber - imgStep],
+ imgA[pixNumber], imgA[pixNumber + imgStep] );
+ pixNumber += imgStep;
+ }
+
+ MemY[0][imageWidth - 1] =
+ MemY[1][imageWidth - 1] = CONV( imgA[imageWidth - 2],
+ imgA[imageWidth - 1], imgA[imageWidth - 1] );
+
+ MemX[0][imageHeight - 1] =
+ MemX[1][imageHeight - 1] = CONV( imgA[pixNumber - imgStep],
+ imgA[pixNumber], imgA[pixNumber] );
+
+
+ /****************************************************************************************/
+ /* begin scan image, calc derivatives and solve system */
+ /****************************************************************************************/
+
+ PixelLine = -VerRadius;
+ ConvLine = 0;
+ BufferAddress = -BufferWidth;
+
+ while( PixelLine < imageHeight )
+ {
+ if( ConvLine < imageHeight )
+ {
+ /*Here we calculate derivatives for line of image */
+ int address;
+
+ i = ConvLine;
+ int L1 = i - 1;
+ int L2 = i;
+ int L3 = i + 1;
+
+ int memYline = L3 & 1;
+
+ if( L1 < 0 )
+ L1 = 0;
+ if( L3 >= imageHeight )
+ L3 = imageHeight - 1;
+
+ BufferAddress += BufferWidth;
+ BufferAddress -= ((BufferAddress >= BufferSize) ? 0xffffffff : 0) & BufferSize;
+
+ address = BufferAddress;
+
+ Line1 = L1 * imgStep;
+ Line2 = L2 * imgStep;
+ Line3 = L3 * imgStep;
+
+ /* Process first pixel */
+ ConvX = CONV( imgA[Line1 + 1], imgA[Line2 + 1], imgA[Line3 + 1] );
+ ConvY = CONV( imgA[Line3], imgA[Line3], imgA[Line3 + 1] );
+
+ GradY = ConvY - MemY[memYline][0];
+ GradX = ConvX - MemX[1][L2];
+
+ MemY[memYline][0] = ConvY;
+ MemX[1][L2] = ConvX;
+
+ GradT = (float) (imgB[Line2] - imgA[Line2]);
+
+ II[address].xx = GradX * GradX;
+ II[address].xy = GradX * GradY;
+ II[address].yy = GradY * GradY;
+ II[address].xt = GradX * GradT;
+ II[address].yt = GradY * GradT;
+ address++;
+ /* Process middle of line */
+ for( j = 1; j < imageWidth - 1; j++ )
+ {
+ ConvX = CONV( imgA[Line1 + j + 1], imgA[Line2 + j + 1], imgA[Line3 + j + 1] );
+ ConvY = CONV( imgA[Line3 + j - 1], imgA[Line3 + j], imgA[Line3 + j + 1] );
+
+ GradY = ConvY - MemY[memYline][j];
+ GradX = ConvX - MemX[(j - 1) & 1][L2];
+
+ MemY[memYline][j] = ConvY;
+ MemX[(j - 1) & 1][L2] = ConvX;
+
+ GradT = (float) (imgB[Line2 + j] - imgA[Line2 + j]);
+
+ II[address].xx = GradX * GradX;
+ II[address].xy = GradX * GradY;
+ II[address].yy = GradY * GradY;
+ II[address].xt = GradX * GradT;
+ II[address].yt = GradY * GradT;
+
+ address++;
+ }
+ /* Process last pixel of line */
+ ConvX = CONV( imgA[Line1 + imageWidth - 1], imgA[Line2 + imageWidth - 1],
+ imgA[Line3 + imageWidth - 1] );
+
+ ConvY = CONV( imgA[Line3 + imageWidth - 2], imgA[Line3 + imageWidth - 1],
+ imgA[Line3 + imageWidth - 1] );
+
+
+ GradY = ConvY - MemY[memYline][imageWidth - 1];
+ GradX = ConvX - MemX[(imageWidth - 2) & 1][L2];
+
+ MemY[memYline][imageWidth - 1] = ConvY;
+
+ GradT = (float) (imgB[Line2 + imageWidth - 1] - imgA[Line2 + imageWidth - 1]);
+
+ II[address].xx = GradX * GradX;
+ II[address].xy = GradX * GradY;
+ II[address].yy = GradY * GradY;
+ II[address].xt = GradX * GradT;
+ II[address].yt = GradY * GradT;
+ address++;
+
+ /* End of derivatives for line */
+
+ /****************************************************************************************/
+ /* ---------Calculating horizontal convolution of processed line----------------------- */
+ /****************************************************************************************/
+ address -= BufferWidth;
+ /* process first HorRadius pixels */
+ for( j = 0; j < HorRadius; j++ )
+ {
+ int jj;
+
+ WII[address].xx = 0;
+ WII[address].xy = 0;
+ WII[address].yy = 0;
+ WII[address].xt = 0;
+ WII[address].yt = 0;
+
+ for( jj = -j; jj <= HorRadius; jj++ )
+ {
+ float Ker = KerX[jj];
+
+ WII[address].xx += II[address + jj].xx * Ker;
+ WII[address].xy += II[address + jj].xy * Ker;
+ WII[address].yy += II[address + jj].yy * Ker;
+ WII[address].xt += II[address + jj].xt * Ker;
+ WII[address].yt += II[address + jj].yt * Ker;
+ }
+ address++;
+ }
+ /* process inner part of line */
+ for( j = HorRadius; j < imageWidth - HorRadius; j++ )
+ {
+ int jj;
+ float Ker0 = KerX[0];
+
+ WII[address].xx = 0;
+ WII[address].xy = 0;
+ WII[address].yy = 0;
+ WII[address].xt = 0;
+ WII[address].yt = 0;
+
+ for( jj = 1; jj <= HorRadius; jj++ )
+ {
+ float Ker = KerX[jj];
+
+ WII[address].xx += (II[address - jj].xx + II[address + jj].xx) * Ker;
+ WII[address].xy += (II[address - jj].xy + II[address + jj].xy) * Ker;
+ WII[address].yy += (II[address - jj].yy + II[address + jj].yy) * Ker;
+ WII[address].xt += (II[address - jj].xt + II[address + jj].xt) * Ker;
+ WII[address].yt += (II[address - jj].yt + II[address + jj].yt) * Ker;
+ }
+ WII[address].xx += II[address].xx * Ker0;
+ WII[address].xy += II[address].xy * Ker0;
+ WII[address].yy += II[address].yy * Ker0;
+ WII[address].xt += II[address].xt * Ker0;
+ WII[address].yt += II[address].yt * Ker0;
+
+ address++;
+ }
+ /* process right side */
+ for( j = imageWidth - HorRadius; j < imageWidth; j++ )
+ {
+ int jj;
+
+ WII[address].xx = 0;
+ WII[address].xy = 0;
+ WII[address].yy = 0;
+ WII[address].xt = 0;
+ WII[address].yt = 0;
+
+ for( jj = -HorRadius; jj < imageWidth - j; jj++ )
+ {
+ float Ker = KerX[jj];
+
+ WII[address].xx += II[address + jj].xx * Ker;
+ WII[address].xy += II[address + jj].xy * Ker;
+ WII[address].yy += II[address + jj].yy * Ker;
+ WII[address].xt += II[address + jj].xt * Ker;
+ WII[address].yt += II[address + jj].yt * Ker;
+ }
+ address++;
+ }
+ }
+
+ /****************************************************************************************/
+ /* Calculating velocity line */
+ /****************************************************************************************/
+ if( PixelLine >= 0 )
+ {
+ int USpace;
+ int BSpace;
+ int address;
+
+ if( PixelLine < VerRadius )
+ USpace = PixelLine;
+ else
+ USpace = VerRadius;
+
+ if( PixelLine >= imageHeight - VerRadius )
+ BSpace = imageHeight - PixelLine - 1;
+ else
+ BSpace = VerRadius;
+
+ address = ((PixelLine - USpace) % BufferHeight) * BufferWidth;
+ for( j = 0; j < imageWidth; j++ )
+ {
+ int addr = address;
+
+ A1B2 = 0;
+ A2 = 0;
+ B1 = 0;
+ C1 = 0;
+ C2 = 0;
+
+ for( i = -USpace; i <= BSpace; i++ )
+ {
+ A2 += WII[addr + j].xx * KerY[i];
+ A1B2 += WII[addr + j].xy * KerY[i];
+ B1 += WII[addr + j].yy * KerY[i];
+ C2 += WII[addr + j].xt * KerY[i];
+ C1 += WII[addr + j].yt * KerY[i];
+
+ addr += BufferWidth;
+ addr -= ((addr >= BufferSize) ? 0xffffffff : 0) & BufferSize;
+ }
+ /****************************************************************************************\
+ * Solve Linear System *
+ \****************************************************************************************/
+ {
+ float delta = (A1B2 * A1B2 - A2 * B1);
+
+ if( delta )
+ {
+ /* system is not singular - solving by Kramer method */
+ float deltaX;
+ float deltaY;
+ float Idelta = 8 / delta;
+
+ deltaX = -(C1 * A1B2 - C2 * B1);
+ deltaY = -(A1B2 * C2 - A2 * C1);
+
+ velocityX[j] = deltaX * Idelta;
+ velocityY[j] = deltaY * Idelta;
+ }
+ else
+ {
+ /* singular system - find optical flow in gradient direction */
+ float Norm = (A1B2 + A2) * (A1B2 + A2) + (B1 + A1B2) * (B1 + A1B2);
+
+ if( Norm )
+ {
+ float IGradNorm = 8 / Norm;
+ float temp = -(C1 + C2) * IGradNorm;
+
+ velocityX[j] = (A1B2 + A2) * temp;
+ velocityY[j] = (B1 + A1B2) * temp;
+
+ }
+ else
+ {
+ velocityX[j] = 0;
+ velocityY[j] = 0;
+ }
+ }
+ }
+ /****************************************************************************************\
+ * End of Solving Linear System *
+ \****************************************************************************************/
+ } /*for */
+ velocityX += velStep;
+ velocityY += velStep;
+ } /*for */
+ PixelLine++;
+ ConvLine++;
+ }
+
+ /* Free memory */
+ for( k = 0; k < 2; k++ )
+ {
+ cvFree( &MemX[k] );
+ cvFree( &MemY[k] );
+ }
+ cvFree( &II );
+ cvFree( &WII );
+
+ return CV_OK;
+} /*icvCalcOpticalFlowLK_8u32fR*/
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvCalcOpticalFlowLK
+// Purpose: Optical flow implementation
+// Context:
+// Parameters:
+// srcA, srcB - source image
+// velx, vely - destination image
+// Returns:
+//
+// Notes:
+//F*/
+CV_IMPL void
+cvCalcOpticalFlowLK( const void* srcarrA, const void* srcarrB, CvSize winSize,
+ void* velarrx, void* velarry )
+{
+ CV_FUNCNAME( "cvCalcOpticalFlowLK" );
+
+ __BEGIN__;
+
+ CvMat stubA, *srcA = (CvMat*)srcarrA;
+ CvMat stubB, *srcB = (CvMat*)srcarrB;
+ CvMat stubx, *velx = (CvMat*)velarrx;
+ CvMat stuby, *vely = (CvMat*)velarry;
+
+ CV_CALL( srcA = cvGetMat( srcA, &stubA ));
+ CV_CALL( srcB = cvGetMat( srcB, &stubB ));
+
+ CV_CALL( velx = cvGetMat( velx, &stubx ));
+ CV_CALL( vely = cvGetMat( vely, &stuby ));
+
+ if( !CV_ARE_TYPES_EQ( srcA, srcB ))
+ CV_ERROR( CV_StsUnmatchedFormats, "Source images have different formats" );
+
+ if( !CV_ARE_TYPES_EQ( velx, vely ))
+ CV_ERROR( CV_StsUnmatchedFormats, "Destination images have different formats" );
+
+ if( !CV_ARE_SIZES_EQ( srcA, srcB ) ||
+ !CV_ARE_SIZES_EQ( velx, vely ) ||
+ !CV_ARE_SIZES_EQ( srcA, velx ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( CV_MAT_TYPE( srcA->type ) != CV_8UC1 ||
+ CV_MAT_TYPE( velx->type ) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Source images must have 8uC1 type and "
+ "destination images must have 32fC1 type" );
+
+ if( srcA->step != srcB->step || velx->step != vely->step )
+ CV_ERROR( CV_BadStep, "source and destination images have different step" );
+
+ IPPI_CALL( icvCalcOpticalFlowLK_8u32fR( (uchar*)srcA->data.ptr, (uchar*)srcB->data.ptr,
+ srcA->step, cvGetMatSize( srcA ), winSize,
+ velx->data.fl, vely->data.fl, velx->step ));
+
+ __END__;
+}
+
+/* End of file. */
diff --git a/cv/src/cvpgh.cpp b/cv/src/cvpgh.cpp
new file mode 100644
index 0000000..8caaf4f
--- /dev/null
+++ b/cv/src/cvpgh.cpp
@@ -0,0 +1,363 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+#define _CV_ACOS_TABLE_SIZE 513
+
+static const float icv_acos_table[_CV_ACOS_TABLE_SIZE] = {
+ 3.14159265f, 3.05317551f, 3.01651113f, 2.98834964f, 2.96458497f, 2.94362719f,
+ 2.92466119f, 2.90720289f, 2.89093699f, 2.87564455f, 2.86116621f, 2.84738169f,
+ 2.83419760f, 2.82153967f, 2.80934770f, 2.79757211f, 2.78617145f, 2.77511069f,
+ 2.76435988f, 2.75389319f, 2.74368816f, 2.73372510f, 2.72398665f, 2.71445741f,
+ 2.70512362f, 2.69597298f, 2.68699438f, 2.67817778f, 2.66951407f, 2.66099493f,
+ 2.65261279f, 2.64436066f, 2.63623214f, 2.62822133f, 2.62032277f, 2.61253138f,
+ 2.60484248f, 2.59725167f, 2.58975488f, 2.58234828f, 2.57502832f, 2.56779164f,
+ 2.56063509f, 2.55355572f, 2.54655073f, 2.53961750f, 2.53275354f, 2.52595650f,
+ 2.51922417f, 2.51255441f, 2.50594525f, 2.49939476f, 2.49290115f, 2.48646269f,
+ 2.48007773f, 2.47374472f, 2.46746215f, 2.46122860f, 2.45504269f, 2.44890314f,
+ 2.44280867f, 2.43675809f, 2.43075025f, 2.42478404f, 2.41885841f, 2.41297232f,
+ 2.40712480f, 2.40131491f, 2.39554173f, 2.38980439f, 2.38410204f, 2.37843388f,
+ 2.37279910f, 2.36719697f, 2.36162673f, 2.35608768f, 2.35057914f, 2.34510044f,
+ 2.33965094f, 2.33423003f, 2.32883709f, 2.32347155f, 2.31813284f, 2.31282041f,
+ 2.30753373f, 2.30227228f, 2.29703556f, 2.29182309f, 2.28663439f, 2.28146900f,
+ 2.27632647f, 2.27120637f, 2.26610827f, 2.26103177f, 2.25597646f, 2.25094195f,
+ 2.24592786f, 2.24093382f, 2.23595946f, 2.23100444f, 2.22606842f, 2.22115104f,
+ 2.21625199f, 2.21137096f, 2.20650761f, 2.20166166f, 2.19683280f, 2.19202074f,
+ 2.18722520f, 2.18244590f, 2.17768257f, 2.17293493f, 2.16820274f, 2.16348574f,
+ 2.15878367f, 2.15409630f, 2.14942338f, 2.14476468f, 2.14011997f, 2.13548903f,
+ 2.13087163f, 2.12626757f, 2.12167662f, 2.11709859f, 2.11253326f, 2.10798044f,
+ 2.10343994f, 2.09891156f, 2.09439510f, 2.08989040f, 2.08539725f, 2.08091550f,
+ 2.07644495f, 2.07198545f, 2.06753681f, 2.06309887f, 2.05867147f, 2.05425445f,
+ 2.04984765f, 2.04545092f, 2.04106409f, 2.03668703f, 2.03231957f, 2.02796159f,
+ 2.02361292f, 2.01927344f, 2.01494300f, 2.01062146f, 2.00630870f, 2.00200457f,
+ 1.99770895f, 1.99342171f, 1.98914271f, 1.98487185f, 1.98060898f, 1.97635399f,
+ 1.97210676f, 1.96786718f, 1.96363511f, 1.95941046f, 1.95519310f, 1.95098292f,
+ 1.94677982f, 1.94258368f, 1.93839439f, 1.93421185f, 1.93003595f, 1.92586659f,
+ 1.92170367f, 1.91754708f, 1.91339673f, 1.90925250f, 1.90511432f, 1.90098208f,
+ 1.89685568f, 1.89273503f, 1.88862003f, 1.88451060f, 1.88040664f, 1.87630806f,
+ 1.87221477f, 1.86812668f, 1.86404371f, 1.85996577f, 1.85589277f, 1.85182462f,
+ 1.84776125f, 1.84370256f, 1.83964848f, 1.83559892f, 1.83155381f, 1.82751305f,
+ 1.82347658f, 1.81944431f, 1.81541617f, 1.81139207f, 1.80737194f, 1.80335570f,
+ 1.79934328f, 1.79533460f, 1.79132959f, 1.78732817f, 1.78333027f, 1.77933581f,
+ 1.77534473f, 1.77135695f, 1.76737240f, 1.76339101f, 1.75941271f, 1.75543743f,
+ 1.75146510f, 1.74749565f, 1.74352900f, 1.73956511f, 1.73560389f, 1.73164527f,
+ 1.72768920f, 1.72373560f, 1.71978441f, 1.71583556f, 1.71188899f, 1.70794462f,
+ 1.70400241f, 1.70006228f, 1.69612416f, 1.69218799f, 1.68825372f, 1.68432127f,
+ 1.68039058f, 1.67646160f, 1.67253424f, 1.66860847f, 1.66468420f, 1.66076139f,
+ 1.65683996f, 1.65291986f, 1.64900102f, 1.64508338f, 1.64116689f, 1.63725148f,
+ 1.63333709f, 1.62942366f, 1.62551112f, 1.62159943f, 1.61768851f, 1.61377831f,
+ 1.60986877f, 1.60595982f, 1.60205142f, 1.59814349f, 1.59423597f, 1.59032882f,
+ 1.58642196f, 1.58251535f, 1.57860891f, 1.57470259f, 1.57079633f, 1.56689007f,
+ 1.56298375f, 1.55907731f, 1.55517069f, 1.55126383f, 1.54735668f, 1.54344917f,
+ 1.53954124f, 1.53563283f, 1.53172389f, 1.52781434f, 1.52390414f, 1.51999323f,
+ 1.51608153f, 1.51216900f, 1.50825556f, 1.50434117f, 1.50042576f, 1.49650927f,
+ 1.49259163f, 1.48867280f, 1.48475270f, 1.48083127f, 1.47690845f, 1.47298419f,
+ 1.46905841f, 1.46513106f, 1.46120207f, 1.45727138f, 1.45333893f, 1.44940466f,
+ 1.44546850f, 1.44153038f, 1.43759024f, 1.43364803f, 1.42970367f, 1.42575709f,
+ 1.42180825f, 1.41785705f, 1.41390346f, 1.40994738f, 1.40598877f, 1.40202755f,
+ 1.39806365f, 1.39409701f, 1.39012756f, 1.38615522f, 1.38217994f, 1.37820164f,
+ 1.37422025f, 1.37023570f, 1.36624792f, 1.36225684f, 1.35826239f, 1.35426449f,
+ 1.35026307f, 1.34625805f, 1.34224937f, 1.33823695f, 1.33422072f, 1.33020059f,
+ 1.32617649f, 1.32214834f, 1.31811607f, 1.31407960f, 1.31003885f, 1.30599373f,
+ 1.30194417f, 1.29789009f, 1.29383141f, 1.28976803f, 1.28569989f, 1.28162688f,
+ 1.27754894f, 1.27346597f, 1.26937788f, 1.26528459f, 1.26118602f, 1.25708205f,
+ 1.25297262f, 1.24885763f, 1.24473698f, 1.24061058f, 1.23647833f, 1.23234015f,
+ 1.22819593f, 1.22404557f, 1.21988898f, 1.21572606f, 1.21155670f, 1.20738080f,
+ 1.20319826f, 1.19900898f, 1.19481283f, 1.19060973f, 1.18639955f, 1.18218219f,
+ 1.17795754f, 1.17372548f, 1.16948589f, 1.16523866f, 1.16098368f, 1.15672081f,
+ 1.15244994f, 1.14817095f, 1.14388370f, 1.13958808f, 1.13528396f, 1.13097119f,
+ 1.12664966f, 1.12231921f, 1.11797973f, 1.11363107f, 1.10927308f, 1.10490563f,
+ 1.10052856f, 1.09614174f, 1.09174500f, 1.08733820f, 1.08292118f, 1.07849378f,
+ 1.07405585f, 1.06960721f, 1.06514770f, 1.06067715f, 1.05619540f, 1.05170226f,
+ 1.04719755f, 1.04268110f, 1.03815271f, 1.03361221f, 1.02905939f, 1.02449407f,
+ 1.01991603f, 1.01532509f, 1.01072102f, 1.00610363f, 1.00147268f, 0.99682798f,
+ 0.99216928f, 0.98749636f, 0.98280898f, 0.97810691f, 0.97338991f, 0.96865772f,
+ 0.96391009f, 0.95914675f, 0.95436745f, 0.94957191f, 0.94475985f, 0.93993099f,
+ 0.93508504f, 0.93022170f, 0.92534066f, 0.92044161f, 0.91552424f, 0.91058821f,
+ 0.90563319f, 0.90065884f, 0.89566479f, 0.89065070f, 0.88561619f, 0.88056088f,
+ 0.87548438f, 0.87038629f, 0.86526619f, 0.86012366f, 0.85495827f, 0.84976956f,
+ 0.84455709f, 0.83932037f, 0.83405893f, 0.82877225f, 0.82345981f, 0.81812110f,
+ 0.81275556f, 0.80736262f, 0.80194171f, 0.79649221f, 0.79101352f, 0.78550497f,
+ 0.77996593f, 0.77439569f, 0.76879355f, 0.76315878f, 0.75749061f, 0.75178826f,
+ 0.74605092f, 0.74027775f, 0.73446785f, 0.72862033f, 0.72273425f, 0.71680861f,
+ 0.71084240f, 0.70483456f, 0.69878398f, 0.69268952f, 0.68654996f, 0.68036406f,
+ 0.67413051f, 0.66784794f, 0.66151492f, 0.65512997f, 0.64869151f, 0.64219789f,
+ 0.63564741f, 0.62903824f, 0.62236849f, 0.61563615f, 0.60883911f, 0.60197515f,
+ 0.59504192f, 0.58803694f, 0.58095756f, 0.57380101f, 0.56656433f, 0.55924437f,
+ 0.55183778f, 0.54434099f, 0.53675018f, 0.52906127f, 0.52126988f, 0.51337132f,
+ 0.50536051f, 0.49723200f, 0.48897987f, 0.48059772f, 0.47207859f, 0.46341487f,
+ 0.45459827f, 0.44561967f, 0.43646903f, 0.42713525f, 0.41760600f, 0.40786755f,
+ 0.39790449f, 0.38769946f, 0.37723277f, 0.36648196f, 0.35542120f, 0.34402054f,
+ 0.33224495f, 0.32005298f, 0.30739505f, 0.29421096f, 0.28042645f, 0.26594810f,
+ 0.25065566f, 0.23438976f, 0.21693146f, 0.19796546f, 0.17700769f, 0.15324301f,
+ 0.12508152f, 0.08841715f, 0.00000000f
+};
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvCalcPGH
+// Purpose:
+// Calculates PGH(pairwise geometric histogram) for contour given.
+// Context:
+// Parameters:
+// contour - pointer to input contour object.
+// pgh - output histogram
+// ang_dim - number of angle bins (vertical size of histogram)
+// dist_dim - number of distance bins (horizontal size of histogram)
+// Returns:
+// CV_OK or error code
+// Notes:
+//F*/
+static CvStatus
+icvCalcPGH( const CvSeq * contour, float *pgh, int angle_dim, int dist_dim )
+{
+ char local_buffer[(1 << 14) + 32];
+ float *local_buffer_ptr = (float *)cvAlignPtr(local_buffer,32);
+ float *buffer = local_buffer_ptr;
+ double angle_scale = (angle_dim - 0.51) / icv_acos_table[0];
+ double dist_scale = DBL_EPSILON;
+ int buffer_size;
+ int i, count, pass;
+ int *pghi = (int *) pgh;
+ int hist_size = angle_dim * dist_dim;
+ CvSeqReader reader1, reader2; /* external and internal readers */
+
+ if( !contour || !pgh )
+ return CV_NULLPTR_ERR;
+
+ if( angle_dim <= 0 || angle_dim > 180 || dist_dim <= 0 )
+ return CV_BADRANGE_ERR;
+
+ if( !CV_IS_SEQ_POLYGON( contour ))
+ return CV_BADFLAG_ERR;
+
+ memset( pgh, 0, hist_size * sizeof( pgh[0] ));
+
+ count = contour->total;
+
+ /* allocate buffer for distances */
+ buffer_size = count * sizeof( float );
+
+ if( buffer_size > (int)sizeof(local_buffer) - 32 )
+ {
+ buffer = (float *) cvAlloc( buffer_size );
+ if( !buffer )
+ return CV_OUTOFMEM_ERR;
+ }
+
+ cvStartReadSeq( contour, &reader1, 0 );
+ cvStartReadSeq( contour, &reader2, 0 );
+
+ /* calc & store squared edge lengths, calculate maximal distance between edges */
+ for( i = 0; i < count; i++ )
+ {
+ CvPoint pt1, pt2;
+ double dx, dy;
+
+ CV_READ_EDGE( pt1, pt2, reader1 );
+
+ dx = pt2.x - pt1.x;
+ dy = pt2.y - pt1.y;
+ buffer[i] = (float)(1./sqrt(dx * dx + dy * dy));
+ }
+
+ /*
+ do 2 passes.
+ First calculates maximal distance.
+ Second calculates histogram itself.
+ */
+ for( pass = 1; pass <= 2; pass++ )
+ {
+ double dist_coeff = 0, angle_coeff = 0;
+
+ /* run external loop */
+ for( i = 0; i < count; i++ )
+ {
+ CvPoint pt1, pt2;
+ int dx, dy;
+ int dist = 0;
+
+ CV_READ_EDGE( pt1, pt2, reader1 );
+
+ dx = pt2.x - pt1.x;
+ dy = pt2.y - pt1.y;
+
+ if( (dx | dy) != 0 )
+ {
+ int j;
+
+ if( pass == 2 )
+ {
+ dist_coeff = buffer[i] * dist_scale;
+ angle_coeff = buffer[i] * (_CV_ACOS_TABLE_SIZE / 2);
+ }
+
+ /* run internal loop (for current edge) */
+ for( j = 0; j < count; j++ )
+ {
+ CvPoint pt3, pt4;
+
+ CV_READ_EDGE( pt3, pt4, reader2 );
+
+ if( i != j ) /* process edge pair */
+ {
+ int d1 = (pt3.y - pt1.y) * dx - (pt3.x - pt1.x) * dy;
+ int d2 = (pt4.y - pt1.y) * dx - (pt2.x - pt1.x) * dy;
+ int cross_flag;
+ int *hist_row = 0;
+
+ if( pass == 2 )
+ {
+ int dp = (pt4.x - pt3.x) * dx + (pt4.y - pt3.y) * dy;
+
+ dp = cvRound( dp * angle_coeff * buffer[j] ) +
+ (_CV_ACOS_TABLE_SIZE / 2);
+ dp = MAX( dp, 0 );
+ dp = MIN( dp, _CV_ACOS_TABLE_SIZE - 1 );
+ hist_row = pghi + dist_dim *
+ cvRound( icv_acos_table[dp] * angle_scale );
+
+ d1 = cvRound( d1 * dist_coeff );
+ d2 = cvRound( d2 * dist_coeff );
+ }
+
+ cross_flag = (d1 ^ d2) < 0;
+
+ d1 = CV_IABS( d1 );
+ d2 = CV_IABS( d2 );
+
+ if( pass == 2 )
+ {
+ if( d1 >= dist_dim )
+ d1 = dist_dim - 1;
+ if( d2 >= dist_dim )
+ d2 = dist_dim - 1;
+
+ if( !cross_flag )
+ {
+ if( d1 > d2 ) /* make d1 <= d2 */
+ {
+ d1 ^= d2;
+ d2 ^= d1;
+ d1 ^= d2;
+ }
+
+ for( ; d1 <= d2; d1++ )
+ hist_row[d1]++;
+ }
+ else
+ {
+ for( ; d1 >= 0; d1-- )
+ hist_row[d1]++;
+ for( ; d2 >= 0; d2-- )
+ hist_row[d2]++;
+ }
+ }
+ else /* 1st pass */
+ {
+ d1 = CV_IMAX( d1, d2 );
+ dist = CV_IMAX( dist, d1 );
+ }
+ } /* end of processing of edge pair */
+
+ } /* end of internal loop */
+
+ if( pass == 1 )
+ {
+ double scale = dist * buffer[i];
+
+ dist_scale = MAX( dist_scale, scale );
+ }
+ }
+ } /* end of external loop */
+
+ if( pass == 1 )
+ {
+ dist_scale = (dist_dim - 0.51) / dist_scale;
+ }
+
+ } /* end of pass on loops */
+
+
+ /* convert hist to floats */
+ for( i = 0; i < hist_size; i++ )
+ {
+ ((float *) pghi)[i] = (float) pghi[i];
+ }
+
+ if( buffer != local_buffer_ptr )
+ cvFree( &buffer );
+
+ return CV_OK;
+}
+
+
+CV_IMPL void
+cvCalcPGH( const CvSeq * contour, CvHistogram * hist )
+{
+ CV_FUNCNAME( "cvCalcPGH" );
+
+ __BEGIN__;
+
+ int size[CV_MAX_DIM];
+ int dims;
+
+ if( !CV_IS_HIST(hist))
+ CV_ERROR( CV_StsBadArg, "The histogram header is invalid " );
+
+ if( CV_IS_SPARSE_HIST( hist ))
+ CV_ERROR( CV_StsUnsupportedFormat, "Sparse histogram are not supported" );
+
+ dims = cvGetDims( hist->bins, size );
+
+ if( dims != 2 )
+ CV_ERROR( CV_StsBadSize, "The histogram must be two-dimensional" );
+
+ if( !CV_IS_SEQ_POLYGON( contour ) || CV_SEQ_ELTYPE( contour ) != CV_32SC2 )
+ CV_ERROR( CV_StsUnsupportedFormat, "The contour is not valid or the point type is not supported" );
+
+ IPPI_CALL( icvCalcPGH( contour, ((CvMatND*)(hist->bins))->data.fl, size[0], size[1] ));
+
+ __END__;
+}
+
+
+/* End of file. */
diff --git a/cv/src/cvposit.cpp b/cv/src/cvposit.cpp
new file mode 100644
index 0000000..65da46d
--- /dev/null
+++ b/cv/src/cvposit.cpp
@@ -0,0 +1,378 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+/* POSIT structure */
+struct CvPOSITObject
+{
+ int N;
+ float* inv_matr;
+ float* obj_vecs;
+ float* img_vecs;
+};
+
+static void icvPseudoInverse3D( float *a, float *b, int n, int method );
+
+static CvStatus icvCreatePOSITObject( CvPoint3D32f *points,
+ int numPoints,
+ CvPOSITObject **ppObject )
+{
+ int i;
+
+ /* Compute size of required memory */
+ /* buffer for inverse matrix = N*3*float */
+ /* buffer for storing weakImagePoints = numPoints * 2 * float */
+ /* buffer for storing object vectors = N*3*float */
+ /* buffer for storing image vectors = N*2*float */
+
+ int N = numPoints - 1;
+ int inv_matr_size = N * 3 * sizeof( float );
+ int obj_vec_size = inv_matr_size;
+ int img_vec_size = N * 2 * sizeof( float );
+ CvPOSITObject *pObject;
+
+ /* check bad arguments */
+ if( points == NULL )
+ return CV_NULLPTR_ERR;
+ if( numPoints < 4 )
+ return CV_BADSIZE_ERR;
+ if( ppObject == NULL )
+ return CV_NULLPTR_ERR;
+
+ /* memory allocation */
+ pObject = (CvPOSITObject *) cvAlloc( sizeof( CvPOSITObject ) +
+ inv_matr_size + obj_vec_size + img_vec_size );
+
+ if( !pObject )
+ return CV_OUTOFMEM_ERR;
+
+ /* part the memory between all structures */
+ pObject->N = N;
+ pObject->inv_matr = (float *) ((char *) pObject + sizeof( CvPOSITObject ));
+ pObject->obj_vecs = (float *) ((char *) (pObject->inv_matr) + inv_matr_size);
+ pObject->img_vecs = (float *) ((char *) (pObject->obj_vecs) + obj_vec_size);
+
+/****************************************************************************************\
+* Construct object vectors from object points *
+\****************************************************************************************/
+ for( i = 0; i < numPoints - 1; i++ )
+ {
+ pObject->obj_vecs[i] = points[i + 1].x - points[0].x;
+ pObject->obj_vecs[N + i] = points[i + 1].y - points[0].y;
+ pObject->obj_vecs[2 * N + i] = points[i + 1].z - points[0].z;
+ }
+/****************************************************************************************\
+* Compute pseudoinverse matrix *
+\****************************************************************************************/
+ icvPseudoInverse3D( pObject->obj_vecs, pObject->inv_matr, N, 0 );
+
+ *ppObject = pObject;
+ return CV_NO_ERR;
+}
+
+
+static CvStatus icvPOSIT( CvPOSITObject *pObject, CvPoint2D32f *imagePoints,
+ float focalLength, CvTermCriteria criteria,
+ CvMatr32f rotation, CvVect32f translation )
+{
+ int i, j, k;
+ int count = 0, converged = 0;
+ float inorm, jnorm, invInorm, invJnorm, invScale, scale = 0, inv_Z = 0;
+ float diff = (float)criteria.epsilon;
+ float inv_focalLength = 1 / focalLength;
+
+ /* init variables */
+ int N = pObject->N;
+ float *objectVectors = pObject->obj_vecs;
+ float *invMatrix = pObject->inv_matr;
+ float *imgVectors = pObject->img_vecs;
+
+ /* Check bad arguments */
+ if( imagePoints == NULL )
+ return CV_NULLPTR_ERR;
+ if( pObject == NULL )
+ return CV_NULLPTR_ERR;
+ if( focalLength <= 0 )
+ return CV_BADFACTOR_ERR;
+ if( !rotation )
+ return CV_NULLPTR_ERR;
+ if( !translation )
+ return CV_NULLPTR_ERR;
+ if( (criteria.type == 0) || (criteria.type > (CV_TERMCRIT_ITER | CV_TERMCRIT_EPS)))
+ return CV_BADFLAG_ERR;
+ if( (criteria.type & CV_TERMCRIT_EPS) && criteria.epsilon < 0 )
+ return CV_BADFACTOR_ERR;
+ if( (criteria.type & CV_TERMCRIT_ITER) && criteria.max_iter <= 0 )
+ return CV_BADFACTOR_ERR;
+
+ while( !converged )
+ {
+ if( count == 0 )
+ {
+ /* subtract out origin to get image vectors */
+ for( i = 0; i < N; i++ )
+ {
+ imgVectors[i] = imagePoints[i + 1].x - imagePoints[0].x;
+ imgVectors[N + i] = imagePoints[i + 1].y - imagePoints[0].y;
+ }
+ }
+ else
+ {
+ diff = 0;
+ /* Compute new SOP (scaled orthograthic projection) image from pose */
+ for( i = 0; i < N; i++ )
+ {
+ /* objectVector * k */
+ float old;
+ float tmp = objectVectors[i] * rotation[6] /*[2][0]*/ +
+ objectVectors[N + i] * rotation[7] /*[2][1]*/ +
+ objectVectors[2 * N + i] * rotation[8] /*[2][2]*/;
+
+ tmp *= inv_Z;
+ tmp += 1;
+
+ old = imgVectors[i];
+ imgVectors[i] = imagePoints[i + 1].x * tmp - imagePoints[0].x;
+
+ diff = MAX( diff, (float) fabs( imgVectors[i] - old ));
+
+ old = imgVectors[N + i];
+ imgVectors[N + i] = imagePoints[i + 1].y * tmp - imagePoints[0].y;
+
+ diff = MAX( diff, (float) fabs( imgVectors[N + i] - old ));
+ }
+ }
+
+ /* calculate I and J vectors */
+ for( i = 0; i < 2; i++ )
+ {
+ for( j = 0; j < 3; j++ )
+ {
+ rotation[3*i+j] /*[i][j]*/ = 0;
+ for( k = 0; k < N; k++ )
+ {
+ rotation[3*i+j] /*[i][j]*/ += invMatrix[j * N + k] * imgVectors[i * N + k];
+ }
+ }
+ }
+
+ inorm = rotation[0] /*[0][0]*/ * rotation[0] /*[0][0]*/ +
+ rotation[1] /*[0][1]*/ * rotation[1] /*[0][1]*/ +
+ rotation[2] /*[0][2]*/ * rotation[2] /*[0][2]*/;
+
+ jnorm = rotation[3] /*[1][0]*/ * rotation[3] /*[1][0]*/ +
+ rotation[4] /*[1][1]*/ * rotation[4] /*[1][1]*/ +
+ rotation[5] /*[1][2]*/ * rotation[5] /*[1][2]*/;
+
+ invInorm = cvInvSqrt( inorm );
+ invJnorm = cvInvSqrt( jnorm );
+
+ inorm *= invInorm;
+ jnorm *= invJnorm;
+
+ rotation[0] /*[0][0]*/ *= invInorm;
+ rotation[1] /*[0][1]*/ *= invInorm;
+ rotation[2] /*[0][2]*/ *= invInorm;
+
+ rotation[3] /*[1][0]*/ *= invJnorm;
+ rotation[4] /*[1][1]*/ *= invJnorm;
+ rotation[5] /*[1][2]*/ *= invJnorm;
+
+ /* row2 = row0 x row1 (cross product) */
+ rotation[6] /*->m[2][0]*/ = rotation[1] /*->m[0][1]*/ * rotation[5] /*->m[1][2]*/ -
+ rotation[2] /*->m[0][2]*/ * rotation[4] /*->m[1][1]*/;
+
+ rotation[7] /*->m[2][1]*/ = rotation[2] /*->m[0][2]*/ * rotation[3] /*->m[1][0]*/ -
+ rotation[0] /*->m[0][0]*/ * rotation[5] /*->m[1][2]*/;
+
+ rotation[8] /*->m[2][2]*/ = rotation[0] /*->m[0][0]*/ * rotation[4] /*->m[1][1]*/ -
+ rotation[1] /*->m[0][1]*/ * rotation[3] /*->m[1][0]*/;
+
+ scale = (inorm + jnorm) / 2.0f;
+ inv_Z = scale * inv_focalLength;
+
+ count++;
+ converged = ((criteria.type & CV_TERMCRIT_EPS) && (diff < criteria.epsilon));
+ converged |= ((criteria.type & CV_TERMCRIT_ITER) && (count == criteria.max_iter));
+ }
+ invScale = 1 / scale;
+ translation[0] = imagePoints[0].x * invScale;
+ translation[1] = imagePoints[0].y * invScale;
+ translation[2] = 1 / inv_Z;
+
+ return CV_NO_ERR;
+}
+
+
+static CvStatus icvReleasePOSITObject( CvPOSITObject ** ppObject )
+{
+ cvFree( ppObject );
+ return CV_NO_ERR;
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvPseudoInverse3D
+// Purpose: Pseudoinverse N x 3 matrix N >= 3
+// Context:
+// Parameters:
+// a - input matrix
+// b - pseudoinversed a
+// n - number of rows in a
+// method - if 0, then b = inv(transpose(a)*a) * transpose(a)
+// if 1, then SVD used.
+// Returns:
+// Notes: Both matrix are stored by n-dimensional vectors.
+// Now only method == 0 supported.
+//F*/
+void
+icvPseudoInverse3D( float *a, float *b, int n, int method )
+{
+ int k;
+
+ if( method == 0 )
+ {
+ float ata00 = 0;
+ float ata11 = 0;
+ float ata22 = 0;
+ float ata01 = 0;
+ float ata02 = 0;
+ float ata12 = 0;
+ float det = 0;
+
+ /* compute matrix ata = transpose(a) * a */
+ for( k = 0; k < n; k++ )
+ {
+ float a0 = a[k];
+ float a1 = a[n + k];
+ float a2 = a[2 * n + k];
+
+ ata00 += a0 * a0;
+ ata11 += a1 * a1;
+ ata22 += a2 * a2;
+
+ ata01 += a0 * a1;
+ ata02 += a0 * a2;
+ ata12 += a1 * a2;
+ }
+ /* inverse matrix ata */
+ {
+ float inv_det;
+ float p00 = ata11 * ata22 - ata12 * ata12;
+ float p01 = -(ata01 * ata22 - ata12 * ata02);
+ float p02 = ata12 * ata01 - ata11 * ata02;
+
+ float p11 = ata00 * ata22 - ata02 * ata02;
+ float p12 = -(ata00 * ata12 - ata01 * ata02);
+ float p22 = ata00 * ata11 - ata01 * ata01;
+
+ det += ata00 * p00;
+ det += ata01 * p01;
+ det += ata02 * p02;
+
+ inv_det = 1 / det;
+
+ /* compute resultant matrix */
+ for( k = 0; k < n; k++ )
+ {
+ float a0 = a[k];
+ float a1 = a[n + k];
+ float a2 = a[2 * n + k];
+
+ b[k] = (p00 * a0 + p01 * a1 + p02 * a2) * inv_det;
+ b[n + k] = (p01 * a0 + p11 * a1 + p12 * a2) * inv_det;
+ b[2 * n + k] = (p02 * a0 + p12 * a1 + p22 * a2) * inv_det;
+ }
+ }
+ }
+
+ /*if ( method == 1 )
+ {
+ }
+ */
+
+ return;
+}
+
+CV_IMPL CvPOSITObject *
+cvCreatePOSITObject( CvPoint3D32f * points, int numPoints )
+{
+ CvPOSITObject *pObject = 0;
+
+ CV_FUNCNAME( "cvCreatePOSITObject" );
+
+ __BEGIN__;
+
+ IPPI_CALL( icvCreatePOSITObject( points, numPoints, &pObject ));
+
+ __END__;
+
+ return pObject;
+}
+
+
+CV_IMPL void
+cvPOSIT( CvPOSITObject * pObject, CvPoint2D32f * imagePoints,
+ double focalLength, CvTermCriteria criteria,
+ CvMatr32f rotation, CvVect32f translation )
+{
+ CV_FUNCNAME( "cvPOSIT" );
+
+ __BEGIN__;
+
+ IPPI_CALL( icvPOSIT( pObject, imagePoints,(float) focalLength, criteria,
+ rotation, translation ));
+
+ __END__;
+}
+
+CV_IMPL void
+cvReleasePOSITObject( CvPOSITObject ** ppObject )
+{
+ CV_FUNCNAME( "cvReleasePOSITObject" );
+
+ __BEGIN__;
+
+ IPPI_CALL( icvReleasePOSITObject( ppObject ));
+
+ __END__;
+}
+
+/* End of file. */
diff --git a/cv/src/cvprecomp.cpp b/cv/src/cvprecomp.cpp
new file mode 100644
index 0000000..d304b17
--- /dev/null
+++ b/cv/src/cvprecomp.cpp
@@ -0,0 +1,44 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+/* End of file. */
diff --git a/cv/src/cvpyramids.cpp b/cv/src/cvpyramids.cpp
new file mode 100644
index 0000000..829c0c9
--- /dev/null
+++ b/cv/src/cvpyramids.cpp
@@ -0,0 +1,1284 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+/****************************************************************************************\
+ Down-sampling pyramids core functions
+\****************************************************************************************/
+
+//////////// Filtering macros /////////////
+
+/* COMMON CASE */
+/* 1/16[1 4 6 4 1] */
+/* ...| x0 | x1 | x2 | x3 | x4 |... */
+#define PD_FILTER( x0, x1, x2, x3, x4 ) ((x2)*6+((x1)+(x3))*4+(x0)+(x4))
+
+/* MACROS FOR BORDERS */
+
+/* | b I a | b | reflection used ("I" denotes the image boundary) */
+
+/* LEFT/TOP */
+/* 1/16[1 4 6 4 1] */
+/* | x2 | x1 I x0 | x1 | x2 |... */
+#define PD_LT(x0,x1,x2) ((x0)*6 + (x1)*8 + (x2)*2)
+
+/* RIGHT/BOTTOM */
+/* 1/16[1 4 6 4 1] */
+/* ...| x0 | x1 | x2 | x3 I x2 | */
+#define PD_RB(x0,x1,x2,x3) ((x0) + ((x1) + (x3))*4 + (x2)*7)
+
+/* SINGULAR CASE ( width == 2 || height == 2 ) */
+/* 1/16[1 4 6 4 1] */
+/* | x0 | x1 I x0 | x1 I x0 | */
+#define PD_SINGULAR(x0,x1) (((x0) + (x1))*8)
+
+#define PD_SCALE_INT(x) (((x) + (1<<7)) >> 8)
+#define PD_SCALE_FLT(x) ((x)*0.00390625f)
+
+#define PD_SZ 5
+
+////////// generic macro ////////////
+
+#define ICV_DEF_PYR_DOWN_FUNC( flavor, type, worktype, _pd_scale_ ) \
+static CvStatus CV_STDCALL \
+icvPyrDownG5x5_##flavor##_CnR( const type* src, int srcstep, type* dst, \
+ int dststep, CvSize size, void *buf, int Cs ) \
+{ \
+ worktype* buffer = (worktype*)buf; /* pointer to temporary buffer */ \
+ worktype* rows[PD_SZ]; /* array of rows pointers. dim(rows) is PD_SZ */ \
+ int y, top_row = 0; \
+ int Wd = size.width/2, Wdn = Wd*Cs; \
+ int buffer_step = Wdn; \
+ int pd_sz = (PD_SZ + 1)*buffer_step; \
+ int fst = 0, lst = size.height <= PD_SZ/2 ? size.height : PD_SZ/2 + 1; \
+ \
+ assert( Cs == 1 || Cs == 3 ); \
+ srcstep /= sizeof(src[0]); dststep /= sizeof(dst[0]); \
+ \
+ /* main loop */ \
+ for( y = 0; y < size.height; y += 2, dst += dststep ) \
+ { \
+ /* set first and last indices of buffer rows which are need to be filled */ \
+ int x, y1, k = top_row; \
+ int x1 = buffer_step; \
+ worktype *row01, *row23, *row4; \
+ \
+ /* assign rows pointers */ \
+ for( y1 = 0; y1 < PD_SZ; y1++ ) \
+ { \
+ rows[y1] = buffer + k; \
+ k += buffer_step; \
+ k &= k < pd_sz ? -1 : 0; \
+ } \
+ \
+ row01 = rows[0]; \
+ row23 = rows[2]; \
+ row4 = rows[4]; \
+ \
+ /* fill new buffer rows with filtered source (horizontal conv) */ \
+ if( Cs == 1 ) \
+ { \
+ if( size.width > PD_SZ/2 ) \
+ for( y1 = fst; y1 < lst; y1++, src += srcstep ) \
+ { \
+ worktype *row = rows[y1]; \
+ \
+ /* process left & right bounds */ \
+ row[0] = PD_LT( src[0], src[1], src[2] ); \
+ row[Wd-1] = PD_RB( src[Wd*2-4], src[Wd*2-3], \
+ src[Wd*2-2], src[Wd*2-1]); \
+ /* other points (even) */ \
+ for( x = 1; x < Wd - 1; x++ ) \
+ { \
+ row[x] = PD_FILTER( src[2*x-2], src[2*x-1], src[2*x], \
+ src[2*x+1], src[2*x+2] ); \
+ } \
+ } \
+ else \
+ for( y1 = fst; y1 < lst; y1++, src += srcstep ) \
+ { \
+ rows[y1][0] = PD_SINGULAR( src[0], src[1] ); \
+ } \
+ } \
+ else /* Cs == 3 */ \
+ { \
+ for( y1 = fst; y1 < lst; y1++, src += srcstep ) \
+ { \
+ worktype *row = rows[y1]; \
+ \
+ if( size.width > PD_SZ/2 ) \
+ { \
+ int c; \
+ for( c = 0; c < 3; c++ ) \
+ { \
+ /* process left & right bounds */ \
+ row[c] = PD_LT( src[c], src[3+c], src[6+c] ); \
+ row[Wdn-3+c] = PD_RB( src[Wdn*2-12+c], src[Wdn*2-9+c], \
+ src[Wdn*2-6+c], src[Wdn*2-3+c] ); \
+ } \
+ /* other points (even) */ \
+ for( x = 3; x < Wdn - 3; x += 3 ) \
+ { \
+ row[x] = PD_FILTER( src[2*x-6], src[2*x-3], src[2*x], \
+ src[2*x+3], src[2*x+6] ); \
+ row[x+1] = PD_FILTER( src[2*x-5], src[2*x-2], src[2*x+1], \
+ src[2*x+4], src[2*x+7] ); \
+ row[x+2] = PD_FILTER( src[2*x-4], src[2*x-1], src[2*x+2], \
+ src[2*x+5], src[2*x+8] ); \
+ } \
+ } \
+ else /* size.width <= PD_SZ/2 */ \
+ { \
+ row[0] = PD_SINGULAR( src[0], src[3] ); \
+ row[1] = PD_SINGULAR( src[1], src[4] ); \
+ row[2] = PD_SINGULAR( src[2], src[5] ); \
+ } \
+ } \
+ } \
+ \
+ /* second pass. Do vertical conv and write results do destination image */ \
+ if( y > 0 ) \
+ { \
+ if( y < size.height - PD_SZ/2 ) \
+ { \
+ for( x = 0; x < Wdn; x++, x1++ ) \
+ { \
+ dst[x] = (type)_pd_scale_( PD_FILTER( row01[x], row01[x1], \
+ row23[x], row23[x1], row4[x] )); \
+ } \
+ top_row += 2*buffer_step; \
+ top_row &= top_row < pd_sz ? -1 : 0; \
+ } \
+ else /* bottom */ \
+ for( x = 0; x < Wdn; x++, x1++ ) \
+ dst[x] = (type)_pd_scale_( PD_RB( row01[x], row01[x1], \
+ row23[x], row23[x1])); \
+ } \
+ else \
+ { \
+ if( size.height > PD_SZ/2 ) /* top */ \
+ { \
+ for( x = 0; x < Wdn; x++, x1++ ) \
+ dst[x] = (type)_pd_scale_( PD_LT( row01[x], row01[x1], row23[x] )); \
+ } \
+ else /* size.height <= PD_SZ/2 */ \
+ { \
+ for( x = 0; x < Wdn; x++, x1++ ) \
+ dst[x] = (type)_pd_scale_( PD_SINGULAR( row01[x], row01[x1] )); \
+ } \
+ fst = PD_SZ - 2; \
+ } \
+ \
+ lst = y + 2 + PD_SZ/2 < size.height ? PD_SZ : size.height - y; \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_PYR_DOWN_FUNC( 8u, uchar, int, PD_SCALE_INT )
+ICV_DEF_PYR_DOWN_FUNC( 16s, short, int, PD_SCALE_INT )
+ICV_DEF_PYR_DOWN_FUNC( 16u, ushort, int, PD_SCALE_INT )
+ICV_DEF_PYR_DOWN_FUNC( 32f, float, float, PD_SCALE_FLT )
+ICV_DEF_PYR_DOWN_FUNC( 64f, double, double, PD_SCALE_FLT )
+
+
+/****************************************************************************************\
+ Up-sampling pyramids core functions
+\****************************************************************************************/
+
+/////////// filtering macros //////////////
+
+/* COMMON CASE: NON ZERO */
+/* 1/16[1 4 6 4 1] */
+/* ...| x0 | 0 | x1 | 0 | x2 |... */
+#define PU_FILTER( x0, x1, x2 ) ((x1)*6 + (x0) + (x2))
+
+/* ZERO POINT AT CENTER */
+/* 1/16[1 4 6 4 1] */
+/* ...| 0 | x0 | 0 | x1 | 0 |... */
+#define PU_FILTER_ZI( x0, x1 ) (((x0) + (x1))*4)
+
+/* MACROS FOR BORDERS */
+
+/* | b I a | b | reflection */
+
+/* LEFT/TOP */
+/* 1/16[1 4 6 4 1] */
+/* | x1 | 0 I x0 | 0 | x1 |... */
+#define PU_LT( x0, x1 ) ((x0)*6 + (x1)*2)
+
+/* 1/16[1 4 6 4 1] */
+/* | 0 I x0 | 0 | x1 | 0 |... */
+#define PU_LT_ZI( x0, x1 ) PU_FILTER_ZI((x0),(x1))
+
+/* RIGHT/BOTTOM: NON ZERO */
+/* 1/16[1 4 6 4 1] */
+/* ...| x0 | 0 | x1 | 0 I x1 | */
+#define PU_RB( x0, x1 ) ((x0) + (x1)*7)
+
+/* RIGHT/BOTTOM: ZERO POINT AT CENTER */
+/* 1/16[1 4 6 4 1] */
+/* ...| 0 | x0 | 0 I x0 | 0 | */
+#define PU_RB_ZI( x0 ) ((x0)*8)
+
+/* SINGULAR CASE */
+/* 1/16[1 4 6 4 1] */
+/* | x0 | 0 I x0 | 0 I x0 | */
+#define PU_SINGULAR( x0 ) PU_RB_ZI((x0)) /* <--| the same formulas */
+#define PU_SINGULAR_ZI( x0 ) PU_RB_ZI((x0)) /* <--| */
+
+/* x/64 - scaling in up-sampling functions */
+#define PU_SCALE_INT(x) (((x) + (1<<5)) >> 6)
+#define PU_SCALE_FLT(x) ((x)*0.015625f)
+
+#define PU_SZ 3
+
+//////////// generic macro /////////////
+
+
+#define ICV_DEF_PYR_UP_FUNC( flavor, type, worktype, _pu_scale_ ) \
+static CvStatus CV_STDCALL \
+icvPyrUpG5x5_##flavor##_CnR( const type* src, int srcstep, type* dst, \
+ int dststep, CvSize size, void *buf, int Cs ) \
+{ \
+ worktype *buffer = (worktype*)buf; \
+ worktype *rows[PU_SZ]; \
+ int y, top_row = 0; \
+ int Wd = size.width * 2, Wdn = Wd * Cs, Wn = size.width * Cs; \
+ int buffer_step = Wdn; \
+ int pu_sz = PU_SZ*buffer_step; \
+ int fst = 0, lst = size.height <= PU_SZ/2 ? size.height : PU_SZ/2 + 1; \
+ \
+ assert( Cs == 1 || Cs == 3 ); \
+ srcstep /= sizeof(src[0]); dststep /= sizeof(dst[0]); \
+ \
+ /* main loop */ \
+ for( y = 0; y < size.height; y++, dst += 2 * dststep ) \
+ { \
+ int x, y1, k = top_row; \
+ worktype *row0, *row1, *row2; \
+ type *dst1; \
+ \
+ /* assign rows pointers */ \
+ for( y1 = 0; y1 < PU_SZ; y1++ ) \
+ { \
+ rows[y1] = buffer + k; \
+ k += buffer_step; \
+ k &= k < pu_sz ? -1 : 0; \
+ } \
+ \
+ row0 = rows[0]; \
+ row1 = rows[1]; \
+ row2 = rows[2]; \
+ dst1 = dst + dststep; \
+ \
+ /* fill new buffer rows with filtered source (horizontal conv) */ \
+ if( Cs == 1 ) \
+ if( size.width > PU_SZ / 2 ) \
+ for( y1 = fst; y1 < lst; y1++, src += srcstep ) \
+ { \
+ worktype *row = rows[y1]; \
+ \
+ /* process left & right bounds */ \
+ row[0] = PU_LT( src[0], src[1] ); \
+ row[1] = PU_LT_ZI( src[0], src[1] ); \
+ row[size.width * 2 - 2] = PU_RB( src[size.width - 2], \
+ src[size.width - 1] ); \
+ row[size.width * 2 - 1] = PU_RB_ZI( src[size.width - 1] ); \
+ /* other points */ \
+ for( x = 1; x < size.width - 1; x++ ) \
+ { \
+ row[2 * x] = PU_FILTER( src[x - 1], src[x], src[x + 1] ); \
+ row[2 * x + 1] = PU_FILTER_ZI( src[x], src[x + 1] ); \
+ } \
+ } \
+ else /* size.width <= PU_SZ/2 */ \
+ for( y1 = fst; y1 < lst; y1++, src += srcstep ) \
+ { \
+ worktype *row = rows[y1]; \
+ worktype val = src[0]; \
+ \
+ row[0] = PU_SINGULAR( val ); \
+ row[1] = PU_SINGULAR_ZI( val ); \
+ } \
+ else /* Cs == 3 */ \
+ for( y1 = fst; y1 < lst; y1++, src += srcstep ) \
+ { \
+ worktype *row = rows[y1]; \
+ \
+ if( size.width > PU_SZ / 2 ) \
+ { \
+ int c; \
+ \
+ for( c = 0; c < 3; c++ ) \
+ { \
+ /* process left & right bounds */ \
+ row[c] = PU_LT( src[c], src[3 + c] ); \
+ row[3 + c] = PU_LT_ZI( src[c], src[3 + c] ); \
+ row[Wn * 2 - 6 + c] = PU_RB( src[Wn - 6 + c], src[Wn - 3 + c]); \
+ row[Wn * 2 - 3 + c] = PU_RB_ZI( src[Wn - 3 + c] ); \
+ } \
+ /* other points */ \
+ for( x = 3; x < Wn - 3; x += 3 ) \
+ { \
+ row[2 * x] = PU_FILTER( src[x - 3], src[x], src[x + 3] ); \
+ row[2 * x + 3] = PU_FILTER_ZI( src[x], src[x + 3] ); \
+ \
+ row[2 * x + 1] = PU_FILTER( src[x - 2], src[x + 1], src[x + 4]);\
+ row[2 * x + 4] = PU_FILTER_ZI( src[x + 1], src[x + 4] ); \
+ \
+ row[2 * x + 2] = PU_FILTER( src[x - 1], src[x + 2], src[x + 5]);\
+ row[2 * x + 5] = PU_FILTER_ZI( src[x + 2], src[x + 5] ); \
+ } \
+ } \
+ else /* size.width <= PU_SZ/2 */ \
+ { \
+ int c; \
+ \
+ for( c = 0; c < 3; c++ ) \
+ { \
+ row[c] = PU_SINGULAR( src[c] ); \
+ row[3 + c] = PU_SINGULAR_ZI( src[c] ); \
+ } \
+ } \
+ } \
+ \
+ /* second pass. Do vertical conv and write results do destination image */ \
+ if( y > 0 ) \
+ { \
+ if( y < size.height - PU_SZ / 2 ) \
+ { \
+ for( x = 0; x < Wdn; x++ ) \
+ { \
+ dst[x] = (type)_pu_scale_( PU_FILTER( row0[x], row1[x], row2[x] )); \
+ dst1[x] = (type)_pu_scale_( PU_FILTER_ZI( row1[x], row2[x] )); \
+ } \
+ top_row += buffer_step; \
+ top_row &= top_row < pu_sz ? -1 : 0; \
+ } \
+ else /* bottom */ \
+ for( x = 0; x < Wdn; x++ ) \
+ { \
+ dst[x] = (type)_pu_scale_( PU_RB( row0[x], row1[x] )); \
+ dst1[x] = (type)_pu_scale_( PU_RB_ZI( row1[x] )); \
+ } \
+ } \
+ else \
+ { \
+ if( size.height > PU_SZ / 2 ) /* top */ \
+ for( x = 0; x < Wdn; x++ ) \
+ { \
+ dst[x] = (type)_pu_scale_( PU_LT( row0[x], row1[x] )); \
+ dst1[x] = (type)_pu_scale_( PU_LT_ZI( row0[x], row1[x] )); \
+ } \
+ else /* size.height <= PU_SZ/2 */ \
+ for( x = 0; x < Wdn; x++ ) \
+ { \
+ dst[x] = (type)_pu_scale_( PU_SINGULAR( row0[x] )); \
+ dst1[x] = (type)_pu_scale_( PU_SINGULAR_ZI( row0[x] )); \
+ } \
+ fst = PU_SZ - 1; \
+ } \
+ \
+ lst = y < size.height - PU_SZ/2 - 1 ? PU_SZ : size.height + PU_SZ/2 - y - 1; \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_PYR_UP_FUNC( 8u, uchar, int, PU_SCALE_INT )
+ICV_DEF_PYR_UP_FUNC( 16s, short, int, PU_SCALE_INT )
+ICV_DEF_PYR_UP_FUNC( 16u, ushort, int, PU_SCALE_INT )
+ICV_DEF_PYR_UP_FUNC( 32f, float, float, PU_SCALE_FLT )
+ICV_DEF_PYR_UP_FUNC( 64f, double, double, PU_SCALE_FLT )
+
+
+static CvStatus CV_STDCALL
+icvPyrUpG5x5_GetBufSize( int roiWidth, CvDataType dataType,
+ int channels, int *bufSize )
+{
+ int bufStep;
+
+ if( !bufSize )
+ return CV_NULLPTR_ERR;
+ *bufSize = 0;
+
+ if( roiWidth < 0 )
+ return CV_BADSIZE_ERR;
+ if( channels != 1 && channels != 3 )
+ return CV_UNSUPPORTED_CHANNELS_ERR;
+
+ bufStep = 2*roiWidth*channels;
+
+ if( dataType == cv64f )
+ bufStep *= sizeof(double);
+ else
+ bufStep *= sizeof(int);
+
+ *bufSize = bufStep * PU_SZ;
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvPyrDownG5x5_GetBufSize( int roiWidth, CvDataType dataType,
+ int channels, int *bufSize )
+{
+ int bufStep;
+
+ if( !bufSize )
+ return CV_NULLPTR_ERR;
+ *bufSize = 0;
+
+ if( roiWidth < 0 || (roiWidth & 1) != 0 )
+ return CV_BADSIZE_ERR;
+ if( channels != 1 && channels != 3 )
+ return CV_UNSUPPORTED_CHANNELS_ERR;
+
+ bufStep = 2*roiWidth*channels;
+
+ if( dataType == cv64f )
+ bufStep *= sizeof(double);
+ else
+ bufStep *= sizeof(int);
+
+ *bufSize = bufStep * (PD_SZ + 1);
+ return CV_OK;
+}
+
+/****************************************************************************************\
+ Downsampled image border completion
+\****************************************************************************************/
+
+#define ICV_DEF_PYR_BORDER_FUNC( flavor, arrtype, worktype, _pd_scale_ ) \
+static CvStatus CV_STDCALL \
+icvPyrDownBorder_##flavor##_CnR( const arrtype *src, int src_step, CvSize src_size, \
+ arrtype *dst, int dst_step, CvSize dst_size, int channels ) \
+{ \
+ int local_alloc = 0; \
+ worktype *buf = 0, *buf0 = 0; \
+ const arrtype* src2; \
+ arrtype* dst2; \
+ int buf_size; \
+ int i, j; \
+ int W = src_size.width, H = src_size.height; \
+ int Wd = dst_size.width, Hd = dst_size.height; \
+ int Wd_, Hd_; \
+ int Wn = W*channels; \
+ int bufW; \
+ int cols, rows; /* columns and rows to modify */ \
+ \
+ assert( channels == 1 || channels == 3 ); \
+ \
+ buf_size = MAX(src_size.width,src_size.height) * sizeof(buf[0]) * 2 * channels; \
+ if( buf_size > (1 << 14) ) \
+ { \
+ buf = (worktype*)cvAlloc( buf_size ); \
+ if( !buf ) \
+ return CV_OUTOFMEM_ERR; \
+ } \
+ else \
+ { \
+ buf = (worktype*)cvAlignPtr(alloca( buf_size+8 ), 8); \
+ local_alloc = 1; \
+ } \
+ \
+ buf0 = buf; \
+ \
+ src_step /= sizeof(src[0]); \
+ dst_step /= sizeof(dst[0]); \
+ \
+ cols = (W & 1) + (Wd*2 > W); \
+ rows = (H & 1) + (Hd*2 > H); \
+ \
+ src2 = src + (H-1)*src_step; \
+ dst2 = dst + (Hd - rows)*dst_step; \
+ src += (W - 1)*channels; \
+ dst += (Wd - cols)*channels; \
+ \
+ /* part of row(column) from 1 to Wd_(Hd_) is processed using PD_FILTER macro */ \
+ Wd_ = Wd - 1 + (cols == 1 && (W & 1) != 0); \
+ Hd_ = Hd - 1 + (rows == 1 && (H & 1) != 0); \
+ \
+ bufW = channels * cols; \
+ \
+ /******************* STAGE 1. ******************/ \
+ \
+ /* do horizontal convolution of the 1-2 right columns and write results to buffer */\
+ if( cols > 0 ) \
+ { \
+ if( W <= 2 ) \
+ { \
+ assert( Wd == 1 ); \
+ for( i = 0; i < H; i++, src += src_step, buf += channels ) \
+ { \
+ if( channels == 1 ) \
+ buf[0] = PD_SINGULAR( src[1-Wn], src[0] ); \
+ else \
+ { \
+ buf[0] = PD_SINGULAR( src[3-Wn], src[0] ); \
+ buf[1] = PD_SINGULAR( src[4-Wn], src[1] ); \
+ buf[2] = PD_SINGULAR( src[5-Wn], src[2] ); \
+ } \
+ } \
+ } \
+ else if( (W == 3 && Wd == 1) || (W > 3 && !(Wd & 1)) ) \
+ { \
+ for( i = 0; i < H; i++, src += src_step, buf += channels ) \
+ { \
+ if( channels == 1 ) \
+ buf[0] = PD_LT( src[-2], src[-1], src[0] ); \
+ else \
+ { \
+ buf[0] = PD_LT( src[-6], src[-3], src[0] ); \
+ buf[1] = PD_LT( src[-5], src[-2], src[1] ); \
+ buf[2] = PD_LT( src[-4], src[-1], src[2] ); \
+ } \
+ } \
+ } \
+ else if( W == 3 ) \
+ { \
+ for( i = 0; i < H; i++, src += src_step, buf += channels*2 ) \
+ { \
+ if( channels == 1 ) \
+ { \
+ buf[0] = PD_LT( src[-2], src[-1], src[0] ); \
+ buf[1] = PD_LT( src[0], src[-1], src[-2] ); \
+ } \
+ else \
+ { \
+ buf[0] = PD_LT( src[-6], src[-3], src[0] ); \
+ buf[1] = PD_LT( src[-5], src[-2], src[1] ); \
+ buf[2] = PD_LT( src[-4], src[-1], src[2] ); \
+ buf[3] = PD_LT( src[0], src[-3], src[-6] ); \
+ buf[4] = PD_LT( src[1], src[-2], src[-5] ); \
+ buf[5] = PD_LT( src[2], src[-1], src[-4] ); \
+ } \
+ } \
+ } \
+ else if( cols == 1 ) \
+ { \
+ for( i = 0; i < H; i++, src += src_step, buf += channels ) \
+ { \
+ if( channels == 1 ) \
+ buf[0] = PD_FILTER( src[-4], src[-3], src[-2], src[-1], src[0]); \
+ else \
+ { \
+ buf[0] = PD_FILTER( src[-12], src[-9], src[-6], src[-3], src[0]); \
+ buf[1] = PD_FILTER( src[-11], src[-8], src[-5], src[-2], src[1]); \
+ buf[2] = PD_FILTER( src[-10], src[-7], src[-4], src[-1], src[2]); \
+ } \
+ } \
+ } \
+ else \
+ { \
+ for( i = 0; i < H; i++, src += src_step, buf += channels*2 ) \
+ { \
+ if( channels == 1 ) \
+ { \
+ buf[0] = PD_FILTER( src[-4], src[-3], src[-2], src[-1], src[0] ); \
+ buf[1] = PD_LT( src[0], src[-1], src[-2] ); \
+ } \
+ else \
+ { \
+ buf[0] = PD_FILTER( src[-12], src[-9], src[-6], src[-3], src[0] ); \
+ buf[1] = PD_FILTER( src[-11], src[-8], src[-5], src[-2], src[1] ); \
+ buf[2] = PD_FILTER( src[-10], src[-7], src[-4], src[-1], src[2] ); \
+ buf[3] = PD_LT( src[0], src[-3], src[-6] ); \
+ buf[4] = PD_LT( src[1], src[-2], src[-5] ); \
+ buf[5] = PD_LT( src[2], src[-1], src[-4] ); \
+ } \
+ } \
+ } \
+ buf = buf0; \
+ } \
+ \
+ src = src2; \
+ \
+ /******************* STAGE 2. ******************/ \
+ \
+ /* do vertical convolution of the pre-processed right columns, */ \
+ /* stored in buffer, and write results to the destination */ \
+ /* do vertical convolution of the 1-2 bottom rows */ \
+ /* and write results to the buffer */ \
+ if( H <= 2 ) \
+ { \
+ if( cols > 0 ) \
+ { \
+ assert( Hd == 1 ); \
+ for( j = 0; j < bufW; j++ ) \
+ dst[j] = (arrtype)_pd_scale_( PD_SINGULAR( buf[j], buf[j+(H-1)*bufW] ));\
+ } \
+ \
+ if( rows > 0 ) \
+ { \
+ for( j = 0; j < Wn; j++ ) \
+ buf[j] = PD_SINGULAR( src[j-src_step], src[j] ); \
+ } \
+ } \
+ else if( H == 3 ) \
+ { \
+ if( cols > 0 ) \
+ { \
+ for( j = 0; j < bufW; j++ ) \
+ { \
+ dst[j]= (arrtype)_pd_scale_(PD_LT( buf[j], buf[j+bufW], buf[j+bufW*2]));\
+ } \
+ if( Hd == 2 ) \
+ { \
+ dst += dst_step; \
+ for( j = 0; j < bufW; j++ ) \
+ dst[j] = (arrtype)_pd_scale_( PD_LT( buf[j+bufW*2], \
+ buf[j+bufW], buf[j] )); \
+ } \
+ } \
+ \
+ if( Hd == 1 ) \
+ { \
+ for( j = 0; j < Wn; j++ ) \
+ buf[j] = PD_LT( src[j-src_step*2], src[j - src_step], src[j] ); \
+ } \
+ else \
+ { \
+ for( j = 0; j < Wn; j++ ) \
+ { \
+ buf[j] = PD_LT( src[j-src_step*2], src[j - src_step], src[j] ); \
+ buf[j+Wn] = PD_LT( src[j],src[j-src_step],src[j-src_step*2] ); \
+ } \
+ } \
+ } \
+ else \
+ { \
+ if( cols > 0 ) \
+ { \
+ /* top of the right border */ \
+ for( j = 0; j < bufW; j++ ) \
+ dst[j]=(arrtype)_pd_scale_( PD_LT( buf[j], buf[j+bufW], buf[j+bufW*2]));\
+ \
+ /* middle part of the right border */ \
+ buf += bufW*2; \
+ dst += dst_step; \
+ for( i = 1; i < Hd_; i++, dst += dst_step, buf += bufW*2 ) \
+ { \
+ for( j = 0; j < bufW; j++ ) \
+ dst[j] = (arrtype)_pd_scale_( PD_FILTER( buf[j-bufW*2], buf[j-bufW],\
+ buf[j], buf[j+bufW], buf[j+bufW*2] ));\
+ } \
+ \
+ /* bottom of the right border */ \
+ if( !(H & 1) ) \
+ { \
+ for( j = 0; j < bufW; j++ ) \
+ dst[j] = (arrtype)_pd_scale_( PD_RB( buf[j-bufW*2], buf[j-bufW], \
+ buf[j], buf[j+bufW] )); \
+ } \
+ else if( rows > 1 ) \
+ { \
+ for( j = 0; j < bufW; j++ ) \
+ dst[j]=(arrtype)_pd_scale_( PD_LT( buf[j-bufW*2], \
+ buf[j-bufW], buf[j])); \
+ } \
+ \
+ buf = buf0; \
+ } \
+ \
+ if( rows > 0 ) \
+ { \
+ if( !(H & 1) ) \
+ { \
+ for( j = 0; j < Wn; j++ ) \
+ buf[j] = PD_LT( src[j], src[j-src_step], src[j-src_step*2] ); \
+ } \
+ else if( cols == 1 ) \
+ { \
+ for( j = 0; j < Wn; j++ ) \
+ buf[j] = PD_FILTER( src[j-src_step*4], src[j-src_step*3], \
+ src[j-src_step*2], src[j-src_step], src[j] ); \
+ } \
+ else \
+ { \
+ for( j = 0; j < Wn; j++ ) \
+ { \
+ buf[j] = PD_FILTER( src[j-src_step*4], src[j-src_step*3], \
+ src[j-src_step*2], src[j-src_step], src[j] ); \
+ buf[j+Wn] = PD_LT( src[j], src[j-src_step], src[j-src_step*2] ); \
+ } \
+ } \
+ } \
+ } \
+ \
+ \
+ /******************* STAGE 3. ******************/ \
+ \
+ /* do horizontal convolution of the pre-processed bottom rows,*/ \
+ /* stored in buffer, and write results to the destination */ \
+ if( rows > 0 ) \
+ { \
+ dst = dst2; \
+ \
+ if( W <= 2 ) \
+ { \
+ assert( Wd == 1 ); \
+ for( ; rows--; dst += dst_step, buf += Wn ) \
+ { \
+ if( channels == 1 ) \
+ dst[0] = (arrtype)_pd_scale_( PD_SINGULAR( buf[0], buf[Wn-1] )); \
+ else \
+ { \
+ dst[0] = (arrtype)_pd_scale_( PD_SINGULAR( buf[0], buf[Wn-3] )); \
+ dst[1] = (arrtype)_pd_scale_( PD_SINGULAR( buf[1], buf[Wn-2] )); \
+ dst[2] = (arrtype)_pd_scale_( PD_SINGULAR( buf[2], buf[Wn-1] )); \
+ } \
+ } \
+ } \
+ else if( W == 3 ) \
+ { \
+ if( Wd == 1 ) \
+ { \
+ for( ; rows--; dst += dst_step, buf += Wn ) \
+ { \
+ if( channels == 1 ) \
+ dst[0] = (arrtype)_pd_scale_( PD_LT(buf[0], buf[1], buf[2] )); \
+ else \
+ { \
+ dst[0] = (arrtype)_pd_scale_( PD_LT(buf[0], buf[3], buf[6] )); \
+ dst[1] = (arrtype)_pd_scale_( PD_LT(buf[1], buf[4], buf[7] )); \
+ dst[2] = (arrtype)_pd_scale_( PD_LT(buf[2], buf[5], buf[8] )); \
+ } \
+ } \
+ } \
+ else \
+ { \
+ for( ; rows--; dst += dst_step, buf += Wn ) \
+ { \
+ if( channels == 1 ) \
+ { \
+ dst[0] = (arrtype)_pd_scale_( PD_LT(buf[0], buf[1], buf[2] )); \
+ dst[1] = (arrtype)_pd_scale_( PD_LT(buf[2], buf[1], buf[0] )); \
+ } \
+ else \
+ { \
+ dst[0] = (arrtype)_pd_scale_( PD_LT(buf[0], buf[3], buf[6] )); \
+ dst[1] = (arrtype)_pd_scale_( PD_LT(buf[1], buf[4], buf[7] )); \
+ dst[2] = (arrtype)_pd_scale_( PD_LT(buf[2], buf[5], buf[8] )); \
+ dst[3] = (arrtype)_pd_scale_( PD_LT(buf[6], buf[3], buf[0] )); \
+ dst[4] = (arrtype)_pd_scale_( PD_LT(buf[7], buf[4], buf[1] )); \
+ dst[5] = (arrtype)_pd_scale_( PD_LT(buf[8], buf[5], buf[2] )); \
+ } \
+ } \
+ } \
+ } \
+ else \
+ { \
+ for( ; rows--; dst += dst_step, buf += Wn ) \
+ { \
+ if( channels == 1 ) \
+ { \
+ /* left part of the bottom row */ \
+ dst[0] = (arrtype)_pd_scale_( PD_LT( buf[0], buf[1], buf[2] )); \
+ \
+ /* middle part of the bottom row */ \
+ for( i = 1; i < Wd_; i++ ) \
+ { \
+ dst[i] = (arrtype)_pd_scale_( PD_FILTER(buf[i*2-2], buf[i*2-1], \
+ buf[i*2],buf[i*2+1], buf[i*2+2] )); \
+ } \
+ \
+ /* right part of the bottom row */ \
+ if( !(W & 1) ) \
+ dst[i] = (arrtype)_pd_scale_( PD_RB( buf[i*2-2],buf[i*2-1], \
+ buf[i*2], buf[i*2+1] )); \
+ else if( cols > 1 ) \
+ dst[i] = (arrtype)_pd_scale_( PD_LT( buf[i*2-2], \
+ buf[i*2-1], buf[i*2] )); \
+ } \
+ else \
+ { \
+ /* left part of the bottom row */ \
+ dst[0] = (arrtype)_pd_scale_( PD_LT( buf[0], buf[3], buf[6] )); \
+ dst[1] = (arrtype)_pd_scale_( PD_LT( buf[1], buf[4], buf[7] )); \
+ dst[2] = (arrtype)_pd_scale_( PD_LT( buf[2], buf[5], buf[8] )); \
+ \
+ /* middle part of the bottom row */ \
+ for( i = 3; i < Wd_*3; i++ ) \
+ { \
+ dst[i] = (arrtype)_pd_scale_( PD_FILTER(buf[i*2-6], buf[i*2-3], \
+ buf[i*2],buf[i*2+3], buf[i*2+6]));\
+ } \
+ \
+ /* right part of the bottom row */ \
+ if( !(W & 1) ) \
+ { \
+ dst[i] = (arrtype)_pd_scale_( PD_RB( buf[i*2-6],buf[i*2-3], \
+ buf[i*2], buf[i*2+3] )); \
+ dst[i+1] = (arrtype)_pd_scale_( PD_RB( buf[i*2-5],buf[i*2-2], \
+ buf[i*2+1], buf[i*2+4] )); \
+ dst[i+2] = (arrtype)_pd_scale_( PD_RB( buf[i*2-4],buf[i*2-1], \
+ buf[i*2+2], buf[i*2+5] )); \
+ } \
+ else if( cols > 1 ) \
+ { \
+ dst[i] = (arrtype)_pd_scale_( PD_LT( buf[i*2-6], buf[i*2-3], buf[i*2] )); \
+ dst[i+1] = (arrtype)_pd_scale_( PD_LT( buf[i*2-5], buf[i*2-2], buf[i*2+1]));\
+ dst[i+2] = (arrtype)_pd_scale_( PD_LT( buf[i*2-4], buf[i*2-1], buf[i*2+2]));\
+ } \
+ } \
+ } \
+ } \
+ } \
+ \
+ if( !local_alloc ) \
+ cvFree( &buf0 ); \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_INIT_PYR_TABLE( FUNCNAME ) \
+static void icvInit##FUNCNAME##Table( CvFuncTable* tab ) \
+{ \
+ tab->fn_2d[CV_8U] = (void*)icv##FUNCNAME##_8u_CnR; \
+ tab->fn_2d[CV_8S] = 0; \
+ tab->fn_2d[CV_16S] = (void*)icv##FUNCNAME##_16s_CnR; \
+ tab->fn_2d[CV_16U] = (void*)icv##FUNCNAME##_16u_CnR; \
+ tab->fn_2d[CV_32F] = (void*)icv##FUNCNAME##_32f_CnR; \
+ tab->fn_2d[CV_64F] = (void*)icv##FUNCNAME##_64f_CnR; \
+}
+
+static void icvInitPyrDownBorderTable( CvFuncTable* tab );
+
+ICV_DEF_INIT_PYR_TABLE( PyrUpG5x5 )
+ICV_DEF_INIT_PYR_TABLE( PyrDownG5x5 )
+
+typedef CvStatus (CV_STDCALL * CvPyrDownBorderFunc)( const void* src, int srcstep,
+ CvSize srcsize, void* dst,
+ int dststep, CvSize dstsize, int cn );
+
+////////////////////////////// IPP pyramid functions /////////////////////////////////////
+
+icvPyrDown_Gauss5x5_8u_C1R_t icvPyrDown_Gauss5x5_8u_C1R_p = 0;
+icvPyrDown_Gauss5x5_8u_C3R_t icvPyrDown_Gauss5x5_8u_C3R_p = 0;
+icvPyrDown_Gauss5x5_32f_C1R_t icvPyrDown_Gauss5x5_32f_C1R_p = 0;
+icvPyrDown_Gauss5x5_32f_C3R_t icvPyrDown_Gauss5x5_32f_C3R_p = 0;
+
+icvPyrUp_Gauss5x5_8u_C1R_t icvPyrUp_Gauss5x5_8u_C1R_p = 0;
+icvPyrUp_Gauss5x5_8u_C3R_t icvPyrUp_Gauss5x5_8u_C3R_p = 0;
+icvPyrUp_Gauss5x5_32f_C1R_t icvPyrUp_Gauss5x5_32f_C1R_p = 0;
+icvPyrUp_Gauss5x5_32f_C3R_t icvPyrUp_Gauss5x5_32f_C3R_p = 0;
+
+icvPyrUpGetBufSize_Gauss5x5_t icvPyrUpGetBufSize_Gauss5x5_p = 0;
+icvPyrDownGetBufSize_Gauss5x5_t icvPyrDownGetBufSize_Gauss5x5_p = 0;
+
+typedef CvStatus (CV_STDCALL * CvPyramidFunc)
+( const void* src, int srcstep, void* dst,
+ int dststep, CvSize size, void* buffer, int cn );
+
+typedef CvStatus (CV_STDCALL * CvPyramidIPPFunc)
+( const void* src, int srcstep, void* dst, int dststep, CvSize size, void* buffer );
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+/****************************************************************************************\
+* External functions *
+\****************************************************************************************/
+
+CV_IMPL void
+cvPyrUp( const void* srcarr, void* dstarr, int _filter )
+{
+ static CvFuncTable pyrup_tab;
+ static int inittab = 0;
+
+ void *buffer = 0;
+ int local_alloc = 0;
+
+ CV_FUNCNAME( "cvPyrUp" );
+
+ __BEGIN__;
+
+ int coi1 = 0, coi2 = 0;
+ int buffer_size = 0;
+ int type, depth, cn;
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvFilter filter = (CvFilter) _filter;
+ CvPyramidFunc func;
+ CvPyramidIPPFunc ipp_func = 0;
+ int use_ipp = 0;
+ CvSize size;
+
+ if( !inittab )
+ {
+ icvInitPyrUpG5x5Table( &pyrup_tab );
+ inittab = 1;
+ }
+
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ if( filter != CV_GAUSSIAN_5x5 )
+ CV_ERROR( CV_StsBadArg, "this filter type not supported" );
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( src->cols*2 != dst->cols || src->rows*2 != dst->rows )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ size = cvGetMatSize(src);
+ type = CV_MAT_TYPE(src->type);
+ depth = CV_MAT_DEPTH(type);
+ cn = CV_MAT_CN(type);
+
+ if( cn != 1 && cn != 3 )
+ CV_ERROR( CV_StsUnsupportedFormat, "The images must have 1 or 3 channel" );
+
+ func = (CvPyramidFunc)pyrup_tab.fn_2d[depth];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( icvPyrUpGetBufSize_Gauss5x5_p )
+ {
+ ipp_func = type == CV_8UC1 ? icvPyrUp_Gauss5x5_8u_C1R_p :
+ type == CV_8UC3 ? icvPyrUp_Gauss5x5_8u_C3R_p :
+ type == CV_32FC1 ? icvPyrUp_Gauss5x5_32f_C1R_p :
+ type == CV_32FC3 ? icvPyrUp_Gauss5x5_32f_C3R_p : 0;
+
+ use_ipp = ipp_func && icvPyrUpGetBufSize_Gauss5x5_p( size.width,
+ icvDepthToDataType(type), cn, &buffer_size ) >= 0;
+ }
+
+ if( !use_ipp )
+ icvPyrUpG5x5_GetBufSize( size.width, icvDepthToDataType(type), cn, &buffer_size );
+
+ if( buffer_size <= CV_MAX_LOCAL_SIZE )
+ {
+ buffer = cvStackAlloc( buffer_size );
+ local_alloc = 1;
+ }
+ else
+ CV_CALL( buffer = cvAlloc( buffer_size ));
+
+ if( !use_ipp )
+ func( src->data.ptr, src->step, dst->data.ptr, dst->step, size, buffer, cn );
+ else
+ IPPI_CALL( ipp_func( src->data.ptr, src->step ? src->step : CV_STUB_STEP,
+ dst->data.ptr, dst->step ? dst->step : CV_STUB_STEP, size, buffer ));
+ __END__;
+
+ if( buffer && !local_alloc )
+ cvFree( &buffer );
+}
+
+
+CV_IMPL void
+cvPyrDown( const void* srcarr, void* dstarr, int _filter )
+{
+ static CvFuncTable pyrdown_tab;
+ static CvFuncTable pyrdownborder_tab;
+ static int inittab = 0;
+
+ void *buffer = 0;
+ int local_alloc = 0;
+
+ CV_FUNCNAME( "cvPyrDown" );
+
+ __BEGIN__;
+
+ int coi1 = 0, coi2 = 0;
+ int buffer_size = 0;
+ int type, depth, cn;
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvFilter filter = (CvFilter) _filter;
+ CvPyramidFunc func;
+ CvPyramidIPPFunc ipp_func = 0;
+ int use_ipp = 0;
+ CvSize src_size, src_size2, dst_size;
+
+ if( !inittab )
+ {
+ icvInitPyrDownG5x5Table( &pyrdown_tab );
+ icvInitPyrDownBorderTable( &pyrdownborder_tab );
+ inittab = 1;
+ }
+
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ if( filter != CV_GAUSSIAN_5x5 )
+ CV_ERROR( CV_StsBadArg, "this filter type not supported" );
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ src_size = cvGetMatSize(src);
+ dst_size = cvGetMatSize(dst);
+ src_size2.width = src_size.width & -2;
+ src_size2.height = src_size.height & -2;
+
+ if( (unsigned)(dst_size.width - src_size.width/2) > 1 ||
+ (unsigned)(dst_size.height - src_size.height/2) > 1 )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ // current restriction of PyrDownBorder*
+ if( (src_size.width <= 2 && dst_size.width != 1) ||
+ (src_size.height <= 2 && dst_size.height != 1) )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ /*if( src->data.ptr == dst->data.ptr )
+ CV_ERROR( CV_StsInplaceNotSupported, "" );*/
+
+ type = CV_MAT_TYPE(src->type);
+ depth = CV_MAT_DEPTH(type);
+ cn = CV_MAT_CN(type);
+
+ if( cn != 1 && cn != 3 )
+ CV_ERROR( CV_StsUnsupportedFormat, "The images must have 1 or 3 channel" );
+
+ func = (CvPyramidFunc)pyrdown_tab.fn_2d[depth];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( icvPyrDownGetBufSize_Gauss5x5_p )
+ {
+ ipp_func = type == CV_8UC1 ? icvPyrDown_Gauss5x5_8u_C1R_p :
+ type == CV_8UC3 ? icvPyrDown_Gauss5x5_8u_C3R_p :
+ type == CV_32FC1 ? icvPyrDown_Gauss5x5_32f_C1R_p :
+ type == CV_32FC3 ? icvPyrDown_Gauss5x5_32f_C3R_p : 0;
+
+ use_ipp = ipp_func && icvPyrDownGetBufSize_Gauss5x5_p( src_size2.width,
+ icvDepthToDataType(type), cn, &buffer_size ) >= 0;
+ }
+
+ if( !use_ipp )
+ icvPyrDownG5x5_GetBufSize( src_size2.width,
+ icvDepthToDataType(type), cn, &buffer_size );
+
+ if( buffer_size <= CV_MAX_LOCAL_SIZE )
+ {
+ buffer = cvStackAlloc( buffer_size );
+ local_alloc = 1;
+ }
+ else
+ CV_CALL( buffer = cvAlloc( buffer_size ));
+
+ if( !use_ipp )
+ func( src->data.ptr, src->step, dst->data.ptr,
+ dst->step, src_size2, buffer, cn );
+ else
+ IPPI_CALL( ipp_func( src->data.ptr, src->step ? src->step : CV_STUB_STEP,
+ dst->data.ptr, dst->step ? dst->step : CV_STUB_STEP, src_size2, buffer ));
+
+ if( src_size.width != dst_size.width*2 || src_size.height != dst_size.height*2 )
+ {
+ CvPyrDownBorderFunc border_func = (CvPyrDownBorderFunc)
+ pyrdownborder_tab.fn_2d[CV_MAT_DEPTH(type)];
+
+ if( !border_func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( border_func( src->data.ptr, src->step, src_size,
+ dst->data.ptr, dst->step, dst_size, CV_MAT_CN(type) ));
+ }
+
+ __END__;
+
+ if( buffer && !local_alloc )
+ cvFree( &buffer );
+}
+
+
+CV_IMPL void
+cvReleasePyramid( CvMat*** _pyramid, int extra_layers )
+{
+ CV_FUNCNAME( "cvReleasePyramid" );
+
+ __BEGIN__;
+
+ CvMat** pyramid;
+ int i;
+
+ if( !_pyramid )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ pyramid = *_pyramid;
+
+ if( pyramid )
+ {
+ for( i = 0; i <= extra_layers; i++ )
+ cvReleaseMat( &pyramid[i] );
+ }
+
+ cvFree( _pyramid );
+
+ __END__;
+}
+
+
+CV_IMPL CvMat**
+cvCreatePyramid( const CvArr* srcarr, int extra_layers, double rate,
+ const CvSize* layer_sizes, CvArr* bufarr,
+ int calc, int filter )
+{
+ CvMat** pyramid = 0;
+ const float eps = 0.1f;
+
+ CV_FUNCNAME( "cvCreatePyramid" );
+
+ __BEGIN__;
+
+ int i, elem_size, layer_step;
+ CvMat stub, *src;
+ CvSize size, layer_size;
+ uchar* ptr = 0;
+
+ CV_CALL( src = cvGetMat( srcarr, &stub ));
+
+ if( extra_layers < 0 )
+ CV_ERROR( CV_StsOutOfRange, "The number of extra layers must be non negative" );
+
+ elem_size = CV_ELEM_SIZE(src->type);
+ size = cvGetMatSize(src);
+
+ if( bufarr )
+ {
+ CvMat bstub, *buf;
+ int bufsize = 0;
+
+ CV_CALL( buf = cvGetMat( bufarr, &bstub ));
+ bufsize = buf->rows*buf->cols*CV_ELEM_SIZE(buf->type);
+ layer_size = size;
+ for( i = 1; i <= extra_layers; i++ )
+ {
+ if( !layer_sizes )
+ {
+ layer_size.width = cvRound(layer_size.width*rate+eps);
+ layer_size.height = cvRound(layer_size.height*rate+eps);
+ }
+ else
+ layer_size = layer_sizes[i-1];
+ layer_step = layer_size.width*elem_size;
+ bufsize -= layer_step*layer_size.height;
+ }
+
+ if( bufsize < 0 )
+ CV_ERROR( CV_StsOutOfRange, "The buffer is too small to fit the pyramid" );
+ ptr = buf->data.ptr;
+ }
+
+ CV_CALL( pyramid = (CvMat**)cvAlloc( (extra_layers+1)*sizeof(pyramid[0]) ));
+ memset( pyramid, 0, (extra_layers+1)*sizeof(pyramid[0]) );
+
+ pyramid[0] = cvCreateMatHeader( size.height, size.width, src->type );
+ cvSetData( pyramid[0], src->data.ptr, src->step );
+ layer_size = size;
+
+ for( i = 1; i <= extra_layers; i++ )
+ {
+ if( !layer_sizes )
+ {
+ layer_size.width = cvRound(layer_size.width*rate + eps);
+ layer_size.height = cvRound(layer_size.height*rate + eps);
+ }
+ else
+ layer_size = layer_sizes[i];
+
+ if( bufarr )
+ {
+ pyramid[i] = cvCreateMatHeader( layer_size.height, layer_size.width, src->type );
+ layer_step = layer_size.width*elem_size;
+ cvSetData( pyramid[i], ptr, layer_step );
+ ptr += layer_step*layer_size.height;
+ }
+ else
+ pyramid[i] = cvCreateMat( layer_size.height, layer_size.width, src->type );
+
+ if( calc )
+ cvPyrDown( pyramid[i-1], pyramid[i], filter );
+ //cvResize( pyramid[i-1], pyramid[i], CV_INTER_LINEAR );
+ }
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvReleasePyramid( &pyramid, extra_layers );
+
+ return pyramid;
+}
+
+
+/* MSVC .NET 2003 spends a long time building this, thus, as the code
+ is not performance-critical, we turn off the optimization here */
+#if defined _MSC_VER && _MSC_VER > 1300 && !defined CV_ICC
+#pragma optimize("", off)
+#endif
+
+ICV_DEF_PYR_BORDER_FUNC( 8u, uchar, int, PD_SCALE_INT )
+ICV_DEF_PYR_BORDER_FUNC( 16u, ushort, int, PD_SCALE_INT )
+ICV_DEF_PYR_BORDER_FUNC( 16s, short, int, PD_SCALE_INT )
+ICV_DEF_PYR_BORDER_FUNC( 32f, float, float, PD_SCALE_FLT )
+ICV_DEF_PYR_BORDER_FUNC( 64f, double, double, PD_SCALE_FLT )
+
+#define ICV_DEF_INIT_PYR_BORDER_TABLE( FUNCNAME ) \
+static void icvInit##FUNCNAME##Table( CvFuncTable* tab ) \
+{ \
+ tab->fn_2d[CV_8U] = (void*)icv##FUNCNAME##_8u_CnR; \
+ tab->fn_2d[CV_8S] = 0; \
+ tab->fn_2d[CV_16U] = (void*)icv##FUNCNAME##_16u_CnR; \
+ tab->fn_2d[CV_16S] = (void*)icv##FUNCNAME##_16s_CnR; \
+ tab->fn_2d[CV_32F] = (void*)icv##FUNCNAME##_32f_CnR; \
+ tab->fn_2d[CV_64F] = (void*)icv##FUNCNAME##_64f_CnR; \
+}
+
+ICV_DEF_INIT_PYR_BORDER_TABLE( PyrDownBorder )
+
+/* End of file. */
diff --git a/cv/src/cvpyrsegmentation.cpp b/cv/src/cvpyrsegmentation.cpp
new file mode 100644
index 0000000..4759d40
--- /dev/null
+++ b/cv/src/cvpyrsegmentation.cpp
@@ -0,0 +1,1883 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+typedef struct _CvRGBf
+{ float blue;
+ float green;
+ float red;
+}
+_CvRGBf;
+
+typedef struct _CvRect16u
+{
+ ushort x1, y1, x2, y2;
+}
+_CvRect16u;
+
+typedef struct _CvPyramid
+{
+ float c;
+ struct _CvPyramid *p;
+ int a;
+ _CvRect16u rect; /* ROI for the connected component */
+} _CvPyramid;
+
+/* element of base layer */
+typedef struct _CvPyramidBase
+{
+ float c;
+ struct _CvPyramid *p;
+}
+_CvPyramidBase;
+
+typedef struct _CvPyramidC3
+{
+ _CvRGBf c;
+ struct _CvPyramidC3 *p;
+ int a;
+ _CvRect16u rect; /* ROI for the connected component */
+} _CvPyramidC3;
+
+/* element of base layer */
+typedef struct _CvPyramidBaseC3
+{
+ _CvRGBf c;
+ struct _CvPyramidC3 *p;
+}
+_CvPyramidBaseC3;
+
+typedef struct _CvListNode
+{
+ struct _CvListNode* next;
+ void* data;
+}
+_CvListNode;
+
+
+static CvStatus icvSegmentClusterC1( CvSeq* cmp_seq, CvSeq* res_seq,
+ double threshold,
+ _CvPyramid* first_level_end,
+ CvSize first_level_size );
+
+static CvStatus icvSegmentClusterC3( CvSeq* cmp_seq, CvSeq* res_seq,
+ double threshold,
+ _CvPyramidC3* first_level_end,
+ CvSize first_level_size );
+
+static CvStatus icvUpdatePyrLinks_8u_C1
+ (int layer, void *layer_data, CvSize size, void *parent_layer,
+ void *_writer, float threshold, int is_last_iter, void *_stub, CvWriteNodeFunction /*func*/);
+
+static CvStatus icvUpdatePyrLinks_8u_C3
+ (int layer, void *layer_data, CvSize size, void *parent_layer,
+ void *_writer, float threshold, int is_last_iter, void *_stub, CvWriteNodeFunction /*func*/);
+
+static void icvMaxRoi( _CvRect16u *max_rect, _CvRect16u* cur_rect );
+static void icvMaxRoi1( _CvRect16u *max_rect, int x, int y );
+
+
+#define _CV_CHECK( icvFun ) \
+ { \
+ if( icvFun != CV_OK ) \
+ goto M_END; \
+ }
+
+
+#define _CV_MAX3( a, b, c) ((a)>(b) ? ((a)>(c) ? (a) : (c)) : ((b)>(c) ? (b) : (c)))
+
+/*#define _CV_RGB_DIST(a, b) _CV_MAX3((float)fabs((a).red - (b).red), \
+ (float)fabs((a).green - (b).green), \
+ (float)fabs((a).blue - (b).blue))*/
+
+#define _CV_NEXT_BASE_C1(p,n) (_CvPyramid*)((char*)(p) + (n)*sizeof(_CvPyramidBase))
+#define _CV_NEXT_BASE_C3(p,n) (_CvPyramidC3*)((char*)(p) + (n)*sizeof(_CvPyramidBaseC3))
+
+
+CV_INLINE float icvRGBDist_Max( const _CvRGBf& a, const _CvRGBf& b )
+{
+ float tr = (float)fabs(a.red - b.red);
+ float tg = (float)fabs(a.green - b.green);
+ float tb = (float)fabs(a.blue - b.blue);
+
+ return _CV_MAX3( tr, tg, tb );
+}
+
+CV_INLINE float icvRGBDist_Sum( const _CvRGBf& a, const _CvRGBf& b )
+{
+ float tr = (float)fabs(a.red - b.red);
+ float tg = (float)fabs(a.green - b.green);
+ float tb = (float)fabs(a.blue - b.blue);
+
+ return (tr + tg + tb);
+}
+
+#if 1
+#define _CV_RGB_DIST icvRGBDist_Max
+#define _CV_RGB_THRESH_SCALE 1
+#else
+#define _CV_RGB_DIST icvRGBDist_Sum
+#define _CV_RGB_THRESH_SCALE 3
+#endif
+
+#define _CV_INV_TAB_SIZE 32
+
+static const float icvInvTab[ /*_CV_INV_TAB_SIZE*/ ] =
+{
+ 1.00000000f, 0.50000000f, 0.33333333f, 0.25000000f, 0.20000000f, 0.16666667f,
+ 0.14285714f, 0.12500000f, 0.11111111f, 0.10000000f, 0.09090909f, 0.08333333f,
+ 0.07692308f, 0.07142857f, 0.06666667f, 0.06250000f, 0.05882353f, 0.05555556f,
+ 0.05263158f, 0.05000000f, 0.04761905f, 0.04545455f, 0.04347826f, 0.04166667f,
+ 0.04000000f, 0.03846154f, 0.03703704f, 0.03571429f, 0.03448276f, 0.03333333f,
+ 0.03225806f, 0.03125000f
+};
+
+static void
+icvWritePyrNode( void *elem, void *writer )
+{
+ CV_WRITE_SEQ_ELEM( *(_CvListNode *) elem, *(CvSeqWriter *) writer );
+}
+
+
+static CvStatus
+icvPyrSegmentation8uC1R( uchar * src_image, int src_step,
+ uchar * dst_image, int dst_step,
+ CvSize roi, CvFilter filter,
+ CvSeq ** dst_comp, CvMemStorage * storage,
+ int level, int threshold1, int threshold2 )
+{
+ int i, j, l;
+ int step;
+ const int max_iter = 3; /* maximum number of iterations */
+ int cur_iter = 0; /* current iteration */
+
+ _CvPyramid *pyram[16]; /* pointers to the pyramid down up to level */
+
+ float *pyramida = 0;
+ _CvPyramid stub;
+
+ _CvPyramid *p_cur;
+ _CvPyramidBase *p_base;
+ _CvListNode cmp_node;
+
+ CvSeq *cmp_seq = 0;
+ CvSeq *res_seq = 0;
+ CvMemStorage *temp_storage = 0;
+ CvSize size;
+ CvStatus status;
+ CvSeqWriter writer;
+
+ int buffer_size;
+ char *buffer = 0;
+
+ status = CV_OK;
+
+ /* clear pointer to resultant sequence */
+ if( dst_comp )
+ *dst_comp = 0;
+
+ /* check args */
+ if( !src_image || !dst_image || !storage || !dst_comp )
+ return CV_NULLPTR_ERR;
+ if( roi.width <= 0 || roi.height <= 0 || src_step < roi.width || dst_step < roi.width )
+ return CV_BADSIZE_ERR;
+ if( filter != CV_GAUSSIAN_5x5 )
+ return CV_BADRANGE_ERR;
+ if( threshold1 < 0 || threshold2 < 0 )
+ return CV_BADRANGE_ERR;
+ if( level <= 0 )
+ return CV_BADRANGE_ERR;
+
+ if( ((roi.width | roi.height) & ((1 << level) - 1)) != 0 )
+ return CV_BADCOEF_ERR;
+
+ temp_storage = cvCreateChildMemStorage( storage );
+
+ /* sequence for temporary components */
+ cmp_seq = cvCreateSeq( 0, sizeof( CvSeq ), sizeof( _CvListNode ), temp_storage );
+ assert( cmp_seq != 0 );
+
+ res_seq = cvCreateSeq( CV_SEQ_CONNECTED_COMP, sizeof( CvSeq ),
+ sizeof( CvConnectedComp ), storage );
+ assert( res_seq != 0 );
+
+ /* calculate buffer size */
+ buffer_size = roi.width * roi.height * (sizeof( float ) + sizeof( _CvPyramidBase ));
+
+ for( l = 1; l <= level; l++ )
+ buffer_size += ((roi.width >> l) + 1) * ((roi.height >> l) + 1) * sizeof(_CvPyramid);
+
+ /* allocate buffer */
+ buffer = (char *) cvAlloc( buffer_size );
+ if( !buffer )
+ {
+ status = CV_OUTOFMEM_ERR;
+ goto M_END;
+ }
+
+ pyramida = (float *) buffer;
+
+ /* initialization pyramid-linking properties down up to level */
+ step = roi.width * sizeof( float );
+
+ {
+ CvMat _src;
+ CvMat _pyramida;
+ cvInitMatHeader( &_src, roi.height, roi.width, CV_8UC1, src_image, src_step );
+ cvInitMatHeader( &_pyramida, roi.height, roi.width, CV_32FC1, pyramida, step );
+ cvConvert( &_src, &_pyramida );
+ /*_CV_CHECK( icvCvtTo_32f_C1R( src_image, src_step, pyramida, step, roi, CV_8UC1 ));*/
+ }
+ p_base = (_CvPyramidBase *) (buffer + step * roi.height);
+ pyram[0] = (_CvPyramid *) p_base;
+
+ /* fill base level of pyramid */
+ for( i = 0; i < roi.height; i++ )
+ {
+ for( j = 0; j < roi.width; j++, p_base++ )
+ {
+ p_base->c = pyramida[i * roi.width + j];
+ p_base->p = &stub;
+ }
+ }
+
+ p_cur = (_CvPyramid *) p_base;
+ size = roi;
+
+ /* calculate initial pyramid */
+ for( l = 1; l <= level; l++ )
+ {
+ CvSize dst_size = { size.width/2+1, size.height/2+1 };
+ CvMat prev_level = cvMat( size.height, size.width, CV_32FC1 );
+ CvMat next_level = cvMat( dst_size.height, dst_size.width, CV_32FC1 );
+
+ cvSetData( &prev_level, pyramida, step );
+ cvSetData( &next_level, pyramida, step );
+ cvPyrDown( &prev_level, &next_level );
+
+ //_CV_CHECK( icvPyrDown_Gauss5x5_32f_C1R( pyramida, step, pyramida, step, size, buff ));
+ //_CV_CHECK( icvPyrDownBorder_32f_CnR( pyramida, step, size, pyramida, step, dst_size, 1 ));
+ pyram[l] = p_cur;
+
+ size.width = dst_size.width - 1;
+ size.height = dst_size.height - 1;
+
+ /* fill layer #l */
+ for( i = 0; i <= size.height; i++ )
+ {
+ for( j = 0; j <= size.width; j++, p_cur++ )
+ {
+ p_cur->c = pyramida[i * roi.width + j];
+ p_cur->p = &stub;
+ p_cur->a = 0;
+ p_cur->rect.x2 = 0;
+ }
+ }
+ }
+
+ cvStartAppendToSeq( cmp_seq, &writer );
+
+ /* do several iterations to determine son-father links */
+ for( cur_iter = 0; cur_iter < max_iter; cur_iter++ )
+ {
+ int is_last_iter = cur_iter == max_iter - 1;
+
+ size = roi;
+
+ /* build son-father links down up to level */
+ for( l = 0; l < level; l++ )
+ {
+ icvUpdatePyrLinks_8u_C1( l, pyram[l], size, pyram[l + 1], &writer,
+ (float) threshold1, is_last_iter, &stub,
+ icvWritePyrNode );
+
+ /* clear last border row */
+ if( l > 0 )
+ {
+ p_cur = pyram[l] + (size.width + 1) * size.height;
+ for( j = 0; j <= size.width; j++ )
+ p_cur[j].c = 0;
+ }
+
+ size.width >>= 1;
+ size.height >>= 1;
+ }
+
+/* clear the old c value for the last level */
+ p_cur = pyram[level];
+ for( i = 0; i <= size.height; i++, p_cur += size.width + 1 )
+ for( j = 0; j <= size.width; j++ )
+ p_cur[j].c = 0;
+
+ size = roi;
+ step = roi.width;
+
+/* calculate average c value for the 0 < l <=level */
+ for( l = 0; l < level; l++, step = (step >> 1) + 1 )
+ {
+ _CvPyramid *p_prev, *p_row_prev;
+
+ stub.c = 0;
+
+ /* calculate average c value for the next level */
+ if( l == 0 )
+ {
+ p_base = (_CvPyramidBase *) pyram[0];
+ for( i = 0; i < roi.height; i++, p_base += size.width )
+ {
+ for( j = 0; j < size.width; j += 2 )
+ {
+ _CvPyramid *p1 = p_base[j].p;
+ _CvPyramid *p2 = p_base[j + 1].p;
+
+ p1->c += p_base[j].c;
+ p2->c += p_base[j + 1].c;
+ }
+ }
+ }
+ else
+ {
+ p_cur = pyram[l];
+ for( i = 0; i < size.height; i++, p_cur += size.width + 1 )
+ {
+ for( j = 0; j < size.width; j += 2 )
+ {
+ _CvPyramid *p1 = p_cur[j].p;
+ _CvPyramid *p2 = p_cur[j + 1].p;
+
+ float t0 = (float) p_cur[j].a * p_cur[j].c;
+ float t1 = (float) p_cur[j + 1].a * p_cur[j + 1].c;
+
+ p1->c += t0;
+ p2->c += t1;
+
+ if( !is_last_iter )
+ p_cur[j].a = p_cur[j + 1].a = 0;
+ }
+ if( !is_last_iter )
+ p_cur[size.width].a = 0;
+ }
+ if( !is_last_iter )
+ {
+ for( j = 0; j <= size.width; j++ )
+ {
+ p_cur[j].a = 0;
+ }
+ }
+ }
+
+ /* assign random values of the next level null c */
+ p_cur = pyram[l + 1];
+ p_row_prev = p_prev = pyram[l];
+
+ size.width >>= 1;
+ size.height >>= 1;
+
+ for( i = 0; i <= size.height; i++, p_cur += size.width + 1 )
+ {
+ if( i < size.height || !is_last_iter )
+ {
+ for( j = 0; j < size.width; j++ )
+ {
+ int a = p_cur[j].a;
+
+ if( a != 0 )
+ {
+ if( a <= _CV_INV_TAB_SIZE )
+ {
+ p_cur[j].c *= icvInvTab[a - 1];
+ }
+ else
+ {
+ p_cur[j].c /= a;
+ }
+ }
+ else
+ {
+ p_cur[j].c = p_prev->c;
+ }
+
+ if( l == 0 )
+ p_prev = _CV_NEXT_BASE_C1(p_prev,2);
+ else
+ p_prev += 2;
+ }
+
+ if( p_cur[size.width].a == 0 )
+ {
+ p_cur[size.width].c = p_prev[(l != 0) - 1].c;
+ }
+ else
+ {
+ p_cur[size.width].c /= p_cur[size.width].a;
+ if( is_last_iter )
+ {
+ cmp_node.data = p_cur + size.width;
+ CV_WRITE_SEQ_ELEM( cmp_node, writer );
+ }
+ }
+ }
+ else
+ {
+ for( j = 0; j <= size.width; j++ )
+ {
+ int a = p_cur[j].a;
+
+ if( a != 0 )
+ {
+ if( a <= _CV_INV_TAB_SIZE )
+ {
+ p_cur[j].c *= icvInvTab[a - 1];
+ }
+ else
+ {
+ p_cur[j].c /= a;
+ }
+
+ cmp_node.data = p_cur + j;
+ CV_WRITE_SEQ_ELEM( cmp_node, writer );
+ }
+ else
+ {
+ p_cur[j].c = p_prev->c;
+ }
+
+ if( l == 0 )
+ {
+ p_prev = _CV_NEXT_BASE_C1(p_prev, (j * 2 < step - 2 ? 2 : 1));
+ }
+ else
+ {
+ p_prev++;
+ }
+ }
+ }
+
+ if( l + 1 == level && !is_last_iter )
+ for( j = 0; j <= size.width; j++ )
+ p_cur[j].a = 0;
+
+ if( !(i & 1) )
+ {
+ p_prev = p_row_prev;
+ }
+ else
+ {
+ p_prev = (_CvPyramid*)((char*)p_row_prev + step *
+ (l == 0 ? sizeof(_CvPyramidBase) : sizeof(_CvPyramid)));
+ }
+ }
+ }
+ } /* end of the iteration process */
+
+ /* construct a connected components */
+ size.width = roi.width >> level;
+ size.height = roi.height >> level;
+
+ p_cur = pyram[level];
+
+ for( i = 0; i < size.height; i++, p_cur += size.width + 1 )
+ {
+ for( j = 0; j < size.width; j++ )
+ {
+ if( p_cur[j].a != 0 )
+ {
+ cmp_node.data = p_cur + j;
+ CV_WRITE_SEQ_ELEM( cmp_node, writer );
+ }
+ }
+ }
+
+ cvEndWriteSeq( &writer );
+
+/* clusterization segmented components and construction
+ output connected components */
+ icvSegmentClusterC1( cmp_seq, res_seq, threshold2, pyram[1], roi );
+
+/* convert (inplace) resultant segment values to int (top level) */
+
+/* propagate segment values top down */
+ for( l = level - 1; l >= 0; l-- )
+ {
+ p_cur = pyram[l];
+
+ size.width <<= 1;
+ size.height <<= 1;
+
+ if( l == 0 )
+ {
+ size.width--;
+ size.height--;
+ }
+
+ for( i = 0; i <= size.height; i++ )
+ {
+ for( j = 0; j <= size.width; j++ )
+ {
+ _CvPyramid *p = p_cur->p;
+
+ assert( p != 0 );
+ if( p != &stub )
+ p_cur->c = p->c;
+
+ if( l == 0 )
+ {
+ Cv32suf _c;
+ /* copy the segmented values to destination image */
+ _c.f = p_cur->c; dst_image[j] = (uchar)_c.i;
+ p_cur = _CV_NEXT_BASE_C1(p_cur, 1);
+ }
+ else
+ {
+ p_cur++;
+ }
+ }
+ if( l == 0 )
+ dst_image += dst_step;
+ }
+ }
+ M_END:
+
+ cvFree( &buffer );
+ cvReleaseMemStorage( &temp_storage );
+
+ if( status == CV_OK )
+ *dst_comp = res_seq;
+
+ return status;
+}
+
+
+
+/****************************************************************************************\
+ color!!! image segmentation by pyramid-linking
+\****************************************************************************************/
+static CvStatus
+icvPyrSegmentation8uC3R( uchar * src_image, int src_step,
+ uchar * dst_image, int dst_step,
+ CvSize roi, CvFilter filter,
+ CvSeq ** dst_comp, CvMemStorage * storage,
+ int level, int threshold1, int threshold2 )
+{
+ int i, j, l;
+
+ int step;
+ const int max_iter = 3; /* maximum number of iterations */
+ int cur_iter = 0; /* current iteration */
+
+ _CvPyramidC3 *pyram[16]; /* pointers to the pyramid down up to level */
+
+ float *pyramida = 0;
+ _CvPyramidC3 stub;
+
+ _CvPyramidC3 *p_cur;
+ _CvPyramidBaseC3 *p_base;
+ _CvListNode cmp_node;
+
+ CvSeq *cmp_seq = 0;
+ CvSeq *res_seq = 0;
+ CvMemStorage *temp_storage = 0;
+ CvSize size;
+ CvStatus status;
+ CvSeqWriter writer;
+
+ int buffer_size;
+ char *buffer = 0;
+
+ status = CV_OK;
+
+ threshold1 *= _CV_RGB_THRESH_SCALE;
+ threshold2 *= _CV_RGB_THRESH_SCALE;
+
+ /* clear pointer to resultant sequence */
+ if( dst_comp )
+ *dst_comp = 0;
+
+ /* check args */
+ if( !src_image || !dst_image || !storage || !dst_comp )
+ return CV_NULLPTR_ERR;
+ if( roi.width <= 0 || roi.height <= 0 ||
+ src_step < roi.width * 3 || dst_step < roi.width * 3 ) return CV_BADSIZE_ERR;
+ if( filter != CV_GAUSSIAN_5x5 )
+ return CV_BADRANGE_ERR;
+ if( threshold1 < 0 || threshold2 < 0 )
+ return CV_BADRANGE_ERR;
+ if( level <= 0 )
+ return CV_BADRANGE_ERR;
+
+ if( ((roi.width | roi.height) & ((1 << level) - 1)) != 0 )
+ return CV_BADCOEF_ERR;
+
+ temp_storage = cvCreateChildMemStorage( storage );
+
+ /* sequence for temporary components */
+ cmp_seq = cvCreateSeq( 0, sizeof( CvSeq ), sizeof( _CvListNode ), temp_storage );
+ assert( cmp_seq != 0 );
+
+ res_seq = cvCreateSeq( CV_SEQ_CONNECTED_COMP, sizeof( CvSeq ),
+ sizeof( CvConnectedComp ), storage );
+ assert( res_seq != 0 );
+
+ /* calculate buffer size */
+ buffer_size = roi.width * roi.height * (sizeof( _CvRGBf ) + sizeof( _CvPyramidBaseC3 ));
+
+ for( l = 1; l <= level; l++ )
+ buffer_size += ((roi.width >> l) + 1) * ((roi.height >> l) + 1) * sizeof(_CvPyramidC3);
+
+ /* allocate buffer */
+ buffer = (char *) cvAlloc( buffer_size );
+ if( !buffer )
+ {
+ status = CV_OUTOFMEM_ERR;
+ goto M_END;
+ }
+
+ pyramida = (float *) buffer;
+
+ /* initialization pyramid-linking properties down up to level */
+ step = roi.width * sizeof( _CvRGBf );
+
+ {
+ CvMat _src;
+ CvMat _pyramida;
+ cvInitMatHeader( &_src, roi.height, roi.width, CV_8UC3, src_image, src_step );
+ cvInitMatHeader( &_pyramida, roi.height, roi.width, CV_32FC3, pyramida, step );
+ cvConvert( &_src, &_pyramida );
+ /*_CV_CHECK( icvCvtTo_32f_C1R( src_image, src_step, pyramida, step,
+ cvSize( roi.width * 3, roi.height ), CV_8UC1 ));*/
+ }
+
+ p_base = (_CvPyramidBaseC3 *) (buffer + step * roi.height);
+ pyram[0] = (_CvPyramidC3 *) p_base;
+
+ /* fill base level of pyramid */
+ for( i = 0; i < roi.height; i++ )
+ {
+ for( j = 0; j < roi.width; j++, p_base++ )
+ {
+ p_base->c = ((_CvRGBf *) pyramida)[i * roi.width + j];
+ p_base->p = &stub;
+ }
+ }
+
+ p_cur = (_CvPyramidC3 *) p_base;
+ size = roi;
+
+ /* calculate initial pyramid */
+ for( l = 1; l <= level; l++ )
+ {
+ CvSize dst_size = { size.width/2 + 1, size.height/2 + 1 };
+ CvMat prev_level = cvMat( size.height, size.width, CV_32FC3 );
+ CvMat next_level = cvMat( dst_size.height, dst_size.width, CV_32FC3 );
+
+ cvSetData( &prev_level, pyramida, step );
+ cvSetData( &next_level, pyramida, step );
+ cvPyrDown( &prev_level, &next_level );
+
+ //_CV_CHECK( icvPyrDown_Gauss5x5_32f_C3R( pyramida, step, pyramida, step, size, buff ));
+ //_CV_CHECK( icvPyrDownBorder_32f_CnR( pyramida, step, size, pyramida, step, dst_size, 3 ));
+ pyram[l] = p_cur;
+
+ size.width = dst_size.width - 1;
+ size.height = dst_size.height - 1;
+
+ /* fill layer #l */
+ for( i = 0; i <= size.height; i++ )
+ {
+ assert( (char*)p_cur - buffer < buffer_size );
+ for( j = 0; j <= size.width; j++, p_cur++ )
+ {
+ p_cur->c = ((_CvRGBf *) pyramida)[i * roi.width + j];
+ p_cur->p = &stub;
+ p_cur->a = 0;
+ p_cur->rect.x2 = 0;
+ }
+ }
+ }
+
+ cvStartAppendToSeq( cmp_seq, &writer );
+
+ /* do several iterations to determine son-father links */
+ for( cur_iter = 0; cur_iter < max_iter; cur_iter++ )
+ {
+ int is_last_iter = cur_iter == max_iter - 1;
+
+ size = roi;
+
+ /* build son-father links down up to level */
+ for( l = 0; l < level; l++ )
+ {
+ icvUpdatePyrLinks_8u_C3( l, pyram[l], size, pyram[l + 1], &writer,
+ (float) threshold1, is_last_iter, &stub,
+ icvWritePyrNode );
+
+ /* clear last border row */
+ if( l > 0 )
+ {
+ p_cur = pyram[l] + (size.width + 1) * size.height;
+ for( j = 0; j <= size.width; j++ )
+ p_cur[j].c.blue = p_cur[j].c.green = p_cur[j].c.red = 0;
+ }
+
+ size.width >>= 1;
+ size.height >>= 1;
+ }
+
+/* clear the old c value for the last level */
+ p_cur = pyram[level];
+ for( i = 0; i <= size.height; i++, p_cur += size.width + 1 )
+ for( j = 0; j <= size.width; j++ )
+ p_cur[j].c.blue = p_cur[j].c.green = p_cur[j].c.red = 0;
+
+ size = roi;
+ step = roi.width;
+
+/* calculate average c value for the 0 < l <=level */
+ for( l = 0; l < level; l++, step = (step >> 1) + 1 )
+ {
+ _CvPyramidC3 *p_prev, *p_row_prev;
+
+ stub.c.blue = stub.c.green = stub.c.red = 0;
+
+ /* calculate average c value for the next level */
+ if( l == 0 )
+ {
+ p_base = (_CvPyramidBaseC3 *) pyram[0];
+ for( i = 0; i < roi.height; i++, p_base += size.width )
+ {
+ for( j = 0; j < size.width; j++ )
+ {
+ _CvPyramidC3 *p = p_base[j].p;
+
+ p->c.blue += p_base[j].c.blue;
+ p->c.green += p_base[j].c.green;
+ p->c.red += p_base[j].c.red;
+ }
+ }
+ }
+ else
+ {
+ p_cur = pyram[l];
+ for( i = 0; i < size.height; i++, p_cur += size.width + 1 )
+ {
+ for( j = 0; j < size.width; j++ )
+ {
+ _CvPyramidC3 *p = p_cur[j].p;
+ float a = (float) p_cur[j].a;
+
+ p->c.blue += a * p_cur[j].c.blue;
+ p->c.green += a * p_cur[j].c.green;
+ p->c.red += a * p_cur[j].c.red;
+
+ if( !is_last_iter )
+ p_cur[j].a = 0;
+ }
+ if( !is_last_iter )
+ p_cur[size.width].a = 0;
+ }
+ if( !is_last_iter )
+ {
+ for( j = 0; j <= size.width; j++ )
+ {
+ p_cur[j].a = 0;
+ }
+ }
+ }
+
+ /* assign random values of the next level null c */
+ p_cur = pyram[l + 1];
+ p_row_prev = p_prev = pyram[l];
+
+ size.width >>= 1;
+ size.height >>= 1;
+
+ for( i = 0; i <= size.height; i++, p_cur += size.width + 1 )
+ {
+ if( i < size.height || !is_last_iter )
+ {
+ for( j = 0; j < size.width; j++ )
+ {
+ int a = p_cur[j].a;
+
+ if( a != 0 )
+ {
+ float inv_a;
+
+ if( a <= _CV_INV_TAB_SIZE )
+ {
+ inv_a = icvInvTab[a - 1];
+ }
+ else
+ {
+ inv_a = 1.f / a;
+ }
+ p_cur[j].c.blue *= inv_a;
+ p_cur[j].c.green *= inv_a;
+ p_cur[j].c.red *= inv_a;
+ }
+ else
+ {
+ p_cur[j].c = p_prev->c;
+ }
+
+ if( l == 0 )
+ p_prev = _CV_NEXT_BASE_C3( p_prev, 2 );
+ else
+ p_prev += 2;
+ }
+
+ if( p_cur[size.width].a == 0 )
+ {
+ p_cur[size.width].c = p_prev[(l != 0) - 1].c;
+ }
+ else
+ {
+ p_cur[size.width].c.blue /= p_cur[size.width].a;
+ p_cur[size.width].c.green /= p_cur[size.width].a;
+ p_cur[size.width].c.red /= p_cur[size.width].a;
+ if( is_last_iter )
+ {
+ cmp_node.data = p_cur + size.width;
+ CV_WRITE_SEQ_ELEM( cmp_node, writer );
+ }
+ }
+ }
+ else
+ {
+ for( j = 0; j <= size.width; j++ )
+ {
+ int a = p_cur[j].a;
+
+ if( a != 0 )
+ {
+ float inv_a;
+
+ if( a <= _CV_INV_TAB_SIZE )
+ {
+ inv_a = icvInvTab[a - 1];
+ }
+ else
+ {
+ inv_a = 1.f / a;
+ }
+ p_cur[j].c.blue *= inv_a;
+ p_cur[j].c.green *= inv_a;
+ p_cur[j].c.red *= inv_a;
+
+ cmp_node.data = p_cur + j;
+ CV_WRITE_SEQ_ELEM( cmp_node, writer );
+ }
+ else
+ {
+ p_cur[j].c = p_prev->c;
+ }
+
+ if( l == 0 )
+ {
+ p_prev = _CV_NEXT_BASE_C3( p_prev, (j * 2 < step - 2 ? 2 : 1));
+ }
+ else
+ {
+ p_prev++;
+ }
+ }
+ }
+
+ if( l + 1 == level && !is_last_iter )
+ for( j = 0; j <= size.width; j++ )
+ p_cur[j].a = 0;
+
+ if( !(i & 1) )
+ {
+ p_prev = p_row_prev;
+ }
+ else
+ {
+ p_prev = (_CvPyramidC3*)((char*)p_row_prev + step *
+ (l == 0 ? sizeof( _CvPyramidBaseC3 ) : sizeof( _CvPyramidC3 )));
+ }
+ }
+ }
+ } /* end of the iteration process */
+
+ /* construct a connected components */
+ size.width = roi.width >> level;
+ size.height = roi.height >> level;
+
+ p_cur = pyram[level];
+
+ for( i = 0; i < size.height; i++, p_cur += size.width + 1 )
+ {
+ for( j = 0; j < size.width; j++ )
+ {
+ if( p_cur[j].a != 0 )
+ {
+ cmp_node.data = p_cur + j;
+ CV_WRITE_SEQ_ELEM( cmp_node, writer );
+ }
+ }
+ }
+
+ cvEndWriteSeq( &writer );
+
+/* clusterization segmented components and construction
+ output connected components */
+ icvSegmentClusterC3( cmp_seq, res_seq, threshold2, pyram[1], roi );
+
+/* convert (inplace) resultant segment values to int (top level) */
+
+/* propagate segment values top down */
+ for( l = level - 1; l >= 0; l-- )
+ {
+ p_cur = pyram[l];
+
+ size.width <<= 1;
+ size.height <<= 1;
+
+ if( l == 0 )
+ {
+ size.width--;
+ size.height--;
+ }
+
+ for( i = 0; i <= size.height; i++ )
+ {
+ for( j = 0; j <= size.width; j++ )
+ {
+ _CvPyramidC3 *p = p_cur->p;
+
+ assert( p != 0 );
+ if( p != &stub )
+ {
+ p_cur->c = p->c;
+ }
+
+ if( l == 0 )
+ {
+ Cv32suf _c;
+ /* copy the segmented values to destination image */
+ _c.f = p_cur->c.blue; dst_image[j*3] = (uchar)_c.i;
+ _c.f = p_cur->c.green; dst_image[j*3+1] = (uchar)_c.i;
+ _c.f = p_cur->c.red; dst_image[j*3+2] = (uchar)_c.i;
+ p_cur = _CV_NEXT_BASE_C3(p_cur,1);
+ }
+ else
+ {
+ p_cur++;
+ }
+ }
+ if( l == 0 )
+ dst_image += dst_step;
+ }
+ }
+
+ M_END:
+
+ cvFree( &buffer );
+ cvReleaseMemStorage( &temp_storage );
+
+ if( status == CV_OK )
+ *dst_comp = res_seq;
+
+ return status;
+}
+
+
+static CvStatus icvUpdatePyrLinks_8u_C1
+ (int layer, void *layer_data, CvSize size, void *parent_layer,
+ void *_writer, float threshold, int is_last_iter, void *_stub, CvWriteNodeFunction /*func*/)
+{
+ int i, j;
+ _CvListNode cmp_node;
+
+ _CvPyramid *stub = (_CvPyramid *) _stub;
+ _CvPyramid *p_cur = (_CvPyramid *) layer_data;
+ _CvPyramid *p_next1 = (_CvPyramid *) parent_layer;
+ _CvPyramid *p_next3 = p_next1 + (size.width >> 1) + 1;
+
+ CvSeqWriter & writer = *(CvSeqWriter *) _writer;
+
+ for( i = 0; i < size.height; i++ )
+ {
+ for( j = 0; j < size.width; j += 2 )
+ {
+ float c0, c1, c2, c3, c4;
+ _CvPyramid *p;
+
+/* son-father threshold linking for the current node establish */
+ c0 = p_cur->c;
+
+/* find pointer for the first pixel */
+ c1 = (float) fabs( c0 - p_next1[0].c );
+ c2 = (float) fabs( c0 - p_next1[1].c );
+ c3 = (float) fabs( c0 - p_next3[0].c );
+ c4 = (float) fabs( c0 - p_next3[1].c );
+
+ p = p_next1;
+
+ if( c1 > c2 )
+ {
+ p = p_next1 + 1;
+ c1 = c2;
+ }
+ if( c1 > c3 )
+ {
+ p = p_next3;
+ c1 = c3;
+ }
+ if( c1 > c4 )
+ {
+ p = p_next3 + 1;
+ c1 = c4;
+ }
+
+ if( c1 <= threshold )
+ {
+ p_cur->p = p;
+
+ if( layer == 0 )
+ {
+ p->a++;
+ p_cur = (_CvPyramid*)((char*)p_cur + sizeof(_CvPyramidBase));
+ if( is_last_iter )
+ icvMaxRoi1( &(p->rect), j, i );
+ }
+ else
+ {
+ int a = p_cur->a;
+
+ p->a += a;
+ p_cur->c = 0;
+ p_cur++;
+ if( is_last_iter && a != 0 )
+ icvMaxRoi( &(p->rect), &(p_cur[-1].rect) );
+ }
+ }
+ else
+ {
+ p_cur->p = stub;
+ if( is_last_iter )
+ {
+ cmp_node.data = p_cur;
+ CV_WRITE_SEQ_ELEM( cmp_node, writer );
+ }
+ if( layer == 0 )
+ {
+ p_cur = _CV_NEXT_BASE_C1(p_cur,1);
+ }
+ else
+ {
+ p_cur->c = 0;
+ p_cur++;
+ }
+ }
+
+ /* find pointer for the second pixel */
+ c0 = p_cur->c;
+
+ c1 = (float) fabs( c0 - p_next1[0].c );
+ c2 = (float) fabs( c0 - p_next1[1].c );
+ c3 = (float) fabs( c0 - p_next3[0].c );
+ c4 = (float) fabs( c0 - p_next3[1].c );
+
+ p = p_next1;
+ p_next1++;
+
+ if( c1 > c2 )
+ {
+ p = p_next1;
+ c1 = c2;
+ }
+ if( c1 > c3 )
+ {
+ p = p_next3;
+ c1 = c3;
+ }
+
+ p_next3++;
+ if( c1 > c4 )
+ {
+ p = p_next3;
+ c1 = c4;
+ }
+
+ if( c1 <= threshold )
+ {
+ p_cur->p = p;
+
+ if( layer == 0 )
+ {
+ p->a++;
+ p_cur = _CV_NEXT_BASE_C1(p_cur,1);
+ if( is_last_iter )
+ icvMaxRoi1( &(p->rect), j + 1, i );
+ }
+ else
+ {
+ int a = p_cur->a;
+
+ p->a += a;
+ p_cur->c = 0;
+ p_cur++;
+ if( is_last_iter && a != 0 )
+ icvMaxRoi( &(p->rect), &(p_cur[-1].rect) );
+ }
+ }
+ else
+ {
+ p_cur->p = stub;
+ if( is_last_iter )
+ {
+ cmp_node.data = p_cur;
+ CV_WRITE_SEQ_ELEM( cmp_node, writer );
+ }
+ if( layer == 0 )
+ {
+ p_cur = _CV_NEXT_BASE_C1(p_cur,1);
+ }
+ else
+ {
+ p_cur->c = 0;
+ p_cur++;
+ }
+ }
+ }
+
+ /* clear c's */
+ if( layer > 0 )
+ {
+ p_cur->c = 0;
+ p_cur++;
+ }
+
+ if( !(i & 1) )
+ {
+ p_next1 -= size.width >> 1;
+ p_next3 -= size.width >> 1;
+ }
+ else
+ {
+ p_next1++;
+ p_next3++;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus icvUpdatePyrLinks_8u_C3
+ (int layer, void *layer_data, CvSize size, void *parent_layer,
+ void *_writer, float threshold, int is_last_iter, void *_stub, CvWriteNodeFunction /*func*/)
+{
+ int i, j;
+ _CvListNode cmp_node;
+
+ _CvPyramidC3 *stub = (_CvPyramidC3 *) _stub;
+ _CvPyramidC3 *p_cur = (_CvPyramidC3 *) layer_data;
+ _CvPyramidC3 *p_next1 = (_CvPyramidC3 *) parent_layer;
+ _CvPyramidC3 *p_next3 = p_next1 + (size.width >> 1) + 1;
+
+ CvSeqWriter & writer = *(CvSeqWriter *) _writer;
+
+ for( i = 0; i < size.height; i++ )
+ {
+ for( j = 0; j < size.width; j += 2 )
+ {
+ float c1, c2, c3, c4;
+ _CvPyramidC3 *p;
+
+/* find pointer for the first pixel */
+ c1 = _CV_RGB_DIST( p_cur->c, p_next1[0].c );
+ c2 = _CV_RGB_DIST( p_cur->c, p_next1[1].c );
+ c3 = _CV_RGB_DIST( p_cur->c, p_next3[0].c );
+ c4 = _CV_RGB_DIST( p_cur->c, p_next3[1].c );
+
+ p = p_next1;
+
+ if( c1 > c2 )
+ {
+ p = p_next1 + 1;
+ c1 = c2;
+ }
+ if( c1 > c3 )
+ {
+ p = p_next3;
+ c1 = c3;
+ }
+ if( c1 > c4 )
+ {
+ p = p_next3 + 1;
+ c1 = c4;
+ }
+
+ if( c1 < threshold )
+ {
+ p_cur->p = p;
+
+ if( layer == 0 )
+ {
+ p->a++;
+ p_cur = _CV_NEXT_BASE_C3(p_cur,1);
+ if( is_last_iter )
+ icvMaxRoi1( &(p->rect), j, i );
+ }
+ else
+ {
+ int a = p_cur->a;
+
+ p->a += a;
+ p_cur->c.blue = p_cur->c.green = p_cur->c.red = 0;
+ p_cur++;
+ if( is_last_iter && a != 0 )
+ icvMaxRoi( &(p->rect), &(p_cur[-1].rect) );
+ }
+ }
+ else
+ {
+ p_cur->p = stub;
+ if( is_last_iter /* && ( == 0 || p_cur->a != 0) */ )
+ {
+ cmp_node.data = p_cur;
+ CV_WRITE_SEQ_ELEM( cmp_node, writer );
+ }
+
+ if( layer == 0 )
+ {
+ p_cur = _CV_NEXT_BASE_C3(p_cur,1);
+ }
+ else
+ {
+ p_cur->c.blue = p_cur->c.green = p_cur->c.red = 0;
+ p_cur++;
+ }
+ }
+
+ /* find pointer for the second pixel */
+ c1 = _CV_RGB_DIST( p_cur->c, p_next1[0].c );
+ c2 = _CV_RGB_DIST( p_cur->c, p_next1[1].c );
+ c3 = _CV_RGB_DIST( p_cur->c, p_next3[0].c );
+ c4 = _CV_RGB_DIST( p_cur->c, p_next3[1].c );
+
+ p = p_next1;
+ p_next1++;
+
+ if( c1 > c2 )
+ {
+ p = p_next1;
+ c1 = c2;
+ }
+ if( c1 > c3 )
+ {
+ p = p_next3;
+ c1 = c3;
+ }
+
+ p_next3++;
+ if( c1 > c4 )
+ {
+ p = p_next3;
+ c1 = c4;
+ }
+
+ if( c1 < threshold )
+ {
+ p_cur->p = p;
+
+ if( layer == 0 )
+ {
+ p->a++;
+ p_cur = _CV_NEXT_BASE_C3(p_cur,1);
+ if( is_last_iter )
+ icvMaxRoi1( &(p->rect), j + 1, i );
+ }
+ else
+ {
+ int a = p_cur->a;
+
+ p->a += a;
+ p_cur->c.blue = p_cur->c.green = p_cur->c.red = 0;
+ p_cur++;
+ if( is_last_iter && a != 0 )
+ icvMaxRoi( &(p->rect), &(p_cur[-1].rect) );
+ }
+ }
+ else
+ {
+ p_cur->p = stub;
+ if( is_last_iter /* && ( == 0 || p_cur->a != 0) */ )
+ {
+ cmp_node.data = p_cur;
+ CV_WRITE_SEQ_ELEM( cmp_node, writer );
+ }
+ if( layer == 0 )
+ {
+ p_cur = _CV_NEXT_BASE_C3(p_cur,1);
+ }
+ else
+ {
+ p_cur->c.blue = p_cur->c.green = p_cur->c.red = 0;
+ p_cur++;
+ }
+ }
+ }
+
+ /* clear c's */
+ if( layer > 0 )
+ {
+ p_cur->c.blue = p_cur->c.green = p_cur->c.red = 0;
+ p_cur++;
+ }
+
+ if( !(i & 1) )
+ {
+ p_next1 -= size.width >> 1;
+ p_next3 -= size.width >> 1;
+ }
+ else
+ {
+ p_next1++;
+ p_next3++;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+
+/****************************************************************************************\
+
+ clusterization segmented components
+
+\****************************************************************************************/
+static void
+icvExpandBaseLevelC1( _CvPyramid * base_p, _CvPyramid * p, _CvPyramidBase * start, int width )
+{
+ int x = (int)((_CvPyramidBase *) base_p - start);
+ int y = x / width;
+
+ x -= y * width;
+ p->a = 1;
+ p->rect.x1 = (ushort) x;
+ p->rect.y1 = (ushort) y;
+ p->rect.x2 = (ushort) (x + 1);
+ p->rect.y2 = (ushort) (y + 1);
+ p->c = base_p->c;
+}
+
+CvStatus
+icvSegmentClusterC1( CvSeq * cmp_seq, CvSeq * res_seq,
+ double threshold, _CvPyramid * first_level_end, CvSize first_level_size )
+{
+ const double eps = 1.;
+ CvSeqWriter writer;
+ CvSeqReader reader;
+ _CvPyramid temp_cmp;
+ _CvPyramidBase *first_level_start = (_CvPyramidBase *) first_level_end -
+ first_level_size.width * first_level_size.height;
+ int c, i, count = cmp_seq->total;
+
+ cvStartReadSeq( cmp_seq, &reader, 0 );
+ cvStartAppendToSeq( res_seq, &writer );
+
+ if( threshold < eps )
+ {
+ /* if threshold is too small then simply copy all
+ the components to the output sequence */
+ for( i = 0; i < count; i++ )
+ {
+ CvConnectedComp comp;
+ _CvPyramid *cmp = (_CvPyramid *) (((_CvListNode *) reader.ptr)->data);
+ Cv32suf _c;
+
+ if( cmp < first_level_end )
+ {
+ icvExpandBaseLevelC1( cmp, &temp_cmp, first_level_start,
+ first_level_size.width );
+ cmp = &temp_cmp;
+ }
+
+ _c.i = cvRound( cmp->c );
+ cmp->c = _c.f;
+ comp.value = cvRealScalar(_c.i);
+ comp.area = cmp->a;
+ comp.rect.x = cmp->rect.x1;
+ comp.rect.y = cmp->rect.y1;
+ comp.rect.width = cmp->rect.x2 - cmp->rect.x1;
+ comp.rect.height = cmp->rect.y2 - cmp->rect.y1;
+ comp.contour = 0;
+
+ CV_WRITE_SEQ_ELEM( comp, writer );
+ CV_NEXT_SEQ_ELEM( sizeof( _CvListNode ), reader );
+ }
+ }
+ else
+ {
+ _CvListNode stub_node;
+ _CvListNode *prev = &stub_node;
+
+ stub_node.next = 0;
+
+ for( i = 0; i < count; i++ )
+ {
+ _CvListNode *node = (_CvListNode *) reader.ptr;
+
+ prev->next = node;
+ prev = node;
+ CV_NEXT_SEQ_ELEM( sizeof( _CvListNode ), reader );
+ }
+ prev->next = 0;
+ prev = stub_node.next;
+
+ while( prev )
+ {
+ _CvListNode *node = prev->next;
+ _CvListNode *acc = prev;
+ _CvPyramid *cmp = (_CvPyramid *) (acc->data);
+ CvConnectedComp comp;
+ float c0 = cmp->c;
+
+ if( cmp < first_level_end )
+ {
+ icvExpandBaseLevelC1( cmp, &temp_cmp, first_level_start,
+ first_level_size.width );
+ }
+ else
+ {
+ temp_cmp = *cmp;
+ temp_cmp.c *= temp_cmp.a;
+ }
+
+ acc->next = 0;
+ stub_node.next = 0;
+ prev = &stub_node;
+
+ while( node )
+ {
+ cmp = (_CvPyramid *) (node->data);
+ if( fabs( c0 - cmp->c ) < threshold )
+ {
+ _CvPyramid temp;
+
+ /* exclude from global list and add to list of joint component */
+ prev->next = node->next;
+ node->next = acc;
+ acc = node;
+
+ if( cmp < first_level_end )
+ {
+ icvExpandBaseLevelC1( cmp, &temp, first_level_start,
+ first_level_size.width );
+ cmp = &temp;
+ }
+
+ temp_cmp.a += cmp->a;
+ temp_cmp.c += cmp->c * cmp->a;
+ icvMaxRoi( &(temp_cmp.rect), &(cmp->rect) );
+ }
+ else
+ {
+ if( prev == &stub_node )
+ {
+ stub_node.next = node;
+ }
+ prev = node;
+ }
+ node = prev->next;
+ }
+
+ if( temp_cmp.a != 0 )
+ {
+ c = cvRound( temp_cmp.c / temp_cmp.a );
+ }
+ else
+ {
+ c = cvRound( c0 );
+ }
+ node = acc;
+
+ while( node )
+ {
+ Cv32suf _c;
+ cmp = (_CvPyramid *) (node->data);
+ _c.i = c; cmp->c = _c.f;
+ node = node->next;
+ }
+
+ comp.value = cvRealScalar(c);
+ comp.area = temp_cmp.a;
+ comp.rect.x = temp_cmp.rect.x1;
+ comp.rect.y = temp_cmp.rect.y1;
+ comp.rect.width = temp_cmp.rect.x2 - temp_cmp.rect.x1;
+ comp.rect.height = temp_cmp.rect.y2 - temp_cmp.rect.y1;
+ comp.contour = 0;
+
+ CV_WRITE_SEQ_ELEM( comp, writer );
+ prev = stub_node.next;
+ }
+ }
+
+ cvEndWriteSeq( &writer );
+ return CV_OK;
+}
+
+/****************************************************************************************\
+
+ clusterization segmented components
+
+\****************************************************************************************/
+static void
+icvExpandBaseLevelC3( _CvPyramidC3 * base_p, _CvPyramidC3 * p,
+ _CvPyramidBaseC3 * start, int width )
+{
+ int x = (int)((_CvPyramidBaseC3 *) base_p - start);
+ int y = x / width;
+
+ x -= y * width;
+ p->a = 1;
+ p->rect.x1 = (ushort) x;
+ p->rect.y1 = (ushort) y;
+ p->rect.x2 = (ushort) (x + 1);
+ p->rect.y2 = (ushort) (y + 1);
+ p->c = base_p->c;
+}
+
+CvStatus
+icvSegmentClusterC3( CvSeq * cmp_seq, CvSeq * res_seq,
+ double threshold,
+ _CvPyramidC3 * first_level_end, CvSize first_level_size )
+{
+ const double eps = 1.;
+ CvSeqWriter writer;
+ CvSeqReader reader;
+ _CvPyramidC3 temp_cmp;
+ _CvPyramidBaseC3 *first_level_start = (_CvPyramidBaseC3 *) first_level_end -
+ first_level_size.width * first_level_size.height;
+ int i, count = cmp_seq->total;
+ int c_blue, c_green, c_red;
+
+ cvStartReadSeq( cmp_seq, &reader, 0 );
+ cvStartAppendToSeq( res_seq, &writer );
+
+ if( threshold < eps )
+ {
+ /* if threshold is too small then simply copy all
+ the components to the output sequence */
+ for( i = 0; i < count; i++ )
+ {
+ CvConnectedComp comp;
+ _CvPyramidC3 *cmp = (_CvPyramidC3 *) (((_CvListNode *) reader.ptr)->data);
+ Cv32suf _c;
+
+ if( cmp < first_level_end )
+ {
+ icvExpandBaseLevelC3( cmp, &temp_cmp, first_level_start,
+ first_level_size.width );
+ cmp = &temp_cmp;
+ }
+
+ c_blue = cvRound( cmp->c.blue );
+ c_green = cvRound( cmp->c.green );
+ c_red = cvRound( cmp->c.red );
+ _c.i = c_blue; cmp->c.blue = _c.f;
+ _c.i = c_green; cmp->c.green = _c.f;
+ _c.i = c_red; cmp->c.red = _c.f;
+ comp.value = cvScalar( c_blue, c_green, c_red );
+ comp.area = cmp->a;
+ comp.rect.x = cmp->rect.x1;
+ comp.rect.y = cmp->rect.y1;
+ comp.rect.width = cmp->rect.x2 - cmp->rect.x1;
+ comp.rect.height = cmp->rect.y2 - cmp->rect.y1;
+ comp.contour = 0;
+
+ CV_WRITE_SEQ_ELEM( comp, writer );
+ CV_NEXT_SEQ_ELEM( sizeof( _CvListNode ), reader );
+ }
+ }
+ else
+ {
+ _CvListNode stub_node;
+ _CvListNode *prev = &stub_node;
+
+ stub_node.next = 0;
+
+ for( i = 0; i < count; i++ )
+ {
+ _CvListNode *node = (_CvListNode *) reader.ptr;
+
+ prev->next = node;
+ prev = node;
+ CV_NEXT_SEQ_ELEM( sizeof( _CvListNode ), reader );
+ }
+ prev->next = 0;
+ prev = stub_node.next;
+
+ while( prev )
+ {
+ _CvListNode *node = prev->next;
+ _CvListNode *acc = prev;
+ _CvPyramidC3 *cmp = (_CvPyramidC3 *) (acc->data);
+ CvConnectedComp comp;
+ _CvRGBf c0 = cmp->c;
+
+ if( cmp < first_level_end )
+ {
+ icvExpandBaseLevelC3( cmp, &temp_cmp, first_level_start,
+ first_level_size.width );
+ }
+ else
+ {
+ temp_cmp = *cmp;
+ temp_cmp.c.blue *= temp_cmp.a;
+ temp_cmp.c.green *= temp_cmp.a;
+ temp_cmp.c.red *= temp_cmp.a;
+ }
+
+ acc->next = 0;
+ stub_node.next = 0;
+ prev = &stub_node;
+
+ while( node )
+ {
+ cmp = (_CvPyramidC3 *) (node->data);
+ if( _CV_RGB_DIST( c0, cmp->c ) < threshold )
+ {
+ _CvPyramidC3 temp;
+
+ /* exclude from global list and add to list of joint component */
+ prev->next = node->next;
+ node->next = acc;
+ acc = node;
+
+ if( cmp < first_level_end )
+ {
+ icvExpandBaseLevelC3( cmp, &temp, first_level_start,
+ first_level_size.width );
+ cmp = &temp;
+ }
+
+ temp_cmp.a += cmp->a;
+ temp_cmp.c.blue += cmp->c.blue * cmp->a;
+ temp_cmp.c.green += cmp->c.green * cmp->a;
+ temp_cmp.c.red += cmp->c.red * cmp->a;
+ icvMaxRoi( &(temp_cmp.rect), &(cmp->rect) );
+ }
+ else
+ {
+ if( prev == &stub_node )
+ {
+ stub_node.next = node;
+ }
+ prev = node;
+ }
+ node = prev->next;
+ }
+
+ if( temp_cmp.a != 0 )
+ {
+ c_blue = cvRound( temp_cmp.c.blue / temp_cmp.a );
+ c_green = cvRound( temp_cmp.c.green / temp_cmp.a );
+ c_red = cvRound( temp_cmp.c.red / temp_cmp.a );
+ }
+ else
+ {
+ c_blue = cvRound( c0.blue );
+ c_green = cvRound( c0.green );
+ c_red = cvRound( c0.red );
+ }
+ node = acc;
+
+ while( node )
+ {
+ Cv32suf _c;
+ cmp = (_CvPyramidC3 *) (node->data);
+ _c.i = c_blue; cmp->c.blue = _c.f;
+ _c.i = c_green; cmp->c.green = _c.f;
+ _c.i = c_red; cmp->c.red = _c.f;
+ node = node->next;
+ }
+
+ comp.value = cvScalar( c_blue, c_green, c_red );
+ comp.area = temp_cmp.a;
+ comp.rect.x = temp_cmp.rect.x1;
+ comp.rect.y = temp_cmp.rect.y1;
+ comp.rect.width = temp_cmp.rect.x2 - temp_cmp.rect.x1;
+ comp.rect.height = temp_cmp.rect.y2 - temp_cmp.rect.y1;
+ comp.contour = 0;
+
+ CV_WRITE_SEQ_ELEM( comp, writer );
+ prev = stub_node.next;
+ }
+ }
+
+ cvEndWriteSeq( &writer );
+ return CV_OK;
+}
+
+/****************************************************************************************\
+
+ definition of the maximum roi size
+
+\****************************************************************************************/
+void
+icvMaxRoi( _CvRect16u * max_rect, _CvRect16u * cur_rect )
+{
+ if( max_rect->x2 == 0 )
+ *max_rect = *cur_rect;
+ else
+ {
+ if( max_rect->x1 > cur_rect->x1 )
+ max_rect->x1 = cur_rect->x1;
+ if( max_rect->y1 > cur_rect->y1 )
+ max_rect->y1 = cur_rect->y1;
+
+ if( max_rect->x2 < cur_rect->x2 )
+ max_rect->x2 = cur_rect->x2;
+ if( max_rect->y2 < cur_rect->y2 )
+ max_rect->y2 = cur_rect->y2;
+ }
+}
+
+void
+icvMaxRoi1( _CvRect16u * max_rect, int x, int y )
+{
+ if( max_rect->x2 == 0 )
+ {
+ max_rect->x1 = (ushort) x;
+ max_rect->y1 = (ushort) y;
+
+ ++x;
+ ++y;
+
+ max_rect->x2 = (ushort) x;
+ max_rect->y2 = (ushort) y;
+ }
+ else
+ {
+ if( max_rect->x1 > x )
+ max_rect->x1 = (ushort) x;
+ if( max_rect->y1 > y )
+ max_rect->y1 = (ushort) y;
+
+ ++x;
+ ++y;
+
+ if( max_rect->x2 < x )
+ max_rect->x2 = (ushort) x;
+ if( max_rect->y2 < y )
+ max_rect->y2 = (ushort) y;
+ }
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvPyrSegmentation
+// Purpose:
+// segments an image using pyramid-linking technique
+// Context:
+// Parameters:
+// src - source image
+// dst - destination image
+// comp - pointer to returned connected component sequence
+// storage - where the sequence is stored
+// level - maximal pyramid level
+// threshold1 - first threshold, affecting on detalization level when pyramid
+// is built.
+// threshold2 - second threshold - affects on final components merging.
+// Returns:
+// Notes:
+// Source and destination image must be equal types and channels
+//F*/
+CV_IMPL void
+cvPyrSegmentation( IplImage * src,
+ IplImage * dst,
+ CvMemStorage * storage,
+ CvSeq ** comp, int level, double threshold1, double threshold2 )
+{
+ CvSize src_size, dst_size;
+ uchar *src_data = 0;
+ uchar *dst_data = 0;
+ int src_step = 0, dst_step = 0;
+ int thresh1 = cvRound( threshold1 );
+ int thresh2 = cvRound( threshold2 );
+
+ CV_FUNCNAME( "cvPyrSegmentation" );
+
+ __BEGIN__;
+
+ if( src->depth != IPL_DEPTH_8U )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+
+ if( src->depth != dst->depth || src->nChannels != dst->nChannels )
+ CV_ERROR( CV_StsBadArg, "src and dst have different formats" );
+
+ cvGetRawData( src, &src_data, &src_step, &src_size );
+ cvGetRawData( dst, &dst_data, &dst_step, &dst_size );
+
+ if( src_size.width != dst_size.width ||
+ src_size.height != dst_size.height )
+ CV_ERROR( CV_StsBadArg, "src and dst have different ROIs" );
+
+ switch (src->nChannels)
+ {
+ case 1:
+ IPPI_CALL( icvPyrSegmentation8uC1R( src_data, src_step,
+ dst_data, dst_step,
+ src_size,
+ CV_GAUSSIAN_5x5,
+ comp, storage, level, thresh1, thresh2 ));
+ break;
+ case 3:
+ IPPI_CALL( icvPyrSegmentation8uC3R( src_data, src_step,
+ dst_data, dst_step,
+ src_size,
+ CV_GAUSSIAN_5x5,
+ comp, storage, level, thresh1, thresh2 ));
+ break;
+ default:
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+ }
+ __END__;
+}
+
+
+/* End of file. */
diff --git a/cv/src/cvrotcalipers.cpp b/cv/src/cvrotcalipers.cpp
new file mode 100644
index 0000000..a6564e1
--- /dev/null
+++ b/cv/src/cvrotcalipers.cpp
@@ -0,0 +1,474 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+typedef struct
+{
+ int bottom;
+ int left;
+ float height;
+ float width;
+ float base_a;
+ float base_b;
+}
+icvMinAreaState;
+
+#define CV_CALIPERS_MAXHEIGHT 0
+#define CV_CALIPERS_MINAREARECT 1
+#define CV_CALIPERS_MAXDIST 2
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvRotatingCalipers
+// Purpose:
+// Rotating calipers algorithm with some applications
+//
+// Context:
+// Parameters:
+// points - convex hull vertices ( any orientation )
+// n - number of vertices
+// mode - concrete application of algorithm
+// can be CV_CALIPERS_MAXDIST or
+// CV_CALIPERS_MINAREARECT
+// left, bottom, right, top - indexes of extremal points
+// out - output info.
+// In case CV_CALIPERS_MAXDIST it points to float value -
+// maximal height of polygon.
+// In case CV_CALIPERS_MINAREARECT
+// ((CvPoint2D32f*)out)[0] - corner
+// ((CvPoint2D32f*)out)[1] - vector1
+// ((CvPoint2D32f*)out)[0] - corner2
+//
+// ^
+// |
+// vector2 |
+// |
+// |____________\
+// corner /
+// vector1
+//
+// Returns:
+// Notes:
+//F*/
+
+/* we will use usual cartesian coordinates */
+static void
+icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
+{
+ float minarea = FLT_MAX;
+ float max_dist = 0;
+ char buffer[32];
+ int i, k;
+ CvPoint2D32f* vect = (CvPoint2D32f*)cvAlloc( n * sizeof(vect[0]) );
+ float* inv_vect_length = (float*)cvAlloc( n * sizeof(inv_vect_length[0]) );
+ int left = 0, bottom = 0, right = 0, top = 0;
+ int seq[4] = { -1, -1, -1, -1 };
+
+ /* rotating calipers sides will always have coordinates
+ (a,b) (-b,a) (-a,-b) (b, -a)
+ */
+ /* this is a first base bector (a,b) initialized by (1,0) */
+ float orientation = 0;
+ float base_a;
+ float base_b = 0;
+
+ float left_x, right_x, top_y, bottom_y;
+ CvPoint2D32f pt0 = points[0];
+
+ left_x = right_x = pt0.x;
+ top_y = bottom_y = pt0.y;
+
+ for( i = 0; i < n; i++ )
+ {
+ double dx, dy;
+
+ if( pt0.x < left_x )
+ left_x = pt0.x, left = i;
+
+ if( pt0.x > right_x )
+ right_x = pt0.x, right = i;
+
+ if( pt0.y > top_y )
+ top_y = pt0.y, top = i;
+
+ if( pt0.y < bottom_y )
+ bottom_y = pt0.y, bottom = i;
+
+ CvPoint2D32f pt = points[(i+1) & (i+1 < n ? -1 : 0)];
+
+ dx = pt.x - pt0.x;
+ dy = pt.y - pt0.y;
+
+ vect[i].x = (float)dx;
+ vect[i].y = (float)dy;
+ inv_vect_length[i] = (float)(1./sqrt(dx*dx + dy*dy));
+
+ pt0 = pt;
+ }
+
+ //cvbInvSqrt( inv_vect_length, inv_vect_length, n );
+
+ /* find convex hull orientation */
+ {
+ double ax = vect[n-1].x;
+ double ay = vect[n-1].y;
+
+ for( i = 0; i < n; i++ )
+ {
+ double bx = vect[i].x;
+ double by = vect[i].y;
+
+ double convexity = ax * by - ay * bx;
+
+ if( convexity != 0 )
+ {
+ orientation = (convexity > 0) ? 1.f : (-1.f);
+ break;
+ }
+ ax = bx;
+ ay = by;
+ }
+ assert( orientation != 0 );
+ }
+ base_a = orientation;
+
+/*****************************************************************************************/
+/* init calipers position */
+ seq[0] = bottom;
+ seq[1] = right;
+ seq[2] = top;
+ seq[3] = left;
+/*****************************************************************************************/
+/* Main loop - evaluate angles and rotate calipers */
+
+ /* all of edges will be checked while rotating calipers by 90 degrees */
+ for( k = 0; k < n; k++ )
+ {
+ /* sinus of minimal angle */
+ /*float sinus;*/
+
+ /* compute cosine of angle between calipers side and polygon edge */
+ /* dp - dot product */
+ float dp0 = base_a * vect[seq[0]].x + base_b * vect[seq[0]].y;
+ float dp1 = -base_b * vect[seq[1]].x + base_a * vect[seq[1]].y;
+ float dp2 = -base_a * vect[seq[2]].x - base_b * vect[seq[2]].y;
+ float dp3 = base_b * vect[seq[3]].x - base_a * vect[seq[3]].y;
+
+ float cosalpha = dp0 * inv_vect_length[seq[0]];
+ float maxcos = cosalpha;
+
+ /* number of calipers edges, that has minimal angle with edge */
+ int main_element = 0;
+
+ /* choose minimal angle */
+ cosalpha = dp1 * inv_vect_length[seq[1]];
+ maxcos = (cosalpha > maxcos) ? (main_element = 1, cosalpha) : maxcos;
+ cosalpha = dp2 * inv_vect_length[seq[2]];
+ maxcos = (cosalpha > maxcos) ? (main_element = 2, cosalpha) : maxcos;
+ cosalpha = dp3 * inv_vect_length[seq[3]];
+ maxcos = (cosalpha > maxcos) ? (main_element = 3, cosalpha) : maxcos;
+
+ /*rotate calipers*/
+ {
+ //get next base
+ int pindex = seq[main_element];
+ float lead_x = vect[pindex].x*inv_vect_length[pindex];
+ float lead_y = vect[pindex].y*inv_vect_length[pindex];
+ switch( main_element )
+ {
+ case 0:
+ base_a = lead_x;
+ base_b = lead_y;
+ break;
+ case 1:
+ base_a = lead_y;
+ base_b = -lead_x;
+ break;
+ case 2:
+ base_a = -lead_x;
+ base_b = -lead_y;
+ break;
+ case 3:
+ base_a = -lead_y;
+ base_b = lead_x;
+ break;
+ default: assert(0);
+ }
+ }
+ /* change base point of main edge */
+ seq[main_element] += 1;
+ seq[main_element] = (seq[main_element] == n) ? 0 : seq[main_element];
+
+
+ switch (mode)
+ {
+ case CV_CALIPERS_MAXHEIGHT:
+ {
+ /* now main element lies on edge alligned to calipers side */
+
+ /* find opposite element i.e. transform */
+ /* 0->2, 1->3, 2->0, 3->1 */
+ int opposite_el = main_element ^ 2;
+
+ float dx = points[seq[opposite_el]].x - points[seq[main_element]].x;
+ float dy = points[seq[opposite_el]].y - points[seq[main_element]].y;
+ float dist;
+
+ if( main_element & 1 )
+ dist = (float)fabs(dx * base_a + dy * base_b);
+ else
+ dist = (float)fabs(dx * (-base_b) + dy * base_a);
+
+ if( dist > max_dist )
+ max_dist = dist;
+
+ break;
+ }
+ case CV_CALIPERS_MINAREARECT:
+ /* find area of rectangle */
+ {
+ float height;
+ float area;
+
+ /* find vector left-right */
+ float dx = points[seq[1]].x - points[seq[3]].x;
+ float dy = points[seq[1]].y - points[seq[3]].y;
+
+ /* dotproduct */
+ float width = dx * base_a + dy * base_b;
+
+ /* find vector left-right */
+ dx = points[seq[2]].x - points[seq[0]].x;
+ dy = points[seq[2]].y - points[seq[0]].y;
+
+ /* dotproduct */
+ height = -dx * base_b + dy * base_a;
+
+ area = width * height;
+ if( area <= minarea )
+ {
+ float *buf = (float *) buffer;
+
+ minarea = area;
+ /* leftist point */
+ ((int *) buf)[0] = seq[3];
+ buf[1] = base_a;
+ buf[2] = width;
+ buf[3] = base_b;
+ buf[4] = height;
+ /* bottom point */
+ ((int *) buf)[5] = seq[0];
+ buf[6] = area;
+ }
+ break;
+ }
+ } /*switch */
+ } /* for */
+
+ switch (mode)
+ {
+ case CV_CALIPERS_MINAREARECT:
+ {
+ float *buf = (float *) buffer;
+
+ float A1 = buf[1];
+ float B1 = buf[3];
+
+ float A2 = -buf[3];
+ float B2 = buf[1];
+
+ float C1 = A1 * points[((int *) buf)[0]].x + points[((int *) buf)[0]].y * B1;
+ float C2 = A2 * points[((int *) buf)[5]].x + points[((int *) buf)[5]].y * B2;
+
+ float idet = 1.f / (A1 * B2 - A2 * B1);
+
+ float px = (C1 * B2 - C2 * B1) * idet;
+ float py = (A1 * C2 - A2 * C1) * idet;
+
+ out[0] = px;
+ out[1] = py;
+
+ out[2] = A1 * buf[2];
+ out[3] = B1 * buf[2];
+
+ out[4] = A2 * buf[4];
+ out[5] = B2 * buf[4];
+ }
+ break;
+ case CV_CALIPERS_MAXHEIGHT:
+ {
+ out[0] = max_dist;
+ }
+ break;
+ }
+
+ cvFree( &vect );
+ cvFree( &inv_vect_length );
+}
+
+
+CV_IMPL CvBox2D
+cvMinAreaRect2( const CvArr* array, CvMemStorage* storage )
+{
+ CvMemStorage* temp_storage = 0;
+ CvBox2D box;
+ CvPoint2D32f* points = 0;
+
+ CV_FUNCNAME( "cvMinAreaRect2" );
+
+ memset(&box, 0, sizeof(box));
+
+ __BEGIN__;
+
+ int i, n;
+ CvSeqReader reader;
+ CvContour contour_header;
+ CvSeqBlock block;
+ CvSeq* ptseq = (CvSeq*)array;
+ CvPoint2D32f out[3];
+
+ if( CV_IS_SEQ(ptseq) )
+ {
+ if( !CV_IS_SEQ_POINT_SET(ptseq) &&
+ (CV_SEQ_KIND(ptseq) != CV_SEQ_KIND_CURVE || !CV_IS_SEQ_CONVEX(ptseq) ||
+ CV_SEQ_ELTYPE(ptseq) != CV_SEQ_ELTYPE_PPOINT ))
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Input sequence must consist of 2d points or pointers to 2d points" );
+ if( !storage )
+ storage = ptseq->storage;
+ }
+ else
+ {
+ CV_CALL( ptseq = cvPointSeqFromMat(
+ CV_SEQ_KIND_GENERIC, array, &contour_header, &block ));
+ }
+
+ if( storage )
+ {
+ CV_CALL( temp_storage = cvCreateChildMemStorage( storage ));
+ }
+ else
+ {
+ CV_CALL( temp_storage = cvCreateMemStorage(1 << 10));
+ }
+
+ if( !CV_IS_SEQ_CONVEX( ptseq ))
+ {
+ CV_CALL( ptseq = cvConvexHull2( ptseq, temp_storage, CV_CLOCKWISE, 1 ));
+ }
+ else if( !CV_IS_SEQ_POINT_SET( ptseq ))
+ {
+ CvSeqWriter writer;
+
+ if( !CV_IS_SEQ(ptseq->v_prev) || !CV_IS_SEQ_POINT_SET(ptseq->v_prev))
+ CV_ERROR( CV_StsBadArg,
+ "Convex hull must have valid pointer to point sequence stored in v_prev" );
+ cvStartReadSeq( ptseq, &reader );
+ cvStartWriteSeq( CV_SEQ_KIND_CURVE|CV_SEQ_FLAG_CONVEX|CV_SEQ_ELTYPE(ptseq->v_prev),
+ sizeof(CvContour), CV_ELEM_SIZE(ptseq->v_prev->flags),
+ temp_storage, &writer );
+
+ for( i = 0; i < ptseq->total; i++ )
+ {
+ CvPoint pt = **(CvPoint**)(reader.ptr);
+ CV_WRITE_SEQ_ELEM( pt, writer );
+ }
+
+ ptseq = cvEndWriteSeq( &writer );
+ }
+
+ n = ptseq->total;
+
+ CV_CALL( points = (CvPoint2D32f*)cvAlloc( n*sizeof(points[0]) ));
+ cvStartReadSeq( ptseq, &reader );
+
+ if( CV_SEQ_ELTYPE( ptseq ) == CV_32SC2 )
+ {
+ for( i = 0; i < n; i++ )
+ {
+ CvPoint pt;
+ CV_READ_SEQ_ELEM( pt, reader );
+ points[i].x = (float)pt.x;
+ points[i].y = (float)pt.y;
+ }
+ }
+ else
+ {
+ for( i = 0; i < n; i++ )
+ {
+ CV_READ_SEQ_ELEM( points[i], reader );
+ }
+ }
+
+ if( n > 2 )
+ {
+ icvRotatingCalipers( points, n, CV_CALIPERS_MINAREARECT, (float*)out );
+ box.center.x = out[0].x + (out[1].x + out[2].x)*0.5f;
+ box.center.y = out[0].y + (out[1].y + out[2].y)*0.5f;
+ box.size.height = (float)sqrt((double)out[1].x*out[1].x + (double)out[1].y*out[1].y);
+ box.size.width = (float)sqrt((double)out[2].x*out[2].x + (double)out[2].y*out[2].y);
+ box.angle = (float)atan2( -(double)out[1].y, (double)out[1].x );
+ }
+ else if( n == 2 )
+ {
+ box.center.x = (points[0].x + points[1].x)*0.5f;
+ box.center.y = (points[0].y + points[1].y)*0.5f;
+ double dx = points[1].x - points[0].x;
+ double dy = points[1].y - points[0].y;
+ box.size.height = (float)sqrt(dx*dx + dy*dy);
+ box.size.width = 0;
+ box.angle = (float)atan2( -dy, dx );
+ }
+ else
+ {
+ if( n == 1 )
+ box.center = points[0];
+ }
+
+ box.angle = (float)(box.angle*180/CV_PI);
+
+ __END__;
+
+ cvReleaseMemStorage( &temp_storage );
+ cvFree( &points );
+
+ return box;
+}
+
diff --git a/cv/src/cvsamplers.cpp b/cv/src/cvsamplers.cpp
new file mode 100644
index 0000000..484fab7
--- /dev/null
+++ b/cv/src/cvsamplers.cpp
@@ -0,0 +1,894 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+/**************************************************************************************\
+* line samplers *
+\**************************************************************************************/
+
+CV_IMPL int
+cvSampleLine( const void* img, CvPoint pt1, CvPoint pt2,
+ void* _buffer, int connectivity )
+{
+ int count = -1;
+
+ CV_FUNCNAME( "cvSampleLine" );
+
+ __BEGIN__;
+
+ int i, coi = 0, pix_size;
+ CvMat stub, *mat = (CvMat*)img;
+ CvLineIterator iterator;
+ uchar* buffer = (uchar*)_buffer;
+
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ if( !buffer )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ CV_CALL( count = cvInitLineIterator( mat, pt1, pt2, &iterator, connectivity ));
+
+ pix_size = CV_ELEM_SIZE(mat->type);
+ for( i = 0; i < count; i++ )
+ {
+ CV_MEMCPY_AUTO( buffer, iterator.ptr, pix_size );
+ buffer += pix_size;
+ CV_NEXT_LINE_POINT( iterator );
+ }
+
+ __END__;
+
+ return count;
+}
+
+
+static const void*
+icvAdjustRect( const void* srcptr, int src_step, int pix_size,
+ CvSize src_size, CvSize win_size,
+ CvPoint ip, CvRect* pRect )
+{
+ CvRect rect;
+ const char* src = (const char*)srcptr;
+
+ if( ip.x >= 0 )
+ {
+ src += ip.x*pix_size;
+ rect.x = 0;
+ }
+ else
+ {
+ rect.x = -ip.x;
+ if( rect.x > win_size.width )
+ rect.x = win_size.width;
+ }
+
+ if( ip.x + win_size.width < src_size.width )
+ rect.width = win_size.width;
+ else
+ {
+ rect.width = src_size.width - ip.x - 1;
+ if( rect.width < 0 )
+ {
+ src += rect.width*pix_size;
+ rect.width = 0;
+ }
+ assert( rect.width <= win_size.width );
+ }
+
+ if( ip.y >= 0 )
+ {
+ src += ip.y * src_step;
+ rect.y = 0;
+ }
+ else
+ rect.y = -ip.y;
+
+ if( ip.y + win_size.height < src_size.height )
+ rect.height = win_size.height;
+ else
+ {
+ rect.height = src_size.height - ip.y - 1;
+ if( rect.height < 0 )
+ {
+ src += rect.height*src_step;
+ rect.height = 0;
+ }
+ }
+
+ *pRect = rect;
+ return src - rect.x*pix_size;
+}
+
+
+#define ICV_DEF_GET_RECT_SUB_PIX_FUNC( flavor, srctype, dsttype, worktype, \
+ cast_macro, scale_macro, cast_macro2 )\
+CvStatus CV_STDCALL icvGetRectSubPix_##flavor##_C1R \
+( const srctype* src, int src_step, CvSize src_size, \
+ dsttype* dst, int dst_step, CvSize win_size, CvPoint2D32f center ) \
+{ \
+ CvPoint ip; \
+ worktype a11, a12, a21, a22, b1, b2; \
+ float a, b; \
+ int i, j; \
+ \
+ center.x -= (win_size.width-1)*0.5f; \
+ center.y -= (win_size.height-1)*0.5f; \
+ \
+ ip.x = cvFloor( center.x ); \
+ ip.y = cvFloor( center.y ); \
+ \
+ a = center.x - ip.x; \
+ b = center.y - ip.y; \
+ a11 = scale_macro((1.f-a)*(1.f-b)); \
+ a12 = scale_macro(a*(1.f-b)); \
+ a21 = scale_macro((1.f-a)*b); \
+ a22 = scale_macro(a*b); \
+ b1 = scale_macro(1.f - b); \
+ b2 = scale_macro(b); \
+ \
+ src_step /= sizeof(src[0]); \
+ dst_step /= sizeof(dst[0]); \
+ \
+ if( 0 <= ip.x && ip.x + win_size.width < src_size.width && \
+ 0 <= ip.y && ip.y + win_size.height < src_size.height ) \
+ { \
+ /* extracted rectangle is totally inside the image */ \
+ src += ip.y * src_step + ip.x; \
+ \
+ if( icvCopySubpix_##flavor##_C1R_p && \
+ icvCopySubpix_##flavor##_C1R_p( src, src_step*sizeof(src[0]), \
+ dst, dst_step*sizeof(dst[0]), \
+ win_size, a, b ) >= 0 ) \
+ return CV_OK; \
+ \
+ for( i = 0; i < win_size.height; i++, src += src_step, \
+ dst += dst_step ) \
+ { \
+ for( j = 0; j <= win_size.width - 2; j += 2 ) \
+ { \
+ worktype s0 = cast_macro(src[j])*a11 + \
+ cast_macro(src[j+1])*a12 + \
+ cast_macro(src[j+src_step])*a21 + \
+ cast_macro(src[j+src_step+1])*a22; \
+ worktype s1 = cast_macro(src[j+1])*a11 + \
+ cast_macro(src[j+2])*a12 + \
+ cast_macro(src[j+src_step+1])*a21 + \
+ cast_macro(src[j+src_step+2])*a22; \
+ \
+ dst[j] = (dsttype)cast_macro2(s0); \
+ dst[j+1] = (dsttype)cast_macro2(s1); \
+ } \
+ \
+ for( ; j < win_size.width; j++ ) \
+ { \
+ worktype s0 = cast_macro(src[j])*a11 + \
+ cast_macro(src[j+1])*a12 + \
+ cast_macro(src[j+src_step])*a21 + \
+ cast_macro(src[j+src_step+1])*a22; \
+ \
+ dst[j] = (dsttype)cast_macro2(s0); \
+ } \
+ } \
+ } \
+ else \
+ { \
+ CvRect r; \
+ \
+ src = (const srctype*)icvAdjustRect( src, src_step*sizeof(*src), \
+ sizeof(*src), src_size, win_size,ip, &r); \
+ \
+ for( i = 0; i < win_size.height; i++, dst += dst_step ) \
+ { \
+ const srctype *src2 = src + src_step; \
+ \
+ if( i < r.y || i >= r.height ) \
+ src2 -= src_step; \
+ \
+ for( j = 0; j < r.x; j++ ) \
+ { \
+ worktype s0 = cast_macro(src[r.x])*b1 + \
+ cast_macro(src2[r.x])*b2; \
+ \
+ dst[j] = (dsttype)cast_macro2(s0); \
+ } \
+ \
+ for( ; j < r.width; j++ ) \
+ { \
+ worktype s0 = cast_macro(src[j])*a11 + \
+ cast_macro(src[j+1])*a12 + \
+ cast_macro(src2[j])*a21 + \
+ cast_macro(src2[j+1])*a22; \
+ \
+ dst[j] = (dsttype)cast_macro2(s0); \
+ } \
+ \
+ for( ; j < win_size.width; j++ ) \
+ { \
+ worktype s0 = cast_macro(src[r.width])*b1 + \
+ cast_macro(src2[r.width])*b2; \
+ \
+ dst[j] = (dsttype)cast_macro2(s0); \
+ } \
+ \
+ if( i < r.height ) \
+ src = src2; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_GET_RECT_SUB_PIX_FUNC_C3( flavor, srctype, dsttype, worktype, \
+ cast_macro, scale_macro, mul_macro )\
+static CvStatus CV_STDCALL icvGetRectSubPix_##flavor##_C3R \
+( const srctype* src, int src_step, CvSize src_size, \
+ dsttype* dst, int dst_step, CvSize win_size, CvPoint2D32f center ) \
+{ \
+ CvPoint ip; \
+ worktype a, b; \
+ int i, j; \
+ \
+ center.x -= (win_size.width-1)*0.5f; \
+ center.y -= (win_size.height-1)*0.5f; \
+ \
+ ip.x = cvFloor( center.x ); \
+ ip.y = cvFloor( center.y ); \
+ \
+ a = scale_macro( center.x - ip.x ); \
+ b = scale_macro( center.y - ip.y ); \
+ \
+ src_step /= sizeof( src[0] ); \
+ dst_step /= sizeof( dst[0] ); \
+ \
+ if( 0 <= ip.x && ip.x + win_size.width < src_size.width && \
+ 0 <= ip.y && ip.y + win_size.height < src_size.height ) \
+ { \
+ /* extracted rectangle is totally inside the image */ \
+ src += ip.y * src_step + ip.x*3; \
+ \
+ for( i = 0; i < win_size.height; i++, src += src_step, \
+ dst += dst_step ) \
+ { \
+ for( j = 0; j < win_size.width; j++ ) \
+ { \
+ worktype s0 = cast_macro(src[j*3]); \
+ worktype s1 = cast_macro(src[j*3 + src_step]); \
+ s0 += mul_macro( a, (cast_macro(src[j*3+3]) - s0)); \
+ s1 += mul_macro( a, (cast_macro(src[j*3+3+src_step]) - s1));\
+ dst[j*3] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
+ \
+ s0 = cast_macro(src[j*3+1]); \
+ s1 = cast_macro(src[j*3+1 + src_step]); \
+ s0 += mul_macro( a, (cast_macro(src[j*3+4]) - s0)); \
+ s1 += mul_macro( a, (cast_macro(src[j*3+4+src_step]) - s1));\
+ dst[j*3+1] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
+ \
+ s0 = cast_macro(src[j*3+2]); \
+ s1 = cast_macro(src[j*3+2 + src_step]); \
+ s0 += mul_macro( a, (cast_macro(src[j*3+5]) - s0)); \
+ s1 += mul_macro( a, (cast_macro(src[j*3+5+src_step]) - s1));\
+ dst[j*3+2] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
+ } \
+ } \
+ } \
+ else \
+ { \
+ CvRect r; \
+ \
+ src = (const srctype*)icvAdjustRect( src, src_step*sizeof(*src), \
+ sizeof(*src)*3, src_size, win_size, ip, &r ); \
+ \
+ for( i = 0; i < win_size.height; i++, dst += dst_step ) \
+ { \
+ const srctype *src2 = src + src_step; \
+ \
+ if( i < r.y || i >= r.height ) \
+ src2 -= src_step; \
+ \
+ for( j = 0; j < r.x; j++ ) \
+ { \
+ worktype s0 = cast_macro(src[r.x*3]); \
+ worktype s1 = cast_macro(src2[r.x*3]); \
+ dst[j*3] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
+ \
+ s0 = cast_macro(src[r.x*3+1]); \
+ s1 = cast_macro(src2[r.x*3+1]); \
+ dst[j*3+1] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
+ \
+ s0 = cast_macro(src[r.x*3+2]); \
+ s1 = cast_macro(src2[r.x*3+2]); \
+ dst[j*3+2] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
+ } \
+ \
+ for( ; j < r.width; j++ ) \
+ { \
+ worktype s0 = cast_macro(src[j*3]); \
+ worktype s1 = cast_macro(src2[j*3]); \
+ s0 += mul_macro( a, (cast_macro(src[j*3 + 3]) - s0)); \
+ s1 += mul_macro( a, (cast_macro(src2[j*3 + 3]) - s1)); \
+ dst[j*3] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
+ \
+ s0 = cast_macro(src[j*3+1]); \
+ s1 = cast_macro(src2[j*3+1]); \
+ s0 += mul_macro( a, (cast_macro(src[j*3 + 4]) - s0)); \
+ s1 += mul_macro( a, (cast_macro(src2[j*3 + 4]) - s1)); \
+ dst[j*3+1] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
+ \
+ s0 = cast_macro(src[j*3+2]); \
+ s1 = cast_macro(src2[j*3+2]); \
+ s0 += mul_macro( a, (cast_macro(src[j*3 + 5]) - s0)); \
+ s1 += mul_macro( a, (cast_macro(src2[j*3 + 5]) - s1)); \
+ dst[j*3+2] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
+ } \
+ \
+ for( ; j < win_size.width; j++ ) \
+ { \
+ worktype s0 = cast_macro(src[r.width*3]); \
+ worktype s1 = cast_macro(src2[r.width*3]); \
+ dst[j*3] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
+ \
+ s0 = cast_macro(src[r.width*3+1]); \
+ s1 = cast_macro(src2[r.width*3+1]); \
+ dst[j*3+1] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
+ \
+ s0 = cast_macro(src[r.width*3+2]); \
+ s1 = cast_macro(src2[r.width*3+2]); \
+ dst[j*3+2] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
+ } \
+ \
+ if( i < r.height ) \
+ src = src2; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+
+CvStatus CV_STDCALL icvGetRectSubPix_8u32f_C1R
+( const uchar* src, int src_step, CvSize src_size,
+ float* dst, int dst_step, CvSize win_size, CvPoint2D32f center )
+{
+ CvPoint ip;
+ float a12, a22, b1, b2;
+ float a, b;
+ double s = 0;
+ int i, j;
+
+ center.x -= (win_size.width-1)*0.5f;
+ center.y -= (win_size.height-1)*0.5f;
+
+ ip.x = cvFloor( center.x );
+ ip.y = cvFloor( center.y );
+
+ if( win_size.width <= 0 || win_size.height <= 0 )
+ return CV_BADRANGE_ERR;
+
+ a = center.x - ip.x;
+ b = center.y - ip.y;
+ a = MAX(a,0.0001f);
+ a12 = a*(1.f-b);
+ a22 = a*b;
+ b1 = 1.f - b;
+ b2 = b;
+ s = (1. - a)/a;
+
+ src_step /= sizeof(src[0]);
+ dst_step /= sizeof(dst[0]);
+
+ if( 0 <= ip.x && ip.x + win_size.width < src_size.width &&
+ 0 <= ip.y && ip.y + win_size.height < src_size.height )
+ {
+ // extracted rectangle is totally inside the image
+ src += ip.y * src_step + ip.x;
+
+#if 0
+ if( icvCopySubpix_8u32f_C1R_p &&
+ icvCopySubpix_8u32f_C1R_p( src, src_step, dst,
+ dst_step*sizeof(dst[0]), win_size, a, b ) >= 0 )
+ return CV_OK;
+#endif
+
+ for( ; win_size.height--; src += src_step, dst += dst_step )
+ {
+ float prev = (1 - a)*(b1*CV_8TO32F(src[0]) + b2*CV_8TO32F(src[src_step]));
+ for( j = 0; j < win_size.width; j++ )
+ {
+ float t = a12*CV_8TO32F(src[j+1]) + a22*CV_8TO32F(src[j+1+src_step]);
+ dst[j] = prev + t;
+ prev = (float)(t*s);
+ }
+ }
+ }
+ else
+ {
+ CvRect r;
+
+ src = (const uchar*)icvAdjustRect( src, src_step*sizeof(*src),
+ sizeof(*src), src_size, win_size,ip, &r);
+
+ for( i = 0; i < win_size.height; i++, dst += dst_step )
+ {
+ const uchar *src2 = src + src_step;
+
+ if( i < r.y || i >= r.height )
+ src2 -= src_step;
+
+ for( j = 0; j < r.x; j++ )
+ {
+ float s0 = CV_8TO32F(src[r.x])*b1 +
+ CV_8TO32F(src2[r.x])*b2;
+
+ dst[j] = (float)(s0);
+ }
+
+ if( j < r.width )
+ {
+ float prev = (1 - a)*(b1*CV_8TO32F(src[j]) + b2*CV_8TO32F(src2[j]));
+
+ for( ; j < r.width; j++ )
+ {
+ float t = a12*CV_8TO32F(src[j+1]) + a22*CV_8TO32F(src2[j+1]);
+ dst[j] = prev + t;
+ prev = (float)(t*s);
+ }
+ }
+
+ for( ; j < win_size.width; j++ )
+ {
+ float s0 = CV_8TO32F(src[r.width])*b1 +
+ CV_8TO32F(src2[r.width])*b2;
+
+ dst[j] = (float)(s0);
+ }
+
+ if( i < r.height )
+ src = src2;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+
+#define ICV_SHIFT 16
+#define ICV_SCALE(x) cvRound((x)*(1 << ICV_SHIFT))
+#define ICV_MUL_SCALE(x,y) (((x)*(y) + (1 << (ICV_SHIFT-1))) >> ICV_SHIFT)
+#define ICV_DESCALE(x) (((x)+(1 << (ICV_SHIFT-1))) >> ICV_SHIFT)
+
+icvCopySubpix_8u_C1R_t icvCopySubpix_8u_C1R_p = 0;
+icvCopySubpix_8u32f_C1R_t icvCopySubpix_8u32f_C1R_p = 0;
+icvCopySubpix_32f_C1R_t icvCopySubpix_32f_C1R_p = 0;
+
+ICV_DEF_GET_RECT_SUB_PIX_FUNC( 8u, uchar, uchar, int, CV_NOP, ICV_SCALE, ICV_DESCALE )
+//ICV_DEF_GET_RECT_SUB_PIX_FUNC( 8u32f, uchar, float, float, CV_8TO32F, CV_NOP, CV_NOP )
+ICV_DEF_GET_RECT_SUB_PIX_FUNC( 32f, float, float, float, CV_NOP, CV_NOP, CV_NOP )
+
+ICV_DEF_GET_RECT_SUB_PIX_FUNC_C3( 8u, uchar, uchar, int, CV_NOP, ICV_SCALE, ICV_MUL_SCALE )
+ICV_DEF_GET_RECT_SUB_PIX_FUNC_C3( 8u32f, uchar, float, float, CV_8TO32F, CV_NOP, CV_MUL )
+ICV_DEF_GET_RECT_SUB_PIX_FUNC_C3( 32f, float, float, float, CV_NOP, CV_NOP, CV_MUL )
+
+
+#define ICV_DEF_INIT_SUBPIX_TAB( FUNCNAME, FLAG ) \
+static void icvInit##FUNCNAME##FLAG##Table( CvFuncTable* tab ) \
+{ \
+ tab->fn_2d[CV_8U] = (void*)icv##FUNCNAME##_8u_##FLAG; \
+ tab->fn_2d[CV_32F] = (void*)icv##FUNCNAME##_32f_##FLAG; \
+ \
+ tab->fn_2d[1] = (void*)icv##FUNCNAME##_8u32f_##FLAG; \
+}
+
+
+ICV_DEF_INIT_SUBPIX_TAB( GetRectSubPix, C1R )
+ICV_DEF_INIT_SUBPIX_TAB( GetRectSubPix, C3R )
+
+typedef CvStatus (CV_STDCALL *CvGetRectSubPixFunc)( const void* src, int src_step,
+ CvSize src_size, void* dst,
+ int dst_step, CvSize win_size,
+ CvPoint2D32f center );
+
+CV_IMPL void
+cvGetRectSubPix( const void* srcarr, void* dstarr, CvPoint2D32f center )
+{
+ static CvFuncTable gr_tab[2];
+ static int inittab = 0;
+ CV_FUNCNAME( "cvGetRectSubPix" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize src_size, dst_size;
+ CvGetRectSubPixFunc func;
+ int cn, src_step, dst_step;
+
+ if( !inittab )
+ {
+ icvInitGetRectSubPixC1RTable( gr_tab + 0 );
+ icvInitGetRectSubPixC3RTable( gr_tab + 1 );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(src))
+ CV_CALL( src = cvGetMat( src, &srcstub ));
+
+ if( !CV_IS_MAT(dst))
+ CV_CALL( dst = cvGetMat( dst, &dststub ));
+
+ cn = CV_MAT_CN( src->type );
+
+ if( (cn != 1 && cn != 3) || !CV_ARE_CNS_EQ( src, dst ))
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ src_size = cvGetMatSize( src );
+ dst_size = cvGetMatSize( dst );
+ src_step = src->step ? src->step : CV_STUB_STEP;
+ dst_step = dst->step ? dst->step : CV_STUB_STEP;
+
+ if( dst_size.width > src_size.width || dst_size.height > src_size.height )
+ CV_ERROR( CV_StsBadSize, "destination ROI must be smaller than source ROI" );
+
+ if( CV_ARE_DEPTHS_EQ( src, dst ))
+ {
+ func = (CvGetRectSubPixFunc)(gr_tab[cn != 1].fn_2d[CV_MAT_DEPTH(src->type)]);
+ }
+ else
+ {
+ if( CV_MAT_DEPTH( src->type ) != CV_8U || CV_MAT_DEPTH( dst->type ) != CV_32F )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ func = (CvGetRectSubPixFunc)(gr_tab[cn != 1].fn_2d[1]);
+ }
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src->data.ptr, src_step, src_size,
+ dst->data.ptr, dst_step, dst_size, center ));
+
+ __END__;
+}
+
+
+#define ICV_32F8U(x) ((uchar)cvRound(x))
+
+#define ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( flavor, srctype, dsttype, \
+ worktype, cast_macro, cvt ) \
+CvStatus CV_STDCALL \
+icvGetQuadrangleSubPix_##flavor##_C1R \
+( const srctype * src, int src_step, CvSize src_size, \
+ dsttype *dst, int dst_step, CvSize win_size, const float *matrix ) \
+{ \
+ int x, y; \
+ double dx = (win_size.width - 1)*0.5; \
+ double dy = (win_size.height - 1)*0.5; \
+ double A11 = matrix[0], A12 = matrix[1], A13 = matrix[2]-A11*dx-A12*dy; \
+ double A21 = matrix[3], A22 = matrix[4], A23 = matrix[5]-A21*dx-A22*dy; \
+ \
+ src_step /= sizeof(srctype); \
+ dst_step /= sizeof(dsttype); \
+ \
+ for( y = 0; y < win_size.height; y++, dst += dst_step ) \
+ { \
+ double xs = A12*y + A13; \
+ double ys = A22*y + A23; \
+ double xe = A11*(win_size.width-1) + A12*y + A13; \
+ double ye = A21*(win_size.width-1) + A22*y + A23; \
+ \
+ if( (unsigned)(cvFloor(xs)-1) < (unsigned)(src_size.width - 3) && \
+ (unsigned)(cvFloor(ys)-1) < (unsigned)(src_size.height - 3) && \
+ (unsigned)(cvFloor(xe)-1) < (unsigned)(src_size.width - 3) && \
+ (unsigned)(cvFloor(ye)-1) < (unsigned)(src_size.height - 3)) \
+ { \
+ for( x = 0; x < win_size.width; x++ ) \
+ { \
+ int ixs = cvFloor( xs ); \
+ int iys = cvFloor( ys ); \
+ const srctype *ptr = src + src_step*iys + ixs; \
+ double a = xs - ixs, b = ys - iys, a1 = 1.f - a; \
+ worktype p0 = cvt(ptr[0])*a1 + cvt(ptr[1])*a; \
+ worktype p1 = cvt(ptr[src_step])*a1 + cvt(ptr[src_step+1])*a;\
+ xs += A11; \
+ ys += A21; \
+ \
+ dst[x] = cast_macro(p0 + b * (p1 - p0)); \
+ } \
+ } \
+ else \
+ { \
+ for( x = 0; x < win_size.width; x++ ) \
+ { \
+ int ixs = cvFloor( xs ), iys = cvFloor( ys ); \
+ double a = xs - ixs, b = ys - iys, a1 = 1.f - a; \
+ const srctype *ptr0, *ptr1; \
+ worktype p0, p1; \
+ xs += A11; ys += A21; \
+ \
+ if( (unsigned)iys < (unsigned)(src_size.height-1) ) \
+ ptr0 = src + src_step*iys, ptr1 = ptr0 + src_step; \
+ else \
+ ptr0 = ptr1 = src + (iys < 0 ? 0 : src_size.height-1)*src_step; \
+ \
+ if( (unsigned)ixs < (unsigned)(src_size.width-1) ) \
+ { \
+ p0 = cvt(ptr0[ixs])*a1 + cvt(ptr0[ixs+1])*a; \
+ p1 = cvt(ptr1[ixs])*a1 + cvt(ptr1[ixs+1])*a; \
+ } \
+ else \
+ { \
+ ixs = ixs < 0 ? 0 : src_size.width - 1; \
+ p0 = cvt(ptr0[ixs]); p1 = cvt(ptr1[ixs]); \
+ } \
+ dst[x] = cast_macro(p0 + b * (p1 - p0)); \
+ } \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC_C3( flavor, srctype, dsttype, \
+ worktype, cast_macro, cvt ) \
+static CvStatus CV_STDCALL \
+icvGetQuadrangleSubPix_##flavor##_C3R \
+( const srctype * src, int src_step, CvSize src_size, \
+ dsttype *dst, int dst_step, CvSize win_size, const float *matrix ) \
+{ \
+ int x, y; \
+ double dx = (win_size.width - 1)*0.5; \
+ double dy = (win_size.height - 1)*0.5; \
+ double A11 = matrix[0], A12 = matrix[1], A13 = matrix[2]-A11*dx-A12*dy; \
+ double A21 = matrix[3], A22 = matrix[4], A23 = matrix[5]-A21*dx-A22*dy; \
+ \
+ src_step /= sizeof(srctype); \
+ dst_step /= sizeof(dsttype); \
+ \
+ for( y = 0; y < win_size.height; y++, dst += dst_step ) \
+ { \
+ double xs = A12*y + A13; \
+ double ys = A22*y + A23; \
+ double xe = A11*(win_size.width-1) + A12*y + A13; \
+ double ye = A21*(win_size.width-1) + A22*y + A23; \
+ \
+ if( (unsigned)(cvFloor(xs)-1) < (unsigned)(src_size.width - 3) && \
+ (unsigned)(cvFloor(ys)-1) < (unsigned)(src_size.height - 3) && \
+ (unsigned)(cvFloor(xe)-1) < (unsigned)(src_size.width - 3) && \
+ (unsigned)(cvFloor(ye)-1) < (unsigned)(src_size.height - 3)) \
+ { \
+ for( x = 0; x < win_size.width; x++ ) \
+ { \
+ int ixs = cvFloor( xs ); \
+ int iys = cvFloor( ys ); \
+ const srctype *ptr = src + src_step*iys + ixs*3; \
+ double a = xs - ixs, b = ys - iys, a1 = 1.f - a; \
+ worktype p0, p1; \
+ xs += A11; \
+ ys += A21; \
+ \
+ p0 = cvt(ptr[0])*a1 + cvt(ptr[3])*a; \
+ p1 = cvt(ptr[src_step])*a1 + cvt(ptr[src_step+3])*a; \
+ dst[x*3] = cast_macro(p0 + b * (p1 - p0)); \
+ \
+ p0 = cvt(ptr[1])*a1 + cvt(ptr[4])*a; \
+ p1 = cvt(ptr[src_step+1])*a1 + cvt(ptr[src_step+4])*a; \
+ dst[x*3+1] = cast_macro(p0 + b * (p1 - p0)); \
+ \
+ p0 = cvt(ptr[2])*a1 + cvt(ptr[5])*a; \
+ p1 = cvt(ptr[src_step+2])*a1 + cvt(ptr[src_step+5])*a; \
+ dst[x*3+2] = cast_macro(p0 + b * (p1 - p0)); \
+ } \
+ } \
+ else \
+ { \
+ for( x = 0; x < win_size.width; x++ ) \
+ { \
+ int ixs = cvFloor(xs), iys = cvFloor(ys); \
+ double a = xs - ixs, b = ys - iys; \
+ const srctype *ptr0, *ptr1; \
+ xs += A11; ys += A21; \
+ \
+ if( (unsigned)iys < (unsigned)(src_size.height-1) ) \
+ ptr0 = src + src_step*iys, ptr1 = ptr0 + src_step; \
+ else \
+ ptr0 = ptr1 = src + (iys < 0 ? 0 : src_size.height-1)*src_step; \
+ \
+ if( (unsigned)ixs < (unsigned)(src_size.width - 1) ) \
+ { \
+ double a1 = 1.f - a; \
+ worktype p0, p1; \
+ ptr0 += ixs*3; ptr1 += ixs*3; \
+ p0 = cvt(ptr0[0])*a1 + cvt(ptr0[3])*a; \
+ p1 = cvt(ptr1[0])*a1 + cvt(ptr1[3])*a; \
+ dst[x*3] = cast_macro(p0 + b * (p1 - p0)); \
+ \
+ p0 = cvt(ptr0[1])*a1 + cvt(ptr0[4])*a; \
+ p1 = cvt(ptr1[1])*a1 + cvt(ptr1[4])*a; \
+ dst[x*3+1] = cast_macro(p0 + b * (p1 - p0)); \
+ \
+ p0 = cvt(ptr0[2])*a1 + cvt(ptr0[5])*a; \
+ p1 = cvt(ptr1[2])*a1 + cvt(ptr1[5])*a; \
+ dst[x*3+2] = cast_macro(p0 + b * (p1 - p0)); \
+ } \
+ else \
+ { \
+ double b1 = 1.f - b; \
+ ixs = ixs < 0 ? 0 : src_size.width - 1; \
+ ptr0 += ixs*3; ptr1 += ixs*3; \
+ \
+ dst[x*3] = cast_macro(cvt(ptr0[0])*b1 + cvt(ptr1[0])*b);\
+ dst[x*3+1]=cast_macro(cvt(ptr0[1])*b1 + cvt(ptr1[1])*b);\
+ dst[x*3+2]=cast_macro(cvt(ptr0[2])*b1 + cvt(ptr1[2])*b);\
+ } \
+ } \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+/*#define srctype uchar
+#define dsttype uchar
+#define worktype float
+#define cvt CV_8TO32F
+#define cast_macro ICV_32F8U
+
+#undef srctype
+#undef dsttype
+#undef worktype
+#undef cvt
+#undef cast_macro*/
+
+ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( 8u, uchar, uchar, double, ICV_32F8U, CV_8TO32F )
+ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( 32f, float, float, double, CV_CAST_32F, CV_NOP )
+ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( 8u32f, uchar, float, double, CV_CAST_32F, CV_8TO32F )
+
+ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC_C3( 8u, uchar, uchar, double, ICV_32F8U, CV_8TO32F )
+ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC_C3( 32f, float, float, double, CV_CAST_32F, CV_NOP )
+ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC_C3( 8u32f, uchar, float, double, CV_CAST_32F, CV_8TO32F )
+
+ICV_DEF_INIT_SUBPIX_TAB( GetQuadrangleSubPix, C1R )
+ICV_DEF_INIT_SUBPIX_TAB( GetQuadrangleSubPix, C3R )
+
+typedef CvStatus (CV_STDCALL *CvGetQuadrangleSubPixFunc)(
+ const void* src, int src_step,
+ CvSize src_size, void* dst,
+ int dst_step, CvSize win_size,
+ const float* matrix );
+
+CV_IMPL void
+cvGetQuadrangleSubPix( const void* srcarr, void* dstarr, const CvMat* mat )
+{
+ static CvFuncTable gq_tab[2];
+ static int inittab = 0;
+ CV_FUNCNAME( "cvGetQuadrangleSubPix" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize src_size, dst_size;
+ CvGetQuadrangleSubPixFunc func;
+ float m[6];
+ int k, cn;
+
+ if( !inittab )
+ {
+ icvInitGetQuadrangleSubPixC1RTable( gq_tab + 0 );
+ icvInitGetQuadrangleSubPixC3RTable( gq_tab + 1 );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(src))
+ CV_CALL( src = cvGetMat( src, &srcstub ));
+
+ if( !CV_IS_MAT(dst))
+ CV_CALL( dst = cvGetMat( dst, &dststub ));
+
+ if( !CV_IS_MAT(mat))
+ CV_ERROR( CV_StsBadArg, "map matrix is not valid" );
+
+ cn = CV_MAT_CN( src->type );
+
+ if( (cn != 1 && cn != 3) || !CV_ARE_CNS_EQ( src, dst ))
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ src_size = cvGetMatSize( src );
+ dst_size = cvGetMatSize( dst );
+
+ /*if( dst_size.width > src_size.width || dst_size.height > src_size.height )
+ CV_ERROR( CV_StsBadSize, "destination ROI must not be larger than source ROI" );*/
+
+ if( mat->rows != 2 || mat->cols != 3 )
+ CV_ERROR( CV_StsBadArg,
+ "Transformation matrix must be 2x3" );
+
+ if( CV_MAT_TYPE( mat->type ) == CV_32FC1 )
+ {
+ for( k = 0; k < 3; k++ )
+ {
+ m[k] = mat->data.fl[k];
+ m[3 + k] = ((float*)(mat->data.ptr + mat->step))[k];
+ }
+ }
+ else if( CV_MAT_TYPE( mat->type ) == CV_64FC1 )
+ {
+ for( k = 0; k < 3; k++ )
+ {
+ m[k] = (float)mat->data.db[k];
+ m[3 + k] = (float)((double*)(mat->data.ptr + mat->step))[k];
+ }
+ }
+ else
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "The transformation matrix should have 32fC1 or 64fC1 type" );
+
+ if( CV_ARE_DEPTHS_EQ( src, dst ))
+ {
+ func = (CvGetQuadrangleSubPixFunc)(gq_tab[cn != 1].fn_2d[CV_MAT_DEPTH(src->type)]);
+ }
+ else
+ {
+ if( CV_MAT_DEPTH( src->type ) != CV_8U || CV_MAT_DEPTH( dst->type ) != CV_32F )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ func = (CvGetQuadrangleSubPixFunc)(gq_tab[cn != 1].fn_2d[1]);
+ }
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src->data.ptr, src->step, src_size,
+ dst->data.ptr, dst->step, dst_size, m ));
+
+ __END__;
+}
+
+
+/* End of file. */
diff --git a/cv/src/cvsegmentation.cpp b/cv/src/cvsegmentation.cpp
new file mode 100644
index 0000000..2bf66b8
--- /dev/null
+++ b/cv/src/cvsegmentation.cpp
@@ -0,0 +1,552 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+/****************************************************************************************\
+* Watershed *
+\****************************************************************************************/
+
+typedef struct CvWSNode
+{
+ struct CvWSNode* next;
+ int mask_ofs;
+ int img_ofs;
+}
+CvWSNode;
+
+typedef struct CvWSQueue
+{
+ CvWSNode* first;
+ CvWSNode* last;
+}
+CvWSQueue;
+
+static CvWSNode*
+icvAllocWSNodes( CvMemStorage* storage )
+{
+ CvWSNode* n = 0;
+
+ CV_FUNCNAME( "icvAllocWSNodes" );
+
+ __BEGIN__;
+
+ int i, count = (storage->block_size - sizeof(CvMemBlock))/sizeof(*n) - 1;
+
+ CV_CALL( n = (CvWSNode*)cvMemStorageAlloc( storage, count*sizeof(*n) ));
+ for( i = 0; i < count-1; i++ )
+ n[i].next = n + i + 1;
+ n[count-1].next = 0;
+
+ __END__;
+
+ return n;
+}
+
+
+CV_IMPL void
+cvWatershed( const CvArr* srcarr, CvArr* dstarr )
+{
+ const int IN_QUEUE = -2;
+ const int WSHED = -1;
+ const int NQ = 256;
+ CvMemStorage* storage = 0;
+
+ CV_FUNCNAME( "cvWatershed" );
+
+ __BEGIN__;
+
+ CvMat sstub, *src;
+ CvMat dstub, *dst;
+ CvSize size;
+ CvWSNode* free_node = 0, *node;
+ CvWSQueue q[NQ];
+ int active_queue;
+ int i, j;
+ int db, dg, dr;
+ int* mask;
+ uchar* img;
+ int mstep, istep;
+ int subs_tab[513];
+
+ // MAX(a,b) = b + MAX(a-b,0)
+ #define ws_max(a,b) ((b) + subs_tab[(a)-(b)+NQ])
+ // MIN(a,b) = a - MAX(a-b,0)
+ #define ws_min(a,b) ((a) - subs_tab[(a)-(b)+NQ])
+
+ #define ws_push(idx,mofs,iofs) \
+ { \
+ if( !free_node ) \
+ CV_CALL( free_node = icvAllocWSNodes( storage ));\
+ node = free_node; \
+ free_node = free_node->next;\
+ node->next = 0; \
+ node->mask_ofs = mofs; \
+ node->img_ofs = iofs; \
+ if( q[idx].last ) \
+ q[idx].last->next=node; \
+ else \
+ q[idx].first = node; \
+ q[idx].last = node; \
+ }
+
+ #define ws_pop(idx,mofs,iofs) \
+ { \
+ node = q[idx].first; \
+ q[idx].first = node->next; \
+ if( !node->next ) \
+ q[idx].last = 0; \
+ node->next = free_node; \
+ free_node = node; \
+ mofs = node->mask_ofs; \
+ iofs = node->img_ofs; \
+ }
+
+ #define c_diff(ptr1,ptr2,diff) \
+ { \
+ db = abs((ptr1)[0] - (ptr2)[0]);\
+ dg = abs((ptr1)[1] - (ptr2)[1]);\
+ dr = abs((ptr1)[2] - (ptr2)[2]);\
+ diff = ws_max(db,dg); \
+ diff = ws_max(diff,dr); \
+ assert( 0 <= diff && diff <= 255 ); \
+ }
+
+ CV_CALL( src = cvGetMat( srcarr, &sstub ));
+ CV_CALL( dst = cvGetMat( dstarr, &dstub ));
+
+ if( CV_MAT_TYPE(src->type) != CV_8UC3 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Only 8-bit, 3-channel input images are supported" );
+
+ if( CV_MAT_TYPE(dst->type) != CV_32SC1 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Only 32-bit, 1-channel output images are supported" );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "The input and output images must have the same size" );
+
+ size = cvGetMatSize(src);
+
+ CV_CALL( storage = cvCreateMemStorage() );
+
+ istep = src->step;
+ img = src->data.ptr;
+ mstep = dst->step / sizeof(mask[0]);
+ mask = dst->data.i;
+
+ memset( q, 0, NQ*sizeof(q[0]) );
+
+ for( i = 0; i < 256; i++ )
+ subs_tab[i] = 0;
+ for( i = 256; i <= 512; i++ )
+ subs_tab[i] = i - 256;
+
+ // draw a pixel-wide border of dummy "watershed" (i.e. boundary) pixels
+ for( j = 0; j < size.width; j++ )
+ mask[j] = mask[j + mstep*(size.height-1)] = WSHED;
+
+ // initial phase: put all the neighbor pixels of each marker to the ordered queue -
+ // determine the initial boundaries of the basins
+ for( i = 1; i < size.height-1; i++ )
+ {
+ img += istep; mask += mstep;
+ mask[0] = mask[size.width-1] = WSHED;
+
+ for( j = 1; j < size.width-1; j++ )
+ {
+ int* m = mask + j;
+ if( m[0] < 0 ) m[0] = 0;
+ if( m[0] == 0 && (m[-1] > 0 || m[1] > 0 || m[-mstep] > 0 || m[mstep] > 0) )
+ {
+ uchar* ptr = img + j*3;
+ int idx = 256, t;
+ if( m[-1] > 0 )
+ c_diff( ptr, ptr - 3, idx );
+ if( m[1] > 0 )
+ {
+ c_diff( ptr, ptr + 3, t );
+ idx = ws_min( idx, t );
+ }
+ if( m[-mstep] > 0 )
+ {
+ c_diff( ptr, ptr - istep, t );
+ idx = ws_min( idx, t );
+ }
+ if( m[mstep] > 0 )
+ {
+ c_diff( ptr, ptr + istep, t );
+ idx = ws_min( idx, t );
+ }
+ assert( 0 <= idx && idx <= 255 );
+ ws_push( idx, i*mstep + j, i*istep + j*3 );
+ m[0] = IN_QUEUE;
+ }
+ }
+ }
+
+ // find the first non-empty queue
+ for( i = 0; i < NQ; i++ )
+ if( q[i].first )
+ break;
+
+ // if there is no markers, exit immediately
+ if( i == NQ )
+ EXIT;
+
+ active_queue = i;
+ img = src->data.ptr;
+ mask = dst->data.i;
+
+ // recursively fill the basins
+ for(;;)
+ {
+ int mofs, iofs;
+ int lab = 0, t;
+ int* m;
+ uchar* ptr;
+
+ if( q[active_queue].first == 0 )
+ {
+ for( i = active_queue+1; i < NQ; i++ )
+ if( q[i].first )
+ break;
+ if( i == NQ )
+ break;
+ active_queue = i;
+ }
+
+ ws_pop( active_queue, mofs, iofs );
+
+ m = mask + mofs;
+ ptr = img + iofs;
+ t = m[-1];
+ if( t > 0 ) lab = t;
+ t = m[1];
+ if( t > 0 )
+ {
+ if( lab == 0 ) lab = t;
+ else if( t != lab ) lab = WSHED;
+ }
+ t = m[-mstep];
+ if( t > 0 )
+ {
+ if( lab == 0 ) lab = t;
+ else if( t != lab ) lab = WSHED;
+ }
+ t = m[mstep];
+ if( t > 0 )
+ {
+ if( lab == 0 ) lab = t;
+ else if( t != lab ) lab = WSHED;
+ }
+ assert( lab != 0 );
+ m[0] = lab;
+ if( lab == WSHED )
+ continue;
+
+ if( m[-1] == 0 )
+ {
+ c_diff( ptr, ptr - 3, t );
+ ws_push( t, mofs - 1, iofs - 3 );
+ active_queue = ws_min( active_queue, t );
+ m[-1] = IN_QUEUE;
+ }
+ if( m[1] == 0 )
+ {
+ c_diff( ptr, ptr + 3, t );
+ ws_push( t, mofs + 1, iofs + 3 );
+ active_queue = ws_min( active_queue, t );
+ m[1] = IN_QUEUE;
+ }
+ if( m[-mstep] == 0 )
+ {
+ c_diff( ptr, ptr - istep, t );
+ ws_push( t, mofs - mstep, iofs - istep );
+ active_queue = ws_min( active_queue, t );
+ m[-mstep] = IN_QUEUE;
+ }
+ if( m[mstep] == 0 )
+ {
+ c_diff( ptr, ptr + 3, t );
+ ws_push( t, mofs + mstep, iofs + istep );
+ active_queue = ws_min( active_queue, t );
+ m[mstep] = IN_QUEUE;
+ }
+ }
+
+ __END__;
+
+ cvReleaseMemStorage( &storage );
+}
+
+
+/****************************************************************************************\
+* Meanshift *
+\****************************************************************************************/
+
+CV_IMPL void
+cvPyrMeanShiftFiltering( const CvArr* srcarr, CvArr* dstarr,
+ double sp0, double sr, int max_level,
+ CvTermCriteria termcrit )
+{
+ const int cn = 3;
+ const int MAX_LEVELS = 8;
+ CvMat* src_pyramid[MAX_LEVELS+1];
+ CvMat* dst_pyramid[MAX_LEVELS+1];
+ CvMat* mask0 = 0;
+ int i, j, level;
+ //uchar* submask = 0;
+
+ #define cdiff(ofs0) (tab[c0-dptr[ofs0]+255] + \
+ tab[c1-dptr[(ofs0)+1]+255] + tab[c2-dptr[(ofs0)+2]+255] >= isr22)
+
+ memset( src_pyramid, 0, sizeof(src_pyramid) );
+ memset( dst_pyramid, 0, sizeof(dst_pyramid) );
+
+ CV_FUNCNAME( "cvPyrMeanShiftFiltering" );
+
+ __BEGIN__;
+
+ double sr2 = sr * sr;
+ int isr2 = cvRound(sr2), isr22 = MAX(isr2,16);
+ int tab[768];
+ CvMat sstub0, *src0;
+ CvMat dstub0, *dst0;
+
+ CV_CALL( src0 = cvGetMat( srcarr, &sstub0 ));
+ CV_CALL( dst0 = cvGetMat( dstarr, &dstub0 ));
+
+ if( CV_MAT_TYPE(src0->type) != CV_8UC3 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Only 8-bit, 3-channel images are supported" );
+
+ if( !CV_ARE_TYPES_EQ( src0, dst0 ))
+ CV_ERROR( CV_StsUnmatchedFormats, "The input and output images must have the same type" );
+
+ if( !CV_ARE_SIZES_EQ( src0, dst0 ))
+ CV_ERROR( CV_StsUnmatchedSizes, "The input and output images must have the same size" );
+
+ if( (unsigned)max_level > (unsigned)MAX_LEVELS )
+ CV_ERROR( CV_StsOutOfRange, "The number of pyramid levels is too large or negative" );
+
+ if( !(termcrit.type & CV_TERMCRIT_ITER) )
+ termcrit.max_iter = 5;
+ termcrit.max_iter = MAX(termcrit.max_iter,1);
+ termcrit.max_iter = MIN(termcrit.max_iter,100);
+ if( !(termcrit.type & CV_TERMCRIT_EPS) )
+ termcrit.epsilon = 1.f;
+ termcrit.epsilon = MAX(termcrit.epsilon, 0.f);
+
+ for( i = 0; i < 768; i++ )
+ tab[i] = (i - 255)*(i - 255);
+
+ // 1. construct pyramid
+ src_pyramid[0] = src0;
+ dst_pyramid[0] = dst0;
+ for( level = 1; level <= max_level; level++ )
+ {
+ CV_CALL( src_pyramid[level] = cvCreateMat( (src_pyramid[level-1]->rows+1)/2,
+ (src_pyramid[level-1]->cols+1)/2, src_pyramid[level-1]->type ));
+ CV_CALL( dst_pyramid[level] = cvCreateMat( src_pyramid[level]->rows,
+ src_pyramid[level]->cols, src_pyramid[level]->type ));
+ CV_CALL( cvPyrDown( src_pyramid[level-1], src_pyramid[level] ));
+ //CV_CALL( cvResize( src_pyramid[level-1], src_pyramid[level], CV_INTER_AREA ));
+ }
+
+ CV_CALL( mask0 = cvCreateMat( src0->rows, src0->cols, CV_8UC1 ));
+ //CV_CALL( submask = (uchar*)cvAlloc( (sp+2)*(sp+2) ));
+
+ // 2. apply meanshift, starting from the pyramid top (i.e. the smallest layer)
+ for( level = max_level; level >= 0; level-- )
+ {
+ CvMat* src = src_pyramid[level];
+ CvSize size = cvGetMatSize(src);
+ uchar* sptr = src->data.ptr;
+ int sstep = src->step;
+ uchar* mask = 0;
+ int mstep = 0;
+ uchar* dptr;
+ int dstep;
+ float sp = (float)(sp0 / (1 << level));
+ sp = MAX( sp, 1 );
+
+ if( level < max_level )
+ {
+ CvSize size1 = cvGetMatSize(dst_pyramid[level+1]);
+ CvMat m = cvMat( size.height, size.width, CV_8UC1, mask0->data.ptr );
+ dstep = dst_pyramid[level+1]->step;
+ dptr = dst_pyramid[level+1]->data.ptr + dstep + cn;
+ mstep = m.step;
+ mask = m.data.ptr + mstep;
+ //cvResize( dst_pyramid[level+1], dst_pyramid[level], CV_INTER_CUBIC );
+ cvPyrUp( dst_pyramid[level+1], dst_pyramid[level] );
+ cvZero( &m );
+
+ for( i = 1; i < size1.height-1; i++, dptr += dstep - (size1.width-2)*3, mask += mstep*2 )
+ {
+ for( j = 1; j < size1.width-1; j++, dptr += cn )
+ {
+ int c0 = dptr[0], c1 = dptr[1], c2 = dptr[2];
+ mask[j*2 - 1] = cdiff(-3) || cdiff(3) || cdiff(-dstep-3) || cdiff(-dstep) ||
+ cdiff(-dstep+3) || cdiff(dstep-3) || cdiff(dstep) || cdiff(dstep+3);
+ }
+ }
+
+ cvDilate( &m, &m, 0, 1 );
+ mask = m.data.ptr;
+ }
+
+ dptr = dst_pyramid[level]->data.ptr;
+ dstep = dst_pyramid[level]->step;
+
+ for( i = 0; i < size.height; i++, sptr += sstep - size.width*3,
+ dptr += dstep - size.width*3,
+ mask += mstep )
+ {
+ for( j = 0; j < size.width; j++, sptr += 3, dptr += 3 )
+ {
+ int x0 = j, y0 = i, x1, y1, iter;
+ int c0, c1, c2;
+
+ if( mask && !mask[j] )
+ continue;
+
+ c0 = sptr[0], c1 = sptr[1], c2 = sptr[2];
+
+ // iterate meanshift procedure
+ for( iter = 0; iter < termcrit.max_iter; iter++ )
+ {
+ uchar* ptr;
+ int x, y, count = 0;
+ int minx, miny, maxx, maxy;
+ int s0 = 0, s1 = 0, s2 = 0, sx = 0, sy = 0;
+ double icount;
+ int stop_flag;
+
+ //mean shift: process pixels in window (p-sigmaSp)x(p+sigmaSp)
+ minx = cvRound(x0 - sp); minx = MAX(minx, 0);
+ miny = cvRound(y0 - sp); miny = MAX(miny, 0);
+ maxx = cvRound(x0 + sp); maxx = MIN(maxx, size.width-1);
+ maxy = cvRound(y0 + sp); maxy = MIN(maxy, size.height-1);
+ ptr = sptr + (miny - i)*sstep + (minx - j)*3;
+
+ for( y = miny; y <= maxy; y++, ptr += sstep - (maxx-minx+1)*3 )
+ {
+ int row_count = 0;
+ x = minx;
+ for( ; x + 3 <= maxx; x += 4, ptr += 12 )
+ {
+ int t0 = ptr[0], t1 = ptr[1], t2 = ptr[2];
+ if( tab[t0-c0+255] + tab[t1-c1+255] + tab[t2-c2+255] <= isr2 )
+ {
+ s0 += t0; s1 += t1; s2 += t2;
+ sx += x; row_count++;
+ }
+ t0 = ptr[3], t1 = ptr[4], t2 = ptr[5];
+ if( tab[t0-c0+255] + tab[t1-c1+255] + tab[t2-c2+255] <= isr2 )
+ {
+ s0 += t0; s1 += t1; s2 += t2;
+ sx += x+1; row_count++;
+ }
+ t0 = ptr[6], t1 = ptr[7], t2 = ptr[8];
+ if( tab[t0-c0+255] + tab[t1-c1+255] + tab[t2-c2+255] <= isr2 )
+ {
+ s0 += t0; s1 += t1; s2 += t2;
+ sx += x+2; row_count++;
+ }
+ t0 = ptr[9], t1 = ptr[10], t2 = ptr[11];
+ if( tab[t0-c0+255] + tab[t1-c1+255] + tab[t2-c2+255] <= isr2 )
+ {
+ s0 += t0; s1 += t1; s2 += t2;
+ sx += x+3; row_count++;
+ }
+ }
+
+ for( ; x <= maxx; x++, ptr += 3 )
+ {
+ int t0 = ptr[0], t1 = ptr[1], t2 = ptr[2];
+ if( tab[t0-c0+255] + tab[t1-c1+255] + tab[t2-c2+255] <= isr2 )
+ {
+ s0 += t0; s1 += t1; s2 += t2;
+ sx += x; row_count++;
+ }
+ }
+ count += row_count;
+ sy += y*row_count;
+ }
+
+ if( count == 0 )
+ break;
+
+ icount = 1./count;
+ x1 = cvRound(sx*icount);
+ y1 = cvRound(sy*icount);
+ s0 = cvRound(s0*icount);
+ s1 = cvRound(s1*icount);
+ s2 = cvRound(s2*icount);
+
+ stop_flag = (x0 == x1 && y0 == y1) || abs(x1-x0) + abs(y1-y0) +
+ tab[s0 - c0 + 255] + tab[s1 - c1 + 255] +
+ tab[s2 - c2 + 255] <= termcrit.epsilon;
+
+ x0 = x1; y0 = y1;
+ c0 = s0; c1 = s1; c2 = s2;
+
+ if( stop_flag )
+ break;
+ }
+
+ dptr[0] = (uchar)c0;
+ dptr[1] = (uchar)c1;
+ dptr[2] = (uchar)c2;
+ }
+ }
+ }
+
+ __END__;
+
+ for( i = 1; i <= MAX_LEVELS; i++ )
+ {
+ cvReleaseMat( &src_pyramid[i] );
+ cvReleaseMat( &dst_pyramid[i] );
+ }
+ cvReleaseMat( &mask0 );
+}
+
diff --git a/cv/src/cvshapedescr.cpp b/cv/src/cvshapedescr.cpp
new file mode 100644
index 0000000..a4c2f88
--- /dev/null
+++ b/cv/src/cvshapedescr.cpp
@@ -0,0 +1,1356 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+/* calculates length of a curve (e.g. contour perimeter) */
+CV_IMPL double
+cvArcLength( const void *array, CvSlice slice, int is_closed )
+{
+ double perimeter = 0;
+
+ CV_FUNCNAME( "cvArcLength" );
+
+ __BEGIN__;
+
+ int i, j = 0, count;
+ const int N = 16;
+ float buf[N];
+ CvMat buffer = cvMat( 1, N, CV_32F, buf );
+ CvSeqReader reader;
+ CvContour contour_header;
+ CvSeq* contour = 0;
+ CvSeqBlock block;
+
+ if( CV_IS_SEQ( array ))
+ {
+ contour = (CvSeq*)array;
+ if( !CV_IS_SEQ_POLYLINE( contour ))
+ CV_ERROR( CV_StsBadArg, "Unsupported sequence type" );
+ if( is_closed < 0 )
+ is_closed = CV_IS_SEQ_CLOSED( contour );
+ }
+ else
+ {
+ is_closed = is_closed > 0;
+ CV_CALL( contour = cvPointSeqFromMat(
+ CV_SEQ_KIND_CURVE | (is_closed ? CV_SEQ_FLAG_CLOSED : 0),
+ array, &contour_header, &block ));
+ }
+
+ if( contour->total > 1 )
+ {
+ int is_float = CV_SEQ_ELTYPE( contour ) == CV_32FC2;
+
+ cvStartReadSeq( contour, &reader, 0 );
+ cvSetSeqReaderPos( &reader, slice.start_index );
+ count = cvSliceLength( slice, contour );
+
+ count -= !is_closed && count == contour->total;
+
+ /* scroll the reader by 1 point */
+ reader.prev_elem = reader.ptr;
+ CV_NEXT_SEQ_ELEM( sizeof(CvPoint), reader );
+
+ for( i = 0; i < count; i++ )
+ {
+ float dx, dy;
+
+ if( !is_float )
+ {
+ CvPoint* pt = (CvPoint*)reader.ptr;
+ CvPoint* prev_pt = (CvPoint*)reader.prev_elem;
+
+ dx = (float)pt->x - (float)prev_pt->x;
+ dy = (float)pt->y - (float)prev_pt->y;
+ }
+ else
+ {
+ CvPoint2D32f* pt = (CvPoint2D32f*)reader.ptr;
+ CvPoint2D32f* prev_pt = (CvPoint2D32f*)reader.prev_elem;
+
+ dx = pt->x - prev_pt->x;
+ dy = pt->y - prev_pt->y;
+ }
+
+ reader.prev_elem = reader.ptr;
+ CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
+
+ buffer.data.fl[j] = dx * dx + dy * dy;
+ if( ++j == N || i == count - 1 )
+ {
+ buffer.cols = j;
+ cvPow( &buffer, &buffer, 0.5 );
+ for( ; j > 0; j-- )
+ perimeter += buffer.data.fl[j-1];
+ }
+ }
+ }
+
+ __END__;
+
+ return perimeter;
+}
+
+
+static CvStatus
+icvFindCircle( CvPoint2D32f pt0, CvPoint2D32f pt1,
+ CvPoint2D32f pt2, CvPoint2D32f * center, float *radius )
+{
+ double x1 = (pt0.x + pt1.x) * 0.5;
+ double dy1 = pt0.x - pt1.x;
+ double x2 = (pt1.x + pt2.x) * 0.5;
+ double dy2 = pt1.x - pt2.x;
+ double y1 = (pt0.y + pt1.y) * 0.5;
+ double dx1 = pt1.y - pt0.y;
+ double y2 = (pt1.y + pt2.y) * 0.5;
+ double dx2 = pt2.y - pt1.y;
+ double t = 0;
+
+ CvStatus result = CV_OK;
+
+ if( icvIntersectLines( x1, dx1, y1, dy1, x2, dx2, y2, dy2, &t ) >= 0 )
+ {
+ center->x = (float) (x2 + dx2 * t);
+ center->y = (float) (y2 + dy2 * t);
+ *radius = (float) icvDistanceL2_32f( *center, pt0 );
+ }
+ else
+ {
+ center->x = center->y = 0.f;
+ radius = 0;
+ result = CV_NOTDEFINED_ERR;
+ }
+
+ return result;
+}
+
+
+CV_INLINE double icvIsPtInCircle( CvPoint2D32f pt, CvPoint2D32f center, float radius )
+{
+ double dx = pt.x - center.x;
+ double dy = pt.y - center.y;
+ return (double)radius*radius - dx*dx - dy*dy;
+}
+
+
+static int
+icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float *_radius )
+{
+ int shuffles[4][4] = { {0, 1, 2, 3}, {0, 1, 3, 2}, {2, 3, 0, 1}, {2, 3, 1, 0} };
+
+ int idxs[4] = { 0, 1, 2, 3 };
+ int i, j, k = 1, mi = 0;
+ float max_dist = 0;
+ CvPoint2D32f center;
+ CvPoint2D32f min_center;
+ float radius, min_radius = FLT_MAX;
+ CvPoint2D32f res_pts[4];
+
+ center = min_center = pts[0];
+ radius = 1.f;
+
+ for( i = 0; i < 4; i++ )
+ for( j = i + 1; j < 4; j++ )
+ {
+ float dist = icvDistanceL2_32f( pts[i], pts[j] );
+
+ if( max_dist < dist )
+ {
+ max_dist = dist;
+ idxs[0] = i;
+ idxs[1] = j;
+ }
+ }
+
+ if( max_dist == 0 )
+ goto function_exit;
+
+ k = 2;
+ for( i = 0; i < 4; i++ )
+ {
+ for( j = 0; j < k; j++ )
+ if( i == idxs[j] )
+ break;
+ if( j == k )
+ idxs[k++] = i;
+ }
+
+ center = cvPoint2D32f( (pts[idxs[0]].x + pts[idxs[1]].x)*0.5f,
+ (pts[idxs[0]].y + pts[idxs[1]].y)*0.5f );
+ radius = (float)(icvDistanceL2_32f( pts[idxs[0]], center )*1.03);
+ if( radius < 1.f )
+ radius = 1.f;
+
+ if( icvIsPtInCircle( pts[idxs[2]], center, radius ) >= 0 &&
+ icvIsPtInCircle( pts[idxs[3]], center, radius ) >= 0 )
+ {
+ k = 2; //rand()%2+2;
+ }
+ else
+ {
+ mi = -1;
+ for( i = 0; i < 4; i++ )
+ {
+ if( icvFindCircle( pts[shuffles[i][0]], pts[shuffles[i][1]],
+ pts[shuffles[i][2]], &center, &radius ) >= 0 )
+ {
+ radius *= 1.03f;
+ if( radius < 2.f )
+ radius = 2.f;
+
+ if( icvIsPtInCircle( pts[shuffles[i][3]], center, radius ) >= 0 &&
+ min_radius > radius )
+ {
+ min_radius = radius;
+ min_center = center;
+ mi = i;
+ }
+ }
+ }
+ assert( mi >= 0 );
+ if( mi < 0 )
+ mi = 0;
+ k = 3;
+ center = min_center;
+ radius = min_radius;
+ for( i = 0; i < 4; i++ )
+ idxs[i] = shuffles[mi][i];
+ }
+
+ function_exit:
+
+ *_center = center;
+ *_radius = radius;
+
+ /* reorder output points */
+ for( i = 0; i < 4; i++ )
+ res_pts[i] = pts[idxs[i]];
+
+ for( i = 0; i < 4; i++ )
+ {
+ pts[i] = res_pts[i];
+ assert( icvIsPtInCircle( pts[i], center, radius ) >= 0 );
+ }
+
+ return k;
+}
+
+
+CV_IMPL int
+cvMinEnclosingCircle( const void* array, CvPoint2D32f * _center, float *_radius )
+{
+ const int max_iters = 100;
+ const float eps = FLT_EPSILON*2;
+ CvPoint2D32f center = { 0, 0 };
+ float radius = 0;
+ int result = 0;
+
+ if( _center )
+ _center->x = _center->y = 0.f;
+ if( _radius )
+ *_radius = 0;
+
+ CV_FUNCNAME( "cvMinEnclosingCircle" );
+
+ __BEGIN__;
+
+ CvSeqReader reader;
+ int i, k, count;
+ CvPoint2D32f pts[8];
+ CvContour contour_header;
+ CvSeqBlock block;
+ CvSeq* sequence = 0;
+ int is_float;
+
+ if( !_center || !_radius )
+ CV_ERROR( CV_StsNullPtr, "Null center or radius pointers" );
+
+ if( CV_IS_SEQ(array) )
+ {
+ sequence = (CvSeq*)array;
+ if( !CV_IS_SEQ_POINT_SET( sequence ))
+ CV_ERROR( CV_StsBadArg, "The passed sequence is not a valid contour" );
+ }
+ else
+ {
+ CV_CALL( sequence = cvPointSeqFromMat(
+ CV_SEQ_KIND_GENERIC, array, &contour_header, &block ));
+ }
+
+ if( sequence->total <= 0 )
+ CV_ERROR_FROM_STATUS( CV_BADSIZE_ERR );
+
+ CV_CALL( cvStartReadSeq( sequence, &reader, 0 ));
+
+ count = sequence->total;
+ is_float = CV_SEQ_ELTYPE(sequence) == CV_32FC2;
+
+ if( !is_float )
+ {
+ CvPoint *pt_left, *pt_right, *pt_top, *pt_bottom;
+ CvPoint pt;
+ pt_left = pt_right = pt_top = pt_bottom = (CvPoint *)(reader.ptr);
+ CV_READ_SEQ_ELEM( pt, reader );
+
+ for( i = 1; i < count; i++ )
+ {
+ CvPoint* pt_ptr = (CvPoint*)reader.ptr;
+ CV_READ_SEQ_ELEM( pt, reader );
+
+ if( pt.x < pt_left->x )
+ pt_left = pt_ptr;
+ if( pt.x > pt_right->x )
+ pt_right = pt_ptr;
+ if( pt.y < pt_top->y )
+ pt_top = pt_ptr;
+ if( pt.y > pt_bottom->y )
+ pt_bottom = pt_ptr;
+ }
+
+ pts[0] = cvPointTo32f( *pt_left );
+ pts[1] = cvPointTo32f( *pt_right );
+ pts[2] = cvPointTo32f( *pt_top );
+ pts[3] = cvPointTo32f( *pt_bottom );
+ }
+ else
+ {
+ CvPoint2D32f *pt_left, *pt_right, *pt_top, *pt_bottom;
+ CvPoint2D32f pt;
+ pt_left = pt_right = pt_top = pt_bottom = (CvPoint2D32f *) (reader.ptr);
+ CV_READ_SEQ_ELEM( pt, reader );
+
+ for( i = 1; i < count; i++ )
+ {
+ CvPoint2D32f* pt_ptr = (CvPoint2D32f*)reader.ptr;
+ CV_READ_SEQ_ELEM( pt, reader );
+
+ if( pt.x < pt_left->x )
+ pt_left = pt_ptr;
+ if( pt.x > pt_right->x )
+ pt_right = pt_ptr;
+ if( pt.y < pt_top->y )
+ pt_top = pt_ptr;
+ if( pt.y > pt_bottom->y )
+ pt_bottom = pt_ptr;
+ }
+
+ pts[0] = *pt_left;
+ pts[1] = *pt_right;
+ pts[2] = *pt_top;
+ pts[3] = *pt_bottom;
+ }
+
+ for( k = 0; k < max_iters; k++ )
+ {
+ double min_delta = 0, delta;
+ CvPoint2D32f ptfl;
+
+ icvFindEnslosingCicle4pts_32f( pts, &center, &radius );
+ cvStartReadSeq( sequence, &reader, 0 );
+
+ for( i = 0; i < count; i++ )
+ {
+ if( !is_float )
+ {
+ ptfl.x = (float)((CvPoint*)reader.ptr)->x;
+ ptfl.y = (float)((CvPoint*)reader.ptr)->y;
+ }
+ else
+ {
+ ptfl = *(CvPoint2D32f*)reader.ptr;
+ }
+ CV_NEXT_SEQ_ELEM( sequence->elem_size, reader );
+
+ delta = icvIsPtInCircle( ptfl, center, radius );
+ if( delta < min_delta )
+ {
+ min_delta = delta;
+ pts[3] = ptfl;
+ }
+ }
+ result = min_delta >= 0;
+ if( result )
+ break;
+ }
+
+ if( !result )
+ {
+ cvStartReadSeq( sequence, &reader, 0 );
+ radius = 0.f;
+
+ for( i = 0; i < count; i++ )
+ {
+ CvPoint2D32f ptfl;
+ float t, dx, dy;
+
+ if( !is_float )
+ {
+ ptfl.x = (float)((CvPoint*)reader.ptr)->x;
+ ptfl.y = (float)((CvPoint*)reader.ptr)->y;
+ }
+ else
+ {
+ ptfl = *(CvPoint2D32f*)reader.ptr;
+ }
+
+ CV_NEXT_SEQ_ELEM( sequence->elem_size, reader );
+ dx = center.x - ptfl.x;
+ dy = center.y - ptfl.y;
+ t = dx*dx + dy*dy;
+ radius = MAX(radius,t);
+ }
+
+ radius = (float)(sqrt(radius)*(1 + eps));
+ result = 1;
+ }
+
+ __END__;
+
+ *_center = center;
+ *_radius = radius;
+
+ return result;
+}
+
+
+/* area of a whole sequence */
+static CvStatus
+icvContourArea( const CvSeq* contour, double *area )
+{
+ if( contour->total )
+ {
+ CvSeqReader reader;
+ int lpt = contour->total;
+ double a00 = 0, xi_1, yi_1;
+ int is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2;
+
+ cvStartReadSeq( contour, &reader, 0 );
+
+ if( !is_float )
+ {
+ xi_1 = ((CvPoint*)(reader.ptr))->x;
+ yi_1 = ((CvPoint*)(reader.ptr))->y;
+ }
+ else
+ {
+ xi_1 = ((CvPoint2D32f*)(reader.ptr))->x;
+ yi_1 = ((CvPoint2D32f*)(reader.ptr))->y;
+ }
+ CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
+
+ while( lpt-- > 0 )
+ {
+ double dxy, xi, yi;
+
+ if( !is_float )
+ {
+ xi = ((CvPoint*)(reader.ptr))->x;
+ yi = ((CvPoint*)(reader.ptr))->y;
+ }
+ else
+ {
+ xi = ((CvPoint2D32f*)(reader.ptr))->x;
+ yi = ((CvPoint2D32f*)(reader.ptr))->y;
+ }
+ CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
+
+ dxy = xi_1 * yi - xi * yi_1;
+ a00 += dxy;
+ xi_1 = xi;
+ yi_1 = yi;
+ }
+
+ *area = a00 * 0.5;
+ }
+ else
+ *area = 0;
+
+ return CV_OK;
+}
+
+
+/****************************************************************************************\
+
+ copy data from one buffer to other buffer
+
+\****************************************************************************************/
+
+static CvStatus
+icvMemCopy( double **buf1, double **buf2, double **buf3, int *b_max )
+{
+ int bb;
+
+ if( (*buf1 == NULL && *buf2 == NULL) || *buf3 == NULL )
+ return CV_NULLPTR_ERR;
+
+ bb = *b_max;
+ if( *buf2 == NULL )
+ {
+ *b_max = 2 * (*b_max);
+ *buf2 = (double *)cvAlloc( (*b_max) * sizeof( double ));
+
+ if( *buf2 == NULL )
+ return CV_OUTOFMEM_ERR;
+
+ memcpy( *buf2, *buf3, bb * sizeof( double ));
+
+ *buf3 = *buf2;
+ cvFree( buf1 );
+ *buf1 = NULL;
+ }
+ else
+ {
+ *b_max = 2 * (*b_max);
+ *buf1 = (double *) cvAlloc( (*b_max) * sizeof( double ));
+
+ if( *buf1 == NULL )
+ return CV_OUTOFMEM_ERR;
+
+ memcpy( *buf1, *buf3, bb * sizeof( double ));
+
+ *buf3 = *buf1;
+ cvFree( buf2 );
+ *buf2 = NULL;
+ }
+ return CV_OK;
+}
+
+
+/* area of a contour sector */
+static CvStatus icvContourSecArea( CvSeq * contour, CvSlice slice, double *area )
+{
+ CvPoint pt; /* pointer to points */
+ CvPoint pt_s, pt_e; /* first and last points */
+ CvSeqReader reader; /* points reader of contour */
+
+ int p_max = 2, p_ind;
+ int lpt, flag, i;
+ double a00; /* unnormalized moments m00 */
+ double xi, yi, xi_1, yi_1, x0, y0, dxy, sk, sk1, t;
+ double x_s, y_s, nx, ny, dx, dy, du, dv;
+ double eps = 1.e-5;
+ double *p_are1, *p_are2, *p_are;
+
+ assert( contour != NULL );
+
+ if( contour == NULL )
+ return CV_NULLPTR_ERR;
+
+ if( !CV_IS_SEQ_POLYGON( contour ))
+ return CV_BADFLAG_ERR;
+
+ lpt = cvSliceLength( slice, contour );
+ /*if( n2 >= n1 )
+ lpt = n2 - n1 + 1;
+ else
+ lpt = contour->total - n1 + n2 + 1;*/
+
+ if( contour->total && lpt > 2 )
+ {
+ a00 = x0 = y0 = xi_1 = yi_1 = 0;
+ sk1 = 0;
+ flag = 0;
+ dxy = 0;
+ p_are1 = (double *) cvAlloc( p_max * sizeof( double ));
+
+ if( p_are1 == NULL )
+ return CV_OUTOFMEM_ERR;
+
+ p_are = p_are1;
+ p_are2 = NULL;
+
+ cvStartReadSeq( contour, &reader, 0 );
+ cvSetSeqReaderPos( &reader, slice.start_index );
+ CV_READ_SEQ_ELEM( pt_s, reader );
+ p_ind = 0;
+ cvSetSeqReaderPos( &reader, slice.end_index );
+ CV_READ_SEQ_ELEM( pt_e, reader );
+
+/* normal coefficients */
+ nx = pt_s.y - pt_e.y;
+ ny = pt_e.x - pt_s.x;
+ cvSetSeqReaderPos( &reader, slice.start_index );
+
+ while( lpt-- > 0 )
+ {
+ CV_READ_SEQ_ELEM( pt, reader );
+
+ if( flag == 0 )
+ {
+ xi_1 = (double) pt.x;
+ yi_1 = (double) pt.y;
+ x0 = xi_1;
+ y0 = yi_1;
+ sk1 = 0;
+ flag = 1;
+ }
+ else
+ {
+ xi = (double) pt.x;
+ yi = (double) pt.y;
+
+/**************** edges intersection examination **************************/
+ sk = nx * (xi - pt_s.x) + ny * (yi - pt_s.y);
+ if( (fabs( sk ) < eps && lpt > 0) || sk * sk1 < -eps )
+ {
+ if( fabs( sk ) < eps )
+ {
+ dxy = xi_1 * yi - xi * yi_1;
+ a00 = a00 + dxy;
+ dxy = xi * y0 - x0 * yi;
+ a00 = a00 + dxy;
+
+ if( p_ind >= p_max )
+ icvMemCopy( &p_are1, &p_are2, &p_are, &p_max );
+
+ p_are[p_ind] = a00 / 2.;
+ p_ind++;
+ a00 = 0;
+ sk1 = 0;
+ x0 = xi;
+ y0 = yi;
+ dxy = 0;
+ }
+ else
+ {
+/* define intersection point */
+ dv = yi - yi_1;
+ du = xi - xi_1;
+ dx = ny;
+ dy = -nx;
+ if( fabs( du ) > eps )
+ t = ((yi_1 - pt_s.y) * du + dv * (pt_s.x - xi_1)) /
+ (du * dy - dx * dv);
+ else
+ t = (xi_1 - pt_s.x) / dx;
+ if( t > eps && t < 1 - eps )
+ {
+ x_s = pt_s.x + t * dx;
+ y_s = pt_s.y + t * dy;
+ dxy = xi_1 * y_s - x_s * yi_1;
+ a00 += dxy;
+ dxy = x_s * y0 - x0 * y_s;
+ a00 += dxy;
+ if( p_ind >= p_max )
+ icvMemCopy( &p_are1, &p_are2, &p_are, &p_max );
+
+ p_are[p_ind] = a00 / 2.;
+ p_ind++;
+
+ a00 = 0;
+ sk1 = 0;
+ x0 = x_s;
+ y0 = y_s;
+ dxy = x_s * yi - xi * y_s;
+ }
+ }
+ }
+ else
+ dxy = xi_1 * yi - xi * yi_1;
+
+ a00 += dxy;
+ xi_1 = xi;
+ yi_1 = yi;
+ sk1 = sk;
+
+ }
+ }
+
+ xi = x0;
+ yi = y0;
+ dxy = xi_1 * yi - xi * yi_1;
+
+ a00 += dxy;
+
+ if( p_ind >= p_max )
+ icvMemCopy( &p_are1, &p_are2, &p_are, &p_max );
+
+ p_are[p_ind] = a00 / 2.;
+ p_ind++;
+
+/* common area calculation */
+ *area = 0;
+ for( i = 0; i < p_ind; i++ )
+ (*area) += fabs( p_are[i] );
+
+ if( p_are1 != NULL )
+ cvFree( &p_are1 );
+ else if( p_are2 != NULL )
+ cvFree( &p_are2 );
+
+ return CV_OK;
+ }
+ else
+ return CV_BADSIZE_ERR;
+}
+
+
+/* external contour area function */
+CV_IMPL double
+cvContourArea( const void *array, CvSlice slice )
+{
+ double area = 0;
+
+ CV_FUNCNAME( "cvContourArea" );
+
+ __BEGIN__;
+
+ CvContour contour_header;
+ CvSeq* contour = 0;
+ CvSeqBlock block;
+
+ if( CV_IS_SEQ( array ))
+ {
+ contour = (CvSeq*)array;
+ if( !CV_IS_SEQ_POLYLINE( contour ))
+ CV_ERROR( CV_StsBadArg, "Unsupported sequence type" );
+ }
+ else
+ {
+ CV_CALL( contour = cvPointSeqFromMat(
+ CV_SEQ_KIND_CURVE, array, &contour_header, &block ));
+ }
+
+ if( cvSliceLength( slice, contour ) == contour->total )
+ {
+ IPPI_CALL( icvContourArea( contour, &area ));
+ }
+ else
+ {
+ if( CV_SEQ_ELTYPE( contour ) != CV_32SC2 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Only curves with integer coordinates are supported in case of contour slice" );
+ IPPI_CALL( icvContourSecArea( contour, slice, &area ));
+ }
+
+ __END__;
+
+ return area;
+}
+
+
+/* for now this function works bad with singular cases
+ You can see in the code, that when some troubles with
+ matrices or some variables occur -
+ box filled with zero values is returned.
+ However in general function works fine.
+*/
+static void
+icvFitEllipse_F( CvSeq* points, CvBox2D* box )
+{
+ CvMat* D = 0;
+
+ CV_FUNCNAME( "icvFitEllipse_F" );
+
+ __BEGIN__;
+
+ double S[36], C[36], T[36];
+
+ int i, j;
+ double eigenvalues[6], eigenvectors[36];
+ double a, b, c, d, e, f;
+ double x0, y0, idet, scale, offx = 0, offy = 0;
+
+ int n = points->total;
+ CvSeqReader reader;
+ int is_float = CV_SEQ_ELTYPE(points) == CV_32FC2;
+
+ CvMat _S = cvMat(6,6,CV_64F,S), _C = cvMat(6,6,CV_64F,C), _T = cvMat(6,6,CV_64F,T);
+ CvMat _EIGVECS = cvMat(6,6,CV_64F,eigenvectors), _EIGVALS = cvMat(6,1,CV_64F,eigenvalues);
+
+ /* create matrix D of input points */
+ CV_CALL( D = cvCreateMat( n, 6, CV_64F ));
+
+ cvStartReadSeq( points, &reader );
+
+ /* shift all points to zero */
+ for( i = 0; i < n; i++ )
+ {
+ if( !is_float )
+ {
+ offx += ((CvPoint*)reader.ptr)->x;
+ offy += ((CvPoint*)reader.ptr)->y;
+ }
+ else
+ {
+ offx += ((CvPoint2D32f*)reader.ptr)->x;
+ offy += ((CvPoint2D32f*)reader.ptr)->y;
+ }
+ CV_NEXT_SEQ_ELEM( points->elem_size, reader );
+ }
+
+ offx /= n;
+ offy /= n;
+
+ // fill matrix rows as (x*x, x*y, y*y, x, y, 1 )
+ for( i = 0; i < n; i++ )
+ {
+ double x, y;
+ double* Dptr = D->data.db + i*6;
+
+ if( !is_float )
+ {
+ x = ((CvPoint*)reader.ptr)->x - offx;
+ y = ((CvPoint*)reader.ptr)->y - offy;
+ }
+ else
+ {
+ x = ((CvPoint2D32f*)reader.ptr)->x - offx;
+ y = ((CvPoint2D32f*)reader.ptr)->y - offy;
+ }
+ CV_NEXT_SEQ_ELEM( points->elem_size, reader );
+
+ Dptr[0] = x * x;
+ Dptr[1] = x * y;
+ Dptr[2] = y * y;
+ Dptr[3] = x;
+ Dptr[4] = y;
+ Dptr[5] = 1.;
+ }
+
+ // S = D^t*D
+ cvMulTransposed( D, &_S, 1 );
+ cvSVD( &_S, &_EIGVALS, &_EIGVECS, 0, CV_SVD_MODIFY_A + CV_SVD_U_T );
+
+ for( i = 0; i < 6; i++ )
+ {
+ double a = eigenvalues[i];
+ a = a < DBL_EPSILON ? 0 : 1./sqrt(sqrt(a));
+ for( j = 0; j < 6; j++ )
+ eigenvectors[i*6 + j] *= a;
+ }
+
+ // C = Q^-1 = transp(INVEIGV) * INVEIGV
+ cvMulTransposed( &_EIGVECS, &_C, 1 );
+
+ cvZero( &_S );
+ S[2] = 2.;
+ S[7] = -1.;
+ S[12] = 2.;
+
+ // S = Q^-1*S*Q^-1
+ cvMatMul( &_C, &_S, &_T );
+ cvMatMul( &_T, &_C, &_S );
+
+ // and find its eigenvalues and vectors too
+ //cvSVD( &_S, &_EIGVALS, &_EIGVECS, 0, CV_SVD_MODIFY_A + CV_SVD_U_T );
+ cvEigenVV( &_S, &_EIGVECS, &_EIGVALS, 0 );
+
+ for( i = 0; i < 3; i++ )
+ if( eigenvalues[i] > 0 )
+ break;
+
+ if( i >= 3 /*eigenvalues[0] < DBL_EPSILON*/ )
+ {
+ box->center.x = box->center.y =
+ box->size.width = box->size.height =
+ box->angle = 0.f;
+ EXIT;
+ }
+
+ // now find truthful eigenvector
+ _EIGVECS = cvMat( 6, 1, CV_64F, eigenvectors + 6*i );
+ _T = cvMat( 6, 1, CV_64F, T );
+ // Q^-1*eigenvecs[0]
+ cvMatMul( &_C, &_EIGVECS, &_T );
+
+ // extract vector components
+ a = T[0]; b = T[1]; c = T[2]; d = T[3]; e = T[4]; f = T[5];
+
+ ///////////////// extract ellipse axes from above values ////////////////
+
+ /*
+ 1) find center of ellipse
+ it satisfy equation
+ | a b/2 | * | x0 | + | d/2 | = |0 |
+ | b/2 c | | y0 | | e/2 | |0 |
+
+ */
+ idet = a * c - b * b * 0.25;
+ idet = idet > DBL_EPSILON ? 1./idet : 0;
+
+ // we must normalize (a b c d e f ) to fit (4ac-b^2=1)
+ scale = sqrt( 0.25 * idet );
+
+ if( scale < DBL_EPSILON )
+ {
+ box->center.x = (float)offx;
+ box->center.y = (float)offy;
+ box->size.width = box->size.height = box->angle = 0.f;
+ EXIT;
+ }
+
+ a *= scale;
+ b *= scale;
+ c *= scale;
+ d *= scale;
+ e *= scale;
+ f *= scale;
+
+ x0 = (-d * c + e * b * 0.5) * 2.;
+ y0 = (-a * e + d * b * 0.5) * 2.;
+
+ // recover center
+ box->center.x = (float)(x0 + offx);
+ box->center.y = (float)(y0 + offy);
+
+ // offset ellipse to (x0,y0)
+ // new f == F(x0,y0)
+ f += a * x0 * x0 + b * x0 * y0 + c * y0 * y0 + d * x0 + e * y0;
+
+ if( fabs(f) < DBL_EPSILON )
+ {
+ box->size.width = box->size.height = box->angle = 0.f;
+ EXIT;
+ }
+
+ scale = -1. / f;
+ // normalize to f = 1
+ a *= scale;
+ b *= scale;
+ c *= scale;
+
+ // extract axis of ellipse
+ // one more eigenvalue operation
+ S[0] = a;
+ S[1] = S[2] = b * 0.5;
+ S[3] = c;
+
+ _S = cvMat( 2, 2, CV_64F, S );
+ _EIGVECS = cvMat( 2, 2, CV_64F, eigenvectors );
+ _EIGVALS = cvMat( 1, 2, CV_64F, eigenvalues );
+ cvSVD( &_S, &_EIGVALS, &_EIGVECS, 0, CV_SVD_MODIFY_A + CV_SVD_U_T );
+
+ // exteract axis length from eigenvectors
+ box->size.width = (float)(2./sqrt(eigenvalues[0]));
+ box->size.height = (float)(2./sqrt(eigenvalues[1]));
+
+ // calc angle
+ box->angle = (float)(180 - atan2(eigenvectors[2], eigenvectors[3])*180/CV_PI);
+
+ __END__;
+
+ cvReleaseMat( &D );
+}
+
+
+CV_IMPL CvBox2D
+cvFitEllipse2( const CvArr* array )
+{
+ CvBox2D box;
+ double* Ad = 0, *bd = 0;
+
+ CV_FUNCNAME( "cvFitEllipse2" );
+
+ memset( &box, 0, sizeof(box));
+
+ __BEGIN__;
+
+ CvContour contour_header;
+ CvSeq* ptseq = 0;
+ CvSeqBlock block;
+ int n;
+
+ if( CV_IS_SEQ( array ))
+ {
+ ptseq = (CvSeq*)array;
+ if( !CV_IS_SEQ_POINT_SET( ptseq ))
+ CV_ERROR( CV_StsBadArg, "Unsupported sequence type" );
+ }
+ else
+ {
+ CV_CALL( ptseq = cvPointSeqFromMat(
+ CV_SEQ_KIND_GENERIC, array, &contour_header, &block ));
+ }
+
+ n = ptseq->total;
+ if( n < 5 )
+ CV_ERROR( CV_StsBadSize, "Number of points should be >= 6" );
+#if 1
+ icvFitEllipse_F( ptseq, &box );
+#else
+ /*
+ * New fitellipse algorithm, contributed by Dr. Daniel Weiss
+ */
+ {
+ double gfp[5], rp[5], t;
+ CvMat A, b, x;
+ const double min_eps = 1e-6;
+ int i, is_float;
+ CvSeqReader reader;
+
+ CV_CALL( Ad = (double*)cvAlloc( n*5*sizeof(Ad[0]) ));
+ CV_CALL( bd = (double*)cvAlloc( n*sizeof(bd[0]) ));
+
+ // first fit for parameters A - E
+ A = cvMat( n, 5, CV_64F, Ad );
+ b = cvMat( n, 1, CV_64F, bd );
+ x = cvMat( 5, 1, CV_64F, gfp );
+
+ cvStartReadSeq( ptseq, &reader );
+ is_float = CV_SEQ_ELTYPE(ptseq) == CV_32FC2;
+
+ for( i = 0; i < n; i++ )
+ {
+ CvPoint2D32f p;
+ if( is_float )
+ p = *(CvPoint2D32f*)(reader.ptr);
+ else
+ {
+ p.x = (float)((int*)reader.ptr)[0];
+ p.y = (float)((int*)reader.ptr)[1];
+ }
+ CV_NEXT_SEQ_ELEM( sizeof(p), reader );
+
+ bd[i] = 10000.0; // 1.0?
+ Ad[i*5] = -(double)p.x * p.x; // A - C signs inverted as proposed by APP
+ Ad[i*5 + 1] = -(double)p.y * p.y;
+ Ad[i*5 + 2] = -(double)p.x * p.y;
+ Ad[i*5 + 3] = p.x;
+ Ad[i*5 + 4] = p.y;
+ }
+
+ cvSolve( &A, &b, &x, CV_SVD );
+
+ // now use general-form parameters A - E to find the ellipse center:
+ // differentiate general form wrt x/y to get two equations for cx and cy
+ A = cvMat( 2, 2, CV_64F, Ad );
+ b = cvMat( 2, 1, CV_64F, bd );
+ x = cvMat( 2, 1, CV_64F, rp );
+ Ad[0] = 2 * gfp[0];
+ Ad[1] = Ad[2] = gfp[2];
+ Ad[3] = 2 * gfp[1];
+ bd[0] = gfp[3];
+ bd[1] = gfp[4];
+ cvSolve( &A, &b, &x, CV_SVD );
+
+ // re-fit for parameters A - C with those center coordinates
+ A = cvMat( n, 3, CV_64F, Ad );
+ b = cvMat( n, 1, CV_64F, bd );
+ x = cvMat( 3, 1, CV_64F, gfp );
+ for( i = 0; i < n; i++ )
+ {
+ CvPoint2D32f p;
+ if( is_float )
+ p = *(CvPoint2D32f*)(reader.ptr);
+ else
+ {
+ p.x = (float)((int*)reader.ptr)[0];
+ p.y = (float)((int*)reader.ptr)[1];
+ }
+ CV_NEXT_SEQ_ELEM( sizeof(p), reader );
+ bd[i] = 1.0;
+ Ad[i * 3] = (p.x - rp[0]) * (p.x - rp[0]);
+ Ad[i * 3 + 1] = (p.y - rp[1]) * (p.y - rp[1]);
+ Ad[i * 3 + 2] = (p.x - rp[0]) * (p.y - rp[1]);
+ }
+ cvSolve(&A, &b, &x, CV_SVD);
+
+ // store angle and radii
+ rp[4] = -0.5 * atan2(gfp[2], gfp[1] - gfp[0]); // convert from APP angle usage
+ t = sin(-2.0 * rp[4]);
+ if( fabs(t) > fabs(gfp[2])*min_eps )
+ t = gfp[2]/t;
+ else
+ t = gfp[1] - gfp[0];
+ rp[2] = fabs(gfp[0] + gfp[1] - t);
+ if( rp[2] > min_eps )
+ rp[2] = sqrt(2.0 / rp[2]);
+ rp[3] = fabs(gfp[0] + gfp[1] + t);
+ if( rp[3] > min_eps )
+ rp[3] = sqrt(2.0 / rp[3]);
+
+ box.center.x = (float)rp[0];
+ box.center.y = (float)rp[1];
+ box.size.width = (float)(rp[2]*2);
+ box.size.height = (float)(rp[3]*2);
+ if( box.size.width > box.size.height )
+ {
+ float tmp;
+ CV_SWAP( box.size.width, box.size.height, tmp );
+ box.angle = (float)(90 + rp[4]*180/CV_PI);
+ }
+ if( box.angle < -180 )
+ box.angle += 360;
+ if( box.angle > 360 )
+ box.angle -= 360;
+ }
+#endif
+ __END__;
+
+ cvFree( &Ad );
+ cvFree( &bd );
+
+ return box;
+}
+
+
+/* Calculates bounding rectagnle of a point set or retrieves already calculated */
+CV_IMPL CvRect
+cvBoundingRect( CvArr* array, int update )
+{
+ CvSeqReader reader;
+ CvRect rect = { 0, 0, 0, 0 };
+ CvContour contour_header;
+ CvSeq* ptseq = 0;
+ CvSeqBlock block;
+
+ CV_FUNCNAME( "cvBoundingRect" );
+
+ __BEGIN__;
+
+ CvMat stub, *mat = 0;
+ int xmin = 0, ymin = 0, xmax = -1, ymax = -1, i, j, k;
+ int calculate = update;
+
+ if( CV_IS_SEQ( array ))
+ {
+ ptseq = (CvSeq*)array;
+ if( !CV_IS_SEQ_POINT_SET( ptseq ))
+ CV_ERROR( CV_StsBadArg, "Unsupported sequence type" );
+
+ if( ptseq->header_size < (int)sizeof(CvContour))
+ {
+ /*if( update == 1 )
+ CV_ERROR( CV_StsBadArg, "The header is too small to fit the rectangle, "
+ "so it could not be updated" );*/
+ update = 0;
+ calculate = 1;
+ }
+ }
+ else
+ {
+ CV_CALL( mat = cvGetMat( array, &stub ));
+ if( CV_MAT_TYPE(mat->type) == CV_32SC2 ||
+ CV_MAT_TYPE(mat->type) == CV_32FC2 )
+ {
+ CV_CALL( ptseq = cvPointSeqFromMat(
+ CV_SEQ_KIND_GENERIC, mat, &contour_header, &block ));
+ mat = 0;
+ }
+ else if( CV_MAT_TYPE(mat->type) != CV_8UC1 &&
+ CV_MAT_TYPE(mat->type) != CV_8SC1 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "The image/matrix format is not supported by the function" );
+ update = 0;
+ calculate = 1;
+ }
+
+ if( !calculate )
+ {
+ rect = ((CvContour*)ptseq)->rect;
+ EXIT;
+ }
+
+ if( mat )
+ {
+ CvSize size = cvGetMatSize(mat);
+ xmin = size.width;
+ ymin = -1;
+
+ for( i = 0; i < size.height; i++ )
+ {
+ uchar* _ptr = mat->data.ptr + i*mat->step;
+ uchar* ptr = (uchar*)cvAlignPtr(_ptr, 4);
+ int have_nz = 0, k_min, offset = (int)(ptr - _ptr);
+ j = 0;
+ offset = MIN(offset, size.width);
+ for( ; j < offset; j++ )
+ if( _ptr[j] )
+ {
+ have_nz = 1;
+ break;
+ }
+ if( j < offset )
+ {
+ if( j < xmin )
+ xmin = j;
+ if( j > xmax )
+ xmax = j;
+ }
+ if( offset < size.width )
+ {
+ xmin -= offset;
+ xmax -= offset;
+ size.width -= offset;
+ j = 0;
+ for( ; j <= xmin - 4; j += 4 )
+ if( *((int*)(ptr+j)) )
+ break;
+ for( ; j < xmin; j++ )
+ if( ptr[j] )
+ {
+ xmin = j;
+ if( j > xmax )
+ xmax = j;
+ have_nz = 1;
+ break;
+ }
+ k_min = MAX(j-1, xmax);
+ k = size.width - 1;
+ for( ; k > k_min && (k&3) != 3; k-- )
+ if( ptr[k] )
+ break;
+ if( k > k_min && (k&3) == 3 )
+ {
+ for( ; k > k_min+3; k -= 4 )
+ if( *((int*)(ptr+k-3)) )
+ break;
+ }
+ for( ; k > k_min; k-- )
+ if( ptr[k] )
+ {
+ xmax = k;
+ have_nz = 1;
+ break;
+ }
+ if( !have_nz )
+ {
+ j &= ~3;
+ for( ; j <= k - 3; j += 4 )
+ if( *((int*)(ptr+j)) )
+ break;
+ for( ; j <= k; j++ )
+ if( ptr[j] )
+ {
+ have_nz = 1;
+ break;
+ }
+ }
+ xmin += offset;
+ xmax += offset;
+ size.width += offset;
+ }
+ if( have_nz )
+ {
+ if( ymin < 0 )
+ ymin = i;
+ ymax = i;
+ }
+ }
+
+ if( xmin >= size.width )
+ xmin = ymin = 0;
+ }
+ else if( ptseq->total )
+ {
+ int is_float = CV_SEQ_ELTYPE(ptseq) == CV_32FC2;
+ cvStartReadSeq( ptseq, &reader, 0 );
+
+ if( !is_float )
+ {
+ CvPoint pt;
+ /* init values */
+ CV_READ_SEQ_ELEM( pt, reader );
+ xmin = xmax = pt.x;
+ ymin = ymax = pt.y;
+
+ for( i = 1; i < ptseq->total; i++ )
+ {
+ CV_READ_SEQ_ELEM( pt, reader );
+
+ if( xmin > pt.x )
+ xmin = pt.x;
+
+ if( xmax < pt.x )
+ xmax = pt.x;
+
+ if( ymin > pt.y )
+ ymin = pt.y;
+
+ if( ymax < pt.y )
+ ymax = pt.y;
+ }
+ }
+ else
+ {
+ CvPoint pt;
+ Cv32suf v;
+ /* init values */
+ CV_READ_SEQ_ELEM( pt, reader );
+ xmin = xmax = CV_TOGGLE_FLT(pt.x);
+ ymin = ymax = CV_TOGGLE_FLT(pt.y);
+
+ for( i = 1; i < ptseq->total; i++ )
+ {
+ CV_READ_SEQ_ELEM( pt, reader );
+ pt.x = CV_TOGGLE_FLT(pt.x);
+ pt.y = CV_TOGGLE_FLT(pt.y);
+
+ if( xmin > pt.x )
+ xmin = pt.x;
+
+ if( xmax < pt.x )
+ xmax = pt.x;
+
+ if( ymin > pt.y )
+ ymin = pt.y;
+
+ if( ymax < pt.y )
+ ymax = pt.y;
+ }
+
+ v.i = CV_TOGGLE_FLT(xmin); xmin = cvFloor(v.f);
+ v.i = CV_TOGGLE_FLT(ymin); ymin = cvFloor(v.f);
+ /* because right and bottom sides of
+ the bounding rectangle are not inclusive
+ (note +1 in width and height calculation below),
+ cvFloor is used here instead of cvCeil */
+ v.i = CV_TOGGLE_FLT(xmax); xmax = cvFloor(v.f);
+ v.i = CV_TOGGLE_FLT(ymax); ymax = cvFloor(v.f);
+ }
+ }
+
+ rect.x = xmin;
+ rect.y = ymin;
+ rect.width = xmax - xmin + 1;
+ rect.height = ymax - ymin + 1;
+
+ if( update )
+ ((CvContour*)ptseq)->rect = rect;
+
+ __END__;
+
+ return rect;
+}
+
+
+/* End of file. */
diff --git a/cv/src/cvsmooth.cpp b/cv/src/cvsmooth.cpp
new file mode 100644
index 0000000..55f8fea
--- /dev/null
+++ b/cv/src/cvsmooth.cpp
@@ -0,0 +1,1530 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+/*
+ * This file includes the code, contributed by Simon Perreault
+ * (the function icvMedianBlur_8u_CnR_O1)
+ *
+ * Constant-time median filtering -- http://nomis80.org/ctmf.html
+ * Copyright (C) 2006 Simon Perreault
+ *
+ * Contact:
+ * Laboratoire de vision et systemes numeriques
+ * Pavillon Adrien-Pouliot
+ * Universite Laval
+ * Sainte-Foy, Quebec, Canada
+ * G1K 7P4
+ *
+ * perreaul@gel.ulaval.ca
+ */
+
+// uncomment the line below to force SSE2 mode
+//#define CV_SSE2 1
+
+/****************************************************************************************\
+ Box Filter
+\****************************************************************************************/
+
+static void icvSumRow_8u32s( const uchar* src0, int* dst, void* params );
+static void icvSumRow_32f64f( const float* src0, double* dst, void* params );
+static void icvSumCol_32s8u( const int** src, uchar* dst, int dst_step,
+ int count, void* params );
+static void icvSumCol_32s16s( const int** src, short* dst, int dst_step,
+ int count, void* params );
+static void icvSumCol_32s32s( const int** src, int* dst, int dst_step,
+ int count, void* params );
+static void icvSumCol_64f32f( const double** src, float* dst, int dst_step,
+ int count, void* params );
+
+CvBoxFilter::CvBoxFilter()
+{
+ min_depth = CV_32S;
+ sum = 0;
+ sum_count = 0;
+ normalized = false;
+}
+
+
+CvBoxFilter::CvBoxFilter( int _max_width, int _src_type, int _dst_type,
+ bool _normalized, CvSize _ksize,
+ CvPoint _anchor, int _border_mode,
+ CvScalar _border_value )
+{
+ min_depth = CV_32S;
+ sum = 0;
+ sum_count = 0;
+ normalized = false;
+ init( _max_width, _src_type, _dst_type, _normalized,
+ _ksize, _anchor, _border_mode, _border_value );
+}
+
+
+CvBoxFilter::~CvBoxFilter()
+{
+ clear();
+}
+
+
+void CvBoxFilter::init( int _max_width, int _src_type, int _dst_type,
+ bool _normalized, CvSize _ksize,
+ CvPoint _anchor, int _border_mode,
+ CvScalar _border_value )
+{
+ CV_FUNCNAME( "CvBoxFilter::init" );
+
+ __BEGIN__;
+
+ sum = 0;
+ normalized = _normalized;
+
+ if( (normalized && CV_MAT_TYPE(_src_type) != CV_MAT_TYPE(_dst_type)) ||
+ (!normalized && CV_MAT_CN(_src_type) != CV_MAT_CN(_dst_type)))
+ CV_ERROR( CV_StsUnmatchedFormats,
+ "In case of normalized box filter input and output must have the same type.\n"
+ "In case of unnormalized box filter the number of input and output channels must be the same" );
+
+ min_depth = CV_MAT_DEPTH(_src_type) == CV_8U ? CV_32S : CV_64F;
+
+ CvBaseImageFilter::init( _max_width, _src_type, _dst_type, 1, _ksize,
+ _anchor, _border_mode, _border_value );
+
+ scale = normalized ? 1./(ksize.width*ksize.height) : 1;
+
+ if( CV_MAT_DEPTH(src_type) == CV_8U )
+ x_func = (CvRowFilterFunc)icvSumRow_8u32s;
+ else if( CV_MAT_DEPTH(src_type) == CV_32F )
+ x_func = (CvRowFilterFunc)icvSumRow_32f64f;
+ else
+ CV_ERROR( CV_StsUnsupportedFormat, "Unknown/unsupported input image format" );
+
+ if( CV_MAT_DEPTH(dst_type) == CV_8U )
+ {
+ if( !normalized )
+ CV_ERROR( CV_StsBadArg, "Only normalized box filter can be used for 8u->8u transformation" );
+ y_func = (CvColumnFilterFunc)icvSumCol_32s8u;
+ }
+ else if( CV_MAT_DEPTH(dst_type) == CV_16S )
+ {
+ if( normalized || CV_MAT_DEPTH(src_type) != CV_8U )
+ CV_ERROR( CV_StsBadArg, "Only 8u->16s unnormalized box filter is supported in case of 16s output" );
+ y_func = (CvColumnFilterFunc)icvSumCol_32s16s;
+ }
+ else if( CV_MAT_DEPTH(dst_type) == CV_32S )
+ {
+ if( normalized || CV_MAT_DEPTH(src_type) != CV_8U )
+ CV_ERROR( CV_StsBadArg, "Only 8u->32s unnormalized box filter is supported in case of 32s output");
+
+ y_func = (CvColumnFilterFunc)icvSumCol_32s32s;
+ }
+ else if( CV_MAT_DEPTH(dst_type) == CV_32F )
+ {
+ if( CV_MAT_DEPTH(src_type) != CV_32F )
+ CV_ERROR( CV_StsBadArg, "Only 32f->32f box filter (normalized or not) is supported in case of 32f output" );
+ y_func = (CvColumnFilterFunc)icvSumCol_64f32f;
+ }
+ else{
+ CV_ERROR( CV_StsBadArg, "Unknown/unsupported destination image format" );
+ }
+
+ __END__;
+}
+
+
+void CvBoxFilter::start_process( CvSlice x_range, int width )
+{
+ CvBaseImageFilter::start_process( x_range, width );
+ int i, psz = CV_ELEM_SIZE(work_type);
+ uchar* s;
+ buf_end -= buf_step;
+ buf_max_count--;
+ assert( buf_max_count >= max_ky*2 + 1 );
+ s = sum = buf_end + cvAlign((width + ksize.width - 1)*CV_ELEM_SIZE(src_type), ALIGN);
+ sum_count = 0;
+
+ width *= psz;
+ for( i = 0; i < width; i++ )
+ s[i] = (uchar)0;
+}
+
+
+static void
+icvSumRow_8u32s( const uchar* src, int* dst, void* params )
+{
+ const CvBoxFilter* state = (const CvBoxFilter*)params;
+ int ksize = state->get_kernel_size().width;
+ int width = state->get_width();
+ int cn = CV_MAT_CN(state->get_src_type());
+ int i, k;
+
+ width = (width - 1)*cn; ksize *= cn;
+
+ for( k = 0; k < cn; k++, src++, dst++ )
+ {
+ int s = 0;
+ for( i = 0; i < ksize; i += cn )
+ s += src[i];
+ dst[0] = s;
+ for( i = 0; i < width; i += cn )
+ {
+ s += src[i+ksize] - src[i];
+ dst[i+cn] = s;
+ }
+ }
+}
+
+
+static void
+icvSumRow_32f64f( const float* src, double* dst, void* params )
+{
+ const CvBoxFilter* state = (const CvBoxFilter*)params;
+ int ksize = state->get_kernel_size().width;
+ int width = state->get_width();
+ int cn = CV_MAT_CN(state->get_src_type());
+ int i, k;
+
+ width = (width - 1)*cn; ksize *= cn;
+
+ for( k = 0; k < cn; k++, src++, dst++ )
+ {
+ double s = 0;
+ for( i = 0; i < ksize; i += cn )
+ s += src[i];
+ dst[0] = s;
+ for( i = 0; i < width; i += cn )
+ {
+ s += (double)src[i+ksize] - src[i];
+ dst[i+cn] = s;
+ }
+ }
+}
+
+
+static void
+icvSumCol_32s8u( const int** src, uchar* dst,
+ int dst_step, int count, void* params )
+{
+#define BLUR_SHIFT 24
+ CvBoxFilter* state = (CvBoxFilter*)params;
+ int ksize = state->get_kernel_size().height;
+ int i, width = state->get_width();
+ int cn = CV_MAT_CN(state->get_src_type());
+ double scale = state->get_scale();
+ int iscale = cvFloor(scale*(1 << BLUR_SHIFT));
+ int* sum = (int*)state->get_sum_buf();
+ int* _sum_count = state->get_sum_count_ptr();
+ int sum_count = *_sum_count;
+
+ width *= cn;
+ src += sum_count;
+ count += ksize - 1 - sum_count;
+
+ for( ; count--; src++ )
+ {
+ const int* sp = src[0];
+ if( sum_count+1 < ksize )
+ {
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = sum[i] + sp[i], s1 = sum[i+1] + sp[i+1];
+ sum[i] = s0; sum[i+1] = s1;
+ }
+
+ for( ; i < width; i++ )
+ sum[i] += sp[i];
+
+ sum_count++;
+ }
+ else
+ {
+ const int* sm = src[-ksize+1];
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = sum[i] + sp[i], s1 = sum[i+1] + sp[i+1];
+ int t0 = CV_DESCALE(s0*iscale, BLUR_SHIFT), t1 = CV_DESCALE(s1*iscale, BLUR_SHIFT);
+ s0 -= sm[i]; s1 -= sm[i+1];
+ sum[i] = s0; sum[i+1] = s1;
+ dst[i] = (uchar)t0; dst[i+1] = (uchar)t1;
+ }
+
+ for( ; i < width; i++ )
+ {
+ int s0 = sum[i] + sp[i], t0 = CV_DESCALE(s0*iscale, BLUR_SHIFT);
+ sum[i] = s0 - sm[i]; dst[i] = (uchar)t0;
+ }
+ dst += dst_step;
+ }
+ }
+
+ *_sum_count = sum_count;
+#undef BLUR_SHIFT
+}
+
+
+static void
+icvSumCol_32s16s( const int** src, short* dst,
+ int dst_step, int count, void* params )
+{
+ CvBoxFilter* state = (CvBoxFilter*)params;
+ int ksize = state->get_kernel_size().height;
+ int ktotal = ksize*state->get_kernel_size().width;
+ int i, width = state->get_width();
+ int cn = CV_MAT_CN(state->get_src_type());
+ int* sum = (int*)state->get_sum_buf();
+ int* _sum_count = state->get_sum_count_ptr();
+ int sum_count = *_sum_count;
+
+ dst_step /= sizeof(dst[0]);
+ width *= cn;
+ src += sum_count;
+ count += ksize - 1 - sum_count;
+
+ for( ; count--; src++ )
+ {
+ const int* sp = src[0];
+ if( sum_count+1 < ksize )
+ {
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = sum[i] + sp[i], s1 = sum[i+1] + sp[i+1];
+ sum[i] = s0; sum[i+1] = s1;
+ }
+
+ for( ; i < width; i++ )
+ sum[i] += sp[i];
+
+ sum_count++;
+ }
+ else if( ktotal < 128 )
+ {
+ const int* sm = src[-ksize+1];
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = sum[i] + sp[i], s1 = sum[i+1] + sp[i+1];
+ dst[i] = (short)s0; dst[i+1] = (short)s1;
+ s0 -= sm[i]; s1 -= sm[i+1];
+ sum[i] = s0; sum[i+1] = s1;
+ }
+
+ for( ; i < width; i++ )
+ {
+ int s0 = sum[i] + sp[i];
+ dst[i] = (short)s0;
+ sum[i] = s0 - sm[i];
+ }
+ dst += dst_step;
+ }
+ else
+ {
+ const int* sm = src[-ksize+1];
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = sum[i] + sp[i], s1 = sum[i+1] + sp[i+1];
+ dst[i] = CV_CAST_16S(s0); dst[i+1] = CV_CAST_16S(s1);
+ s0 -= sm[i]; s1 -= sm[i+1];
+ sum[i] = s0; sum[i+1] = s1;
+ }
+
+ for( ; i < width; i++ )
+ {
+ int s0 = sum[i] + sp[i];
+ dst[i] = CV_CAST_16S(s0);
+ sum[i] = s0 - sm[i];
+ }
+ dst += dst_step;
+ }
+ }
+
+ *_sum_count = sum_count;
+}
+
+static void
+icvSumCol_32s32s( const int** src, int * dst,
+ int dst_step, int count, void* params )
+{
+ CvBoxFilter* state = (CvBoxFilter*)params;
+ int ksize = state->get_kernel_size().height;
+ int i, width = state->get_width();
+ int cn = CV_MAT_CN(state->get_src_type());
+ int* sum = (int*)state->get_sum_buf();
+ int* _sum_count = state->get_sum_count_ptr();
+ int sum_count = *_sum_count;
+
+ dst_step /= sizeof(dst[0]);
+ width *= cn;
+ src += sum_count;
+ count += ksize - 1 - sum_count;
+
+ for( ; count--; src++ )
+ {
+ const int* sp = src[0];
+ if( sum_count+1 < ksize )
+ {
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = sum[i] + sp[i], s1 = sum[i+1] + sp[i+1];
+ sum[i] = s0; sum[i+1] = s1;
+ }
+
+ for( ; i < width; i++ )
+ sum[i] += sp[i];
+
+ sum_count++;
+ }
+ else
+ {
+ const int* sm = src[-ksize+1];
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ int s0 = sum[i] + sp[i], s1 = sum[i+1] + sp[i+1];
+ dst[i] = s0; dst[i+1] = s1;
+ s0 -= sm[i]; s1 -= sm[i+1];
+ sum[i] = s0; sum[i+1] = s1;
+ }
+
+ for( ; i < width; i++ )
+ {
+ int s0 = sum[i] + sp[i];
+ dst[i] = s0;
+ sum[i] = s0 - sm[i];
+ }
+ dst += dst_step;
+ }
+ }
+
+ *_sum_count = sum_count;
+}
+
+
+static void
+icvSumCol_64f32f( const double** src, float* dst,
+ int dst_step, int count, void* params )
+{
+ CvBoxFilter* state = (CvBoxFilter*)params;
+ int ksize = state->get_kernel_size().height;
+ int i, width = state->get_width();
+ int cn = CV_MAT_CN(state->get_src_type());
+ double scale = state->get_scale();
+ bool normalized = state->is_normalized();
+ double* sum = (double*)state->get_sum_buf();
+ int* _sum_count = state->get_sum_count_ptr();
+ int sum_count = *_sum_count;
+
+ dst_step /= sizeof(dst[0]);
+ width *= cn;
+ src += sum_count;
+ count += ksize - 1 - sum_count;
+
+ for( ; count--; src++ )
+ {
+ const double* sp = src[0];
+ if( sum_count+1 < ksize )
+ {
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ double s0 = sum[i] + sp[i], s1 = sum[i+1] + sp[i+1];
+ sum[i] = s0; sum[i+1] = s1;
+ }
+
+ for( ; i < width; i++ )
+ sum[i] += sp[i];
+
+ sum_count++;
+ }
+ else
+ {
+ const double* sm = src[-ksize+1];
+ if( normalized )
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ double s0 = sum[i] + sp[i], s1 = sum[i+1] + sp[i+1];
+ double t0 = s0*scale, t1 = s1*scale;
+ s0 -= sm[i]; s1 -= sm[i+1];
+ dst[i] = (float)t0; dst[i+1] = (float)t1;
+ sum[i] = s0; sum[i+1] = s1;
+ }
+ else
+ for( i = 0; i <= width - 2; i += 2 )
+ {
+ double s0 = sum[i] + sp[i], s1 = sum[i+1] + sp[i+1];
+ dst[i] = (float)s0; dst[i+1] = (float)s1;
+ s0 -= sm[i]; s1 -= sm[i+1];
+ sum[i] = s0; sum[i+1] = s1;
+ }
+
+ for( ; i < width; i++ )
+ {
+ double s0 = sum[i] + sp[i], t0 = s0*scale;
+ sum[i] = s0 - sm[i]; dst[i] = (float)t0;
+ }
+ dst += dst_step;
+ }
+ }
+
+ *_sum_count = sum_count;
+}
+
+
+/****************************************************************************************\
+ Median Filter
+\****************************************************************************************/
+
+#define CV_MINMAX_8U(a,b) \
+ (t = CV_FAST_CAST_8U((a) - (b)), (b) += t, a -= t)
+
+#if CV_SSE2 && !defined __SSE2__
+#define __SSE2__ 1
+#include "emmintrin.h"
+#endif
+
+#if defined(__VEC__) || defined(__ALTIVEC__)
+#include <altivec.h>
+#undef bool
+#endif
+
+#if defined(__GNUC__)
+#define align(x) __attribute__ ((aligned (x)))
+#elif CV_SSE2 && (defined(__ICL) || (_MSC_VER >= 1300))
+#define align(x) __declspec(align(x))
+#else
+#define align(x)
+#endif
+
+#if _MSC_VER >= 1200
+#pragma warning( disable: 4244 )
+#endif
+
+/**
+ * This structure represents a two-tier histogram. The first tier (known as the
+ * "coarse" level) is 4 bit wide and the second tier (known as the "fine" level)
+ * is 8 bit wide. Pixels inserted in the fine level also get inserted into the
+ * coarse bucket designated by the 4 MSBs of the fine bucket value.
+ *
+ * The structure is aligned on 16 bits, which is a prerequisite for SIMD
+ * instructions. Each bucket is 16 bit wide, which means that extra care must be
+ * taken to prevent overflow.
+ */
+typedef struct align(16)
+{
+ ushort coarse[16];
+ ushort fine[16][16];
+} Histogram;
+
+/**
+ * HOP is short for Histogram OPeration. This macro makes an operation \a op on
+ * histogram \a h for pixel value \a x. It takes care of handling both levels.
+ */
+#define HOP(h,x,op) \
+ h.coarse[x>>4] op; \
+ *((ushort*) h.fine + x) op;
+
+#define COP(c,j,x,op) \
+ h_coarse[ 16*(n*c+j) + (x>>4) ] op; \
+ h_fine[ 16 * (n*(16*c+(x>>4)) + j) + (x & 0xF) ] op;
+
+#if defined __SSE2__ || defined __MMX__ || defined __ALTIVEC__
+#define MEDIAN_HAVE_SIMD 1
+#else
+#define MEDIAN_HAVE_SIMD 0
+#endif
+
+/**
+ * Adds histograms \a x and \a y and stores the result in \a y. Makes use of
+ * SSE2, MMX or Altivec, if available.
+ */
+#if defined(__SSE2__)
+static inline void histogram_add( const ushort x[16], ushort y[16] )
+{
+ _mm_store_si128( (__m128i*) &y[0], _mm_add_epi16(
+ _mm_load_si128((__m128i*) &y[0]), _mm_load_si128((__m128i*) &x[0] )));
+ _mm_store_si128( (__m128i*) &y[8], _mm_add_epi16(
+ _mm_load_si128((__m128i*) &y[8]), _mm_load_si128((__m128i*) &x[8] )));
+}
+#elif defined(__MMX__)
+static inline void histogram_add( const ushort x[16], ushort y[16] )
+{
+ *(__m64*) &y[0] = _mm_add_pi16( *(__m64*) &y[0], *(__m64*) &x[0] );
+ *(__m64*) &y[4] = _mm_add_pi16( *(__m64*) &y[4], *(__m64*) &x[4] );
+ *(__m64*) &y[8] = _mm_add_pi16( *(__m64*) &y[8], *(__m64*) &x[8] );
+ *(__m64*) &y[12] = _mm_add_pi16( *(__m64*) &y[12], *(__m64*) &x[12] );
+}
+#elif defined(__ALTIVEC__)
+static inline void histogram_add( const ushort x[16], ushort y[16] )
+{
+ *(vector ushort*) &y[0] = vec_add( *(vector ushort*) &y[0], *(vector ushort*) &x[0] );
+ *(vector ushort*) &y[8] = vec_add( *(vector ushort*) &y[8], *(vector ushort*) &x[8] );
+}
+#else
+static inline void histogram_add( const ushort x[16], ushort y[16] )
+{
+ int i;
+ for( i = 0; i < 16; ++i )
+ y[i] = (ushort)(y[i] + x[i]);
+}
+#endif
+
+/**
+ * Subtracts histogram \a x from \a y and stores the result in \a y. Makes use
+ * of SSE2, MMX or Altivec, if available.
+ */
+#if defined(__SSE2__)
+static inline void histogram_sub( const ushort x[16], ushort y[16] )
+{
+ _mm_store_si128( (__m128i*) &y[0], _mm_sub_epi16(
+ _mm_load_si128((__m128i*) &y[0]), _mm_load_si128((__m128i*) &x[0] )));
+ _mm_store_si128( (__m128i*) &y[8], _mm_sub_epi16(
+ _mm_load_si128((__m128i*) &y[8]), _mm_load_si128((__m128i*) &x[8] )));
+}
+#elif defined(__MMX__)
+static inline void histogram_sub( const ushort x[16], ushort y[16] )
+{
+ *(__m64*) &y[0] = _mm_sub_pi16( *(__m64*) &y[0], *(__m64*) &x[0] );
+ *(__m64*) &y[4] = _mm_sub_pi16( *(__m64*) &y[4], *(__m64*) &x[4] );
+ *(__m64*) &y[8] = _mm_sub_pi16( *(__m64*) &y[8], *(__m64*) &x[8] );
+ *(__m64*) &y[12] = _mm_sub_pi16( *(__m64*) &y[12], *(__m64*) &x[12] );
+}
+#elif defined(__ALTIVEC__)
+static inline void histogram_sub( const ushort x[16], ushort y[16] )
+{
+ *(vector ushort*) &y[0] = vec_sub( *(vector ushort*) &y[0], *(vector ushort*) &x[0] );
+ *(vector ushort*) &y[8] = vec_sub( *(vector ushort*) &y[8], *(vector ushort*) &x[8] );
+}
+#else
+static inline void histogram_sub( const ushort x[16], ushort y[16] )
+{
+ int i;
+ for( i = 0; i < 16; ++i )
+ y[i] = (ushort)(y[i] - x[i]);
+}
+#endif
+
+static inline void histogram_muladd( int a, const ushort x[16],
+ ushort y[16] )
+{
+ int i;
+ for ( i = 0; i < 16; ++i )
+ y[i] = (ushort)(y[i] + a * x[i]);
+}
+
+static CvStatus CV_STDCALL
+icvMedianBlur_8u_CnR_O1( uchar* src, int src_step, uchar* dst, int dst_step,
+ CvSize size, int kernel_size, int cn, int pad_left, int pad_right )
+{
+ int r = (kernel_size-1)/2;
+ const int m = size.height, n = size.width;
+ int i, j, k, c;
+ const unsigned char *p, *q;
+ Histogram H[4];
+ ushort *h_coarse, *h_fine, luc[4][16];
+
+ if( size.height < r || size.width < r )
+ return CV_BADSIZE_ERR;
+
+ assert( src );
+ assert( dst );
+ assert( r >= 0 );
+ assert( size.width >= 2*r+1 );
+ assert( size.height >= 2*r+1 );
+ assert( src_step != 0 );
+ assert( dst_step != 0 );
+
+ h_coarse = (ushort*) cvAlloc( 1 * 16 * n * cn * sizeof(ushort) );
+ h_fine = (ushort*) cvAlloc( 16 * 16 * n * cn * sizeof(ushort) );
+ memset( h_coarse, 0, 1 * 16 * n * cn * sizeof(ushort) );
+ memset( h_fine, 0, 16 * 16 * n * cn * sizeof(ushort) );
+
+ /* First row initialization */
+ for ( j = 0; j < n; ++j ) {
+ for ( c = 0; c < cn; ++c ) {
+ COP( c, j, src[cn*j+c], += r+1 );
+ }
+ }
+ for ( i = 0; i < r; ++i ) {
+ for ( j = 0; j < n; ++j ) {
+ for ( c = 0; c < cn; ++c ) {
+ COP( c, j, src[src_step*i+cn*j+c], ++ );
+ }
+ }
+ }
+
+ for ( i = 0; i < m; ++i ) {
+
+ /* Update column histograms for entire row. */
+ p = src + src_step * MAX( 0, i-r-1 );
+ q = p + cn * n;
+ for ( j = 0; p != q; ++j ) {
+ for ( c = 0; c < cn; ++c, ++p ) {
+ COP( c, j, *p, -- );
+ }
+ }
+
+ p = src + src_step * MIN( m-1, i+r );
+ q = p + cn * n;
+ for ( j = 0; p != q; ++j ) {
+ for ( c = 0; c < cn; ++c, ++p ) {
+ COP( c, j, *p, ++ );
+ }
+ }
+
+ /* First column initialization */
+ memset( H, 0, cn*sizeof(H[0]) );
+ memset( luc, 0, cn*sizeof(luc[0]) );
+ if ( pad_left ) {
+ for ( c = 0; c < cn; ++c ) {
+ histogram_muladd( r, &h_coarse[16*n*c], H[c].coarse );
+ }
+ }
+ for ( j = 0; j < (pad_left ? r : 2*r); ++j ) {
+ for ( c = 0; c < cn; ++c ) {
+ histogram_add( &h_coarse[16*(n*c+j)], H[c].coarse );
+ }
+ }
+ for ( c = 0; c < cn; ++c ) {
+ for ( k = 0; k < 16; ++k ) {
+ histogram_muladd( 2*r+1, &h_fine[16*n*(16*c+k)], &H[c].fine[k][0] );
+ }
+ }
+
+ for ( j = pad_left ? 0 : r; j < (pad_right ? n : n-r); ++j ) {
+ for ( c = 0; c < cn; ++c ) {
+ int t = 2*r*r + 2*r, b, sum = 0;
+ ushort* segment;
+
+ histogram_add( &h_coarse[16*(n*c + MIN(j+r,n-1))], H[c].coarse );
+
+ /* Find median at coarse level */
+ for ( k = 0; k < 16 ; ++k ) {
+ sum += H[c].coarse[k];
+ if ( sum > t ) {
+ sum -= H[c].coarse[k];
+ break;
+ }
+ }
+ assert( k < 16 );
+
+ /* Update corresponding histogram segment */
+ if ( luc[c][k] <= j-r ) {
+ memset( &H[c].fine[k], 0, 16 * sizeof(ushort) );
+ for ( luc[c][k] = j-r; luc[c][k] < MIN(j+r+1,n); ++luc[c][k] ) {
+ histogram_add( &h_fine[16*(n*(16*c+k)+luc[c][k])], H[c].fine[k] );
+ }
+ if ( luc[c][k] < j+r+1 ) {
+ histogram_muladd( j+r+1 - n, &h_fine[16*(n*(16*c+k)+(n-1))], &H[c].fine[k][0] );
+ luc[c][k] = (ushort)(j+r+1);
+ }
+ }
+ else {
+ for ( ; luc[c][k] < j+r+1; ++luc[c][k] ) {
+ histogram_sub( &h_fine[16*(n*(16*c+k)+MAX(luc[c][k]-2*r-1,0))], H[c].fine[k] );
+ histogram_add( &h_fine[16*(n*(16*c+k)+MIN(luc[c][k],n-1))], H[c].fine[k] );
+ }
+ }
+
+ histogram_sub( &h_coarse[16*(n*c+MAX(j-r,0))], H[c].coarse );
+
+ /* Find median in segment */
+ segment = H[c].fine[k];
+ for ( b = 0; b < 16 ; ++b ) {
+ sum += segment[b];
+ if ( sum > t ) {
+ dst[dst_step*i+cn*j+c] = (uchar)(16*k + b);
+ break;
+ }
+ }
+ assert( b < 16 );
+ }
+ }
+ }
+
+#if defined(__MMX__)
+ _mm_empty();
+#endif
+
+ cvFree(&h_coarse);
+ cvFree(&h_fine);
+
+#undef HOP
+#undef COP
+ return CV_OK;
+}
+
+
+#if _MSC_VER >= 1200
+#pragma warning( default: 4244 )
+#endif
+
+
+static CvStatus CV_STDCALL
+icvMedianBlur_8u_CnR_Om( uchar* src, int src_step, uchar* dst, int dst_step,
+ CvSize size, int m, int cn )
+{
+ #define N 16
+ int zone0[4][N];
+ int zone1[4][N*N];
+ int x, y;
+ int n2 = m*m/2;
+ int nx = (m + 1)/2 - 1;
+ uchar* src_max = src + size.height*src_step;
+ uchar* src_right = src + size.width*cn;
+
+ #define UPDATE_ACC01( pix, cn, op ) \
+ { \
+ int p = (pix); \
+ zone1[cn][p] op; \
+ zone0[cn][p >> 4] op; \
+ }
+
+ if( size.height < nx || size.width < nx )
+ return CV_BADSIZE_ERR;
+
+ if( m == 3 )
+ {
+ size.width *= cn;
+
+ for( y = 0; y < size.height; y++, dst += dst_step )
+ {
+ const uchar* src0 = src + src_step*(y-1);
+ const uchar* src1 = src0 + src_step;
+ const uchar* src2 = src1 + src_step;
+ if( y == 0 )
+ src0 = src1;
+ else if( y == size.height - 1 )
+ src2 = src1;
+
+ for( x = 0; x < 2*cn; x++ )
+ {
+ int x0 = x < cn ? x : size.width - 3*cn + x;
+ int x2 = x < cn ? x + cn : size.width - 2*cn + x;
+ int x1 = x < cn ? x0 : x2, t;
+
+ int p0 = src0[x0], p1 = src0[x1], p2 = src0[x2];
+ int p3 = src1[x0], p4 = src1[x1], p5 = src1[x2];
+ int p6 = src2[x0], p7 = src2[x1], p8 = src2[x2];
+
+ CV_MINMAX_8U(p1, p2); CV_MINMAX_8U(p4, p5);
+ CV_MINMAX_8U(p7, p8); CV_MINMAX_8U(p0, p1);
+ CV_MINMAX_8U(p3, p4); CV_MINMAX_8U(p6, p7);
+ CV_MINMAX_8U(p1, p2); CV_MINMAX_8U(p4, p5);
+ CV_MINMAX_8U(p7, p8); CV_MINMAX_8U(p0, p3);
+ CV_MINMAX_8U(p5, p8); CV_MINMAX_8U(p4, p7);
+ CV_MINMAX_8U(p3, p6); CV_MINMAX_8U(p1, p4);
+ CV_MINMAX_8U(p2, p5); CV_MINMAX_8U(p4, p7);
+ CV_MINMAX_8U(p4, p2); CV_MINMAX_8U(p6, p4);
+ CV_MINMAX_8U(p4, p2);
+ dst[x1] = (uchar)p4;
+ }
+
+ for( x = cn; x < size.width - cn; x++ )
+ {
+ int p0 = src0[x-cn], p1 = src0[x], p2 = src0[x+cn];
+ int p3 = src1[x-cn], p4 = src1[x], p5 = src1[x+cn];
+ int p6 = src2[x-cn], p7 = src2[x], p8 = src2[x+cn];
+ int t;
+
+ CV_MINMAX_8U(p1, p2); CV_MINMAX_8U(p4, p5);
+ CV_MINMAX_8U(p7, p8); CV_MINMAX_8U(p0, p1);
+ CV_MINMAX_8U(p3, p4); CV_MINMAX_8U(p6, p7);
+ CV_MINMAX_8U(p1, p2); CV_MINMAX_8U(p4, p5);
+ CV_MINMAX_8U(p7, p8); CV_MINMAX_8U(p0, p3);
+ CV_MINMAX_8U(p5, p8); CV_MINMAX_8U(p4, p7);
+ CV_MINMAX_8U(p3, p6); CV_MINMAX_8U(p1, p4);
+ CV_MINMAX_8U(p2, p5); CV_MINMAX_8U(p4, p7);
+ CV_MINMAX_8U(p4, p2); CV_MINMAX_8U(p6, p4);
+ CV_MINMAX_8U(p4, p2);
+
+ dst[x] = (uchar)p4;
+ }
+ }
+
+ return CV_OK;
+ }
+
+ for( x = 0; x < size.width; x++, dst += cn )
+ {
+ uchar* dst_cur = dst;
+ uchar* src_top = src;
+ uchar* src_bottom = src;
+ int k, c;
+ int x0 = -1;
+ int src_step1 = src_step, dst_step1 = dst_step;
+
+ if( x % 2 != 0 )
+ {
+ src_bottom = src_top += src_step*(size.height-1);
+ dst_cur += dst_step*(size.height-1);
+ src_step1 = -src_step1;
+ dst_step1 = -dst_step1;
+ }
+
+ if( x <= m/2 )
+ nx++;
+
+ if( nx < m )
+ x0 = x < m/2 ? 0 : (nx-1)*cn;
+
+ // init accumulator
+ memset( zone0, 0, sizeof(zone0[0])*cn );
+ memset( zone1, 0, sizeof(zone1[0])*cn );
+
+ for( y = 0; y <= m/2; y++ )
+ {
+ for( c = 0; c < cn; c++ )
+ {
+ if( y > 0 )
+ {
+ if( x0 >= 0 )
+ UPDATE_ACC01( src_bottom[x0+c], c, += (m - nx) );
+ for( k = 0; k < nx*cn; k += cn )
+ UPDATE_ACC01( src_bottom[k+c], c, ++ );
+ }
+ else
+ {
+ if( x0 >= 0 )
+ UPDATE_ACC01( src_bottom[x0+c], c, += (m - nx)*(m/2+1) );
+ for( k = 0; k < nx*cn; k += cn )
+ UPDATE_ACC01( src_bottom[k+c], c, += m/2+1 );
+ }
+ }
+
+ if( (src_step1 > 0 && y < size.height-1) ||
+ (src_step1 < 0 && size.height-y-1 > 0) )
+ src_bottom += src_step1;
+ }
+
+ for( y = 0; y < size.height; y++, dst_cur += dst_step1 )
+ {
+ // find median
+ for( c = 0; c < cn; c++ )
+ {
+ int s = 0;
+ for( k = 0; ; k++ )
+ {
+ int t = s + zone0[c][k];
+ if( t > n2 ) break;
+ s = t;
+ }
+
+ for( k *= N; ;k++ )
+ {
+ s += zone1[c][k];
+ if( s > n2 ) break;
+ }
+
+ dst_cur[c] = (uchar)k;
+ }
+
+ if( y+1 == size.height )
+ break;
+
+ if( cn == 1 )
+ {
+ for( k = 0; k < nx; k++ )
+ {
+ int p = src_top[k];
+ int q = src_bottom[k];
+ zone1[0][p]--;
+ zone0[0][p>>4]--;
+ zone1[0][q]++;
+ zone0[0][q>>4]++;
+ }
+ }
+ else if( cn == 3 )
+ {
+ for( k = 0; k < nx*3; k += 3 )
+ {
+ UPDATE_ACC01( src_top[k], 0, -- );
+ UPDATE_ACC01( src_top[k+1], 1, -- );
+ UPDATE_ACC01( src_top[k+2], 2, -- );
+
+ UPDATE_ACC01( src_bottom[k], 0, ++ );
+ UPDATE_ACC01( src_bottom[k+1], 1, ++ );
+ UPDATE_ACC01( src_bottom[k+2], 2, ++ );
+ }
+ }
+ else
+ {
+ assert( cn == 4 );
+ for( k = 0; k < nx*4; k += 4 )
+ {
+ UPDATE_ACC01( src_top[k], 0, -- );
+ UPDATE_ACC01( src_top[k+1], 1, -- );
+ UPDATE_ACC01( src_top[k+2], 2, -- );
+ UPDATE_ACC01( src_top[k+3], 3, -- );
+
+ UPDATE_ACC01( src_bottom[k], 0, ++ );
+ UPDATE_ACC01( src_bottom[k+1], 1, ++ );
+ UPDATE_ACC01( src_bottom[k+2], 2, ++ );
+ UPDATE_ACC01( src_bottom[k+3], 3, ++ );
+ }
+ }
+
+ if( x0 >= 0 )
+ {
+ for( c = 0; c < cn; c++ )
+ {
+ UPDATE_ACC01( src_top[x0+c], c, -= (m - nx) );
+ UPDATE_ACC01( src_bottom[x0+c], c, += (m - nx) );
+ }
+ }
+
+ if( (src_step1 > 0 && src_bottom + src_step1 < src_max) ||
+ (src_step1 < 0 && src_bottom + src_step1 >= src) )
+ src_bottom += src_step1;
+
+ if( y >= m/2 )
+ src_top += src_step1;
+ }
+
+ if( x >= m/2 )
+ src += cn;
+ if( src + nx*cn > src_right ) nx--;
+ }
+#undef N
+#undef UPDATE_ACC
+ return CV_OK;
+}
+
+
+/****************************************************************************************\
+ Bilateral Filtering
+\****************************************************************************************/
+
+static void
+icvBilateralFiltering_8u( const CvMat* src, CvMat* dst, int d,
+ double sigma_color, double sigma_space )
+{
+ CvMat* temp = 0;
+ float* color_weight = 0;
+ float* space_weight = 0;
+ int* space_ofs = 0;
+
+ CV_FUNCNAME( "icvBilateralFiltering_8u" );
+
+ __BEGIN__;
+
+ double gauss_color_coeff = -0.5/(sigma_color*sigma_color);
+ double gauss_space_coeff = -0.5/(sigma_space*sigma_space);
+ int cn = CV_MAT_CN(src->type);
+ int i, j, k, maxk, radius;
+ CvSize size = cvGetMatSize(src);
+
+ if( (CV_MAT_TYPE(src->type) != CV_8UC1 &&
+ CV_MAT_TYPE(src->type) != CV_8UC3) ||
+ !CV_ARE_TYPES_EQ(src, dst) )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Both source and destination must be 8-bit, single-channel or 3-channel images" );
+
+ if( sigma_color <= 0 )
+ sigma_color = 1;
+ if( sigma_space <= 0 )
+ sigma_space = 1;
+
+ if( d == 0 )
+ radius = cvRound(sigma_space*1.5);
+ else
+ radius = d/2;
+ radius = MAX(radius, 1);
+ d = radius*2 + 1;
+
+ CV_CALL( temp = cvCreateMat( src->rows + radius*2,
+ src->cols + radius*2, src->type ));
+ CV_CALL( cvCopyMakeBorder( src, temp, cvPoint(radius,radius), IPL_BORDER_REPLICATE ));
+ CV_CALL( color_weight = (float*)cvAlloc(cn*256*sizeof(color_weight[0])));
+ CV_CALL( space_weight = (float*)cvAlloc(d*d*sizeof(space_weight[0])));
+ CV_CALL( space_ofs = (int*)cvAlloc(d*d*sizeof(space_ofs[0])));
+
+ // initialize color-related bilateral filter coefficients
+ for( i = 0; i < 256*cn; i++ )
+ color_weight[i] = (float)exp(i*i*gauss_color_coeff);
+
+ // initialize space-related bilateral filter coefficients
+ for( i = -radius, maxk = 0; i <= radius; i++ )
+ for( j = -radius; j <= radius; j++ )
+ {
+ double r = sqrt((double)i*i + (double)j*j);
+ if( r > radius )
+ continue;
+ space_weight[maxk] = (float)exp(r*r*gauss_space_coeff);
+ space_ofs[maxk++] = i*temp->step + j*cn;
+ }
+
+ for( i = 0; i < size.height; i++ )
+ {
+ const uchar* sptr = temp->data.ptr + (i+radius)*temp->step + radius*cn;
+ uchar* dptr = dst->data.ptr + i*dst->step;
+
+ if( cn == 1 )
+ {
+ for( j = 0; j < size.width; j++ )
+ {
+ float sum = 0, wsum = 0;
+ int val0 = sptr[j];
+ for( k = 0; k < maxk; k++ )
+ {
+ int val = sptr[j + space_ofs[k]];
+ float w = space_weight[k]*color_weight[abs(val - val0)];
+ sum += val*w;
+ wsum += w;
+ }
+ // overflow is not possible here => there is no need to use CV_CAST_8U
+ dptr[j] = (uchar)cvRound(sum/wsum);
+ }
+ }
+ else
+ {
+ assert( cn == 3 );
+ for( j = 0; j < size.width*3; j += 3 )
+ {
+ float sum_b = 0, sum_g = 0, sum_r = 0, wsum = 0;
+ int b0 = sptr[j], g0 = sptr[j+1], r0 = sptr[j+2];
+ for( k = 0; k < maxk; k++ )
+ {
+ const uchar* sptr_k = sptr + j + space_ofs[k];
+ int b = sptr_k[0], g = sptr_k[1], r = sptr_k[2];
+ float w = space_weight[k]*color_weight[abs(b - b0) +
+ abs(g - g0) + abs(r - r0)];
+ sum_b += b*w; sum_g += g*w; sum_r += r*w;
+ wsum += w;
+ }
+ wsum = 1.f/wsum;
+ b0 = cvRound(sum_b*wsum);
+ g0 = cvRound(sum_g*wsum);
+ r0 = cvRound(sum_r*wsum);
+ dptr[j] = (uchar)b0; dptr[j+1] = (uchar)g0; dptr[j+2] = (uchar)r0;
+ }
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &temp );
+ cvFree( &color_weight );
+ cvFree( &space_weight );
+ cvFree( &space_ofs );
+}
+
+
+static void icvBilateralFiltering_32f( const CvMat* src, CvMat* dst, int d,
+ double sigma_color, double sigma_space )
+{
+ CvMat* temp = 0;
+ float* space_weight = 0;
+ int* space_ofs = 0;
+ float *expLUT = 0;
+
+ CV_FUNCNAME( "icvBilateralFiltering_32f" );
+
+ __BEGIN__;
+
+ double gauss_color_coeff = -0.5/(sigma_color*sigma_color);
+ double gauss_space_coeff = -0.5/(sigma_space*sigma_space);
+ int cn = CV_MAT_CN(src->type);
+ int i, j, k, maxk, radius;
+ double minValSrc=-1, maxValSrc=1;
+ const int kExpNumBinsPerChannel = 1 << 12;
+ int kExpNumBins = 0;
+ float lastExpVal = 1.f;
+ int temp_step;
+ float len, scale_index;
+ CvMat src_reshaped;
+
+ CvSize size = cvGetMatSize(src);
+
+ if( (CV_MAT_TYPE(src->type) != CV_32FC1 &&
+ CV_MAT_TYPE(src->type) != CV_32FC3) ||
+ !CV_ARE_TYPES_EQ(src, dst) )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Both source and destination must be 32-bit float, single-channel or 3-channel images" );
+
+ if( sigma_color <= 0 )
+ sigma_color = 1;
+ if( sigma_space <= 0 )
+ sigma_space = 1;
+
+ if( d == 0 )
+ radius = cvRound(sigma_space*1.5);
+ else
+ radius = d/2;
+ radius = MAX(radius, 1);
+ d = radius*2 + 1;
+ // compute the min/max range for the input image (even if multichannel)
+
+ CV_CALL( cvReshape( src, &src_reshaped, 1 ) );
+ CV_CALL( cvMinMaxLoc(&src_reshaped, &minValSrc, &maxValSrc) );
+
+ // temporary copy of the image with borders for easy processing
+ CV_CALL( temp = cvCreateMat( src->rows + radius*2,
+ src->cols + radius*2, src->type ));
+ temp_step = temp->step/sizeof(float);
+ CV_CALL( cvCopyMakeBorder( src, temp, cvPoint(radius,radius), IPL_BORDER_REPLICATE ));
+ // allocate lookup tables
+ CV_CALL( space_weight = (float*)cvAlloc(d*d*sizeof(space_weight[0])));
+ CV_CALL( space_ofs = (int*)cvAlloc(d*d*sizeof(space_ofs[0])));
+
+ // assign a length which is slightly more than needed
+ len = (float)(maxValSrc - minValSrc) * cn;
+ kExpNumBins = kExpNumBinsPerChannel * cn;
+ CV_CALL( expLUT = (float*)cvAlloc((kExpNumBins+2) * sizeof(expLUT[0])));
+ scale_index = kExpNumBins/len;
+
+ // initialize the exp LUT
+ for( i = 0; i < kExpNumBins+2; i++ )
+ {
+ if( lastExpVal > 0.f )
+ {
+ double val = i / scale_index;
+ expLUT[i] = (float)exp(val * val * gauss_color_coeff);
+ lastExpVal = expLUT[i];
+ }
+ else
+ expLUT[i] = 0.f;
+ }
+
+ // initialize space-related bilateral filter coefficients
+ for( i = -radius, maxk = 0; i <= radius; i++ )
+ for( j = -radius; j <= radius; j++ )
+ {
+ double r = sqrt((double)i*i + (double)j*j);
+ if( r > radius )
+ continue;
+ space_weight[maxk] = (float)exp(r*r*gauss_space_coeff);
+ space_ofs[maxk++] = i*temp_step + j*cn;
+ }
+
+ for( i = 0; i < size.height; i++ )
+ {
+ const float* sptr = temp->data.fl + (i+radius)*temp_step + radius*cn;
+ float* dptr = (float*)(dst->data.ptr + i*dst->step);
+
+ if( cn == 1 )
+ {
+ for( j = 0; j < size.width; j++ )
+ {
+ float sum = 0, wsum = 0;
+ float val0 = sptr[j];
+ for( k = 0; k < maxk; k++ )
+ {
+ float val = sptr[j + space_ofs[k]];
+ float alpha = (float)(fabs(val - val0)*scale_index);
+ int idx = cvFloor(alpha);
+ alpha -= idx;
+ float w = space_weight[k]*(expLUT[idx] + alpha*(expLUT[idx+1] - expLUT[idx]));
+ sum += val*w;
+ wsum += w;
+ }
+ dptr[j] = (float)(sum/wsum);
+ }
+ }
+ else
+ {
+ assert( cn == 3 );
+ for( j = 0; j < size.width*3; j += 3 )
+ {
+ float sum_b = 0, sum_g = 0, sum_r = 0, wsum = 0;
+ float b0 = sptr[j], g0 = sptr[j+1], r0 = sptr[j+2];
+ for( k = 0; k < maxk; k++ )
+ {
+ const float* sptr_k = sptr + j + space_ofs[k];
+ float b = sptr_k[0], g = sptr_k[1], r = sptr_k[2];
+ float alpha = (float)((fabs(b - b0) + fabs(g - g0) + fabs(r - r0))*scale_index);
+ int idx = cvFloor(alpha);
+ alpha -= idx;
+ float w = space_weight[k]*(expLUT[idx] + alpha*(expLUT[idx+1] - expLUT[idx]));
+ sum_b += b*w; sum_g += g*w; sum_r += r*w;
+ wsum += w;
+ }
+ wsum = 1.f/wsum;
+ b0 = sum_b*wsum;
+ g0 = sum_g*wsum;
+ r0 = sum_r*wsum;
+ dptr[j] = b0; dptr[j+1] = g0; dptr[j+2] = r0;
+ }
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &temp );
+ cvFree( &space_weight );
+ cvFree( &space_ofs );
+ cvFree( &expLUT );
+}
+
+//////////////////////////////// IPP smoothing functions /////////////////////////////////
+
+icvFilterMedian_8u_C1R_t icvFilterMedian_8u_C1R_p = 0;
+icvFilterMedian_8u_C3R_t icvFilterMedian_8u_C3R_p = 0;
+icvFilterMedian_8u_C4R_t icvFilterMedian_8u_C4R_p = 0;
+
+icvFilterBox_8u_C1R_t icvFilterBox_8u_C1R_p = 0;
+icvFilterBox_8u_C3R_t icvFilterBox_8u_C3R_p = 0;
+icvFilterBox_8u_C4R_t icvFilterBox_8u_C4R_p = 0;
+icvFilterBox_32f_C1R_t icvFilterBox_32f_C1R_p = 0;
+icvFilterBox_32f_C3R_t icvFilterBox_32f_C3R_p = 0;
+icvFilterBox_32f_C4R_t icvFilterBox_32f_C4R_p = 0;
+
+typedef CvStatus (CV_STDCALL * CvSmoothFixedIPPFunc)
+( const void* src, int srcstep, void* dst, int dststep,
+ CvSize size, CvSize ksize, CvPoint anchor );
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+CV_IMPL void
+cvSmooth( const void* srcarr, void* dstarr, int smooth_type,
+ int param1, int param2, double param3, double param4 )
+{
+ CvBoxFilter box_filter;
+ CvSepFilter gaussian_filter;
+
+ CvMat* temp = 0;
+
+ CV_FUNCNAME( "cvSmooth" );
+
+ __BEGIN__;
+
+ int coi1 = 0, coi2 = 0;
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize size;
+ int src_type, dst_type, depth, cn;
+ double sigma1 = 0, sigma2 = 0;
+ bool have_ipp = icvFilterMedian_8u_C1R_p != 0;
+
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ src_type = CV_MAT_TYPE( src->type );
+ dst_type = CV_MAT_TYPE( dst->type );
+ depth = CV_MAT_DEPTH(src_type);
+ cn = CV_MAT_CN(src_type);
+ size = cvGetMatSize(src);
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( smooth_type != CV_BLUR_NO_SCALE && !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats,
+ "The specified smoothing algorithm requires input and ouput arrays be of the same type" );
+
+ if( smooth_type == CV_BLUR || smooth_type == CV_BLUR_NO_SCALE ||
+ smooth_type == CV_GAUSSIAN || smooth_type == CV_MEDIAN )
+ {
+ // automatic detection of kernel size from sigma
+ if( smooth_type == CV_GAUSSIAN )
+ {
+ sigma1 = param3;
+ sigma2 = param4 ? param4 : param3;
+
+ if( param1 == 0 && sigma1 > 0 )
+ param1 = cvRound(sigma1*(depth == CV_8U ? 3 : 4)*2 + 1)|1;
+ if( param2 == 0 && sigma2 > 0 )
+ param2 = cvRound(sigma2*(depth == CV_8U ? 3 : 4)*2 + 1)|1;
+ }
+
+ if( param2 == 0 )
+ param2 = size.height == 1 ? 1 : param1;
+ if( param1 < 1 || (param1 & 1) == 0 || param2 < 1 || (param2 & 1) == 0 )
+ CV_ERROR( CV_StsOutOfRange,
+ "Both mask width and height must be >=1 and odd" );
+
+ if( param1 == 1 && param2 == 1 )
+ {
+ cvConvert( src, dst );
+ EXIT;
+ }
+ }
+
+ if( have_ipp && (smooth_type == CV_BLUR || (smooth_type == CV_MEDIAN && param1 <= 15)) &&
+ size.width >= param1 && size.height >= param2 && param1 > 1 && param2 > 1 )
+ {
+ CvSmoothFixedIPPFunc ipp_median_box_func = 0;
+
+ if( smooth_type == CV_BLUR )
+ {
+ ipp_median_box_func =
+ src_type == CV_8UC1 ? icvFilterBox_8u_C1R_p :
+ src_type == CV_8UC3 ? icvFilterBox_8u_C3R_p :
+ src_type == CV_8UC4 ? icvFilterBox_8u_C4R_p :
+ src_type == CV_32FC1 ? icvFilterBox_32f_C1R_p :
+ src_type == CV_32FC3 ? icvFilterBox_32f_C3R_p :
+ src_type == CV_32FC4 ? icvFilterBox_32f_C4R_p : 0;
+ }
+ else if( smooth_type == CV_MEDIAN )
+ {
+ ipp_median_box_func =
+ src_type == CV_8UC1 ? icvFilterMedian_8u_C1R_p :
+ src_type == CV_8UC3 ? icvFilterMedian_8u_C3R_p :
+ src_type == CV_8UC4 ? icvFilterMedian_8u_C4R_p : 0;
+ }
+
+ if( ipp_median_box_func )
+ {
+ CvSize el_size = { param1, param2 };
+ CvPoint el_anchor = { param1/2, param2/2 };
+ int stripe_size = 1 << 14; // the optimal value may depend on CPU cache,
+ // overhead of the current IPP code etc.
+ const uchar* shifted_ptr;
+ int y, dy = 0;
+ int temp_step, dst_step = dst->step;
+
+ CV_CALL( temp = icvIPPFilterInit( src, stripe_size, el_size ));
+
+ shifted_ptr = temp->data.ptr +
+ el_anchor.y*temp->step + el_anchor.x*CV_ELEM_SIZE(src_type);
+ temp_step = temp->step ? temp->step : CV_STUB_STEP;
+
+ for( y = 0; y < src->rows; y += dy )
+ {
+ dy = icvIPPFilterNextStripe( src, temp, y, el_size, el_anchor );
+ IPPI_CALL( ipp_median_box_func( shifted_ptr, temp_step,
+ dst->data.ptr + y*dst_step, dst_step, cvSize(src->cols, dy),
+ el_size, el_anchor ));
+ }
+ EXIT;
+ }
+ }
+
+ if( smooth_type == CV_BLUR || smooth_type == CV_BLUR_NO_SCALE )
+ {
+ CV_CALL( box_filter.init( src->cols, src_type, dst_type,
+ smooth_type == CV_BLUR, cvSize(param1, param2) ));
+ CV_CALL( box_filter.process( src, dst ));
+ }
+ else if( smooth_type == CV_MEDIAN )
+ {
+ int img_size_mp = size.width*size.height;
+ img_size_mp = (img_size_mp + (1<<19)) >> 20;
+
+ if( depth != CV_8U || (cn != 1 && cn != 3 && cn != 4) )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Median filter only supports 8uC1, 8uC3 and 8uC4 images" );
+
+ if( size.width < param1*2 || size.height < param1*2 ||
+ param1 <= 3 + (img_size_mp < 1 ? 12 : img_size_mp < 4 ? 6 : 2)*(MEDIAN_HAVE_SIMD ? 1 : 3))
+ {
+ // Special case optimized for 3x3
+ IPPI_CALL( icvMedianBlur_8u_CnR_Om( src->data.ptr, src->step,
+ dst->data.ptr, dst->step, size, param1, cn ));
+ }
+ else
+ {
+ const int r = (param1 - 1) / 2;
+ const int CACHE_SIZE = (int) ( 0.95 * 256 * 1024 / cn ); // assume a 256 kB cache size
+ const int STRIPES = (int) cvCeil( (double) (size.width - 2*r) /
+ (CACHE_SIZE / sizeof(Histogram) - 2*r) );
+ const int STRIPE_SIZE = (int) cvCeil(
+ (double) ( size.width + STRIPES*2*r - 2*r ) / STRIPES );
+
+ for( int i = 0; i < size.width; i += STRIPE_SIZE - 2*r )
+ {
+ int stripe = STRIPE_SIZE;
+ // Make sure that the filter kernel fits into one stripe.
+ if( i + STRIPE_SIZE - 2*r >= size.width ||
+ size.width - (i + STRIPE_SIZE - 2*r) < 2*r+1 )
+ stripe = size.width - i;
+
+ IPPI_CALL( icvMedianBlur_8u_CnR_O1( src->data.ptr + cn*i, src->step,
+ dst->data.ptr + cn*i, dst->step, cvSize(stripe, size.height),
+ param1, cn, i == 0, stripe == size.width - i ));
+
+ if( stripe == size.width - i )
+ break;
+ }
+ }
+ }
+ else if( smooth_type == CV_GAUSSIAN )
+ {
+ CvSize ksize = { param1, param2 };
+ float* kx = (float*)cvStackAlloc( ksize.width*sizeof(kx[0]) );
+ float* ky = (float*)cvStackAlloc( ksize.height*sizeof(ky[0]) );
+ CvMat KX = cvMat( 1, ksize.width, CV_32F, kx );
+ CvMat KY = cvMat( 1, ksize.height, CV_32F, ky );
+
+ CvSepFilter::init_gaussian_kernel( &KX, sigma1 );
+ if( ksize.width != ksize.height || fabs(sigma1 - sigma2) > FLT_EPSILON )
+ CvSepFilter::init_gaussian_kernel( &KY, sigma2 );
+ else
+ KY.data.fl = kx;
+
+ if( have_ipp && size.width >= param1*3 &&
+ size.height >= param2 && param1 > 1 && param2 > 1 )
+ {
+ int done;
+ CV_CALL( done = icvIPPSepFilter( src, dst, &KX, &KY,
+ cvPoint(ksize.width/2,ksize.height/2)));
+ if( done )
+ EXIT;
+ }
+
+ CV_CALL( gaussian_filter.init( src->cols, src_type, dst_type, &KX, &KY ));
+ CV_CALL( gaussian_filter.process( src, dst ));
+ }
+ else if( smooth_type == CV_BILATERAL )
+ {
+ if( param2 != 0 && (param2 != param1 || param1 % 2 == 0) )
+ CV_ERROR( CV_StsBadSize, "Bilateral filter only supports square windows of odd size" );
+
+ switch( src_type )
+ {
+ case CV_32FC1:
+ case CV_32FC3:
+ CV_CALL( icvBilateralFiltering_32f( src, dst, param1, param3, param4 ));
+ break;
+ case CV_8UC1:
+ case CV_8UC3:
+ CV_CALL( icvBilateralFiltering_8u( src, dst, param1, param3, param4 ));
+ break;
+ default:
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Unknown/unsupported format: bilateral filter only supports 8uC1, 8uC3, 32fC1 and 32fC3 formats" );
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &temp );
+}
+
+/* End of file. */
diff --git a/cv/src/cvsnakes.cpp b/cv/src/cvsnakes.cpp
new file mode 100644
index 0000000..734e90a
--- /dev/null
+++ b/cv/src/cvsnakes.cpp
@@ -0,0 +1,438 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+#define _CV_SNAKE_BIG 2.e+38f
+#define _CV_SNAKE_IMAGE 1
+#define _CV_SNAKE_GRAD 2
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvSnake8uC1R
+// Purpose:
+// Context:
+// Parameters:
+// src - source image,
+// srcStep - its step in bytes,
+// roi - size of ROI,
+// pt - pointer to snake points array
+// n - size of points array,
+// alpha - pointer to coefficient of continuity energy,
+// beta - pointer to coefficient of curvature energy,
+// gamma - pointer to coefficient of image energy,
+// coeffUsage - if CV_VALUE - alpha, beta, gamma point to single value
+// if CV_MATAY - point to arrays
+// criteria - termination criteria.
+// scheme - image energy scheme
+// if _CV_SNAKE_IMAGE - image intensity is energy
+// if _CV_SNAKE_GRAD - magnitude of gradient is energy
+// Returns:
+//F*/
+
+static CvStatus
+icvSnake8uC1R( unsigned char *src,
+ int srcStep,
+ CvSize roi,
+ CvPoint * pt,
+ int n,
+ float *alpha,
+ float *beta,
+ float *gamma,
+ int coeffUsage, CvSize win, CvTermCriteria criteria, int scheme )
+{
+ int i, j, k;
+ int neighbors = win.height * win.width;
+
+ int centerx = win.width >> 1;
+ int centery = win.height >> 1;
+
+ float invn;
+ int iteration = 0;
+ int converged = 0;
+
+
+ float *Econt;
+ float *Ecurv;
+ float *Eimg;
+ float *E;
+
+ float _alpha, _beta, _gamma;
+
+ /*#ifdef GRAD_SNAKE */
+ float *gradient = NULL;
+ uchar *map = NULL;
+ int map_width = ((roi.width - 1) >> 3) + 1;
+ int map_height = ((roi.height - 1) >> 3) + 1;
+ CvSepFilter pX, pY;
+ #define WTILE_SIZE 8
+ #define TILE_SIZE (WTILE_SIZE + 2)
+ short dx[TILE_SIZE*TILE_SIZE], dy[TILE_SIZE*TILE_SIZE];
+ CvMat _dx = cvMat( TILE_SIZE, TILE_SIZE, CV_16SC1, dx );
+ CvMat _dy = cvMat( TILE_SIZE, TILE_SIZE, CV_16SC1, dy );
+ CvMat _src = cvMat( roi.height, roi.width, CV_8UC1, src );
+
+ /* inner buffer of convolution process */
+ //char ConvBuffer[400];
+
+ /*#endif */
+
+
+ /* check bad arguments */
+ if( src == NULL )
+ return CV_NULLPTR_ERR;
+ if( (roi.height <= 0) || (roi.width <= 0) )
+ return CV_BADSIZE_ERR;
+ if( srcStep < roi.width )
+ return CV_BADSIZE_ERR;
+ if( pt == NULL )
+ return CV_NULLPTR_ERR;
+ if( n < 3 )
+ return CV_BADSIZE_ERR;
+ if( alpha == NULL )
+ return CV_NULLPTR_ERR;
+ if( beta == NULL )
+ return CV_NULLPTR_ERR;
+ if( gamma == NULL )
+ return CV_NULLPTR_ERR;
+ if( coeffUsage != CV_VALUE && coeffUsage != CV_ARRAY )
+ return CV_BADFLAG_ERR;
+ if( (win.height <= 0) || (!(win.height & 1)))
+ return CV_BADSIZE_ERR;
+ if( (win.width <= 0) || (!(win.width & 1)))
+ return CV_BADSIZE_ERR;
+
+ invn = 1 / ((float) n);
+
+ if( scheme == _CV_SNAKE_GRAD )
+ {
+ pX.init_deriv( TILE_SIZE+2, CV_8UC1, CV_16SC1, 1, 0, 3 );
+ pY.init_deriv( TILE_SIZE+2, CV_8UC1, CV_16SC1, 0, 1, 3 );
+
+ gradient = (float *) cvAlloc( roi.height * roi.width * sizeof( float ));
+
+ if( !gradient )
+ return CV_OUTOFMEM_ERR;
+ map = (uchar *) cvAlloc( map_width * map_height );
+ if( !map )
+ {
+ cvFree( &gradient );
+ return CV_OUTOFMEM_ERR;
+ }
+ /* clear map - no gradient computed */
+ memset( (void *) map, 0, map_width * map_height );
+ }
+ Econt = (float *) cvAlloc( neighbors * sizeof( float ));
+ Ecurv = (float *) cvAlloc( neighbors * sizeof( float ));
+ Eimg = (float *) cvAlloc( neighbors * sizeof( float ));
+ E = (float *) cvAlloc( neighbors * sizeof( float ));
+
+ while( !converged )
+ {
+ float ave_d = 0;
+ int moved = 0;
+
+ converged = 0;
+ iteration++;
+ /* compute average distance */
+ for( i = 1; i < n; i++ )
+ {
+ int diffx = pt[i - 1].x - pt[i].x;
+ int diffy = pt[i - 1].y - pt[i].y;
+
+ ave_d += cvSqrt( (float) (diffx * diffx + diffy * diffy) );
+ }
+ ave_d += cvSqrt( (float) ((pt[0].x - pt[n - 1].x) *
+ (pt[0].x - pt[n - 1].x) +
+ (pt[0].y - pt[n - 1].y) * (pt[0].y - pt[n - 1].y)));
+
+ ave_d *= invn;
+ /* average distance computed */
+ for( i = 0; i < n; i++ )
+ {
+ /* Calculate Econt */
+ float maxEcont = 0;
+ float maxEcurv = 0;
+ float maxEimg = 0;
+ float minEcont = _CV_SNAKE_BIG;
+ float minEcurv = _CV_SNAKE_BIG;
+ float minEimg = _CV_SNAKE_BIG;
+ float Emin = _CV_SNAKE_BIG;
+
+ int offsetx = 0;
+ int offsety = 0;
+ float tmp;
+
+ /* compute bounds */
+ int left = MIN( pt[i].x, win.width >> 1 );
+ int right = MIN( roi.width - 1 - pt[i].x, win.width >> 1 );
+ int upper = MIN( pt[i].y, win.height >> 1 );
+ int bottom = MIN( roi.height - 1 - pt[i].y, win.height >> 1 );
+
+ maxEcont = 0;
+ minEcont = _CV_SNAKE_BIG;
+ for( j = -upper; j <= bottom; j++ )
+ {
+ for( k = -left; k <= right; k++ )
+ {
+ int diffx, diffy;
+ float energy;
+
+ if( i == 0 )
+ {
+ diffx = pt[n - 1].x - (pt[i].x + k);
+ diffy = pt[n - 1].y - (pt[i].y + j);
+ }
+ else
+ {
+ diffx = pt[i - 1].x - (pt[i].x + k);
+ diffy = pt[i - 1].y - (pt[i].y + j);
+ }
+ Econt[(j + centery) * win.width + k + centerx] = energy =
+ (float) fabs( ave_d -
+ cvSqrt( (float) (diffx * diffx + diffy * diffy) ));
+
+ maxEcont = MAX( maxEcont, energy );
+ minEcont = MIN( minEcont, energy );
+ }
+ }
+ tmp = maxEcont - minEcont;
+ tmp = (tmp == 0) ? 0 : (1 / tmp);
+ for( k = 0; k < neighbors; k++ )
+ {
+ Econt[k] = (Econt[k] - minEcont) * tmp;
+ }
+
+ /* Calculate Ecurv */
+ maxEcurv = 0;
+ minEcurv = _CV_SNAKE_BIG;
+ for( j = -upper; j <= bottom; j++ )
+ {
+ for( k = -left; k <= right; k++ )
+ {
+ int tx, ty;
+ float energy;
+
+ if( i == 0 )
+ {
+ tx = pt[n - 1].x - 2 * (pt[i].x + k) + pt[i + 1].x;
+ ty = pt[n - 1].y - 2 * (pt[i].y + j) + pt[i + 1].y;
+ }
+ else if( i == n - 1 )
+ {
+ tx = pt[i - 1].x - 2 * (pt[i].x + k) + pt[0].x;
+ ty = pt[i - 1].y - 2 * (pt[i].y + j) + pt[0].y;
+ }
+ else
+ {
+ tx = pt[i - 1].x - 2 * (pt[i].x + k) + pt[i + 1].x;
+ ty = pt[i - 1].y - 2 * (pt[i].y + j) + pt[i + 1].y;
+ }
+ Ecurv[(j + centery) * win.width + k + centerx] = energy =
+ (float) (tx * tx + ty * ty);
+ maxEcurv = MAX( maxEcurv, energy );
+ minEcurv = MIN( minEcurv, energy );
+ }
+ }
+ tmp = maxEcurv - minEcurv;
+ tmp = (tmp == 0) ? 0 : (1 / tmp);
+ for( k = 0; k < neighbors; k++ )
+ {
+ Ecurv[k] = (Ecurv[k] - minEcurv) * tmp;
+ }
+
+ /* Calculate Eimg */
+ for( j = -upper; j <= bottom; j++ )
+ {
+ for( k = -left; k <= right; k++ )
+ {
+ float energy;
+
+ if( scheme == _CV_SNAKE_GRAD )
+ {
+ /* look at map and check status */
+ int x = (pt[i].x + k)/WTILE_SIZE;
+ int y = (pt[i].y + j)/WTILE_SIZE;
+
+ if( map[y * map_width + x] == 0 )
+ {
+ int l, m;
+
+ /* evaluate block location */
+ int upshift = y ? 1 : 0;
+ int leftshift = x ? 1 : 0;
+ int bottomshift = MIN( 1, roi.height - (y + 1)*WTILE_SIZE );
+ int rightshift = MIN( 1, roi.width - (x + 1)*WTILE_SIZE );
+ CvRect g_roi = { x*WTILE_SIZE - leftshift, y*WTILE_SIZE - upshift,
+ leftshift + WTILE_SIZE + rightshift, upshift + WTILE_SIZE + bottomshift };
+ CvMat _src1;
+ cvGetSubArr( &_src, &_src1, g_roi );
+
+ pX.process( &_src1, &_dx );
+ pY.process( &_src1, &_dy );
+
+ for( l = 0; l < WTILE_SIZE + bottomshift; l++ )
+ {
+ for( m = 0; m < WTILE_SIZE + rightshift; m++ )
+ {
+ gradient[(y*WTILE_SIZE + l) * roi.width + x*WTILE_SIZE + m] =
+ (float) (dx[(l + upshift) * TILE_SIZE + m + leftshift] *
+ dx[(l + upshift) * TILE_SIZE + m + leftshift] +
+ dy[(l + upshift) * TILE_SIZE + m + leftshift] *
+ dy[(l + upshift) * TILE_SIZE + m + leftshift]);
+ }
+ }
+ map[y * map_width + x] = 1;
+ }
+ Eimg[(j + centery) * win.width + k + centerx] = energy =
+ gradient[(pt[i].y + j) * roi.width + pt[i].x + k];
+ }
+ else
+ {
+ Eimg[(j + centery) * win.width + k + centerx] = energy =
+ src[(pt[i].y + j) * srcStep + pt[i].x + k];
+ }
+
+ maxEimg = MAX( maxEimg, energy );
+ minEimg = MIN( minEimg, energy );
+ }
+ }
+
+ tmp = (maxEimg - minEimg);
+ tmp = (tmp == 0) ? 0 : (1 / tmp);
+
+ for( k = 0; k < neighbors; k++ )
+ {
+ Eimg[k] = (minEimg - Eimg[k]) * tmp;
+ }
+
+ /* locate coefficients */
+ if( coeffUsage == CV_VALUE)
+ {
+ _alpha = *alpha;
+ _beta = *beta;
+ _gamma = *gamma;
+ }
+ else
+ {
+ _alpha = alpha[i];
+ _beta = beta[i];
+ _gamma = gamma[i];
+ }
+
+ /* Find Minimize point in the neighbors */
+ for( k = 0; k < neighbors; k++ )
+ {
+ E[k] = _alpha * Econt[k] + _beta * Ecurv[k] + _gamma * Eimg[k];
+ }
+ Emin = _CV_SNAKE_BIG;
+ for( j = -upper; j <= bottom; j++ )
+ {
+ for( k = -left; k <= right; k++ )
+ {
+
+ if( E[(j + centery) * win.width + k + centerx] < Emin )
+ {
+ Emin = E[(j + centery) * win.width + k + centerx];
+ offsetx = k;
+ offsety = j;
+ }
+ }
+ }
+
+ if( offsetx || offsety )
+ {
+ pt[i].x += offsetx;
+ pt[i].y += offsety;
+ moved++;
+ }
+ }
+ converged = (moved == 0);
+ if( (criteria.type & CV_TERMCRIT_ITER) && (iteration >= criteria.max_iter) )
+ converged = 1;
+ if( (criteria.type & CV_TERMCRIT_EPS) && (moved <= criteria.epsilon) )
+ converged = 1;
+ }
+
+ cvFree( &Econt );
+ cvFree( &Ecurv );
+ cvFree( &Eimg );
+ cvFree( &E );
+
+ if( scheme == _CV_SNAKE_GRAD )
+ {
+ cvFree( &gradient );
+ cvFree( &map );
+ }
+ return CV_OK;
+}
+
+
+CV_IMPL void
+cvSnakeImage( const IplImage* src, CvPoint* points,
+ int length, float *alpha,
+ float *beta, float *gamma,
+ int coeffUsage, CvSize win,
+ CvTermCriteria criteria, int calcGradient )
+{
+
+ CV_FUNCNAME( "cvSnakeImage" );
+
+ __BEGIN__;
+
+ uchar *data;
+ CvSize size;
+ int step;
+
+ if( src->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, "input image has more than one channel" );
+
+ if( src->depth != IPL_DEPTH_8U )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+
+ cvGetRawData( src, &data, &step, &size );
+
+ IPPI_CALL( icvSnake8uC1R( data, step, size, points, length,
+ alpha, beta, gamma, coeffUsage, win, criteria,
+ calcGradient ? _CV_SNAKE_GRAD : _CV_SNAKE_IMAGE ));
+ __END__;
+}
+
+/* end of file */
diff --git a/cv/src/cvstereobm.cpp b/cv/src/cvstereobm.cpp
new file mode 100644
index 0000000..3e9f731
--- /dev/null
+++ b/cv/src/cvstereobm.cpp
@@ -0,0 +1,681 @@
+//M*//////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/****************************************************************************************\
+* Very fast SAD-based (Sum-of-Absolute-Diffrences) stereo correspondence algorithm. *
+* Contributed by Kurt Konolige *
+\****************************************************************************************/
+
+#include "_cv.h"
+/*
+#undef CV_SSE2
+#define CV_SSE2 1
+#include "emmintrin.h"
+*/
+
+CV_IMPL CvStereoBMState*
+cvCreateStereoBMState( int /*preset*/, int numberOfDisparities )
+{
+ CvStereoBMState* state = 0;
+
+ //CV_FUNCNAME( "cvCreateStereoBMState" );
+
+ __BEGIN__;
+
+ state = (CvStereoBMState*)cvAlloc( sizeof(*state) );
+ if( !state )
+ EXIT;
+
+ state->preFilterType = CV_STEREO_BM_NORMALIZED_RESPONSE;
+ state->preFilterSize = 9;
+ state->preFilterCap = 31;
+ state->SADWindowSize = 15;
+ state->minDisparity = 0;
+ state->numberOfDisparities = numberOfDisparities > 0 ? numberOfDisparities : 64;
+ state->textureThreshold = 10;
+ state->uniquenessRatio = 15;
+ state->speckleRange = state->speckleWindowSize = 0;
+
+ state->preFilteredImg0 = state->preFilteredImg1 = state->slidingSumBuf = 0;
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvReleaseStereoBMState( &state );
+ return state;
+}
+
+
+CV_IMPL void
+cvReleaseStereoBMState( CvStereoBMState** state )
+{
+ CV_FUNCNAME( "cvReleaseStereoBMState" );
+
+ __BEGIN__;
+
+ if( !state )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !*state )
+ EXIT;
+
+ cvReleaseMat( &(*state)->preFilteredImg0 );
+ cvReleaseMat( &(*state)->preFilteredImg1 );
+ cvReleaseMat( &(*state)->slidingSumBuf );
+ cvFree( state );
+
+ __END__;
+}
+
+static void icvPrefilter( const CvMat* src, CvMat* dst, int winsize, int ftzero, uchar* buf )
+{
+ int x, y, wsz2 = winsize/2;
+ int* vsum = (int*)cvAlignPtr(buf + (wsz2 + 1)*sizeof(vsum[0]), 32);
+ int scale_g = winsize*winsize/8, scale_s = (1024 + scale_g)/(scale_g*2);
+ const int OFS = 256*5, TABSZ = OFS*2 + 256;
+ uchar tab[TABSZ];
+ const uchar* sptr = src->data.ptr;
+ int srcstep = src->step;
+ CvSize size = cvGetMatSize(src);
+
+ scale_g *= scale_s;
+
+ for( x = 0; x < TABSZ; x++ )
+ tab[x] = (uchar)(x - OFS < -ftzero ? 0 : x - OFS > ftzero ? ftzero*2 : x - OFS + ftzero);
+
+ for( x = 0; x < size.width; x++ )
+ vsum[x] = (ushort)(sptr[x]*(wsz2 + 2));
+
+ for( y = 1; y < wsz2; y++ )
+ {
+ for( x = 0; x < size.width; x++ )
+ vsum[x] = (ushort)(vsum[x] + sptr[srcstep*y + x]);
+ }
+
+ for( y = 0; y < size.height; y++ )
+ {
+ const uchar* top = sptr + srcstep*MAX(y-wsz2-1,0);
+ const uchar* bottom = sptr + srcstep*MIN(y+wsz2,size.height-1);
+ const uchar* prev = sptr + srcstep*MAX(y-1,0);
+ const uchar* curr = sptr + srcstep*y;
+ const uchar* next = sptr + srcstep*MIN(y+1,size.height-1);
+ uchar* dptr = dst->data.ptr + dst->step*y;
+ x = 0;
+
+ for( ; x < size.width; x++ )
+ vsum[x] = (ushort)(vsum[x] + bottom[x] - top[x]);
+
+ for( x = 0; x <= wsz2; x++ )
+ {
+ vsum[-x-1] = vsum[0];
+ vsum[size.width+x] = vsum[size.width-1];
+ }
+
+ int sum = vsum[0]*(wsz2 + 1);
+ for( x = 1; x <= wsz2; x++ )
+ sum += vsum[x];
+
+ int val = ((curr[0]*5 + curr[1] + prev[0] + next[0])*scale_g - sum*scale_s) >> 10;
+ dptr[0] = tab[val + OFS];
+
+ for( x = 1; x < size.width-1; x++ )
+ {
+ sum += vsum[x+wsz2] - vsum[x-wsz2-1];
+ val = ((curr[x]*4 + curr[x-1] + curr[x+1] + prev[x] + next[x])*scale_g - sum*scale_s) >> 10;
+ dptr[x] = tab[val + OFS];
+ }
+
+ sum += vsum[x+wsz2] - vsum[x-wsz2-1];
+ val = ((curr[x]*5 + curr[x-1] + prev[x] + next[x])*scale_g - sum*scale_s) >> 10;
+ dptr[x] = tab[val + OFS];
+ }
+}
+
+
+static const int DISPARITY_SHIFT = 4;
+
+#if CV_SSE2
+static void
+icvFindStereoCorrespondenceBM_SSE2( const CvMat* left, const CvMat* right,
+ CvMat* disp, CvStereoBMState* state,
+ uchar* buf, int _dy0, int _dy1 )
+{
+ int x, y, d;
+ int wsz = state->SADWindowSize, wsz2 = wsz/2;
+ int dy0 = MIN(_dy0, wsz2+1), dy1 = MIN(_dy1, wsz2+1);
+ int ndisp = state->numberOfDisparities;
+ int mindisp = state->minDisparity;
+ int lofs = MAX(ndisp - 1 + mindisp, 0);
+ int rofs = -MIN(ndisp - 1 + mindisp, 0);
+ int width = left->cols, height = left->rows;
+ int width1 = width - rofs - ndisp + 1;
+ int ftzero = state->preFilterCap;
+ int textureThreshold = state->textureThreshold;
+ int uniquenessRatio = state->uniquenessRatio;
+ short FILTERED = (short)((mindisp - 1) << DISPARITY_SHIFT);
+
+ ushort *sad, *hsad0, *hsad, *hsad_sub;
+ int *htext;
+ uchar *cbuf0, *cbuf;
+ const uchar* lptr0 = left->data.ptr + lofs;
+ const uchar* rptr0 = right->data.ptr + rofs;
+ const uchar *lptr, *lptr_sub, *rptr;
+ short* dptr = disp->data.s;
+ int sstep = left->step;
+ int dstep = disp->step/sizeof(dptr[0]);
+ int cstep = (height + dy0 + dy1)*ndisp;
+ const int TABSZ = 256;
+ uchar tab[TABSZ];
+ const __m128i d0_8 = _mm_setr_epi16(0,1,2,3,4,5,6,7), dd_8 = _mm_set1_epi16(8);
+
+ sad = (ushort*)cvAlignPtr(buf + sizeof(sad[0]));
+ hsad0 = (ushort*)cvAlignPtr(sad + ndisp + 1 + dy0*ndisp);
+ htext = (int*)cvAlignPtr((int*)(hsad0 + (height+dy1)*ndisp) + wsz2 + 2);
+ cbuf0 = (uchar*)cvAlignPtr(htext + height + wsz2 + 2 + dy0*ndisp);
+
+ for( x = 0; x < TABSZ; x++ )
+ tab[x] = (uchar)abs(x - ftzero);
+
+ // initialize buffers
+ memset( hsad0 - dy0*ndisp, 0, (height + dy0 + dy1)*ndisp*sizeof(hsad0[0]) );
+ memset( htext - wsz2 - 1, 0, (height + wsz + 1)*sizeof(htext[0]) );
+
+ for( x = -wsz2-1; x < wsz2; x++ )
+ {
+ hsad = hsad0 - dy0*ndisp; cbuf = cbuf0 + (x + wsz2 + 1)*cstep - dy0*ndisp;
+ lptr = lptr0 + MIN(MAX(x, -lofs), width-lofs-1) - dy0*sstep;
+ rptr = rptr0 + MIN(MAX(x, -rofs), width-rofs-1) - dy0*sstep;
+
+ for( y = -dy0; y < height + dy1; y++, hsad += ndisp, cbuf += ndisp, lptr += sstep, rptr += sstep )
+ {
+ int lval = lptr[0];
+ for( d = 0; d < ndisp; d++ )
+ {
+ int diff = abs(lval - rptr[d]);
+ cbuf[d] = (uchar)diff;
+ hsad[d] = (ushort)(hsad[d] + diff);
+ }
+ htext[y] += tab[lval];
+ }
+ }
+
+ // initialize the left and right borders of the disparity map
+ for( y = 0; y < height; y++ )
+ {
+ for( x = 0; x < lofs; x++ )
+ dptr[y*dstep + x] = FILTERED;
+ for( x = lofs + width1; x < width; x++ )
+ dptr[y*dstep + x] = FILTERED;
+ }
+ dptr += lofs;
+
+ for( x = 0; x < width1; x++, dptr++ )
+ {
+ int x0 = x - wsz2 - 1, x1 = x + wsz2;
+ const uchar* cbuf_sub = cbuf0 + ((x0 + wsz2 + 1) % (wsz + 1))*cstep - dy0*ndisp;
+ uchar* cbuf = cbuf0 + ((x1 + wsz2 + 1) % (wsz + 1))*cstep - dy0*ndisp;
+ hsad = hsad0 - dy0*ndisp;
+ lptr_sub = lptr0 + MIN(MAX(x0, -lofs), width-1-lofs) - dy0*sstep;
+ lptr = lptr0 + MIN(MAX(x1, -lofs), width-1-lofs) - dy0*sstep;
+ rptr = rptr0 + MIN(MAX(x1, -rofs), width-1-rofs) - dy0*sstep;
+
+ for( y = -dy0; y < height + dy1; y++, cbuf += ndisp, cbuf_sub += ndisp,
+ hsad += ndisp, lptr += sstep, lptr_sub += sstep, rptr += sstep )
+ {
+ int lval = lptr[0];
+ __m128i lv = _mm_set1_epi8((char)lval), z = _mm_setzero_si128();
+ for( d = 0; d < ndisp; d += 16 )
+ {
+ __m128i rv = _mm_loadu_si128((const __m128i*)(rptr + d));
+ __m128i hsad_l = _mm_load_si128((__m128i*)(hsad + d));
+ __m128i hsad_h = _mm_load_si128((__m128i*)(hsad + d + 8));
+ __m128i cbs = _mm_load_si128((const __m128i*)(cbuf_sub + d));
+ __m128i diff = _mm_adds_epu8(_mm_subs_epu8(lv, rv), _mm_subs_epu8(rv, lv));
+ __m128i diff_h = _mm_sub_epi16(_mm_unpackhi_epi8(diff, z), _mm_unpackhi_epi8(cbs, z));
+ _mm_store_si128((__m128i*)(cbuf + d), diff);
+ diff = _mm_sub_epi16(_mm_unpacklo_epi8(diff, z), _mm_unpacklo_epi8(cbs, z));
+ hsad_h = _mm_add_epi16(hsad_h, diff_h);
+ hsad_l = _mm_add_epi16(hsad_l, diff);
+ _mm_store_si128((__m128i*)(hsad + d), hsad_l);
+ _mm_store_si128((__m128i*)(hsad + d + 8), hsad_h);
+ }
+ htext[y] += tab[lval] - tab[lptr_sub[0]];
+ }
+
+ // fill borders
+ for( y = dy1; y <= wsz2; y++ )
+ htext[height+y] = htext[height+dy1-1];
+ for( y = -wsz2-1; y < -dy0; y++ )
+ htext[y] = htext[-dy0];
+
+ // initialize sums
+ for( d = 0; d < ndisp; d++ )
+ sad[d] = (ushort)(hsad0[d-ndisp*dy0]*(wsz2 + 2 - dy0));
+
+ hsad = hsad0 + (1 - dy0)*ndisp;
+ for( y = 1 - dy0; y < wsz2; y++, hsad += ndisp )
+ for( d = 0; d < ndisp; d++ )
+ sad[d] = (ushort)(sad[d] + hsad[d]);
+ int tsum = 0;
+ for( y = -wsz2-1; y < wsz2; y++ )
+ tsum += htext[y];
+
+ // finally, start the real processing
+ for( y = 0; y < height; y++ )
+ {
+ int minsad = INT_MAX, mind = -1;
+ hsad = hsad0 + MIN(y + wsz2, height+dy1-1)*ndisp;
+ hsad_sub = hsad0 + MAX(y - wsz2 - 1, -dy0)*ndisp;
+ __m128i minsad8 = _mm_set1_epi16(SHRT_MAX);
+ __m128i mind8 = _mm_set1_epi16(-1), d8 = d0_8, mask;
+
+ for( d = 0; d < ndisp; d += 8 )
+ {
+ __m128i v0 = _mm_load_si128((__m128i*)(hsad_sub + d));
+ __m128i v1 = _mm_load_si128((__m128i*)(hsad + d));
+ __m128i sad8 = _mm_load_si128((__m128i*)(sad + d));
+ sad8 = _mm_sub_epi16(sad8, v0);
+ sad8 = _mm_add_epi16(sad8, v1);
+
+ mask = _mm_cmpgt_epi16(minsad8, sad8);
+ _mm_store_si128((__m128i*)(sad + d), sad8);
+ minsad8 = _mm_min_epi16(minsad8, sad8);
+ mind8 = _mm_xor_si128(mind8,_mm_and_si128(_mm_xor_si128(d8,mind8),mask));
+ d8 = _mm_add_epi16(d8, dd_8);
+ }
+
+ __m128i minsad82 = _mm_unpackhi_epi64(minsad8, minsad8);
+ __m128i mind82 = _mm_unpackhi_epi64(mind8, mind8);
+ mask = _mm_cmpgt_epi16(minsad8, minsad82);
+ mind8 = _mm_xor_si128(mind8,_mm_and_si128(_mm_xor_si128(mind82,mind8),mask));
+ minsad8 = _mm_min_epi16(minsad8, minsad82);
+
+ minsad82 = _mm_shufflelo_epi16(minsad8, _MM_SHUFFLE(3,2,3,2));
+ mind82 = _mm_shufflelo_epi16(mind8, _MM_SHUFFLE(3,2,3,2));
+ mask = _mm_cmpgt_epi16(minsad8, minsad82);
+ mind8 = _mm_xor_si128(mind8,_mm_and_si128(_mm_xor_si128(mind82,mind8),mask));
+ minsad8 = _mm_min_epi16(minsad8, minsad82);
+
+ minsad82 = _mm_shufflelo_epi16(minsad8, 1);
+ mind82 = _mm_shufflelo_epi16(mind8, 1);
+ mask = _mm_cmpgt_epi16(minsad8, minsad82);
+ mind8 = _mm_xor_si128(mind8,_mm_and_si128(_mm_xor_si128(mind82,mind8),mask));
+ mind = (short)_mm_cvtsi128_si32(mind8);
+ minsad = sad[mind];
+ tsum += htext[y + wsz2] - htext[y - wsz2 - 1];
+ if( tsum < textureThreshold )
+ {
+ dptr[y*dstep] = FILTERED;
+ continue;
+ }
+
+ if( uniquenessRatio > 0 )
+ {
+ int thresh = minsad + (minsad * uniquenessRatio/100);
+ __m128i thresh8 = _mm_set1_epi16((short)(thresh + 1));
+ __m128i d1 = _mm_set1_epi16((short)(mind-1)), d2 = _mm_set1_epi16((short)(mind+1));
+ __m128i d8 = d0_8;
+
+ for( d = 0; d < ndisp; d += 8 )
+ {
+ __m128i sad8 = _mm_load_si128((__m128i*)(sad + d));
+ __m128i mask = _mm_cmpgt_epi16( thresh8, sad8 );
+ mask = _mm_and_si128(mask, _mm_or_si128(_mm_cmpgt_epi16(d1,d8), _mm_cmpgt_epi16(d8,d2)));
+ if( _mm_movemask_epi8(mask) )
+ break;
+ d8 = _mm_add_epi16(d8, dd_8);
+ }
+ if( d < ndisp )
+ {
+ dptr[y*dstep] = FILTERED;
+ continue;
+ }
+ }
+
+ {
+ sad[-1] = sad[1];
+ sad[ndisp] = sad[ndisp-2];
+ int p = sad[mind+1], n = sad[mind-1], d = p + n - 2*sad[mind];
+ dptr[y*dstep] = (short)(((ndisp - mind - 1 + mindisp)*256 + (d != 0 ? (p-n)*128/d : 0) + 15) >> 4);
+ }
+ }
+ }
+}
+#endif
+
+static void
+icvFindStereoCorrespondenceBM( const CvMat* left, const CvMat* right,
+ CvMat* disp, CvStereoBMState* state,
+ uchar* buf, int _dy0, int _dy1 )
+{
+ int x, y, d;
+ int wsz = state->SADWindowSize, wsz2 = wsz/2;
+ int dy0 = MIN(_dy0, wsz2+1), dy1 = MIN(_dy1, wsz2+1);
+ int ndisp = state->numberOfDisparities;
+ int mindisp = state->minDisparity;
+ int lofs = MAX(ndisp - 1 + mindisp, 0);
+ int rofs = -MIN(ndisp - 1 + mindisp, 0);
+ int width = left->cols, height = left->rows;
+ int width1 = width - rofs - ndisp + 1;
+ int ftzero = state->preFilterCap;
+ int textureThreshold = state->textureThreshold;
+ int uniquenessRatio = state->uniquenessRatio;
+ short FILTERED = (short)((mindisp - 1) << DISPARITY_SHIFT);
+
+ int *sad, *hsad0, *hsad, *hsad_sub, *htext;
+ uchar *cbuf0, *cbuf;
+ const uchar* lptr0 = left->data.ptr + lofs;
+ const uchar* rptr0 = right->data.ptr + rofs;
+ const uchar *lptr, *lptr_sub, *rptr;
+ short* dptr = disp->data.s;
+ int sstep = left->step;
+ int dstep = disp->step/sizeof(dptr[0]);
+ int cstep = (height+dy0+dy1)*ndisp;
+ const int TABSZ = 256;
+ uchar tab[TABSZ];
+
+ sad = (int*)cvAlignPtr(buf + sizeof(sad[0]));
+ hsad0 = (int*)cvAlignPtr(sad + ndisp + 1 + dy0*ndisp);
+ htext = (int*)cvAlignPtr((int*)(hsad0 + (height+dy1)*ndisp) + wsz2 + 2);
+ cbuf0 = (uchar*)cvAlignPtr(htext + height + wsz2 + 2 + dy0*ndisp);
+
+ for( x = 0; x < TABSZ; x++ )
+ tab[x] = (uchar)abs(x - ftzero);
+
+ // initialize buffers
+ memset( hsad0 - dy0*ndisp, 0, (height + dy0 + dy1)*ndisp*sizeof(hsad0[0]) );
+ memset( htext - wsz2 - 1, 0, (height + wsz + 1)*sizeof(htext[0]) );
+
+ for( x = -wsz2-1; x < wsz2; x++ )
+ {
+ hsad = hsad0 - dy0*ndisp; cbuf = cbuf0 + (x + wsz2 + 1)*cstep - dy0*ndisp;
+ lptr = lptr0 + MIN(MAX(x, -lofs), width-lofs-1) - dy0*sstep;
+ rptr = rptr0 + MIN(MAX(x, -rofs), width-rofs-1) - dy0*sstep;
+
+ for( y = -dy0; y < height + dy1; y++, hsad += ndisp, cbuf += ndisp, lptr += sstep, rptr += sstep )
+ {
+ int lval = lptr[0];
+ for( d = 0; d < ndisp; d++ )
+ {
+ int diff = abs(lval - rptr[d]);
+ cbuf[d] = (uchar)diff;
+ hsad[d] = (int)(hsad[d] + diff);
+ }
+ htext[y] += tab[lval];
+ }
+ }
+
+ // initialize the left and right borders of the disparity map
+ for( y = 0; y < height; y++ )
+ {
+ for( x = 0; x < lofs; x++ )
+ dptr[y*dstep + x] = FILTERED;
+ for( x = lofs + width1; x < width; x++ )
+ dptr[y*dstep + x] = FILTERED;
+ }
+ dptr += lofs;
+
+ for( x = 0; x < width1; x++, dptr++ )
+ {
+ int x0 = x - wsz2 - 1, x1 = x + wsz2;
+ const uchar* cbuf_sub = cbuf0 + ((x0 + wsz2 + 1) % (wsz + 1))*cstep - dy0*ndisp;
+ uchar* cbuf = cbuf0 + ((x1 + wsz2 + 1) % (wsz + 1))*cstep - dy0*ndisp;
+ hsad = hsad0 - dy0*ndisp;
+ lptr_sub = lptr0 + MIN(MAX(x0, -lofs), width-1-lofs) - dy0*sstep;
+ lptr = lptr0 + MIN(MAX(x1, -lofs), width-1-lofs) - dy0*sstep;
+ rptr = rptr0 + MIN(MAX(x1, -rofs), width-1-rofs) - dy0*sstep;
+
+ for( y = -dy0; y < height + dy1; y++, cbuf += ndisp, cbuf_sub += ndisp,
+ hsad += ndisp, lptr += sstep, lptr_sub += sstep, rptr += sstep )
+ {
+ int lval = lptr[0];
+ for( d = 0; d < ndisp; d++ )
+ {
+ int diff = abs(lval - rptr[d]);
+ cbuf[d] = (uchar)diff;
+ hsad[d] = hsad[d] + diff - cbuf_sub[d];
+ }
+ htext[y] += tab[lval] - tab[lptr_sub[0]];
+ }
+
+ // fill borders
+ for( y = dy1; y <= wsz2; y++ )
+ htext[height+y] = htext[height+dy1-1];
+ for( y = -wsz2-1; y < -dy0; y++ )
+ htext[y] = htext[-dy0];
+
+ // initialize sums
+ for( d = 0; d < ndisp; d++ )
+ sad[d] = (int)(hsad0[d-ndisp*dy0]*(wsz2 + 2 - dy0));
+
+ hsad = hsad0 + (1 - dy0)*ndisp;
+ for( y = 1 - dy0; y < wsz2; y++, hsad += ndisp )
+ for( d = 0; d < ndisp; d++ )
+ sad[d] = (int)(sad[d] + hsad[d]);
+ int tsum = 0;
+ for( y = -wsz2-1; y < wsz2; y++ )
+ tsum += htext[y];
+
+ // finally, start the real processing
+ for( y = 0; y < height; y++ )
+ {
+ int minsad = INT_MAX, mind = -1;
+ hsad = hsad0 + MIN(y + wsz2, height+dy1-1)*ndisp;
+ hsad_sub = hsad0 + MAX(y - wsz2 - 1, -dy0)*ndisp;
+
+ for( d = 0; d < ndisp; d++ )
+ {
+ int currsad = sad[d] + hsad[d] - hsad_sub[d];
+ sad[d] = currsad;
+ if( currsad < minsad )
+ {
+ minsad = currsad;
+ mind = d;
+ }
+ }
+ tsum += htext[y + wsz2] - htext[y - wsz2 - 1];
+ if( tsum < textureThreshold )
+ {
+ dptr[y*dstep] = FILTERED;
+ continue;
+ }
+
+ if( uniquenessRatio > 0 )
+ {
+ int thresh = minsad + (minsad * uniquenessRatio/100);
+ for( d = 0; d < ndisp; d++ )
+ {
+ if( sad[d] <= thresh && (d < mind-1 || d > mind+1))
+ break;
+ }
+ if( d < ndisp )
+ {
+ dptr[y*dstep] = FILTERED;
+ continue;
+ }
+ }
+
+ {
+ sad[-1] = sad[1];
+ sad[ndisp] = sad[ndisp-2];
+ int p = sad[mind+1], n = sad[mind-1], d = p + n - 2*sad[mind];
+ dptr[y*dstep] = (short)(((ndisp - mind - 1 + mindisp)*256 + (d != 0 ? (p-n)*128/d : 0) + 15) >> 4);
+ }
+ }
+ }
+}
+
+
+CV_IMPL void
+cvFindStereoCorrespondenceBM( const CvArr* leftarr, const CvArr* rightarr,
+ CvArr* disparr, CvStereoBMState* state )
+{
+ CV_FUNCNAME( "cvFindStereoCorrespondenceBM" );
+
+ __BEGIN__;
+
+ CvMat lstub, *left0 = cvGetMat( leftarr, &lstub );
+ CvMat rstub, *right0 = cvGetMat( rightarr, &rstub );
+ CvMat left, right;
+ CvMat dstub, *disp = cvGetMat( disparr, &dstub );
+ int bufSize0, bufSize1, bufSize, width, width1, height;
+ int wsz, ndisp, mindisp, lofs, rofs;
+ int i, n = cvGetNumThreads();
+
+ if( !CV_ARE_SIZES_EQ(left0, right0) ||
+ !CV_ARE_SIZES_EQ(disp, left0) )
+ CV_ERROR( CV_StsUnmatchedSizes, "All the images must have the same size" );
+
+ if( CV_MAT_TYPE(left0->type) != CV_8UC1 ||
+ !CV_ARE_TYPES_EQ(left0, right0) ||
+ CV_MAT_TYPE(disp->type) != CV_16SC1 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Both input images must have 8uC1 format and the disparity image must have 16sC1 format" );
+
+ if( !state )
+ CV_ERROR( CV_StsNullPtr, "Stereo BM state is NULL." );
+
+ if( state->preFilterType != CV_STEREO_BM_NORMALIZED_RESPONSE )
+ CV_ERROR( CV_StsOutOfRange, "preFilterType must be =CV_STEREO_BM_NORMALIZED_RESPONSE" );
+
+ if( state->preFilterSize < 5 || state->preFilterSize > 255 || state->preFilterSize % 2 == 0 )
+ CV_ERROR( CV_StsOutOfRange, "preFilterSize must be odd and be within 5..255" );
+
+ if( state->preFilterCap < 1 || state->preFilterCap > 63 )
+ CV_ERROR( CV_StsOutOfRange, "preFilterCap must be within 1..63" );
+
+ if( state->SADWindowSize < 5 || state->SADWindowSize > 255 || state->SADWindowSize % 2 == 0 ||
+ state->SADWindowSize >= MIN(left0->cols, left0->rows) )
+ CV_ERROR( CV_StsOutOfRange, "SADWindowSize must be odd, be within 5..255 and "
+ "be not larger than image width or height" );
+
+ if( state->numberOfDisparities <= 0 || state->numberOfDisparities % 16 != 0 )
+ CV_ERROR( CV_StsOutOfRange, "numberOfDisparities must be positive and divisble by 16" );
+ if( state->textureThreshold < 0 )
+ CV_ERROR( CV_StsOutOfRange, "texture threshold must be non-negative" );
+ if( state->uniquenessRatio < 0 )
+ CV_ERROR( CV_StsOutOfRange, "uniqueness ratio must be non-negative" );
+
+ if( !state->preFilteredImg0 ||
+ state->preFilteredImg0->cols*state->preFilteredImg0->rows < left0->cols*left0->rows )
+ {
+ cvReleaseMat( &state->preFilteredImg0 );
+ cvReleaseMat( &state->preFilteredImg1 );
+
+ state->preFilteredImg0 = cvCreateMat( left0->rows, left0->cols, CV_8U );
+ state->preFilteredImg1 = cvCreateMat( left0->rows, left0->cols, CV_8U );
+ }
+ left = cvMat(left0->rows, left0->cols, CV_8U, state->preFilteredImg0->data.ptr);
+ right = cvMat(right0->rows, right0->cols, CV_8U, state->preFilteredImg1->data.ptr);
+
+ mindisp = state->minDisparity;
+ ndisp = state->numberOfDisparities;
+
+ width = left0->cols;
+ height = left0->rows;
+ lofs = MAX(ndisp - 1 + mindisp, 0);
+ rofs = -MIN(ndisp - 1 + mindisp, 0);
+ width1 = width - rofs - ndisp + 1;
+ if( lofs >= width || rofs >= width || width1 < 1 )
+ {
+ int FILTERED = (short)((state->minDisparity - 1) << DISPARITY_SHIFT);
+ cvSet( disp, cvScalarAll(FILTERED) );
+ EXIT;
+ }
+
+ wsz = state->SADWindowSize;
+ bufSize0 = (ndisp + 2)*sizeof(int) + (height+wsz+2)*ndisp*sizeof(int) +
+ (height + wsz + 2)*sizeof(int) + (height+wsz+2)*ndisp*(wsz+1)*sizeof(uchar) + 256;
+ bufSize1 = (width + state->preFilterSize + 2)*sizeof(int) + 256;
+ bufSize = MAX(bufSize0, bufSize1);
+ n = MAX(MIN(height/wsz, n), 1);
+
+ if( !state->slidingSumBuf || state->slidingSumBuf->cols < bufSize*n )
+ {
+ cvReleaseMat( &state->slidingSumBuf );
+ state->slidingSumBuf = cvCreateMat( 1, bufSize*n, CV_8U );
+ }
+
+#ifdef _OPENMP
+#pragma omp parallel sections num_threads(n)
+#endif
+ {
+ #ifdef _OPENMP
+ #pragma omp section
+ #endif
+ icvPrefilter( left0, &left, state->preFilterSize,
+ state->preFilterCap, state->slidingSumBuf->data.ptr );
+ #ifdef _OPENMP
+ #pragma omp section
+ #endif
+ icvPrefilter( right0, &right, state->preFilterSize,
+ state->preFilterCap, state->slidingSumBuf->data.ptr + bufSize1*(n>1) );
+ }
+
+#ifdef _OPENMP
+ #pragma omp parallel for num_threads(n) schedule(static)
+#endif
+ for( i = 0; i < n; i++ )
+ {
+ int thread_id = cvGetThreadNum();
+ CvMat left_i, right_i, disp_i;
+ int row0 = i*left.rows/n, row1 = (i+1)*left.rows/n;
+ cvGetRows( &left, &left_i, row0, row1 );
+ cvGetRows( &right, &right_i, row0, row1 );
+ cvGetRows( disp, &disp_i, row0, row1 );
+ #if CV_SSE2
+ if( state->preFilterCap <= 31 && state->SADWindowSize <= 21 )
+ {
+ icvFindStereoCorrespondenceBM_SSE2( &left_i, &right_i, &disp_i, state,
+ state->slidingSumBuf->data.ptr + thread_id*bufSize0, row0, left.rows-row1 );
+ }
+ else
+ #endif
+ {
+ icvFindStereoCorrespondenceBM( &left_i, &right_i, &disp_i, state,
+ state->slidingSumBuf->data.ptr + thread_id*bufSize0, row0, left.rows-row1 );
+ }
+ }
+
+ __END__;
+}
+
+/* End of file. */
diff --git a/cv/src/cvstereogc.cpp b/cv/src/cvstereogc.cpp
new file mode 100644
index 0000000..0f6f806
--- /dev/null
+++ b/cv/src/cvstereogc.cpp
@@ -0,0 +1,960 @@
+//M*//////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+#undef INFINITY
+#define INFINITY 10000
+#define OCCLUSION_PENALTY 10000
+#define OCCLUSION_PENALTY2 1000
+#define DENOMINATOR 16
+#undef OCCLUDED
+#define OCCLUDED CV_STEREO_GC_OCCLUDED
+#define CUTOFF 1000
+#define IS_BLOCKED(d1, d2) ((d1) > (d2))
+
+typedef struct GCVtx
+{
+ GCVtx *next;
+ int parent;
+ int first;
+ int ts;
+ int dist;
+ short weight;
+ uchar t;
+}
+GCVtx;
+
+typedef struct GCEdge
+{
+ GCVtx* dst;
+ int next;
+ int weight;
+}
+GCEdge;
+
+typedef struct CvStereoGCState2
+{
+ int Ithreshold, interactionRadius;
+ int lambda, lambda1, lambda2, K;
+ int dataCostFuncTab[CUTOFF+1];
+ int smoothnessR[CUTOFF*2+1];
+ int smoothnessGrayDiff[512];
+ GCVtx** orphans;
+ int maxOrphans;
+}
+CvStereoGCState2;
+
+// truncTab[x+255] = MAX(x-255,0)
+static uchar icvTruncTab[512];
+// cutoffSqrTab[x] = MIN(x*x, CUTOFF)
+static int icvCutoffSqrTab[256];
+
+static void icvInitStereoConstTabs()
+{
+ static volatile int initialized = 0;
+ if( !initialized )
+ {
+ int i;
+ for( i = 0; i < 512; i++ )
+ icvTruncTab[i] = (uchar)MIN(MAX(i-255,0),255);
+ for( i = 0; i < 256; i++ )
+ icvCutoffSqrTab[i] = MIN(i*i, CUTOFF);
+ initialized = 1;
+ }
+}
+
+static void icvInitStereoTabs( CvStereoGCState2* state2 )
+{
+ int i, K = state2->K;
+
+ for( i = 0; i <= CUTOFF; i++ )
+ state2->dataCostFuncTab[i] = MIN(i*DENOMINATOR - K, 0);
+
+ for( i = 0; i < CUTOFF*2 + 1; i++ )
+ state2->smoothnessR[i] = MIN(abs(i-CUTOFF), state2->interactionRadius);
+
+ for( i = 0; i < 512; i++ )
+ {
+ int diff = abs(i - 255);
+ state2->smoothnessGrayDiff[i] = diff < state2->Ithreshold ? state2->lambda1 : state2->lambda2;
+ }
+}
+
+
+static int icvGCResizeOrphansBuf( GCVtx**& orphans, int norphans )
+{
+ int i, newNOrphans = MAX(norphans*3/2, 256);
+ GCVtx** newOrphans = (GCVtx**)cvAlloc( newNOrphans*sizeof(orphans[0]) );
+ for( i = 0; i < norphans; i++ )
+ newOrphans[i] = orphans[i];
+ cvFree( &orphans );
+ orphans = newOrphans;
+ return newNOrphans;
+}
+
+static int64 icvGCMaxFlow( GCVtx* vtx, int nvtx, GCEdge* edges, GCVtx**& _orphans, int& _maxOrphans )
+{
+ const int TERMINAL = -1, ORPHAN = -2;
+ GCVtx stub, *nil = &stub, *first = nil, *last = nil;
+ int i, k;
+ int curr_ts = 0;
+ int64 flow = 0;
+ int norphans = 0, maxOrphans = _maxOrphans;
+ GCVtx** orphans = _orphans;
+ stub.next = nil;
+
+ // initialize the active queue and the graph vertices
+ for( i = 0; i < nvtx; i++ )
+ {
+ GCVtx* v = vtx + i;
+ v->ts = 0;
+ if( v->weight != 0 )
+ {
+ last = last->next = v;
+ v->dist = 1;
+ v->parent = TERMINAL;
+ v->t = v->weight < 0;
+ }
+ else
+ v->parent = 0;
+ }
+
+ first = first->next;
+ last->next = nil;
+ nil->next = 0;
+
+ // run the search-path -> augment-graph -> restore-trees loop
+ for(;;)
+ {
+ GCVtx* v, *u;
+ int e0 = -1, ei = 0, ej = 0, min_weight, weight;
+ uchar vt;
+
+ // grow S & T search trees, find an edge connecting them
+ while( first != nil )
+ {
+ v = first;
+ if( v->parent )
+ {
+ vt = v->t;
+ for( ei = v->first; ei != 0; ei = edges[ei].next )
+ {
+ if( edges[ei^vt].weight == 0 )
+ continue;
+ u = edges[ei].dst;
+ if( !u->parent )
+ {
+ u->t = vt;
+ u->parent = ei ^ 1;
+ u->ts = v->ts;
+ u->dist = v->dist + 1;
+ if( !u->next )
+ {
+ u->next = nil;
+ last = last->next = u;
+ }
+ continue;
+ }
+
+ if( u->t != vt )
+ {
+ e0 = ei ^ vt;
+ break;
+ }
+
+ if( u->dist > v->dist+1 && u->ts <= v->ts )
+ {
+ // reassign the parent
+ u->parent = ei ^ 1;
+ u->ts = v->ts;
+ u->dist = v->dist + 1;
+ }
+ }
+ if( e0 > 0 )
+ break;
+ }
+ // exclude the vertex from the active list
+ first = first->next;
+ v->next = 0;
+ }
+
+ if( e0 <= 0 )
+ break;
+
+ // find the minimum edge weight along the path
+ min_weight = edges[e0].weight;
+ assert( min_weight > 0 );
+ // k = 1: source tree, k = 0: destination tree
+ for( k = 1; k >= 0; k-- )
+ {
+ for( v = edges[e0^k].dst;; v = edges[ei].dst )
+ {
+ if( (ei = v->parent) < 0 )
+ break;
+ weight = edges[ei^k].weight;
+ min_weight = MIN(min_weight, weight);
+ assert( min_weight > 0 );
+ }
+ weight = abs(v->weight);
+ min_weight = MIN(min_weight, weight);
+ assert( min_weight > 0 );
+ }
+
+ // modify weights of the edges along the path and collect orphans
+ edges[e0].weight -= min_weight;
+ edges[e0^1].weight += min_weight;
+ flow += min_weight;
+
+ // k = 1: source tree, k = 0: destination tree
+ for( k = 1; k >= 0; k-- )
+ {
+ for( v = edges[e0^k].dst;; v = edges[ei].dst )
+ {
+ if( (ei = v->parent) < 0 )
+ break;
+ edges[ei^(k^1)].weight += min_weight;
+ if( (edges[ei^k].weight -= min_weight) == 0 )
+ {
+ if( norphans >= maxOrphans )
+ maxOrphans = icvGCResizeOrphansBuf( orphans, norphans );
+ orphans[norphans++] = v;
+ v->parent = ORPHAN;
+ }
+ }
+
+ v->weight = (short)(v->weight + min_weight*(1-k*2));
+ if( v->weight == 0 )
+ {
+ if( norphans >= maxOrphans )
+ maxOrphans = icvGCResizeOrphansBuf( orphans, norphans );
+ orphans[norphans++] = v;
+ v->parent = ORPHAN;
+ }
+ }
+
+ // restore the search trees by finding new parents for the orphans
+ curr_ts++;
+ while( norphans > 0 )
+ {
+ GCVtx* v = orphans[--norphans];
+ int d, min_dist = INT_MAX;
+ e0 = 0;
+ vt = v->t;
+
+ for( ei = v->first; ei != 0; ei = edges[ei].next )
+ {
+ if( edges[ei^(vt^1)].weight == 0 )
+ continue;
+ u = edges[ei].dst;
+ if( u->t != vt || u->parent == 0 )
+ continue;
+ // compute the distance to the tree root
+ for( d = 0;; )
+ {
+ if( u->ts == curr_ts )
+ {
+ d += u->dist;
+ break;
+ }
+ ej = u->parent;
+ d++;
+ if( ej < 0 )
+ {
+ if( ej == ORPHAN )
+ d = INT_MAX-1;
+ else
+ {
+ u->ts = curr_ts;
+ u->dist = 1;
+ }
+ break;
+ }
+ u = edges[ej].dst;
+ }
+
+ // update the distance
+ if( ++d < INT_MAX )
+ {
+ if( d < min_dist )
+ {
+ min_dist = d;
+ e0 = ei;
+ }
+ for( u = edges[ei].dst; u->ts != curr_ts; u = edges[u->parent].dst )
+ {
+ u->ts = curr_ts;
+ u->dist = --d;
+ }
+ }
+ }
+
+ if( (v->parent = e0) > 0 )
+ {
+ v->ts = curr_ts;
+ v->dist = min_dist;
+ continue;
+ }
+
+ /* no parent is found */
+ v->ts = 0;
+ for( ei = v->first; ei != 0; ei = edges[ei].next )
+ {
+ u = edges[ei].dst;
+ ej = u->parent;
+ if( u->t != vt || !ej )
+ continue;
+ if( edges[ei^(vt^1)].weight && !u->next )
+ {
+ u->next = nil;
+ last = last->next = u;
+ }
+ if( ej > 0 && edges[ej].dst == v )
+ {
+ if( norphans >= maxOrphans )
+ maxOrphans = icvGCResizeOrphansBuf( orphans, norphans );
+ orphans[norphans++] = u;
+ u->parent = ORPHAN;
+ }
+ }
+ }
+ }
+
+ _orphans = orphans;
+ _maxOrphans = maxOrphans;
+
+ return flow;
+}
+
+
+CvStereoGCState* cvCreateStereoGCState( int numberOfDisparities, int maxIters )
+{
+ CvStereoGCState* state = 0;
+
+ //CV_FUNCNAME("cvCreateStereoGCState");
+
+ __BEGIN__;
+
+ state = (CvStereoGCState*)cvAlloc( sizeof(*state) );
+ memset( state, 0, sizeof(*state) );
+ state->minDisparity = 0;
+ state->numberOfDisparities = numberOfDisparities;
+ state->maxIters = maxIters <= 0 ? 3 : maxIters;
+ state->Ithreshold = 5;
+ state->interactionRadius = 1;
+ state->K = state->lambda = state->lambda1 = state->lambda2 = -1.f;
+ state->occlusionCost = OCCLUSION_PENALTY;
+
+ __END__;
+
+ return state;
+}
+
+void cvReleaseStereoGCState( CvStereoGCState** _state )
+{
+ CvStereoGCState* state;
+
+ if( !_state && !*_state )
+ return;
+
+ state = *_state;
+ cvReleaseMat( &state->left );
+ cvReleaseMat( &state->right );
+ cvReleaseMat( &state->ptrLeft );
+ cvReleaseMat( &state->ptrRight );
+ cvReleaseMat( &state->vtxBuf );
+ cvReleaseMat( &state->edgeBuf );
+ cvFree( _state );
+}
+
+// ||I(x) - J(x')|| =
+// min(CUTOFF,
+// min(
+// max(
+// max(minJ(x') - I(x), 0),
+// max(I(x) - maxJ(x'), 0)),
+// max(
+// max(minI(x) - J(x'), 0),
+// max(J(x') - maxI(x), 0)))**2) ==
+// min(CUTOFF,
+// min(
+// max(minJ(x') - I(x), 0) +
+// max(I(x) - maxJ(x'), 0),
+//
+// max(minI(x) - J(x'), 0) +
+// max(J(x') - maxI(x), 0)))**2)
+// where (I, minI, maxI) and
+// (J, minJ, maxJ) are stored as interleaved 3-channel images.
+// minI, maxI are computed from I,
+// minJ, maxJ are computed from J - see icvInitGraySubPix.
+static inline int icvDataCostFuncGraySubpix( const uchar* a, const uchar* b )
+{
+ int va = a[0], vb = b[0];
+ int da = icvTruncTab[b[1] - va + 255] + icvTruncTab[va - b[2] + 255];
+ int db = icvTruncTab[a[1] - vb + 255] + icvTruncTab[vb - a[2] + 255];
+ return icvCutoffSqrTab[MIN(da,db)];
+}
+
+static inline int icvSmoothnessCostFunc( int da, int db, int maxR, const int* stabR, int scale )
+{
+ return da == db ? 0 : (da == OCCLUDED || db == OCCLUDED ? maxR : stabR[da - db])*scale;
+}
+
+static void icvInitGraySubpix( const CvMat* left, const CvMat* right,
+ CvMat* left3, CvMat* right3 )
+{
+ int k, x, y, rows = left->rows, cols = left->cols;
+
+ for( k = 0; k < 2; k++ )
+ {
+ const CvMat* src = k == 0 ? left : right;
+ CvMat* dst = k == 0 ? left3 : right3;
+ int sstep = src->step;
+
+ for( y = 0; y < rows; y++ )
+ {
+ const uchar* sptr = src->data.ptr + sstep*y;
+ const uchar* sptr_prev = y > 0 ? sptr - sstep : sptr;
+ const uchar* sptr_next = y < rows-1 ? sptr + sstep : sptr;
+ uchar* dptr = dst->data.ptr + dst->step*y;
+ int v_prev = sptr[0];
+
+ for( x = 0; x < cols; x++, dptr += 3 )
+ {
+ int v = sptr[x], v1, minv = v, maxv = v;
+
+ v1 = (v + v_prev)/2;
+ minv = MIN(minv, v1); maxv = MAX(maxv, v1);
+ v1 = (v + sptr_prev[x])/2;
+ minv = MIN(minv, v1); maxv = MAX(maxv, v1);
+ v1 = (v + sptr_next[x])/2;
+ minv = MIN(minv, v1); maxv = MAX(maxv, v1);
+ if( x < cols-1 )
+ {
+ v1 = (v + sptr[x+1])/2;
+ minv = MIN(minv, v1); maxv = MAX(maxv, v1);
+ }
+ v_prev = v;
+ dptr[0] = (uchar)v;
+ dptr[1] = (uchar)minv;
+ dptr[2] = (uchar)maxv;
+ }
+ }
+ }
+}
+
+// Optimal K is computed as avg_x(k-th-smallest_d(||I(x)-J(x+d)||)),
+// where k = number_of_disparities*0.25.
+static float
+icvComputeK( CvStereoGCState* state )
+{
+ int x, y, x1, d, i, j, rows = state->left->rows, cols = state->left->cols, n = 0;
+ int mind = state->minDisparity, nd = state->numberOfDisparities, maxd = mind + nd;
+ int k = MIN(MAX((nd + 2)/4, 3), nd);
+ int *arr = (int*)cvStackAlloc(k*sizeof(arr[0])), delta, t, sum = 0;
+
+ for( y = 0; y < rows; y++ )
+ {
+ const uchar* lptr = state->left->data.ptr + state->left->step*y;
+ const uchar* rptr = state->right->data.ptr + state->right->step*y;
+
+ for( x = 0; x < cols; x++ )
+ {
+ for( d = maxd-1, i = 0; d >= mind; d-- )
+ {
+ x1 = x - d;
+ if( (unsigned)x1 >= (unsigned)cols )
+ continue;
+ delta = icvDataCostFuncGraySubpix( lptr + x*3, rptr + x1*3 );
+ if( i < k )
+ arr[i++] = delta;
+ else
+ for( i = 0; i < k; i++ )
+ if( delta < arr[i] )
+ CV_SWAP( arr[i], delta, t );
+ }
+ delta = arr[0];
+ for( j = 1; j < i; j++ )
+ delta = MAX(delta, arr[j]);
+ sum += delta;
+ n++;
+ }
+ }
+
+ return (float)sum/n;
+}
+
+static int64 icvComputeEnergy( const CvStereoGCState* state, const CvStereoGCState2* state2,
+ bool allOccluded )
+{
+ int x, y, rows = state->left->rows, cols = state->left->cols;
+ int64 E = 0;
+ const int* dtab = state2->dataCostFuncTab;
+ int maxR = state2->interactionRadius;
+ const int* stabR = state2->smoothnessR + CUTOFF;
+ const int* stabI = state2->smoothnessGrayDiff + 255;
+ const uchar* left = state->left->data.ptr;
+ const uchar* right = state->right->data.ptr;
+ short* dleft = state->dispLeft->data.s;
+ short* dright = state->dispRight->data.s;
+ int step = state->left->step;
+ int dstep = (int)(state->dispLeft->step/sizeof(short));
+
+ assert( state->left->step == state->right->step &&
+ state->dispLeft->step == state->dispRight->step );
+
+ if( allOccluded )
+ return (int64)OCCLUSION_PENALTY*rows*cols*2;
+
+ for( y = 0; y < rows; y++, left += step, right += step, dleft += dstep, dright += dstep )
+ {
+ for( x = 0; x < cols; x++ )
+ {
+ int d = dleft[x], x1, d1;
+ if( d == OCCLUDED )
+ E += OCCLUSION_PENALTY;
+ else
+ {
+ x1 = x + d;
+ if( (unsigned)x1 >= (unsigned)cols )
+ continue;
+ d1 = dright[x1];
+ if( d == -d1 )
+ E += dtab[icvDataCostFuncGraySubpix( left + x*3, right + x1*3 )];
+ }
+
+ if( x < cols-1 )
+ {
+ d1 = dleft[x+1];
+ E += icvSmoothnessCostFunc(d, d1, maxR, stabR, stabI[left[x*3] - left[x*3+3]] );
+ }
+ if( y < rows-1 )
+ {
+ d1 = dleft[x+dstep];
+ E += icvSmoothnessCostFunc(d, d1, maxR, stabR, stabI[left[x*3] - left[x*3+step]] );
+ }
+
+ d = dright[x];
+ if( d == OCCLUDED )
+ E += OCCLUSION_PENALTY;
+
+ if( x < cols-1 )
+ {
+ d1 = dright[x+1];
+ E += icvSmoothnessCostFunc(d, d1, maxR, stabR, stabI[right[x*3] - right[x*3+3]] );
+ }
+ if( y < rows-1 )
+ {
+ d1 = dright[x+dstep];
+ E += icvSmoothnessCostFunc(d, d1, maxR, stabR, stabI[right[x*3] - right[x*3+step]] );
+ }
+ assert( E >= 0 );
+ }
+ }
+
+ return E;
+}
+
+static inline void icvAddEdge( GCVtx *x, GCVtx* y, GCEdge* edgeBuf, int nedges, int w, int rw )
+{
+ GCEdge *xy = edgeBuf + nedges, *yx = xy + 1;
+
+ assert( x != 0 && y != 0 );
+ xy->dst = y;
+ xy->next = x->first;
+ xy->weight = (short)w;
+ x->first = nedges;
+
+ yx->dst = x;
+ yx->next = y->first;
+ yx->weight = (short)rw;
+ y->first = nedges+1;
+}
+
+static inline int icvAddTWeights( GCVtx* vtx, int sourceWeight, int sinkWeight )
+{
+ int w = vtx->weight;
+ if( w > 0 )
+ sourceWeight += w;
+ else
+ sinkWeight -= w;
+ vtx->weight = (short)(sourceWeight - sinkWeight);
+ return MIN(sourceWeight, sinkWeight);
+}
+
+static inline int icvAddTerm( GCVtx* x, GCVtx* y, int A, int B, int C, int D,
+ GCEdge* edgeBuf, int& nedges )
+{
+ int dE = 0, w;
+
+ assert(B - A + C - D >= 0);
+ if( B < A )
+ {
+ dE += icvAddTWeights(x, D, B);
+ dE += icvAddTWeights(y, 0, A - B);
+ if( (w = B - A + C - D) != 0 )
+ {
+ icvAddEdge( x, y, edgeBuf, nedges, 0, w );
+ nedges += 2;
+ }
+ }
+ else if( C < D )
+ {
+ dE += icvAddTWeights(x, D, A + D - C);
+ dE += icvAddTWeights(y, 0, C - D);
+ if( (w = B - A + C - D) != 0 )
+ {
+ icvAddEdge( x, y, edgeBuf, nedges, w, 0 );
+ nedges += 2;
+ }
+ }
+ else
+ {
+ dE += icvAddTWeights(x, D, A);
+ if( B != A || C != D )
+ {
+ icvAddEdge( x, y, edgeBuf, nedges, B - A, C - D );
+ nedges += 2;
+ }
+ }
+ return dE;
+}
+
+static int64 icvAlphaExpand( int64 Eprev, int alpha, CvStereoGCState* state, CvStereoGCState2* state2 )
+{
+ GCVtx *var, *var1;
+ int64 E = 0;
+ int delta, E00=0, E0a=0, Ea0=0, Eaa=0;
+ int k, a, d, d1, x, y, x1, y1, rows = state->left->rows, cols = state->left->cols;
+ int nvtx = 0, nedges = 2;
+ GCVtx* vbuf = (GCVtx*)state->vtxBuf->data.ptr;
+ GCEdge* ebuf = (GCEdge*)state->edgeBuf->data.ptr;
+ int maxR = state2->interactionRadius;
+ const int* dtab = state2->dataCostFuncTab;
+ const int* stabR = state2->smoothnessR + CUTOFF;
+ const int* stabI = state2->smoothnessGrayDiff + 255;
+ const uchar* left0 = state->left->data.ptr;
+ const uchar* right0 = state->right->data.ptr;
+ short* dleft0 = state->dispLeft->data.s;
+ short* dright0 = state->dispRight->data.s;
+ GCVtx** pleft0 = (GCVtx**)state->ptrLeft->data.ptr;
+ GCVtx** pright0 = (GCVtx**)state->ptrRight->data.ptr;
+ int step = state->left->step;
+ int dstep = (int)(state->dispLeft->step/sizeof(short));
+ int pstep = (int)(state->ptrLeft->step/sizeof(GCVtx*));
+ int aa[] = { alpha, -alpha };
+
+ double t = (double)cvGetTickCount();
+
+ assert( state->left->step == state->right->step &&
+ state->dispLeft->step == state->dispRight->step &&
+ state->ptrLeft->step == state->ptrRight->step );
+ for( k = 0; k < 2; k++ )
+ {
+ ebuf[k].dst = 0;
+ ebuf[k].next = 0;
+ ebuf[k].weight = 0;
+ }
+
+ for( y = 0; y < rows; y++ )
+ {
+ const uchar* left = left0 + step*y;
+ const uchar* right = right0 + step*y;
+ const short* dleft = dleft0 + dstep*y;
+ const short* dright = dright0 + dstep*y;
+ GCVtx** pleft = pleft0 + pstep*y;
+ GCVtx** pright = pright0 + pstep*y;
+ const uchar* lr[] = { left, right };
+ const short* dlr[] = { dleft, dright };
+ GCVtx** plr[] = { pleft, pright };
+
+ for( k = 0; k < 2; k++ )
+ {
+ a = aa[k];
+ for( y1 = y+(y>0); y1 <= y+(y<rows-1); y1++ )
+ {
+ const short* disp = (k == 0 ? dleft0 : dright0) + y1*dstep;
+ GCVtx** ptr = (k == 0 ? pleft0 : pright0) + y1*pstep;
+ for( x = 0; x < cols; x++ )
+ {
+ GCVtx* v = ptr[x] = &vbuf[nvtx++];
+ v->first = 0;
+ v->weight = disp[x] == (short)(OCCLUDED ? -OCCLUSION_PENALTY2 : 0);
+ }
+ }
+ }
+
+ for( x = 0; x < cols; x++ )
+ {
+ d = dleft[x];
+ x1 = x + d;
+ var = pleft[x];
+
+ // (left + x, right + x + d)
+ if( d != alpha && d != OCCLUDED && (unsigned)x1 < (unsigned)cols )
+ {
+ var1 = pright[x1];
+ d1 = dright[x1];
+ if( d == -d1 )
+ {
+ assert( var1 != 0 );
+ delta = IS_BLOCKED(alpha, d) ? INFINITY : 0;
+ //add inter edge
+ E += icvAddTerm( var, var1,
+ dtab[icvDataCostFuncGraySubpix( left + x*3, right + x1*3 )],
+ delta, delta, 0, ebuf, nedges );
+ }
+ else if( IS_BLOCKED(alpha, d) )
+ E += icvAddTerm( var, var1, 0, INFINITY, 0, 0, ebuf, nedges );
+ }
+
+ // (left + x, right + x + alpha)
+ x1 = x + alpha;
+ if( (unsigned)x1 < (unsigned)cols )
+ {
+ var1 = pright[x1];
+ d1 = dright[x1];
+
+ E0a = IS_BLOCKED(d, alpha) ? INFINITY : 0;
+ Ea0 = IS_BLOCKED(-d1, alpha) ? INFINITY : 0;
+ Eaa = dtab[icvDataCostFuncGraySubpix( left + x*3, right + x1*3 )];
+ E += icvAddTerm( var, var1, 0, E0a, Ea0, Eaa, ebuf, nedges );
+ }
+
+ // smoothness
+ for( k = 0; k < 2; k++ )
+ {
+ GCVtx** p = plr[k];
+ const short* disp = dlr[k];
+ const uchar* img = lr[k] + x*3;
+ int scale;
+ var = p[x];
+ d = disp[x];
+ a = aa[k];
+
+ if( x < cols - 1 )
+ {
+ var1 = p[x+1];
+ d1 = disp[x+1];
+ scale = stabI[img[0] - img[3]];
+ E0a = icvSmoothnessCostFunc( d, a, maxR, stabR, scale );
+ Ea0 = icvSmoothnessCostFunc( a, d1, maxR, stabR, scale );
+ E00 = icvSmoothnessCostFunc( d, d1, maxR, stabR, scale );
+ E += icvAddTerm( var, var1, E00, E0a, Ea0, 0, ebuf, nedges );
+ }
+
+ if( y < rows - 1 )
+ {
+ var1 = p[x+pstep];
+ d1 = disp[x+dstep];
+ scale = stabI[img[0] - img[step]];
+ E0a = icvSmoothnessCostFunc( d, a, maxR, stabR, scale );
+ Ea0 = icvSmoothnessCostFunc( a, d1, maxR, stabR, scale );
+ E00 = icvSmoothnessCostFunc( d, d1, maxR, stabR, scale );
+ E += icvAddTerm( var, var1, E00, E0a, Ea0, 0, ebuf, nedges );
+ }
+ }
+
+ // visibility term
+ if( d != OCCLUDED && IS_BLOCKED(alpha, -d))
+ {
+ x1 = x + d;
+ if( (unsigned)x1 < (unsigned)cols )
+ {
+ if( d != -dleft[x1] )
+ {
+ var1 = pleft[x1];
+ E += icvAddTerm( var, var1, 0, INFINITY, 0, 0, ebuf, nedges );
+ }
+ }
+ }
+ }
+ }
+
+ t = (double)cvGetTickCount() - t;
+ ebuf[0].weight = ebuf[1].weight = 0;
+ E += icvGCMaxFlow( vbuf, nvtx, ebuf, state2->orphans, state2->maxOrphans );
+
+ if( E < Eprev )
+ {
+ for( y = 0; y < rows; y++ )
+ {
+ short* dleft = dleft0 + dstep*y;
+ short* dright = dright0 + dstep*y;
+ GCVtx** pleft = pleft0 + pstep*y;
+ GCVtx** pright = pright0 + pstep*y;
+ for( x = 0; x < cols; x++ )
+ {
+ GCVtx* var = pleft[x];
+ if( var && var->parent && var->t )
+ dleft[x] = (short)alpha;
+
+ var = pright[x];
+ if( var && var->parent && var->t )
+ dright[x] = (short)-alpha;
+ }
+ }
+ }
+
+ return MIN(E, Eprev);
+}
+
+
+CV_IMPL void cvFindStereoCorrespondenceGC( const CvArr* _left, const CvArr* _right,
+ CvArr* _dispLeft, CvArr* _dispRight, CvStereoGCState* state, int useDisparityGuess )
+{
+ CvStereoGCState2 state2;
+ state2.orphans = 0;
+ state2.maxOrphans = 0;
+
+ CV_FUNCNAME( "cvFindStereoCorrespondenceGC" );
+
+ __BEGIN__;
+
+ CvMat lstub, *left = cvGetMat( _left, &lstub );
+ CvMat rstub, *right = cvGetMat( _right, &rstub );
+ CvMat dlstub, *dispLeft = cvGetMat( _dispLeft, &dlstub );
+ CvMat drstub, *dispRight = cvGetMat( _dispRight, &drstub );
+ CvSize size;
+ int iter, i, nZeroExpansions = 0;
+ CvRNG rng = cvRNG(-1);
+ int* disp;
+ CvMat _disp;
+ int64 E;
+
+ CV_ASSERT( state != 0 );
+ CV_ASSERT( CV_ARE_SIZES_EQ(left, right) && CV_ARE_TYPES_EQ(left, right) &&
+ CV_MAT_TYPE(left->type) == CV_8UC1 );
+ CV_ASSERT( !dispLeft ||
+ (CV_ARE_SIZES_EQ(dispLeft, left) && CV_MAT_CN(dispLeft->type) == 1) );
+ CV_ASSERT( !dispRight ||
+ (CV_ARE_SIZES_EQ(dispRight, left) && CV_MAT_CN(dispRight->type) == 1) );
+
+ size = cvGetSize(left);
+ if( !state->left || state->left->width != size.width || state->left->height != size.height )
+ {
+ int pcn = (int)(sizeof(GCVtx*)/sizeof(int));
+ int vcn = (int)(sizeof(GCVtx)/sizeof(int));
+ int ecn = (int)(sizeof(GCEdge)/sizeof(int));
+ cvReleaseMat( &state->left );
+ cvReleaseMat( &state->right );
+ cvReleaseMat( &state->ptrLeft );
+ cvReleaseMat( &state->ptrRight );
+ cvReleaseMat( &state->dispLeft );
+ cvReleaseMat( &state->dispRight );
+
+ state->left = cvCreateMat( size.height, size.width, CV_8UC3 );
+ state->right = cvCreateMat( size.height, size.width, CV_8UC3 );
+ state->dispLeft = cvCreateMat( size.height, size.width, CV_16SC1 );
+ state->dispRight = cvCreateMat( size.height, size.width, CV_16SC1 );
+ state->ptrLeft = cvCreateMat( size.height, size.width, CV_32SC(pcn) );
+ state->ptrRight = cvCreateMat( size.height, size.width, CV_32SC(pcn) );
+ state->vtxBuf = cvCreateMat( 1, size.height*size.width*2, CV_32SC(vcn) );
+ state->edgeBuf = cvCreateMat( 1, size.height*size.width*12 + 16, CV_32SC(ecn) );
+ }
+
+ if( !useDisparityGuess )
+ {
+ cvSet( state->dispLeft, cvScalarAll(OCCLUDED));
+ cvSet( state->dispRight, cvScalarAll(OCCLUDED));
+ }
+ else
+ {
+ CV_ASSERT( dispLeft && dispRight );
+ cvConvert( dispLeft, state->dispLeft );
+ cvConvert( dispRight, state->dispRight );
+ }
+
+ state2.Ithreshold = state->Ithreshold;
+ state2.interactionRadius = state->interactionRadius;
+ state2.lambda = cvRound(state->lambda*DENOMINATOR);
+ state2.lambda1 = cvRound(state->lambda1*DENOMINATOR);
+ state2.lambda2 = cvRound(state->lambda2*DENOMINATOR);
+ state2.K = cvRound(state->K*DENOMINATOR);
+
+ icvInitStereoConstTabs();
+ icvInitGraySubpix( left, right, state->left, state->right );
+ disp = (int*)cvStackAlloc( state->numberOfDisparities*sizeof(disp[0]) );
+ _disp = cvMat( 1, state->numberOfDisparities, CV_32S, disp );
+ cvRange( &_disp, state->minDisparity, state->minDisparity + state->numberOfDisparities );
+ cvRandShuffle( &_disp, &rng );
+
+ if( state2.lambda < 0 && (state2.K < 0 || state2.lambda1 < 0 || state2.lambda2 < 0) )
+ {
+ float L = icvComputeK(state)*0.2f;
+ state2.lambda = cvRound(L*DENOMINATOR);
+ }
+
+ if( state2.K < 0 )
+ state2.K = state2.lambda*5;
+ if( state2.lambda1 < 0 )
+ state2.lambda1 = state2.lambda*3;
+ if( state2.lambda2 < 0 )
+ state2.lambda2 = state2.lambda;
+
+ icvInitStereoTabs( &state2 );
+
+ E = icvComputeEnergy( state, &state2, !useDisparityGuess );
+ for( iter = 0; iter < state->maxIters; iter++ )
+ {
+ for( i = 0; i < state->numberOfDisparities; i++ )
+ {
+ int alpha = disp[i];
+ int64 Enew = icvAlphaExpand( E, -alpha, state, &state2 );
+ if( Enew < E )
+ {
+ nZeroExpansions = 0;
+ E = Enew;
+ }
+ else if( ++nZeroExpansions >= state->numberOfDisparities )
+ break;
+ }
+ }
+
+ if( dispLeft )
+ cvConvert( state->dispLeft, dispLeft );
+ if( dispRight )
+ cvConvert( state->dispRight, dispRight );
+
+ __END__;
+
+ cvFree( &state2.orphans );
+}
diff --git a/cv/src/cvsubdivision2d.cpp b/cv/src/cvsubdivision2d.cpp
new file mode 100644
index 0000000..99778e5
--- /dev/null
+++ b/cv/src/cvsubdivision2d.cpp
@@ -0,0 +1,850 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cv.h"
+
+CV_IMPL CvSubdiv2D *
+cvCreateSubdiv2D( int subdiv_type, int header_size,
+ int vtx_size, int quadedge_size, CvMemStorage * storage )
+{
+ CvSubdiv2D *subdiv = 0;
+
+ CV_FUNCNAME( "cvCleateSubdiv2D" );
+
+ __BEGIN__;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( header_size < (int)sizeof( *subdiv ) ||
+ quadedge_size < (int)sizeof( CvQuadEdge2D ) ||
+ vtx_size < (int)sizeof( CvSubdiv2DPoint ))
+ CV_ERROR_FROM_STATUS( CV_BADSIZE_ERR );
+
+ subdiv = (CvSubdiv2D *) cvCreateGraph( subdiv_type, header_size,
+ vtx_size, quadedge_size, storage );
+
+
+ __END__;
+
+ return subdiv;
+}
+
+
+/****************************************************************************************\
+* Quad Edge algebra *
+\****************************************************************************************/
+
+static CvSubdiv2DEdge
+cvSubdiv2DMakeEdge( CvSubdiv2D * subdiv )
+{
+ CvQuadEdge2D *edge = 0;
+ CvSubdiv2DEdge edgehandle = 0;
+
+ CV_FUNCNAME( "cvSubdiv2DMakeEdge" );
+
+ __BEGIN__;
+
+ if( !subdiv )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ edge = (CvQuadEdge2D*)cvSetNew( (CvSet*)subdiv->edges );
+ CV_CHECK();
+
+ memset( edge->pt, 0, sizeof( edge->pt ));
+ edgehandle = (CvSubdiv2DEdge) edge;
+
+ edge->next[0] = edgehandle;
+ edge->next[1] = edgehandle + 3;
+ edge->next[2] = edgehandle + 2;
+ edge->next[3] = edgehandle + 1;
+
+ subdiv->quad_edges++;
+
+
+ __END__;
+
+ return edgehandle;
+}
+
+
+static CvSubdiv2DPoint *
+cvSubdiv2DAddPoint( CvSubdiv2D * subdiv, CvPoint2D32f pt, int is_virtual )
+{
+ CvSubdiv2DPoint *subdiv_point = 0;
+
+ subdiv_point = (CvSubdiv2DPoint*)cvSetNew( (CvSet*)subdiv );
+ if( subdiv_point )
+ {
+ memset( subdiv_point, 0, subdiv->elem_size );
+ subdiv_point->pt = pt;
+ subdiv_point->first = 0;
+ subdiv_point->flags |= is_virtual ? CV_SUBDIV2D_VIRTUAL_POINT_FLAG : 0;
+ }
+
+ return subdiv_point;
+}
+
+
+static void
+cvSubdiv2DSplice( CvSubdiv2DEdge edgeA, CvSubdiv2DEdge edgeB )
+{
+ CvSubdiv2DEdge *a_next = &CV_SUBDIV2D_NEXT_EDGE( edgeA );
+ CvSubdiv2DEdge *b_next = &CV_SUBDIV2D_NEXT_EDGE( edgeB );
+ CvSubdiv2DEdge a_rot = cvSubdiv2DRotateEdge( *a_next, 1 );
+ CvSubdiv2DEdge b_rot = cvSubdiv2DRotateEdge( *b_next, 1 );
+ CvSubdiv2DEdge *a_rot_next = &CV_SUBDIV2D_NEXT_EDGE( a_rot );
+ CvSubdiv2DEdge *b_rot_next = &CV_SUBDIV2D_NEXT_EDGE( b_rot );
+ CvSubdiv2DEdge t;
+
+ CV_SWAP( *a_next, *b_next, t );
+ CV_SWAP( *a_rot_next, *b_rot_next, t );
+}
+
+
+static void
+cvSubdiv2DSetEdgePoints( CvSubdiv2DEdge edge,
+ CvSubdiv2DPoint * org_pt, CvSubdiv2DPoint * dst_pt )
+{
+ CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (edge & ~3);
+
+ CV_FUNCNAME( "cvSubdiv2DSetEdgePoints" );
+
+ __BEGIN__;
+
+ if( !quadedge )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ quadedge->pt[edge & 3] = org_pt;
+ quadedge->pt[(edge + 2) & 3] = dst_pt;
+
+
+ __END__;
+}
+
+
+static void
+cvSubdiv2DDeleteEdge( CvSubdiv2D * subdiv, CvSubdiv2DEdge edge )
+{
+ CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (edge & ~3);
+
+ CV_FUNCNAME( "cvSubdiv2DDeleteEdge" );
+
+ __BEGIN__;
+
+ if( !subdiv || !quadedge )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ cvSubdiv2DSplice( edge, cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_ORG ));
+
+ {
+ CvSubdiv2DEdge sym_edge = cvSubdiv2DSymEdge( edge );
+ cvSubdiv2DSplice( sym_edge, cvSubdiv2DGetEdge( sym_edge, CV_PREV_AROUND_ORG ));
+ }
+
+ cvSetRemoveByPtr( (CvSet*)(subdiv->edges), quadedge );
+ subdiv->quad_edges--;
+
+
+ __END__;
+}
+
+
+static CvSubdiv2DEdge
+cvSubdiv2DConnectEdges( CvSubdiv2D * subdiv, CvSubdiv2DEdge edgeA, CvSubdiv2DEdge edgeB )
+{
+ CvSubdiv2DEdge new_edge = 0;
+
+ CV_FUNCNAME( "cvSubdiv2DConnectPoints" );
+
+ __BEGIN__;
+
+ CvSubdiv2DPoint *orgB, *dstA;
+
+ if( !subdiv )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ new_edge = cvSubdiv2DMakeEdge( subdiv );
+
+ cvSubdiv2DSplice( new_edge, cvSubdiv2DGetEdge( edgeA, CV_NEXT_AROUND_LEFT ));
+ cvSubdiv2DSplice( cvSubdiv2DSymEdge( new_edge ), edgeB );
+
+ dstA = cvSubdiv2DEdgeDst( edgeA );
+ orgB = cvSubdiv2DEdgeOrg( edgeB );
+ cvSubdiv2DSetEdgePoints( new_edge, dstA, orgB );
+
+ __END__;
+
+ return new_edge;
+}
+
+
+static void
+cvSubdiv2DSwapEdges( CvSubdiv2DEdge edge )
+{
+ CvSubdiv2DEdge sym_edge = cvSubdiv2DSymEdge( edge );
+ CvSubdiv2DEdge a = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_ORG );
+ CvSubdiv2DEdge b = cvSubdiv2DGetEdge( sym_edge, CV_PREV_AROUND_ORG );
+ CvSubdiv2DPoint *dstB, *dstA;
+
+ cvSubdiv2DSplice( edge, a );
+ cvSubdiv2DSplice( sym_edge, b );
+
+ dstA = cvSubdiv2DEdgeDst( a );
+ dstB = cvSubdiv2DEdgeDst( b );
+ cvSubdiv2DSetEdgePoints( edge, dstA, dstB );
+
+ cvSubdiv2DSplice( edge, cvSubdiv2DGetEdge( a, CV_NEXT_AROUND_LEFT ));
+ cvSubdiv2DSplice( sym_edge, cvSubdiv2DGetEdge( b, CV_NEXT_AROUND_LEFT ));
+}
+
+
+static int
+icvIsRightOf( CvPoint2D32f& pt, CvSubdiv2DEdge edge )
+{
+ CvSubdiv2DPoint *org = cvSubdiv2DEdgeOrg(edge), *dst = cvSubdiv2DEdgeDst(edge);
+ Cv32suf cw_area;
+ cw_area.f = (float)cvTriangleArea( pt, dst->pt, org->pt );
+
+ return (cw_area.i > 0)*2 - (cw_area.i*2 != 0);
+}
+
+
+CV_IMPL CvSubdiv2DPointLocation
+cvSubdiv2DLocate( CvSubdiv2D * subdiv, CvPoint2D32f pt,
+ CvSubdiv2DEdge * _edge, CvSubdiv2DPoint ** _point )
+{
+ CvSubdiv2DEdge edge = 0;
+ CvSubdiv2DPoint *point = 0;
+ CvSubdiv2DPointLocation location = CV_PTLOC_ERROR;
+
+ int i, max_edges;
+ int right_of_curr = 0;
+
+ CV_FUNCNAME( "cvSubdiv2DLocate" );
+
+ __BEGIN__;
+
+ if( !subdiv )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !CV_IS_SUBDIV2D(subdiv) )
+ CV_ERROR_FROM_STATUS( CV_BADFLAG_ERR );
+
+ max_edges = subdiv->quad_edges * 4;
+ edge = subdiv->recent_edge;
+
+ if( max_edges == 0 )
+ CV_ERROR_FROM_STATUS( CV_BADSIZE_ERR );
+ if( !edge )
+ CV_ERROR_FROM_STATUS( CV_NOTDEFINED_ERR );
+
+ location = CV_PTLOC_OUTSIDE_RECT;
+ if( pt.x < subdiv->topleft.x || pt.y < subdiv->topleft.y ||
+ pt.x >= subdiv->bottomright.x || pt.y >= subdiv->bottomright.y )
+ CV_ERROR_FROM_STATUS( CV_BADRANGE_ERR );
+
+ location = CV_PTLOC_ERROR;
+
+ right_of_curr = icvIsRightOf( pt, edge );
+ if( right_of_curr > 0 )
+ {
+ edge = cvSubdiv2DSymEdge( edge );
+ right_of_curr = -right_of_curr;
+ }
+
+ for( i = 0; i < max_edges; i++ )
+ {
+ CvSubdiv2DEdge onext_edge = cvSubdiv2DNextEdge( edge );
+ CvSubdiv2DEdge dprev_edge = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_DST );
+
+ int right_of_onext = icvIsRightOf( pt, onext_edge );
+ int right_of_dprev = icvIsRightOf( pt, dprev_edge );
+
+ if( right_of_dprev > 0 )
+ {
+ if( right_of_onext > 0 || (right_of_onext == 0 && right_of_curr == 0) )
+ {
+ location = CV_PTLOC_INSIDE;
+ EXIT;
+ }
+ else
+ {
+ right_of_curr = right_of_onext;
+ edge = onext_edge;
+ }
+ }
+ else
+ {
+ if( right_of_onext > 0 )
+ {
+ if( right_of_dprev == 0 && right_of_curr == 0 )
+ {
+ location = CV_PTLOC_INSIDE;
+ EXIT;
+ }
+ else
+ {
+ right_of_curr = right_of_dprev;
+ edge = dprev_edge;
+ }
+ }
+ else if( right_of_curr == 0 &&
+ icvIsRightOf( cvSubdiv2DEdgeDst( onext_edge )->pt, edge ) >= 0 )
+ {
+ edge = cvSubdiv2DSymEdge( edge );
+ }
+ else
+ {
+ right_of_curr = right_of_onext;
+ edge = onext_edge;
+ }
+ }
+ }
+
+
+ __END__;
+
+ subdiv->recent_edge = edge;
+
+ if( location == CV_PTLOC_INSIDE )
+ {
+ double t1, t2, t3;
+ CvPoint2D32f org_pt = cvSubdiv2DEdgeOrg( edge )->pt;
+ CvPoint2D32f dst_pt = cvSubdiv2DEdgeDst( edge )->pt;
+
+ t1 = fabs( pt.x - org_pt.x );
+ t1 += fabs( pt.y - org_pt.y );
+ t2 = fabs( pt.x - dst_pt.x );
+ t2 += fabs( pt.y - dst_pt.y );
+ t3 = fabs( org_pt.x - dst_pt.x );
+ t3 += fabs( org_pt.y - dst_pt.y );
+
+ if( t1 < FLT_EPSILON )
+ {
+ location = CV_PTLOC_VERTEX;
+ point = cvSubdiv2DEdgeOrg( edge );
+ edge = 0;
+ }
+ else if( t2 < FLT_EPSILON )
+ {
+ location = CV_PTLOC_VERTEX;
+ point = cvSubdiv2DEdgeDst( edge );
+ edge = 0;
+ }
+ else if( (t1 < t3 || t2 < t3) &&
+ fabs( cvTriangleArea( pt, org_pt, dst_pt )) < FLT_EPSILON )
+ {
+ location = CV_PTLOC_ON_EDGE;
+ point = 0;
+ }
+ }
+
+ if( location == CV_PTLOC_ERROR )
+ {
+ edge = 0;
+ point = 0;
+ }
+
+ if( _edge )
+ *_edge = edge;
+ if( _point )
+ *_point = point;
+
+ return location;
+}
+
+
+CV_INLINE int
+icvIsPtInCircle3( CvPoint2D32f pt, CvPoint2D32f a, CvPoint2D32f b, CvPoint2D32f c )
+{
+ double val = (a.x * a.x + a.y * a.y) * cvTriangleArea( b, c, pt );
+ val -= (b.x * b.x + b.y * b.y) * cvTriangleArea( a, c, pt );
+ val += (c.x * c.x + c.y * c.y) * cvTriangleArea( a, b, pt );
+ val -= (pt.x * pt.x + pt.y * pt.y) * cvTriangleArea( a, b, c );
+
+ return val > FLT_EPSILON ? 1 : val < -FLT_EPSILON ? -1 : 0;
+}
+
+
+CV_IMPL CvSubdiv2DPoint *
+cvSubdivDelaunay2DInsert( CvSubdiv2D * subdiv, CvPoint2D32f pt )
+{
+ CvSubdiv2DPoint *point = 0;
+ CvSubdiv2DPointLocation location = CV_PTLOC_ERROR;
+
+ CvSubdiv2DPoint *curr_point = 0, *first_point = 0;
+ CvSubdiv2DEdge curr_edge = 0, deleted_edge = 0, base_edge = 0;
+ int i, max_edges;
+
+ CV_FUNCNAME( "cvSubdivDelaunay2DInsert" );
+
+ __BEGIN__;
+
+ if( !subdiv )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !CV_IS_SUBDIV2D(subdiv) )
+ CV_ERROR_FROM_STATUS( CV_BADFLAG_ERR );
+
+
+ location = cvSubdiv2DLocate( subdiv, pt, &curr_edge, &curr_point );
+
+ switch (location)
+ {
+ case CV_PTLOC_ERROR:
+ CV_ERROR_FROM_STATUS( CV_BADSIZE_ERR );
+
+ case CV_PTLOC_OUTSIDE_RECT:
+ CV_ERROR_FROM_STATUS( CV_BADRANGE_ERR );
+
+ case CV_PTLOC_VERTEX:
+ point = curr_point;
+ break;
+
+ case CV_PTLOC_ON_EDGE:
+ deleted_edge = curr_edge;
+ subdiv->recent_edge = curr_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG );
+ cvSubdiv2DDeleteEdge( subdiv, deleted_edge );
+ /* no break */
+
+ case CV_PTLOC_INSIDE:
+
+ assert( curr_edge != 0 );
+ subdiv->is_geometry_valid = 0;
+
+ curr_point = cvSubdiv2DAddPoint( subdiv, pt, 0 );
+ CV_CHECK();
+
+ base_edge = cvSubdiv2DMakeEdge( subdiv );
+ first_point = cvSubdiv2DEdgeOrg( curr_edge );
+ cvSubdiv2DSetEdgePoints( base_edge, first_point, curr_point );
+ cvSubdiv2DSplice( base_edge, curr_edge );
+
+ do
+ {
+ base_edge = cvSubdiv2DConnectEdges( subdiv, curr_edge,
+ cvSubdiv2DSymEdge( base_edge ));
+ curr_edge = cvSubdiv2DGetEdge( base_edge, CV_PREV_AROUND_ORG );
+ }
+ while( cvSubdiv2DEdgeDst( curr_edge ) != first_point );
+
+ curr_edge = cvSubdiv2DGetEdge( base_edge, CV_PREV_AROUND_ORG );
+
+ max_edges = subdiv->quad_edges * 4;
+
+ for( i = 0; i < max_edges; i++ )
+ {
+ CvSubdiv2DPoint *temp_dst = 0, *curr_org = 0, *curr_dst = 0;
+ CvSubdiv2DEdge temp_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG );
+
+ temp_dst = cvSubdiv2DEdgeDst( temp_edge );
+ curr_org = cvSubdiv2DEdgeOrg( curr_edge );
+ curr_dst = cvSubdiv2DEdgeDst( curr_edge );
+
+ if( icvIsRightOf( temp_dst->pt, curr_edge ) > 0 &&
+ icvIsPtInCircle3( curr_org->pt, temp_dst->pt,
+ curr_dst->pt, curr_point->pt ) < 0 )
+ {
+ cvSubdiv2DSwapEdges( curr_edge );
+ curr_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG );
+ }
+ else if( curr_org == first_point )
+ {
+ break;
+ }
+ else
+ {
+ curr_edge = cvSubdiv2DGetEdge( cvSubdiv2DNextEdge( curr_edge ),
+ CV_PREV_AROUND_LEFT );
+ }
+ }
+ break;
+ default:
+ assert( 0 );
+ CV_ERROR_FROM_STATUS( CV_NOTDEFINED_ERR );
+ }
+
+ point = curr_point;
+
+
+ __END__;
+
+ //icvSubdiv2DCheck( subdiv );
+
+ return point;
+}
+
+
+CV_IMPL void
+cvInitSubdivDelaunay2D( CvSubdiv2D * subdiv, CvRect rect )
+{
+ float big_coord = 3.f * MAX( rect.width, rect.height );
+ CvPoint2D32f ppA, ppB, ppC;
+ CvSubdiv2DPoint *pA, *pB, *pC;
+ CvSubdiv2DEdge edge_AB, edge_BC, edge_CA;
+ float rx = (float) rect.x;
+ float ry = (float) rect.y;
+
+ CV_FUNCNAME( "cvSubdivDelaunay2DInit" );
+
+ __BEGIN__;
+
+ if( !subdiv )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ cvClearSet( (CvSet *) (subdiv->edges) );
+ cvClearSet( (CvSet *) subdiv );
+
+ subdiv->quad_edges = 0;
+ subdiv->recent_edge = 0;
+ subdiv->is_geometry_valid = 0;
+
+ subdiv->topleft = cvPoint2D32f( rx, ry );
+ subdiv->bottomright = cvPoint2D32f( rx + rect.width, ry + rect.height );
+
+ ppA = cvPoint2D32f( rx + big_coord, ry );
+ ppB = cvPoint2D32f( rx, ry + big_coord );
+ ppC = cvPoint2D32f( rx - big_coord, ry - big_coord );
+
+ pA = cvSubdiv2DAddPoint( subdiv, ppA, 0 );
+ pB = cvSubdiv2DAddPoint( subdiv, ppB, 0 );
+ pC = cvSubdiv2DAddPoint( subdiv, ppC, 0 );
+
+ edge_AB = cvSubdiv2DMakeEdge( subdiv );
+ edge_BC = cvSubdiv2DMakeEdge( subdiv );
+ edge_CA = cvSubdiv2DMakeEdge( subdiv );
+
+ cvSubdiv2DSetEdgePoints( edge_AB, pA, pB );
+ cvSubdiv2DSetEdgePoints( edge_BC, pB, pC );
+ cvSubdiv2DSetEdgePoints( edge_CA, pC, pA );
+
+ cvSubdiv2DSplice( edge_AB, cvSubdiv2DSymEdge( edge_CA ));
+ cvSubdiv2DSplice( edge_BC, cvSubdiv2DSymEdge( edge_AB ));
+ cvSubdiv2DSplice( edge_CA, cvSubdiv2DSymEdge( edge_BC ));
+
+ subdiv->recent_edge = edge_AB;
+
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvClearSubdivVoronoi2D( CvSubdiv2D * subdiv )
+{
+ int elem_size;
+ int i, total;
+ CvSeqReader reader;
+
+ CV_FUNCNAME( "cvClearVoronoi2D" );
+
+ __BEGIN__;
+
+ if( !subdiv )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ /* clear pointers to voronoi points */
+ total = subdiv->edges->total;
+ elem_size = subdiv->edges->elem_size;
+
+ cvStartReadSeq( (CvSeq *) (subdiv->edges), &reader, 0 );
+
+ for( i = 0; i < total; i++ )
+ {
+ CvQuadEdge2D *quadedge = (CvQuadEdge2D *) reader.ptr;
+
+ quadedge->pt[1] = quadedge->pt[3] = 0;
+ CV_NEXT_SEQ_ELEM( elem_size, reader );
+ }
+
+ /* remove voronoi points */
+ total = subdiv->total;
+ elem_size = subdiv->elem_size;
+
+ cvStartReadSeq( (CvSeq *) subdiv, &reader, 0 );
+
+ for( i = 0; i < total; i++ )
+ {
+ CvSubdiv2DPoint *pt = (CvSubdiv2DPoint *) reader.ptr;
+
+ /* check for virtual point. it is also check that the point exists */
+ if( pt->flags & CV_SUBDIV2D_VIRTUAL_POINT_FLAG )
+ {
+ cvSetRemoveByPtr( (CvSet*)subdiv, pt );
+ }
+ CV_NEXT_SEQ_ELEM( elem_size, reader );
+ }
+
+ subdiv->is_geometry_valid = 0;
+
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvCalcSubdivVoronoi2D( CvSubdiv2D * subdiv )
+{
+ CvSeqReader reader;
+ int i, total, elem_size;
+
+ CV_FUNCNAME( "cvCalcSubdivVoronoi2D" );
+
+ __BEGIN__;
+
+ if( !subdiv )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ /* check if it is already calculated */
+ if( subdiv->is_geometry_valid )
+ EXIT;
+
+ total = subdiv->edges->total;
+ elem_size = subdiv->edges->elem_size;
+
+ cvClearSubdivVoronoi2D( subdiv );
+
+ cvStartReadSeq( (CvSeq *) (subdiv->edges), &reader, 0 );
+
+ if( total <= 3 )
+ EXIT;
+
+ /* skip first three edges (bounding triangle) */
+ for( i = 0; i < 3; i++ )
+ CV_NEXT_SEQ_ELEM( elem_size, reader );
+
+ /* loop through all quad-edges */
+ for( ; i < total; i++ )
+ {
+ CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (reader.ptr);
+
+ if( CV_IS_SET_ELEM( quadedge ))
+ {
+ CvSubdiv2DEdge edge0 = (CvSubdiv2DEdge) quadedge, edge1, edge2;
+ double a0, b0, c0, a1, b1, c1;
+ CvPoint2D32f virt_point;
+ CvSubdiv2DPoint *voronoi_point;
+
+ if( !quadedge->pt[3] )
+ {
+ edge1 = cvSubdiv2DGetEdge( edge0, CV_NEXT_AROUND_LEFT );
+ edge2 = cvSubdiv2DGetEdge( edge1, CV_NEXT_AROUND_LEFT );
+
+ icvCreateCenterNormalLine( edge0, &a0, &b0, &c0 );
+ icvCreateCenterNormalLine( edge1, &a1, &b1, &c1 );
+
+ icvIntersectLines3( &a0, &b0, &c0, &a1, &b1, &c1, &virt_point );
+ if( fabs( virt_point.x ) < FLT_MAX * 0.5 &&
+ fabs( virt_point.y ) < FLT_MAX * 0.5 )
+ {
+ voronoi_point = cvSubdiv2DAddPoint( subdiv, virt_point, 1 );
+
+ quadedge->pt[3] =
+ ((CvQuadEdge2D *) (edge1 & ~3))->pt[3 - (edge1 & 2)] =
+ ((CvQuadEdge2D *) (edge2 & ~3))->pt[3 - (edge2 & 2)] = voronoi_point;
+ }
+ }
+
+ if( !quadedge->pt[1] )
+ {
+ edge1 = cvSubdiv2DGetEdge( edge0, CV_NEXT_AROUND_RIGHT );
+ edge2 = cvSubdiv2DGetEdge( edge1, CV_NEXT_AROUND_RIGHT );
+
+ icvCreateCenterNormalLine( edge0, &a0, &b0, &c0 );
+ icvCreateCenterNormalLine( edge1, &a1, &b1, &c1 );
+
+ icvIntersectLines3( &a0, &b0, &c0, &a1, &b1, &c1, &virt_point );
+
+ if( fabs( virt_point.x ) < FLT_MAX * 0.5 &&
+ fabs( virt_point.y ) < FLT_MAX * 0.5 )
+ {
+ voronoi_point = cvSubdiv2DAddPoint( subdiv, virt_point, 1 );
+
+ quadedge->pt[1] =
+ ((CvQuadEdge2D *) (edge1 & ~3))->pt[1 + (edge1 & 2)] =
+ ((CvQuadEdge2D *) (edge2 & ~3))->pt[1 + (edge2 & 2)] = voronoi_point;
+ }
+ }
+ }
+
+ CV_NEXT_SEQ_ELEM( elem_size, reader );
+ }
+
+ subdiv->is_geometry_valid = 1;
+
+
+ __END__;
+}
+
+
+static int
+icvIsRightOf2( const CvPoint2D32f& pt, const CvPoint2D32f& org, const CvPoint2D32f& diff )
+{
+ Cv32suf cw_area;
+ cw_area.f = (org.x - pt.x)*diff.y - (org.y - pt.y)*diff.x;
+ return (cw_area.i > 0)*2 - (cw_area.i*2 != 0);
+}
+
+
+CV_IMPL CvSubdiv2DPoint*
+cvFindNearestPoint2D( CvSubdiv2D* subdiv, CvPoint2D32f pt )
+{
+ CvSubdiv2DPoint* point = 0;
+ CvPoint2D32f start;
+ CvPoint2D32f diff;
+ CvSubdiv2DPointLocation loc;
+ CvSubdiv2DEdge edge;
+ int i;
+
+ CV_FUNCNAME("cvFindNearestPoint2D");
+
+ __BEGIN__;
+
+ if( !subdiv )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !CV_IS_SUBDIV2D( subdiv ))
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !subdiv->is_geometry_valid )
+ cvCalcSubdivVoronoi2D( subdiv );
+
+ loc = cvSubdiv2DLocate( subdiv, pt, &edge, &point );
+
+ switch( loc )
+ {
+ case CV_PTLOC_ON_EDGE:
+ case CV_PTLOC_INSIDE:
+ break;
+ default:
+ EXIT;
+ }
+
+ point = 0;
+
+ start = cvSubdiv2DEdgeOrg( edge )->pt;
+ diff.x = pt.x - start.x;
+ diff.y = pt.y - start.y;
+
+ edge = cvSubdiv2DRotateEdge( edge, 1 );
+
+ for( i = 0; i < subdiv->total; i++ )
+ {
+ CvPoint2D32f t;
+
+ for(;;)
+ {
+ assert( cvSubdiv2DEdgeDst( edge ));
+
+ t = cvSubdiv2DEdgeDst( edge )->pt;
+ if( icvIsRightOf2( t, start, diff ) >= 0 )
+ break;
+
+ edge = cvSubdiv2DGetEdge( edge, CV_NEXT_AROUND_LEFT );
+ }
+
+ for(;;)
+ {
+ assert( cvSubdiv2DEdgeOrg( edge ));
+
+ t = cvSubdiv2DEdgeOrg( edge )->pt;
+ if( icvIsRightOf2( t, start, diff ) < 0 )
+ break;
+
+ edge = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_LEFT );
+ }
+
+ {
+ CvPoint2D32f tempDiff = cvSubdiv2DEdgeDst( edge )->pt;
+ t = cvSubdiv2DEdgeOrg( edge )->pt;
+ tempDiff.x -= t.x;
+ tempDiff.y -= t.y;
+
+ if( icvIsRightOf2( pt, t, tempDiff ) >= 0 )
+ {
+ point = cvSubdiv2DEdgeOrg( cvSubdiv2DRotateEdge( edge, 3 ));
+ break;
+ }
+ }
+
+ edge = cvSubdiv2DSymEdge( edge );
+ }
+
+ __END__;
+
+ return point;
+}
+
+/* Removed from the main interface */
+
+#if 0
+/* Adds new isolated quadedge to the subdivision */
+OPENCVAPI CvSubdiv2DEdge cvSubdiv2DMakeEdge( CvSubdiv2D* subdiv );
+
+
+/* Adds new isolated point to subdivision */
+OPENCVAPI CvSubdiv2DPoint* cvSubdiv2DAddPoint( CvSubdiv2D* subdiv,
+ CvPoint2D32f pt, int is_virtual );
+
+
+/* Does a splice operation for two quadedges */
+OPENCVAPI void cvSubdiv2DSplice( CvSubdiv2DEdge edgeA, CvSubdiv2DEdge edgeB );
+
+
+/* Assigns ending [non-virtual] points for given quadedge */
+OPENCVAPI void cvSubdiv2DSetEdgePoints( CvSubdiv2DEdge edge,
+ CvSubdiv2DPoint* org_pt,
+ CvSubdiv2DPoint* dst_pt );
+
+/* Removes quadedge from subdivision */
+OPENCVAPI void cvSubdiv2DDeleteEdge( CvSubdiv2D* subdiv, CvSubdiv2DEdge edge );
+
+
+/* Connects estination point of the first edge with origin point of the second edge */
+OPENCVAPI CvSubdiv2DEdge cvSubdiv2DConnectEdges( CvSubdiv2D* subdiv,
+ CvSubdiv2DEdge edgeA,
+ CvSubdiv2DEdge edgeB );
+
+/* Swaps diagonal in two connected Delaunay facets */
+OPENCVAPI void cvSubdiv2DSwapEdges( CvSubdiv2DEdge edge );
+#endif
+
+/* End of file. */
diff --git a/cv/src/cvsumpixels.cpp b/cv/src/cvsumpixels.cpp
new file mode 100644
index 0000000..3603468
--- /dev/null
+++ b/cv/src/cvsumpixels.cpp
@@ -0,0 +1,435 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+#define ICV_DEF_INTEGRAL_OP_C1( flavor, arrtype, sumtype, sqsumtype, worktype, \
+ cast_macro, cast_sqr_macro ) \
+static CvStatus CV_STDCALL \
+icvIntegralImage_##flavor##_C1R( const arrtype* src, int srcstep,\
+ sumtype* sum, int sumstep, \
+ sqsumtype* sqsum, int sqsumstep,\
+ sumtype* tilted, int tiltedstep,\
+ CvSize size ) \
+{ \
+ int x, y; \
+ sumtype s; \
+ sqsumtype sq; \
+ sumtype* buf = 0; \
+ \
+ srcstep /= sizeof(src[0]); \
+ \
+ memset( sum, 0, (size.width+1)*sizeof(sum[0])); \
+ sumstep /= sizeof(sum[0]); \
+ sum += sumstep + 1; \
+ \
+ if( sqsum ) \
+ { \
+ memset( sqsum, 0, (size.width+1)*sizeof(sqsum[0])); \
+ sqsumstep /= sizeof(sqsum[0]); \
+ sqsum += sqsumstep + 1; \
+ } \
+ \
+ if( tilted ) \
+ { \
+ memset( tilted, 0, (size.width+1)*sizeof(tilted[0])); \
+ tiltedstep /= sizeof(tilted[0]); \
+ tilted += tiltedstep + 1; \
+ } \
+ \
+ if( sqsum == 0 && tilted == 0 ) \
+ { \
+ for( y = 0; y < size.height; y++, src += srcstep, \
+ sum += sumstep ) \
+ { \
+ sum[-1] = 0; \
+ for( x = 0, s = 0; x < size.width; x++ ) \
+ { \
+ sumtype t = cast_macro(src[x]); \
+ s += t; \
+ sum[x] = sum[x - sumstep] + s; \
+ } \
+ } \
+ } \
+ else if( tilted == 0 ) \
+ { \
+ for( y = 0; y < size.height; y++, src += srcstep, \
+ sum += sumstep, sqsum += sqsumstep ) \
+ { \
+ sum[-1] = 0; \
+ sqsum[-1] = 0; \
+ \
+ for( x = 0, s = 0, sq = 0; x < size.width; x++ ) \
+ { \
+ worktype it = src[x]; \
+ sumtype t = cast_macro(it); \
+ sqsumtype tq = cast_sqr_macro(it); \
+ s += t; \
+ sq += tq; \
+ t = sum[x - sumstep] + s; \
+ tq = sqsum[x - sqsumstep] + sq; \
+ sum[x] = t; \
+ sqsum[x] = tq; \
+ } \
+ } \
+ } \
+ else \
+ { \
+ if( sqsum == 0 ) \
+ { \
+ assert(0); \
+ return CV_NULLPTR_ERR; \
+ } \
+ \
+ buf = (sumtype*)cvStackAlloc((size.width + 1 )* sizeof(buf[0]));\
+ sum[-1] = tilted[-1] = 0; \
+ sqsum[-1] = 0; \
+ \
+ for( x = 0, s = 0, sq = 0; x < size.width; x++ ) \
+ { \
+ worktype it = src[x]; \
+ sumtype t = cast_macro(it); \
+ sqsumtype tq = cast_sqr_macro(it); \
+ buf[x] = tilted[x] = t; \
+ s += t; \
+ sq += tq; \
+ sum[x] = s; \
+ sqsum[x] = sq; \
+ } \
+ \
+ if( size.width == 1 ) \
+ buf[1] = 0; \
+ \
+ for( y = 1; y < size.height; y++ ) \
+ { \
+ worktype it; \
+ sumtype t0; \
+ sqsumtype tq0; \
+ \
+ src += srcstep; \
+ sum += sumstep; \
+ sqsum += sqsumstep; \
+ tilted += tiltedstep; \
+ \
+ it = src[0/*x*/]; \
+ s = t0 = cast_macro(it); \
+ sq = tq0 = cast_sqr_macro(it); \
+ \
+ sum[-1] = 0; \
+ sqsum[-1] = 0; \
+ /*tilted[-1] = buf[0];*/ \
+ tilted[-1] = tilted[-tiltedstep]; \
+ \
+ sum[0] = sum[-sumstep] + t0; \
+ sqsum[0] = sqsum[-sqsumstep] + tq0; \
+ tilted[0] = tilted[-tiltedstep] + t0 + buf[1]; \
+ \
+ for( x = 1; x < size.width - 1; x++ ) \
+ { \
+ sumtype t1 = buf[x]; \
+ buf[x-1] = t1 + t0; \
+ it = src[x]; \
+ t0 = cast_macro(it); \
+ tq0 = cast_sqr_macro(it); \
+ s += t0; \
+ sq += tq0; \
+ sum[x] = sum[x - sumstep] + s; \
+ sqsum[x] = sqsum[x - sqsumstep] + sq; \
+ t1 += buf[x+1] + t0 + tilted[x - tiltedstep - 1];\
+ tilted[x] = t1; \
+ } \
+ \
+ if( size.width > 1 ) \
+ { \
+ sumtype t1 = buf[x]; \
+ buf[x-1] = t1 + t0; \
+ it = src[x]; /*+*/ \
+ t0 = cast_macro(it); \
+ tq0 = cast_sqr_macro(it); \
+ s += t0; \
+ sq += tq0; \
+ sum[x] = sum[x - sumstep] + s; \
+ sqsum[x] = sqsum[x - sqsumstep] + sq; \
+ tilted[x] = t0 + t1 + tilted[x - tiltedstep - 1];\
+ buf[x] = t0; \
+ } \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_INTEGRAL_OP_C1( 8u32s, uchar, int, double, int, CV_NOP, CV_8TO32F_SQR )
+ICV_DEF_INTEGRAL_OP_C1( 8u64f, uchar, double, double, int, CV_8TO32F, CV_8TO32F_SQR )
+ICV_DEF_INTEGRAL_OP_C1( 32f64f, float, double, double, double, CV_NOP, CV_SQR )
+ICV_DEF_INTEGRAL_OP_C1( 64f, double, double, double, double, CV_NOP, CV_SQR )
+
+
+#define ICV_DEF_INTEGRAL_OP_CN( flavor, arrtype, sumtype, sqsumtype, \
+ worktype, cast_macro, cast_sqr_macro ) \
+static CvStatus CV_STDCALL \
+icvIntegralImage_##flavor##_CnR( const arrtype* src, int srcstep,\
+ sumtype* sum, int sumstep, \
+ sqsumtype* sqsum, int sqsumstep,\
+ CvSize size, int cn ) \
+{ \
+ int x, y; \
+ srcstep /= sizeof(src[0]); \
+ \
+ memset( sum, 0, (size.width+1)*cn*sizeof(sum[0])); \
+ sumstep /= sizeof(sum[0]); \
+ sum += sumstep + cn; \
+ \
+ if( sqsum ) \
+ { \
+ memset( sqsum, 0, (size.width+1)*cn*sizeof(sqsum[0])); \
+ sqsumstep /= sizeof(sqsum[0]); \
+ sqsum += sqsumstep + cn; \
+ } \
+ \
+ size.width *= cn; \
+ \
+ if( sqsum == 0 ) \
+ { \
+ for( y = 0; y < size.height; y++, src += srcstep, \
+ sum += sumstep ) \
+ { \
+ for( x = -cn; x < 0; x++ ) \
+ sum[x] = 0; \
+ \
+ for( x = 0; x < size.width; x++ ) \
+ sum[x] = cast_macro(src[x]) + sum[x - cn]; \
+ \
+ for( x = 0; x < size.width; x++ ) \
+ sum[x] = sum[x] + sum[x - sumstep]; \
+ } \
+ } \
+ else \
+ { \
+ for( y = 0; y < size.height; y++, src += srcstep, \
+ sum += sumstep, sqsum += sqsumstep ) \
+ { \
+ for( x = -cn; x < 0; x++ ) \
+ { \
+ sum[x] = 0; \
+ sqsum[x] = 0; \
+ } \
+ \
+ for( x = 0; x < size.width; x++ ) \
+ { \
+ worktype it = src[x]; \
+ sumtype t = cast_macro(it) + sum[x-cn]; \
+ sqsumtype tq = cast_sqr_macro(it) + sqsum[x-cn];\
+ sum[x] = t; \
+ sqsum[x] = tq; \
+ } \
+ \
+ for( x = 0; x < size.width; x++ ) \
+ { \
+ sumtype t = sum[x] + sum[x - sumstep]; \
+ sqsumtype tq = sqsum[x] + sqsum[x - sqsumstep]; \
+ sum[x] = t; \
+ sqsum[x] = tq; \
+ } \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_INTEGRAL_OP_CN( 8u32s, uchar, int, double, int, CV_NOP, CV_8TO32F_SQR )
+ICV_DEF_INTEGRAL_OP_CN( 8u64f, uchar, double, double, int, CV_8TO32F, CV_8TO32F_SQR )
+ICV_DEF_INTEGRAL_OP_CN( 32f64f, float, double, double, double, CV_NOP, CV_SQR )
+ICV_DEF_INTEGRAL_OP_CN( 64f, double, double, double, double, CV_NOP, CV_SQR )
+
+
+static void icvInitIntegralImageTable( CvFuncTable* table_c1, CvFuncTable* table_cn )
+{
+ table_c1->fn_2d[CV_8U] = (void*)icvIntegralImage_8u64f_C1R;
+ table_c1->fn_2d[CV_32F] = (void*)icvIntegralImage_32f64f_C1R;
+ table_c1->fn_2d[CV_64F] = (void*)icvIntegralImage_64f_C1R;
+
+ table_cn->fn_2d[CV_8U] = (void*)icvIntegralImage_8u64f_CnR;
+ table_cn->fn_2d[CV_32F] = (void*)icvIntegralImage_32f64f_CnR;
+ table_cn->fn_2d[CV_64F] = (void*)icvIntegralImage_64f_CnR;
+}
+
+
+typedef CvStatus (CV_STDCALL * CvIntegralImageFuncC1)(
+ const void* src, int srcstep, void* sum, int sumstep,
+ void* sqsum, int sqsumstep, void* tilted, int tiltedstep,
+ CvSize size );
+
+typedef CvStatus (CV_STDCALL * CvIntegralImageFuncCn)(
+ const void* src, int srcstep, void* sum, int sumstep,
+ void* sqsum, int sqsumstep, CvSize size, int cn );
+
+icvIntegral_8u32s_C1R_t icvIntegral_8u32s_C1R_p = 0;
+icvSqrIntegral_8u32s64f_C1R_t icvSqrIntegral_8u32s64f_C1R_p = 0;
+
+CV_IMPL void
+cvIntegral( const CvArr* image, CvArr* sumImage,
+ CvArr* sumSqImage, CvArr* tiltedSumImage )
+{
+ static CvFuncTable tab_c1, tab_cn;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvIntegralImage" );
+
+ __BEGIN__;
+
+ CvMat src_stub, *src = (CvMat*)image;
+ CvMat sum_stub, *sum = (CvMat*)sumImage;
+ CvMat sqsum_stub, *sqsum = (CvMat*)sumSqImage;
+ CvMat tilted_stub, *tilted = (CvMat*)tiltedSumImage;
+ int coi0 = 0, coi1 = 0, coi2 = 0, coi3 = 0;
+ int depth, cn;
+ int src_step, sum_step, sqsum_step, tilted_step;
+ CvIntegralImageFuncC1 func_c1 = 0;
+ CvIntegralImageFuncCn func_cn = 0;
+ CvSize size;
+
+ if( !inittab )
+ {
+ icvInitIntegralImageTable( &tab_c1, &tab_cn );
+ inittab = 1;
+ }
+
+ CV_CALL( src = cvGetMat( src, &src_stub, &coi0 ));
+ CV_CALL( sum = cvGetMat( sum, &sum_stub, &coi1 ));
+
+ if( sum->width != src->width + 1 ||
+ sum->height != src->height + 1 )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( (CV_MAT_DEPTH( sum->type ) != CV_64F &&
+ (CV_MAT_DEPTH( src->type ) != CV_8U ||
+ CV_MAT_DEPTH( sum->type ) != CV_32S )) ||
+ !CV_ARE_CNS_EQ( src, sum ))
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Sum array must have 64f type (or 32s type in case of 8u source array) "
+ "and the same number of channels as the source array" );
+
+ if( sqsum )
+ {
+ CV_CALL( sqsum = cvGetMat( sqsum, &sqsum_stub, &coi2 ));
+ if( !CV_ARE_SIZES_EQ( sum, sqsum ) )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+ if( CV_MAT_DEPTH( sqsum->type ) != CV_64F || !CV_ARE_CNS_EQ( src, sqsum ))
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Squares sum array must be 64f "
+ "and the same number of channels as the source array" );
+ }
+
+ if( tilted )
+ {
+ if( !sqsum )
+ CV_ERROR( CV_StsNullPtr,
+ "Squared sum array must be passed if tilted sum array is passed" );
+
+ CV_CALL( tilted = cvGetMat( tilted, &tilted_stub, &coi3 ));
+ if( !CV_ARE_SIZES_EQ( sum, tilted ) )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+ if( !CV_ARE_TYPES_EQ( sum, tilted ) )
+ CV_ERROR( CV_StsUnmatchedFormats,
+ "Sum and tilted sum must have the same types" );
+ if( CV_MAT_CN(tilted->type) != 1 )
+ CV_ERROR( CV_StsNotImplemented,
+ "Tilted sum can not be computed for multi-channel arrays" );
+ }
+
+ if( coi0 || coi1 || coi2 || coi3 )
+ CV_ERROR( CV_BadCOI, "COI is not supported by the function" );
+
+ depth = CV_MAT_DEPTH(src->type);
+ cn = CV_MAT_CN(src->type);
+
+ if( CV_MAT_DEPTH( sum->type ) == CV_32S )
+ {
+ func_c1 = (CvIntegralImageFuncC1)icvIntegralImage_8u32s_C1R;
+ func_cn = (CvIntegralImageFuncCn)icvIntegralImage_8u32s_CnR;
+ }
+ else
+ {
+ func_c1 = (CvIntegralImageFuncC1)tab_c1.fn_2d[depth];
+ func_cn = (CvIntegralImageFuncCn)tab_cn.fn_2d[depth];
+ if( !func_c1 && !func_cn )
+ CV_ERROR( CV_StsUnsupportedFormat, "This source image format is unsupported" );
+ }
+
+ size = cvGetMatSize(src);
+ src_step = src->step ? src->step : CV_STUB_STEP;
+ sum_step = sum->step ? sum->step : CV_STUB_STEP;
+ sqsum_step = !sqsum ? 0 : sqsum->step ? sqsum->step : CV_STUB_STEP;
+ tilted_step = !tilted ? 0 : tilted->step ? tilted->step : CV_STUB_STEP;
+
+ if( cn == 1 )
+ {
+ if( depth == CV_8U && !tilted && CV_MAT_DEPTH(sum->type) == CV_32S )
+ {
+ if( !sqsum && icvIntegral_8u32s_C1R_p &&
+ icvIntegral_8u32s_C1R_p( src->data.ptr, src_step,
+ sum->data.i, sum_step, size, 0 ) >= 0 )
+ EXIT;
+
+ if( sqsum && icvSqrIntegral_8u32s64f_C1R_p &&
+ icvSqrIntegral_8u32s64f_C1R_p( src->data.ptr, src_step, sum->data.i,
+ sum_step, sqsum->data.db, sqsum_step, size, 0, 0 ) >= 0 )
+ EXIT;
+ }
+
+ IPPI_CALL( func_c1( src->data.ptr, src_step, sum->data.ptr, sum_step,
+ sqsum ? sqsum->data.ptr : 0, sqsum_step,
+ tilted ? tilted->data.ptr : 0, tilted_step, size ));
+ }
+ else
+ {
+ IPPI_CALL( func_cn( src->data.ptr, src_step, sum->data.ptr, sum_step,
+ sqsum ? sqsum->data.ptr : 0, sqsum_step, size, cn ));
+ }
+
+ __END__;
+}
+
+
+/* End of file. */
diff --git a/cv/src/cvsurf.cpp b/cv/src/cvsurf.cpp
new file mode 100644
index 0000000..75b0f41
--- /dev/null
+++ b/cv/src/cvsurf.cpp
@@ -0,0 +1,562 @@
+/* Original code has been submitted by Liu Liu. Here is the copyright.
+----------------------------------------------------------------------------------
+ * An OpenCV Implementation of SURF
+ * Further Information Refer to "SURF: Speed-Up Robust Feature"
+ * Author: Liu Liu
+ * liuliu.1987+opencv@gmail.com
+ *
+ * There are still serveral lacks for this experimental implementation:
+ * 1.The interpolation of sub-pixel mentioned in article was not implemented yet;
+ * 2.A comparision with original libSurf.so shows that the hessian detector is not a 100% match to their implementation;
+ * 3.Due to above reasons, I recommanded the original one for study and reuse;
+ *
+ * However, the speed of this implementation is something comparable to original one.
+ *
+ * Copyright© 2008, Liu Liu All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ * The name of Contributor may not be used to endorse or
+ * promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+/*
+ The following changes have been made, comparing to the original contribution:
+ 1. A lot of small optimizations, less memory allocations, got rid of global buffers
+ 2. Reversed order of cvGetQuadrangleSubPix and cvResize calls; probably less accurate, but much faster
+ 3. The descriptor computing part (which is most expensive) is threaded using OpenMP
+ (subpixel-accurate keypoint localization and scale estimation are still TBD)
+*/
+
+#include "_cv.h"
+
+CvSURFParams cvSURFParams(double threshold, int extended)
+{
+ CvSURFParams params;
+ params.hessianThreshold = threshold;
+ params.extended = extended;
+ params.nOctaves = 3;
+ params.nOctaveLayers = 4;
+ return params;
+}
+
+struct CvSurfHF
+{
+ int p0, p1, p2, p3;
+ float w;
+};
+
+CV_INLINE float
+icvCalcHaarPattern( const int* origin, const CvSurfHF* f, int n )
+{
+ double d = 0;
+ for( int k = 0; k < n; k++ )
+ d += (origin[f[k].p0] + origin[f[k].p3] - origin[f[k].p1] - origin[f[k].p2])*f[k].w;
+ return (float)d;
+}
+
+static void
+icvResizeHaarPattern( const int src[][5], CvSurfHF* dst, int n, int oldSize, int newSize, int widthStep )
+{
+ for( int k = 0; k < n; k++ )
+ {
+ int dx1 = src[k][0]*newSize/oldSize;
+ int dy1 = src[k][1]*newSize/oldSize;
+ int dx2 = src[k][2]*newSize/oldSize;
+ int dy2 = src[k][3]*newSize/oldSize;
+ dst[k].p0 = dy1*widthStep + dx1;
+ dst[k].p1 = dy2*widthStep + dx1;
+ dst[k].p2 = dy1*widthStep + dx2;
+ dst[k].p3 = dy2*widthStep + dx2;
+ dst[k].w = src[k][4]/((float)(dx2-dx1)*(dy2-dy1));
+ }
+}
+
+static CvSeq* icvFastHessianDetector( const CvMat* sum, const CvMat* mask_sum,
+ CvMemStorage* storage, const CvSURFParams* params )
+{
+ CvSeq* points = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSURFPoint), storage );
+
+ int totalLayers = params->nOctaves*(params->nOctaveLayers+2);
+ CvMat** hessians = (CvMat**)cvStackAlloc(totalLayers*sizeof(hessians[0]));
+ CvMat** traces = (CvMat**)cvStackAlloc(totalLayers*sizeof(traces[0]));
+ int size, *sizeCache = (int*)cvStackAlloc(totalLayers*sizeof(sizeCache[0]));
+ int scale, *scaleCache = (int*)cvStackAlloc(totalLayers*sizeof(scaleCache[0]));
+
+ const int NX=3, NY=3, NXY=4, SIZE0=9;
+ int dx_s[NX][5] = { {0, 2, 3, 7, 1}, {3, 2, 6, 7, -2}, {6, 2, 9, 7, 1} };
+ int dy_s[NY][5] = { {2, 0, 7, 3, 1}, {2, 3, 7, 6, -2}, {2, 6, 7, 9, 1} };
+ int dxy_s[NXY][5] = { {1, 1, 4, 4, 1}, {5, 1, 8, 4, -1}, {1, 5, 4, 8, -1}, {5, 5, 8, 8, 1} };
+ int dm[1][5] = { {0, 0, 9, 9, 1} };
+ CvSurfHF Dx[NX], Dy[NY], Dxy[NXY], Dm;
+ double dx = 0, dy = 0, dxy = 0;
+ int hessian_rows, hessian_cols;
+
+ int octave, sc;
+ int i, j, k, z;
+ int* xofs = (int*)cvStackAlloc(sum->cols*sizeof(xofs[0]));
+
+ /* hessian detector */
+ for( octave = k = 0; octave < params->nOctaves; octave++ )
+ {
+ for( sc = -1; sc <= params->nOctaveLayers; sc++, k++ )
+ {
+ if ( sc < 0 )
+ sizeCache[k] = size = 7 << octave; // gaussian scale 1.0;
+ else
+ sizeCache[k] = size = (sc*6 + 9) << octave; // gaussian scale size*1.2/9.;
+ scaleCache[k] = scale = MAX(size, SIZE0);
+
+ hessian_rows = (sum->rows)*SIZE0/scale;
+ hessian_cols = (sum->cols)*SIZE0/scale;
+ hessians[k] = cvCreateMat( hessian_rows, hessian_cols, CV_32FC1 );
+ traces[k] = cvCreateMat( hessian_rows, hessian_cols, CV_32FC1 );
+
+ icvResizeHaarPattern( dx_s, Dx, NX, SIZE0, size, sum->cols );
+ icvResizeHaarPattern( dy_s, Dy, NY, SIZE0, size, sum->cols );
+ icvResizeHaarPattern( dxy_s, Dxy, NXY, SIZE0, size, sum->cols );
+ for( i = 0; i < NXY; i++ )
+ Dxy[i].w *= 0.9f;
+
+ float* hessian = hessians[k]->data.fl;
+ float* trace = traces[k]->data.fl;
+
+ for( i = 0; i < hessian_cols*(SIZE0/2); i++ )
+ hessian[i] = hessian[hessian_cols*hessian_rows-1-i] =
+ trace[i] = trace[hessian_cols*hessian_rows-1-i] = 0.f;
+
+ hessian += (SIZE0/2)*(hessian_cols + 1);
+ trace += (SIZE0/2)*(hessian_cols + 1);
+
+ for( j = 0; j <= hessian_cols - SIZE0; j++ )
+ xofs[j] = j*scale/SIZE0;
+
+ for( i = 0; i < hessian_rows - SIZE0; i++,
+ trace += hessian_cols, hessian += hessian_cols )
+ {
+ const int* sum_ptr = sum->data.i + sum->cols*(i*scale/SIZE0);
+ for( j = 0; j < SIZE0/2; j++ )
+ hessian[-j-1] = hessian[hessian_cols - SIZE0 + j] =
+ trace[-j-1] = trace[hessian_cols - SIZE0 + j] = 0.f;
+ for( j = 0; j <= hessian_cols - SIZE0; j++ )
+ {
+ const int* s = sum_ptr + xofs[j];
+ dx = (s[Dx[0].p0] + s[Dx[0].p3] - s[Dx[0].p1] - s[Dx[0].p2])*Dx[0].w +
+ (s[Dx[1].p0] + s[Dx[1].p3] - s[Dx[1].p1] - s[Dx[1].p2])*Dx[1].w +
+ (s[Dx[2].p0] + s[Dx[2].p3] - s[Dx[2].p1] - s[Dx[2].p2])*Dx[2].w;
+ dy = (s[Dy[0].p0] + s[Dy[0].p3] - s[Dy[0].p1] - s[Dy[0].p2])*Dy[0].w +
+ (s[Dy[1].p0] + s[Dy[1].p3] - s[Dy[1].p1] - s[Dy[1].p2])*Dy[1].w +
+ (s[Dy[2].p0] + s[Dy[2].p3] - s[Dy[2].p1] - s[Dy[2].p2])*Dy[2].w;
+ dxy = (s[Dxy[0].p0] + s[Dxy[0].p3] - s[Dxy[0].p1] - s[Dxy[0].p2])*Dxy[0].w +
+ (s[Dxy[1].p0] + s[Dxy[1].p3] - s[Dxy[1].p1] - s[Dxy[1].p2])*Dxy[1].w +
+ (s[Dxy[2].p0] + s[Dxy[2].p3] - s[Dxy[2].p1] - s[Dxy[2].p2])*Dxy[2].w +
+ (s[Dxy[3].p0] + s[Dxy[3].p3] - s[Dxy[3].p1] - s[Dxy[3].p2])*Dxy[3].w;
+ hessian[j] = (float)(dx*dy - dxy*dxy);
+ trace[j] = (float)(dx + dy);
+ }
+ }
+ }
+ }
+
+ for( octave = 0, k = 1; octave < params->nOctaves; octave++, k+=2 )
+ {
+ for( sc = 0; sc < params->nOctaveLayers; sc++, k++ )
+ {
+ size = sizeCache[k];
+ scale = scaleCache[k];
+ hessian_rows = hessians[k]->rows;
+ hessian_cols = hessians[k]->cols;
+ icvResizeHaarPattern( dm, &Dm, 1, SIZE0, size, mask_sum ? mask_sum->cols : sum->cols );
+ int margin = 5*scaleCache[k+1]/scale;
+ for( i = margin; i < hessian_rows-margin; i++ )
+ {
+ const float* hessian = hessians[k]->data.fl + i*hessian_cols;
+ const float* trace = traces[k]->data.fl + i*hessian_cols;
+ for( j = margin; j < hessian_cols-margin; j++ )
+ {
+ float val0 = hessian[j];
+ if( val0 > params->hessianThreshold )
+ {
+ bool suppressed = false;
+ if( mask_sum )
+ {
+ const int* mask_ptr = mask_sum->data.i +
+ mask_sum->cols*((i-SIZE0/2)*scale/SIZE0) +
+ (j - SIZE0/2)*scale/SIZE0;
+ float mval = icvCalcHaarPattern( mask_ptr, &Dm, 1 );
+ if( mval < 0.5 )
+ continue;
+ }
+
+ /* non-maxima suppression */
+ for( z = k-1; z < k+2; z++ )
+ {
+ int hcols_z = hessians[z]->cols;
+ const float* hessian = hessians[z]->data.fl + (j*scale+scaleCache[z]/2)/scaleCache[z]-1 +
+ ((i*scale + scaleCache[z]/2)/scaleCache[z]-1)*hcols_z;
+ if( val0 < hessian[0] || val0 < hessian[1] || val0 < hessian[2] ||
+ val0 < hessian[hcols_z] || val0 < hessian[hcols_z+1] ||
+ val0 < hessian[hcols_z+2] || val0 < hessian[hcols_z*2] ||
+ val0 < hessian[hcols_z*2+1] || val0 < hessian[hcols_z*2+2] )
+ {
+ suppressed = true;
+ break;
+ }
+ }
+ if( !suppressed )
+ {
+ double trace_val = trace[j];
+ CvSURFPoint point = cvSURFPoint( cvPoint2D32f(j*scale/9.f, i*scale/9.f),
+ CV_SIGN(trace_val), sizeCache[k], 0, val0 );
+ cvSeqPush( points, &point );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for( octave = k = 0; octave < params->nOctaves; octave++ )
+ for( sc = -1; sc <= params->nOctaveLayers; sc++, k++ )
+ {
+ cvReleaseMat( &hessians[k] );
+ cvReleaseMat( &traces[k] );
+ }
+ return points;
+}
+
+
+CV_IMPL void
+cvExtractSURF( const CvArr* _img, const CvArr* _mask,
+ CvSeq** _keypoints, CvSeq** _descriptors,
+ CvMemStorage* storage, CvSURFParams params )
+{
+ CvMat *sum = 0, *mask1 = 0, *mask_sum = 0;
+
+ if( _keypoints )
+ *_keypoints = 0;
+ if( _descriptors )
+ *_descriptors = 0;
+
+ CV_FUNCNAME( "cvExtractSURF" );
+
+ __BEGIN__;
+
+ CvSeq *keypoints, *descriptors = 0;
+ CvMat imghdr, *img = cvGetMat(_img, &imghdr);
+ CvMat maskhdr, *mask = _mask ? cvGetMat(_mask, &maskhdr) : 0;
+
+ int descriptor_size = params.extended ? 128 : 64;
+ const int descriptor_data_type = CV_32F;
+ const int NX=2, NY=2;
+ const float sqrt_2 = 1.4142135623730950488016887242097f;
+ const int PATCH_SZ = 20;
+ const int RS_PATCH_SZ = 30; // ceil((PATCH_SZ+1)*sqrt_2);
+ int dx_s[NX][5] = {{0, 0, 2, 4, -1}, {2, 0, 4, 4, 1}};
+ int dy_s[NY][5] = {{0, 0, 4, 2, 1}, {0, 2, 4, 4, -1}};
+ float G[9] = {0,0,0,0,0,0,0,0,0};
+ CvMat _G = cvMat(1, 9, CV_32F, G);
+ float DW[PATCH_SZ][PATCH_SZ];
+ CvMat _DW = cvMat(PATCH_SZ, PATCH_SZ, CV_32F, DW);
+ CvPoint apt[81];
+ int i, j, k, nangle0 = 0, N;
+
+ CV_ASSERT( img != 0 && CV_MAT_TYPE(img->type) == CV_8UC1 &&
+ (mask == 0 || (CV_ARE_SIZES_EQ(img,mask) &&
+ CV_MAT_TYPE(mask->type) == CV_8UC1)) &&
+ storage != 0 && params.hessianThreshold >= 0 &&
+ params.nOctaves > 0 && params.nOctaveLayers > 0 );
+
+ sum = cvCreateMat( img->height+1, img->width+1, CV_32SC1 );
+ cvIntegral( img, sum );
+ if( mask )
+ {
+ mask1 = cvCreateMat( img->height, img->width, CV_8UC1 );
+ mask_sum = cvCreateMat( img->height+1, img->width+1, CV_32SC1 );
+ cvMinS( mask, 1, mask1 );
+ cvIntegral( mask1, mask_sum );
+ }
+ keypoints = icvFastHessianDetector( sum, mask_sum, storage, &params );
+ N = keypoints->total;
+ if( _descriptors )
+ {
+ descriptors = cvCreateSeq( 0, sizeof(CvSeq),
+ descriptor_size*CV_ELEM_SIZE(descriptor_data_type), storage );
+ cvSeqPushMulti( descriptors, 0, N );
+ }
+
+ CvSepFilter::init_gaussian_kernel( &_G, 2.5 );
+
+ {
+ const double sigma = 3.3;
+ double c2 = 1./(sigma*sigma*2), gs = 0;
+ for( i = 0; i < PATCH_SZ; i++ )
+ {
+ for( j = 0; j < PATCH_SZ; j++ )
+ {
+ double x = j - PATCH_SZ*0.5, y = i - PATCH_SZ*0.5;
+ double val = exp(-(x*x+y*y)*c2);
+ DW[i][j] = (float)val;
+ gs += val;
+ }
+ }
+ cvScale( &_DW, &_DW, 1./gs );
+ }
+
+ for( i = -4; i <= 4; i++ )
+ for( j = -4; j <= 4; j++ )
+ {
+ if( i*i + j*j <= 16 )
+ apt[nangle0++] = cvPoint(j,i);
+ }
+
+ {
+#ifdef _OPENMP
+ int nthreads = cvGetNumThreads();
+#pragma omp parallel for num_threads(nthreads) schedule(dynamic)
+#endif
+ for( k = 0; k < N; k++ )
+ {
+ const int* sum_ptr = sum->data.i;
+ int sum_cols = sum->cols;
+ int i, j, kk, x, y, nangle;
+ CvSurfHF dx_t[NX], dy_t[NY];
+ float X[81], Y[81], angle[81];
+ uchar PATCH[PATCH_SZ+1][PATCH_SZ+1], RS_PATCH[RS_PATCH_SZ][RS_PATCH_SZ];
+ float DX[PATCH_SZ][PATCH_SZ], DY[PATCH_SZ][PATCH_SZ];
+ CvMat _X = cvMat(1, 81, CV_32F, X);
+ CvMat _Y = cvMat(1, 81, CV_32F, Y);
+ CvMat _angle = cvMat(1, 81, CV_32F, angle);
+ CvMat _patch = cvMat(PATCH_SZ+1, PATCH_SZ+1, CV_8U, PATCH);
+ CvMat _rs_patch = cvMat(RS_PATCH_SZ, RS_PATCH_SZ, CV_8U, RS_PATCH);
+ CvMat _src, *src = img;
+
+ CvSURFPoint* kp = (CvSURFPoint*)cvGetSeqElem( keypoints, k );
+ CvPoint2D32f center = kp->pt;
+ int size = kp->size;
+ icvResizeHaarPattern( dx_s, dx_t, NX, 9, size, sum->cols );
+ icvResizeHaarPattern( dy_s, dy_t, NY, 9, size, sum->cols );
+ CvPoint pt = cvPointFrom32f(center);
+ float* vec;
+ float alpha0, beta0, sz0, scale0;
+
+ for( kk = 0, nangle = 0; kk < nangle0; kk++ )
+ {
+ j = apt[kk].x; i = apt[kk].y;
+ int x = pt.x + (j-2)*size/9;
+ int y = pt.y + (i-2)*size/9;
+ const int* ptr;
+ float vx, vy, w;
+ if( (unsigned)y >= (unsigned)sum->rows - size ||
+ (unsigned)x >= (unsigned)sum->cols - size )
+ continue;
+ ptr = sum_ptr + x + y*sum_cols;
+ w = G[i+4]*G[j+4];
+ vx = icvCalcHaarPattern( ptr, dx_t, NX )*w;
+ vy = icvCalcHaarPattern( ptr, dy_t, NX )*w;
+ X[nangle] = vx; Y[nangle] = vy;
+ nangle++;
+ }
+ _X.cols = _Y.cols = _angle.cols = nangle;
+ cvCartToPolar( &_X, &_Y, 0, &_angle, 1 );
+
+ float bestx = 0, besty = 0, descriptor_mod = 0;
+ for( i = 0; i < 360; i += 5 )
+ {
+ float sumx = 0, sumy = 0, temp_mod;
+ for( j = 0; j < nangle; j++ )
+ {
+ int d = abs(cvRound(angle[j]) - i);
+ if( d < 60 || d > 300 )
+ {
+ sumx += X[j];
+ sumy += Y[j];
+ }
+ }
+ temp_mod = sumx*sumx + sumy*sumy;
+ if( temp_mod > descriptor_mod )
+ {
+ descriptor_mod = temp_mod;
+ bestx = sumx;
+ besty = sumy;
+ }
+ }
+
+ float descriptor_dir = cvFastArctan( besty, bestx );
+ kp->dir = descriptor_dir;
+
+ if( !_descriptors )
+ continue;
+ descriptor_dir *= (float)(CV_PI/180);
+
+ alpha0 = (float)cos(descriptor_dir);
+ beta0 = (float)sin(descriptor_dir);
+ sz0 = (float)((PATCH_SZ+1)*size*1.2/9.);
+ scale0 = sz0/(PATCH_SZ+1);
+
+ if( sz0 > (PATCH_SZ+1)*1.5f )
+ {
+ float rd = (float)(sz0*sqrt_2*0.5);
+ float alpha1 = (alpha0 - beta0)*sqrt_2*0.5f, beta1 = (alpha0 + beta0)*sqrt_2*0.5f;
+ CvRect patch_rect0 = { INT_MAX, INT_MAX, INT_MIN, INT_MIN }, patch_rect, sr_patch_rect;
+
+ for( i = 0; i < 4; i++ )
+ {
+ float a, b, r = i < 2 ? rd : -rd;
+ if( i % 2 == 0 )
+ a = alpha1, b = beta1;
+ else
+ a = -beta1, b = alpha1;
+ float xf = center.x + r*a;
+ float yf = center.y - r*b;
+ x = cvFloor(xf); patch_rect0.x = MIN(patch_rect0.x, x);
+ y = cvFloor(yf); patch_rect0.y = MIN(patch_rect0.y, y);
+ x = cvCeil(xf)+1; patch_rect0.width = MAX(patch_rect0.width, x);
+ y = cvCeil(yf)+1; patch_rect0.height = MAX(patch_rect0.height, y);
+ }
+
+ patch_rect = patch_rect0;
+ patch_rect.x = MAX(patch_rect.x, 0);
+ patch_rect.y = MAX(patch_rect.y, 0);
+ patch_rect.width = MIN(patch_rect.width, img->width) - patch_rect.x;
+ patch_rect.height = MIN(patch_rect.height, img->height) - patch_rect.y;
+ patch_rect0.width -= patch_rect0.x;
+ patch_rect0.height -= patch_rect0.y;
+
+ CvMat _src0;
+ float scale = MIN(1.f,MIN((float)RS_PATCH_SZ/patch_rect0.width,
+ (float)RS_PATCH_SZ/patch_rect0.height));
+ cvGetSubArr( img, &_src0, patch_rect );
+ sr_patch_rect = cvRect(0,0, RS_PATCH_SZ, RS_PATCH_SZ);
+ sr_patch_rect.width = cvRound(patch_rect.width*scale);
+ sr_patch_rect.height = cvRound(patch_rect.height*scale);
+ src = cvGetSubArr( &_rs_patch, &_src, sr_patch_rect );
+ cvResize( &_src0, &_src, CV_INTER_AREA );
+ center.x = RS_PATCH_SZ*0.5f - (patch_rect.x - patch_rect0.x)*scale;
+ center.y = RS_PATCH_SZ*0.5f - (patch_rect.y - patch_rect0.y)*scale;
+ scale0 *= scale;
+ }
+
+ {
+ float w[] =
+ {
+ alpha0*scale0, beta0*scale0, center.x,
+ -beta0*scale0, alpha0*scale0, center.y
+ };
+ CvMat W = cvMat(2, 3, CV_32F, w);
+ cvGetQuadrangleSubPix( src, &_patch, &W );
+ }
+
+ for( i = 0; i < PATCH_SZ; i++ )
+ for( j = 0; j < PATCH_SZ; j++ )
+ {
+ float dw = DW[i][j];
+ float vx = (PATCH[i][j+1] - PATCH[i][j] + PATCH[i+1][j+1] - PATCH[i+1][j])*dw;
+ float vy = (PATCH[i+1][j] - PATCH[i][j] + PATCH[i+1][j+1] - PATCH[i][j+1])*dw;
+ DX[i][j] = vx;
+ DY[i][j] = vy;
+ }
+
+ vec = (float*)cvGetSeqElem( descriptors, k );
+ for( kk = 0; kk < (int)(descriptors->elem_size/sizeof(vec[0])); kk++ )
+ vec[kk] = 0;
+ if( params.extended )
+ {
+ /* 128-bin descriptor */
+ for( i = 0; i < 4; i++ )
+ for( j = 0; j < 4; j++ )
+ {
+ for( y = i*5; y < i*5+5; y++ )
+ {
+ for( x = j*5; x < j*5+5; x++ )
+ {
+ float tx = DX[y][x], ty = DY[y][x];
+ if( ty >= 0 )
+ {
+ vec[0] += tx;
+ vec[1] += (float)fabs(tx);
+ } else {
+ vec[2] += tx;
+ vec[3] += (float)fabs(tx);
+ }
+ if ( tx >= 0 )
+ {
+ vec[4] += ty;
+ vec[5] += (float)fabs(ty);
+ } else {
+ vec[6] += ty;
+ vec[7] += (float)fabs(ty);
+ }
+ }
+ }
+ /* unit vector is essential for contrast invariance */
+ double normalize = 0;
+ for( kk = 0; kk < 8; kk++ )
+ normalize += vec[kk]*vec[kk];
+ normalize = 1./(sqrt(normalize) + DBL_EPSILON);
+ for( kk = 0; kk < 8; kk++ )
+ vec[kk] = (float)(vec[kk]*normalize);
+ vec += 8;
+ }
+ }
+ else
+ {
+ /* 64-bin descriptor */
+ for( i = 0; i < 4; i++ )
+ for( j = 0; j < 4; j++ )
+ {
+ for( y = i*5; y < i*5+5; y++ )
+ {
+ for( x = j*5; x < j*5+5; x++ )
+ {
+ float tx = DX[y][x], ty = DY[y][x];
+ vec[0] += tx; vec[1] += ty;
+ vec[2] += (float)fabs(tx); vec[3] += (float)fabs(ty);
+ }
+ }
+ double normalize = 0;
+ for( kk = 0; kk < 4; kk++ )
+ normalize += vec[kk]*vec[kk];
+ normalize = 1./(sqrt(normalize) + DBL_EPSILON);
+ for( kk = 0; kk < 4; kk++ )
+ vec[kk] = (float)(vec[kk]*normalize);
+ vec+=4;
+ }
+ }
+ }
+ }
+
+ if( _keypoints )
+ *_keypoints = keypoints;
+ if( _descriptors )
+ *_descriptors = descriptors;
+
+ __END__;
+
+ cvReleaseMat( &sum );
+ cvReleaseMat( &mask1 );
+ cvReleaseMat( &mask_sum );
+}
diff --git a/cv/src/cvswitcher.cpp b/cv/src/cvswitcher.cpp
new file mode 100644
index 0000000..bbcc4ff
--- /dev/null
+++ b/cv/src/cvswitcher.cpp
@@ -0,0 +1,59 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+#undef IPCVAPI_EX
+#define IPCVAPI_EX(type,func_name,names,modules,arg) \
+ { (void**)&func_name##_p, (void*)(size_t)-1, names, modules, 0 },
+
+static CvPluginFuncInfo cv_ipp_tab[] =
+{
+#undef _CV_IPP_H_
+#include "_cvipp.h"
+#undef _CV_IPP_H_
+ {0, 0, 0, 0, 0}
+};
+
+static CvModuleInfo cv_info = { 0, "cv", CV_VERSION, cv_ipp_tab };
+CvModule cv_module( &cv_info );
+
+/* End of file. */
diff --git a/cv/src/cvtables.cpp b/cv/src/cvtables.cpp
new file mode 100644
index 0000000..9fe7d81
--- /dev/null
+++ b/cv/src/cvtables.cpp
@@ -0,0 +1,214 @@
+/* ////////////////////////////////////////////////////////////////////
+//
+// CvMat helper tables
+//
+// */
+
+#include "_cv.h"
+
+const float icv8x32fTab_cv[] =
+{
+ -256.f, -255.f, -254.f, -253.f, -252.f, -251.f, -250.f, -249.f,
+ -248.f, -247.f, -246.f, -245.f, -244.f, -243.f, -242.f, -241.f,
+ -240.f, -239.f, -238.f, -237.f, -236.f, -235.f, -234.f, -233.f,
+ -232.f, -231.f, -230.f, -229.f, -228.f, -227.f, -226.f, -225.f,
+ -224.f, -223.f, -222.f, -221.f, -220.f, -219.f, -218.f, -217.f,
+ -216.f, -215.f, -214.f, -213.f, -212.f, -211.f, -210.f, -209.f,
+ -208.f, -207.f, -206.f, -205.f, -204.f, -203.f, -202.f, -201.f,
+ -200.f, -199.f, -198.f, -197.f, -196.f, -195.f, -194.f, -193.f,
+ -192.f, -191.f, -190.f, -189.f, -188.f, -187.f, -186.f, -185.f,
+ -184.f, -183.f, -182.f, -181.f, -180.f, -179.f, -178.f, -177.f,
+ -176.f, -175.f, -174.f, -173.f, -172.f, -171.f, -170.f, -169.f,
+ -168.f, -167.f, -166.f, -165.f, -164.f, -163.f, -162.f, -161.f,
+ -160.f, -159.f, -158.f, -157.f, -156.f, -155.f, -154.f, -153.f,
+ -152.f, -151.f, -150.f, -149.f, -148.f, -147.f, -146.f, -145.f,
+ -144.f, -143.f, -142.f, -141.f, -140.f, -139.f, -138.f, -137.f,
+ -136.f, -135.f, -134.f, -133.f, -132.f, -131.f, -130.f, -129.f,
+ -128.f, -127.f, -126.f, -125.f, -124.f, -123.f, -122.f, -121.f,
+ -120.f, -119.f, -118.f, -117.f, -116.f, -115.f, -114.f, -113.f,
+ -112.f, -111.f, -110.f, -109.f, -108.f, -107.f, -106.f, -105.f,
+ -104.f, -103.f, -102.f, -101.f, -100.f, -99.f, -98.f, -97.f,
+ -96.f, -95.f, -94.f, -93.f, -92.f, -91.f, -90.f, -89.f,
+ -88.f, -87.f, -86.f, -85.f, -84.f, -83.f, -82.f, -81.f,
+ -80.f, -79.f, -78.f, -77.f, -76.f, -75.f, -74.f, -73.f,
+ -72.f, -71.f, -70.f, -69.f, -68.f, -67.f, -66.f, -65.f,
+ -64.f, -63.f, -62.f, -61.f, -60.f, -59.f, -58.f, -57.f,
+ -56.f, -55.f, -54.f, -53.f, -52.f, -51.f, -50.f, -49.f,
+ -48.f, -47.f, -46.f, -45.f, -44.f, -43.f, -42.f, -41.f,
+ -40.f, -39.f, -38.f, -37.f, -36.f, -35.f, -34.f, -33.f,
+ -32.f, -31.f, -30.f, -29.f, -28.f, -27.f, -26.f, -25.f,
+ -24.f, -23.f, -22.f, -21.f, -20.f, -19.f, -18.f, -17.f,
+ -16.f, -15.f, -14.f, -13.f, -12.f, -11.f, -10.f, -9.f,
+ -8.f, -7.f, -6.f, -5.f, -4.f, -3.f, -2.f, -1.f,
+ 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f,
+ 8.f, 9.f, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f,
+ 16.f, 17.f, 18.f, 19.f, 20.f, 21.f, 22.f, 23.f,
+ 24.f, 25.f, 26.f, 27.f, 28.f, 29.f, 30.f, 31.f,
+ 32.f, 33.f, 34.f, 35.f, 36.f, 37.f, 38.f, 39.f,
+ 40.f, 41.f, 42.f, 43.f, 44.f, 45.f, 46.f, 47.f,
+ 48.f, 49.f, 50.f, 51.f, 52.f, 53.f, 54.f, 55.f,
+ 56.f, 57.f, 58.f, 59.f, 60.f, 61.f, 62.f, 63.f,
+ 64.f, 65.f, 66.f, 67.f, 68.f, 69.f, 70.f, 71.f,
+ 72.f, 73.f, 74.f, 75.f, 76.f, 77.f, 78.f, 79.f,
+ 80.f, 81.f, 82.f, 83.f, 84.f, 85.f, 86.f, 87.f,
+ 88.f, 89.f, 90.f, 91.f, 92.f, 93.f, 94.f, 95.f,
+ 96.f, 97.f, 98.f, 99.f, 100.f, 101.f, 102.f, 103.f,
+ 104.f, 105.f, 106.f, 107.f, 108.f, 109.f, 110.f, 111.f,
+ 112.f, 113.f, 114.f, 115.f, 116.f, 117.f, 118.f, 119.f,
+ 120.f, 121.f, 122.f, 123.f, 124.f, 125.f, 126.f, 127.f,
+ 128.f, 129.f, 130.f, 131.f, 132.f, 133.f, 134.f, 135.f,
+ 136.f, 137.f, 138.f, 139.f, 140.f, 141.f, 142.f, 143.f,
+ 144.f, 145.f, 146.f, 147.f, 148.f, 149.f, 150.f, 151.f,
+ 152.f, 153.f, 154.f, 155.f, 156.f, 157.f, 158.f, 159.f,
+ 160.f, 161.f, 162.f, 163.f, 164.f, 165.f, 166.f, 167.f,
+ 168.f, 169.f, 170.f, 171.f, 172.f, 173.f, 174.f, 175.f,
+ 176.f, 177.f, 178.f, 179.f, 180.f, 181.f, 182.f, 183.f,
+ 184.f, 185.f, 186.f, 187.f, 188.f, 189.f, 190.f, 191.f,
+ 192.f, 193.f, 194.f, 195.f, 196.f, 197.f, 198.f, 199.f,
+ 200.f, 201.f, 202.f, 203.f, 204.f, 205.f, 206.f, 207.f,
+ 208.f, 209.f, 210.f, 211.f, 212.f, 213.f, 214.f, 215.f,
+ 216.f, 217.f, 218.f, 219.f, 220.f, 221.f, 222.f, 223.f,
+ 224.f, 225.f, 226.f, 227.f, 228.f, 229.f, 230.f, 231.f,
+ 232.f, 233.f, 234.f, 235.f, 236.f, 237.f, 238.f, 239.f,
+ 240.f, 241.f, 242.f, 243.f, 244.f, 245.f, 246.f, 247.f,
+ 248.f, 249.f, 250.f, 251.f, 252.f, 253.f, 254.f, 255.f,
+ 256.f, 257.f, 258.f, 259.f, 260.f, 261.f, 262.f, 263.f,
+ 264.f, 265.f, 266.f, 267.f, 268.f, 269.f, 270.f, 271.f,
+ 272.f, 273.f, 274.f, 275.f, 276.f, 277.f, 278.f, 279.f,
+ 280.f, 281.f, 282.f, 283.f, 284.f, 285.f, 286.f, 287.f,
+ 288.f, 289.f, 290.f, 291.f, 292.f, 293.f, 294.f, 295.f,
+ 296.f, 297.f, 298.f, 299.f, 300.f, 301.f, 302.f, 303.f,
+ 304.f, 305.f, 306.f, 307.f, 308.f, 309.f, 310.f, 311.f,
+ 312.f, 313.f, 314.f, 315.f, 316.f, 317.f, 318.f, 319.f,
+ 320.f, 321.f, 322.f, 323.f, 324.f, 325.f, 326.f, 327.f,
+ 328.f, 329.f, 330.f, 331.f, 332.f, 333.f, 334.f, 335.f,
+ 336.f, 337.f, 338.f, 339.f, 340.f, 341.f, 342.f, 343.f,
+ 344.f, 345.f, 346.f, 347.f, 348.f, 349.f, 350.f, 351.f,
+ 352.f, 353.f, 354.f, 355.f, 356.f, 357.f, 358.f, 359.f,
+ 360.f, 361.f, 362.f, 363.f, 364.f, 365.f, 366.f, 367.f,
+ 368.f, 369.f, 370.f, 371.f, 372.f, 373.f, 374.f, 375.f,
+ 376.f, 377.f, 378.f, 379.f, 380.f, 381.f, 382.f, 383.f,
+ 384.f, 385.f, 386.f, 387.f, 388.f, 389.f, 390.f, 391.f,
+ 392.f, 393.f, 394.f, 395.f, 396.f, 397.f, 398.f, 399.f,
+ 400.f, 401.f, 402.f, 403.f, 404.f, 405.f, 406.f, 407.f,
+ 408.f, 409.f, 410.f, 411.f, 412.f, 413.f, 414.f, 415.f,
+ 416.f, 417.f, 418.f, 419.f, 420.f, 421.f, 422.f, 423.f,
+ 424.f, 425.f, 426.f, 427.f, 428.f, 429.f, 430.f, 431.f,
+ 432.f, 433.f, 434.f, 435.f, 436.f, 437.f, 438.f, 439.f,
+ 440.f, 441.f, 442.f, 443.f, 444.f, 445.f, 446.f, 447.f,
+ 448.f, 449.f, 450.f, 451.f, 452.f, 453.f, 454.f, 455.f,
+ 456.f, 457.f, 458.f, 459.f, 460.f, 461.f, 462.f, 463.f,
+ 464.f, 465.f, 466.f, 467.f, 468.f, 469.f, 470.f, 471.f,
+ 472.f, 473.f, 474.f, 475.f, 476.f, 477.f, 478.f, 479.f,
+ 480.f, 481.f, 482.f, 483.f, 484.f, 485.f, 486.f, 487.f,
+ 488.f, 489.f, 490.f, 491.f, 492.f, 493.f, 494.f, 495.f,
+ 496.f, 497.f, 498.f, 499.f, 500.f, 501.f, 502.f, 503.f,
+ 504.f, 505.f, 506.f, 507.f, 508.f, 509.f, 510.f, 511.f,
+};
+
+const float icv8x32fSqrTab[] =
+{
+ 16384.f, 16129.f, 15876.f, 15625.f, 15376.f, 15129.f, 14884.f, 14641.f,
+ 14400.f, 14161.f, 13924.f, 13689.f, 13456.f, 13225.f, 12996.f, 12769.f,
+ 12544.f, 12321.f, 12100.f, 11881.f, 11664.f, 11449.f, 11236.f, 11025.f,
+ 10816.f, 10609.f, 10404.f, 10201.f, 10000.f, 9801.f, 9604.f, 9409.f,
+ 9216.f, 9025.f, 8836.f, 8649.f, 8464.f, 8281.f, 8100.f, 7921.f,
+ 7744.f, 7569.f, 7396.f, 7225.f, 7056.f, 6889.f, 6724.f, 6561.f,
+ 6400.f, 6241.f, 6084.f, 5929.f, 5776.f, 5625.f, 5476.f, 5329.f,
+ 5184.f, 5041.f, 4900.f, 4761.f, 4624.f, 4489.f, 4356.f, 4225.f,
+ 4096.f, 3969.f, 3844.f, 3721.f, 3600.f, 3481.f, 3364.f, 3249.f,
+ 3136.f, 3025.f, 2916.f, 2809.f, 2704.f, 2601.f, 2500.f, 2401.f,
+ 2304.f, 2209.f, 2116.f, 2025.f, 1936.f, 1849.f, 1764.f, 1681.f,
+ 1600.f, 1521.f, 1444.f, 1369.f, 1296.f, 1225.f, 1156.f, 1089.f,
+ 1024.f, 961.f, 900.f, 841.f, 784.f, 729.f, 676.f, 625.f,
+ 576.f, 529.f, 484.f, 441.f, 400.f, 361.f, 324.f, 289.f,
+ 256.f, 225.f, 196.f, 169.f, 144.f, 121.f, 100.f, 81.f,
+ 64.f, 49.f, 36.f, 25.f, 16.f, 9.f, 4.f, 1.f,
+ 0.f, 1.f, 4.f, 9.f, 16.f, 25.f, 36.f, 49.f,
+ 64.f, 81.f, 100.f, 121.f, 144.f, 169.f, 196.f, 225.f,
+ 256.f, 289.f, 324.f, 361.f, 400.f, 441.f, 484.f, 529.f,
+ 576.f, 625.f, 676.f, 729.f, 784.f, 841.f, 900.f, 961.f,
+ 1024.f, 1089.f, 1156.f, 1225.f, 1296.f, 1369.f, 1444.f, 1521.f,
+ 1600.f, 1681.f, 1764.f, 1849.f, 1936.f, 2025.f, 2116.f, 2209.f,
+ 2304.f, 2401.f, 2500.f, 2601.f, 2704.f, 2809.f, 2916.f, 3025.f,
+ 3136.f, 3249.f, 3364.f, 3481.f, 3600.f, 3721.f, 3844.f, 3969.f,
+ 4096.f, 4225.f, 4356.f, 4489.f, 4624.f, 4761.f, 4900.f, 5041.f,
+ 5184.f, 5329.f, 5476.f, 5625.f, 5776.f, 5929.f, 6084.f, 6241.f,
+ 6400.f, 6561.f, 6724.f, 6889.f, 7056.f, 7225.f, 7396.f, 7569.f,
+ 7744.f, 7921.f, 8100.f, 8281.f, 8464.f, 8649.f, 8836.f, 9025.f,
+ 9216.f, 9409.f, 9604.f, 9801.f, 10000.f, 10201.f, 10404.f, 10609.f,
+ 10816.f, 11025.f, 11236.f, 11449.f, 11664.f, 11881.f, 12100.f, 12321.f,
+ 12544.f, 12769.f, 12996.f, 13225.f, 13456.f, 13689.f, 13924.f, 14161.f,
+ 14400.f, 14641.f, 14884.f, 15129.f, 15376.f, 15625.f, 15876.f, 16129.f,
+ 16384.f, 16641.f, 16900.f, 17161.f, 17424.f, 17689.f, 17956.f, 18225.f,
+ 18496.f, 18769.f, 19044.f, 19321.f, 19600.f, 19881.f, 20164.f, 20449.f,
+ 20736.f, 21025.f, 21316.f, 21609.f, 21904.f, 22201.f, 22500.f, 22801.f,
+ 23104.f, 23409.f, 23716.f, 24025.f, 24336.f, 24649.f, 24964.f, 25281.f,
+ 25600.f, 25921.f, 26244.f, 26569.f, 26896.f, 27225.f, 27556.f, 27889.f,
+ 28224.f, 28561.f, 28900.f, 29241.f, 29584.f, 29929.f, 30276.f, 30625.f,
+ 30976.f, 31329.f, 31684.f, 32041.f, 32400.f, 32761.f, 33124.f, 33489.f,
+ 33856.f, 34225.f, 34596.f, 34969.f, 35344.f, 35721.f, 36100.f, 36481.f,
+ 36864.f, 37249.f, 37636.f, 38025.f, 38416.f, 38809.f, 39204.f, 39601.f,
+ 40000.f, 40401.f, 40804.f, 41209.f, 41616.f, 42025.f, 42436.f, 42849.f,
+ 43264.f, 43681.f, 44100.f, 44521.f, 44944.f, 45369.f, 45796.f, 46225.f,
+ 46656.f, 47089.f, 47524.f, 47961.f, 48400.f, 48841.f, 49284.f, 49729.f,
+ 50176.f, 50625.f, 51076.f, 51529.f, 51984.f, 52441.f, 52900.f, 53361.f,
+ 53824.f, 54289.f, 54756.f, 55225.f, 55696.f, 56169.f, 56644.f, 57121.f,
+ 57600.f, 58081.f, 58564.f, 59049.f, 59536.f, 60025.f, 60516.f, 61009.f,
+ 61504.f, 62001.f, 62500.f, 63001.f, 63504.f, 64009.f, 64516.f, 65025.f
+};
+
+const uchar icvSaturate8u_cv[] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+ 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255
+};
+
+/* End of file. */
diff --git a/cv/src/cvtemplmatch.cpp b/cv/src/cvtemplmatch.cpp
new file mode 100644
index 0000000..cd79528
--- /dev/null
+++ b/cv/src/cvtemplmatch.cpp
@@ -0,0 +1,536 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+void
+icvCrossCorr( const CvArr* _img, const CvArr* _templ, CvArr* _corr, CvPoint anchor )
+{
+ const double block_scale = 4.5;
+ const int min_block_size = 256;
+ CvMat* dft_img[CV_MAX_THREADS] = {0};
+ CvMat* dft_templ = 0;
+ void* buf[CV_MAX_THREADS] = {0};
+ int k, num_threads = 0;
+
+ CV_FUNCNAME( "icvCrossCorr" );
+
+ __BEGIN__;
+
+ CvMat istub, *img = (CvMat*)_img;
+ CvMat tstub, *templ = (CvMat*)_templ;
+ CvMat cstub, *corr = (CvMat*)_corr;
+ CvSize dftsize, blocksize;
+ int depth, templ_depth, corr_depth, max_depth = CV_32F,
+ cn, templ_cn, corr_cn, buf_size = 0,
+ tile_count_x, tile_count_y, tile_count;
+
+ CV_CALL( img = cvGetMat( img, &istub ));
+ CV_CALL( templ = cvGetMat( templ, &tstub ));
+ CV_CALL( corr = cvGetMat( corr, &cstub ));
+
+ if( CV_MAT_DEPTH( img->type ) != CV_8U &&
+ CV_MAT_DEPTH( img->type ) != CV_16U &&
+ CV_MAT_DEPTH( img->type ) != CV_32F )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "The function supports only 8u, 16u and 32f data types" );
+
+ if( !CV_ARE_DEPTHS_EQ( img, templ ) && CV_MAT_DEPTH( templ->type ) != CV_32F )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Template (kernel) must be of the same depth as the input image, or be 32f" );
+
+ if( !CV_ARE_DEPTHS_EQ( img, corr ) && CV_MAT_DEPTH( corr->type ) != CV_32F &&
+ CV_MAT_DEPTH( corr->type ) != CV_64F )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "The output image must have the same depth as the input image, or be 32f/64f" );
+
+ if( (!CV_ARE_CNS_EQ( img, corr ) || CV_MAT_CN(templ->type) > 1) &&
+ (CV_MAT_CN( corr->type ) > 1 || !CV_ARE_CNS_EQ( img, templ)) )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "The output must have the same number of channels as the input (when the template has 1 channel), "
+ "or the output must have 1 channel when the input and the template have the same number of channels" );
+
+ depth = CV_MAT_DEPTH(img->type);
+ cn = CV_MAT_CN(img->type);
+ templ_depth = CV_MAT_DEPTH(templ->type);
+ templ_cn = CV_MAT_CN(templ->type);
+ corr_depth = CV_MAT_DEPTH(corr->type);
+ corr_cn = CV_MAT_CN(corr->type);
+ max_depth = MAX( max_depth, templ_depth );
+ max_depth = MAX( max_depth, depth );
+ max_depth = MAX( max_depth, corr_depth );
+ if( depth > CV_8U )
+ max_depth = CV_64F;
+
+ if( img->cols < templ->cols || img->rows < templ->rows )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Such a combination of image and template/filter size is not supported" );
+
+ if( corr->rows > img->rows + templ->rows - 1 ||
+ corr->cols > img->cols + templ->cols - 1 )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "output image should not be greater than (W + w - 1)x(H + h - 1)" );
+
+ blocksize.width = cvRound(templ->cols*block_scale);
+ blocksize.width = MAX( blocksize.width, min_block_size - templ->cols + 1 );
+ blocksize.width = MIN( blocksize.width, corr->cols );
+ blocksize.height = cvRound(templ->rows*block_scale);
+ blocksize.height = MAX( blocksize.height, min_block_size - templ->rows + 1 );
+ blocksize.height = MIN( blocksize.height, corr->rows );
+
+ dftsize.width = cvGetOptimalDFTSize(blocksize.width + templ->cols - 1);
+ if( dftsize.width == 1 )
+ dftsize.width = 2;
+ dftsize.height = cvGetOptimalDFTSize(blocksize.height + templ->rows - 1);
+ if( dftsize.width <= 0 || dftsize.height <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "the input arrays are too big" );
+
+ // recompute block size
+ blocksize.width = dftsize.width - templ->cols + 1;
+ blocksize.width = MIN( blocksize.width, corr->cols );
+ blocksize.height = dftsize.height - templ->rows + 1;
+ blocksize.height = MIN( blocksize.height, corr->rows );
+
+ CV_CALL( dft_templ = cvCreateMat( dftsize.height*templ_cn, dftsize.width, max_depth ));
+
+ num_threads = cvGetNumThreads();
+
+ for( k = 0; k < num_threads; k++ )
+ CV_CALL( dft_img[k] = cvCreateMat( dftsize.height, dftsize.width, max_depth ));
+
+ if( templ_cn > 1 && templ_depth != max_depth )
+ buf_size = templ->cols*templ->rows*CV_ELEM_SIZE(templ_depth);
+
+ if( cn > 1 && depth != max_depth )
+ buf_size = MAX( buf_size, (blocksize.width + templ->cols - 1)*
+ (blocksize.height + templ->rows - 1)*CV_ELEM_SIZE(depth));
+
+ if( (corr_cn > 1 || cn > 1) && corr_depth != max_depth )
+ buf_size = MAX( buf_size, blocksize.width*blocksize.height*CV_ELEM_SIZE(corr_depth));
+
+ if( buf_size > 0 )
+ {
+ for( k = 0; k < num_threads; k++ )
+ CV_CALL( buf[k] = cvAlloc(buf_size) );
+ }
+
+ // compute DFT of each template plane
+ for( k = 0; k < templ_cn; k++ )
+ {
+ CvMat dstub, *src, *dst, temp;
+ CvMat* planes[] = { 0, 0, 0, 0 };
+ int yofs = k*dftsize.height;
+
+ src = templ;
+ dst = cvGetSubRect( dft_templ, &dstub, cvRect(0,yofs,templ->cols,templ->rows));
+
+ if( templ_cn > 1 )
+ {
+ planes[k] = templ_depth == max_depth ? dst :
+ cvInitMatHeader( &temp, templ->rows, templ->cols, templ_depth, buf[0] );
+ cvSplit( templ, planes[0], planes[1], planes[2], planes[3] );
+ src = planes[k];
+ planes[k] = 0;
+ }
+
+ if( dst != src )
+ cvConvert( src, dst );
+
+ if( dft_templ->cols > templ->cols )
+ {
+ cvGetSubRect( dft_templ, dst, cvRect(templ->cols, yofs,
+ dft_templ->cols - templ->cols, templ->rows) );
+ cvZero( dst );
+ }
+ cvGetSubRect( dft_templ, dst, cvRect(0,yofs,dftsize.width,dftsize.height) );
+ cvDFT( dst, dst, CV_DXT_FORWARD + CV_DXT_SCALE, templ->rows );
+ }
+
+ tile_count_x = (corr->cols + blocksize.width - 1)/blocksize.width;
+ tile_count_y = (corr->rows + blocksize.height - 1)/blocksize.height;
+ tile_count = tile_count_x*tile_count_y;
+
+ {
+#ifdef _OPENMP
+ #pragma omp parallel for num_threads(num_threads) schedule(dynamic)
+#endif
+ // calculate correlation by blocks
+ for( k = 0; k < tile_count; k++ )
+ {
+ int thread_idx = cvGetThreadNum();
+ int x = (k%tile_count_x)*blocksize.width;
+ int y = (k/tile_count_x)*blocksize.height;
+ int i, yofs;
+ CvMat sstub, dstub, *src, *dst, temp;
+ CvMat* planes[] = { 0, 0, 0, 0 };
+ CvMat* _dft_img = dft_img[thread_idx];
+ void* _buf = buf[thread_idx];
+ CvSize csz = { blocksize.width, blocksize.height }, isz;
+ int x0 = x - anchor.x, y0 = y - anchor.y;
+ int x1 = MAX( 0, x0 ), y1 = MAX( 0, y0 ), x2, y2;
+ csz.width = MIN( csz.width, corr->cols - x );
+ csz.height = MIN( csz.height, corr->rows - y );
+ isz.width = csz.width + templ->cols - 1;
+ isz.height = csz.height + templ->rows - 1;
+ x2 = MIN( img->cols, x0 + isz.width );
+ y2 = MIN( img->rows, y0 + isz.height );
+
+ for( i = 0; i < cn; i++ )
+ {
+ CvMat dstub1, *dst1;
+ yofs = i*dftsize.height;
+
+ src = cvGetSubRect( img, &sstub, cvRect(x1,y1,x2-x1,y2-y1) );
+ dst = cvGetSubRect( _dft_img, &dstub,
+ cvRect(0,0,isz.width,isz.height) );
+ dst1 = dst;
+
+ if( x2 - x1 < isz.width || y2 - y1 < isz.height )
+ dst1 = cvGetSubRect( _dft_img, &dstub1,
+ cvRect( x1 - x0, y1 - y0, x2 - x1, y2 - y1 ));
+
+ if( cn > 1 )
+ {
+ planes[i] = dst1;
+ if( depth != max_depth )
+ planes[i] = cvInitMatHeader( &temp, y2 - y1, x2 - x1, depth, _buf );
+ cvSplit( src, planes[0], planes[1], planes[2], planes[3] );
+ src = planes[i];
+ planes[i] = 0;
+ }
+
+ if( dst1 != src )
+ cvConvert( src, dst1 );
+
+ if( dst != dst1 )
+ cvCopyMakeBorder( dst1, dst, cvPoint(x1 - x0, y1 - y0), IPL_BORDER_REPLICATE );
+
+ if( dftsize.width > isz.width )
+ {
+ cvGetSubRect( _dft_img, dst, cvRect(isz.width, 0,
+ dftsize.width - isz.width,dftsize.height) );
+ cvZero( dst );
+ }
+
+ cvDFT( _dft_img, _dft_img, CV_DXT_FORWARD, isz.height );
+ cvGetSubRect( dft_templ, dst,
+ cvRect(0,(templ_cn>1?yofs:0),dftsize.width,dftsize.height) );
+
+ cvMulSpectrums( _dft_img, dst, _dft_img, CV_DXT_MUL_CONJ );
+ cvDFT( _dft_img, _dft_img, CV_DXT_INVERSE, csz.height );
+
+ src = cvGetSubRect( _dft_img, &sstub, cvRect(0,0,csz.width,csz.height) );
+ dst = cvGetSubRect( corr, &dstub, cvRect(x,y,csz.width,csz.height) );
+
+ if( corr_cn > 1 )
+ {
+ planes[i] = src;
+ if( corr_depth != max_depth )
+ {
+ planes[i] = cvInitMatHeader( &temp, csz.height, csz.width,
+ corr_depth, _buf );
+ cvConvert( src, planes[i] );
+ }
+ cvMerge( planes[0], planes[1], planes[2], planes[3], dst );
+ planes[i] = 0;
+ }
+ else
+ {
+ if( i == 0 )
+ cvConvert( src, dst );
+ else
+ {
+ if( max_depth > corr_depth )
+ {
+ cvInitMatHeader( &temp, csz.height, csz.width,
+ corr_depth, _buf );
+ cvConvert( src, &temp );
+ src = &temp;
+ }
+ cvAcc( src, dst );
+ }
+ }
+ }
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &dft_templ );
+
+ for( k = 0; k < num_threads; k++ )
+ {
+ cvReleaseMat( &dft_img[k] );
+ cvFree( &buf[k] );
+ }
+}
+
+
+/***************************** IPP Match Template Functions ******************************/
+
+icvCrossCorrValid_Norm_8u32f_C1R_t icvCrossCorrValid_Norm_8u32f_C1R_p = 0;
+icvCrossCorrValid_NormLevel_8u32f_C1R_t icvCrossCorrValid_NormLevel_8u32f_C1R_p = 0;
+icvSqrDistanceValid_Norm_8u32f_C1R_t icvSqrDistanceValid_Norm_8u32f_C1R_p = 0;
+icvCrossCorrValid_Norm_32f_C1R_t icvCrossCorrValid_Norm_32f_C1R_p = 0;
+icvCrossCorrValid_NormLevel_32f_C1R_t icvCrossCorrValid_NormLevel_32f_C1R_p = 0;
+icvSqrDistanceValid_Norm_32f_C1R_t icvSqrDistanceValid_Norm_32f_C1R_p = 0;
+
+typedef CvStatus (CV_STDCALL * CvTemplMatchIPPFunc)
+ ( const void* img, int imgstep, CvSize imgsize,
+ const void* templ, int templstep, CvSize templsize,
+ void* result, int rstep );
+
+/*****************************************************************************************/
+
+CV_IMPL void
+cvMatchTemplate( const CvArr* _img, const CvArr* _templ, CvArr* _result, int method )
+{
+ CvMat* sum = 0;
+ CvMat* sqsum = 0;
+
+ CV_FUNCNAME( "cvMatchTemplate" );
+
+ __BEGIN__;
+
+ int coi1 = 0, coi2 = 0;
+ int depth, cn;
+ int i, j, k;
+ CvMat stub, *img = (CvMat*)_img;
+ CvMat tstub, *templ = (CvMat*)_templ;
+ CvMat rstub, *result = (CvMat*)_result;
+ CvScalar templ_mean = cvScalarAll(0);
+ double templ_norm = 0, templ_sum2 = 0;
+
+ int idx = 0, idx2 = 0;
+ double *p0, *p1, *p2, *p3;
+ double *q0, *q1, *q2, *q3;
+ double inv_area;
+ int sum_step, sqsum_step;
+ int num_type = method == CV_TM_CCORR || method == CV_TM_CCORR_NORMED ? 0 :
+ method == CV_TM_CCOEFF || method == CV_TM_CCOEFF_NORMED ? 1 : 2;
+ int is_normed = method == CV_TM_CCORR_NORMED ||
+ method == CV_TM_SQDIFF_NORMED ||
+ method == CV_TM_CCOEFF_NORMED;
+
+ CV_CALL( img = cvGetMat( img, &stub, &coi1 ));
+ CV_CALL( templ = cvGetMat( templ, &tstub, &coi2 ));
+ CV_CALL( result = cvGetMat( result, &rstub ));
+
+ if( CV_MAT_DEPTH( img->type ) != CV_8U &&
+ CV_MAT_DEPTH( img->type ) != CV_32F )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "The function supports only 8u and 32f data types" );
+
+ if( !CV_ARE_TYPES_EQ( img, templ ))
+ CV_ERROR( CV_StsUnmatchedSizes, "image and template should have the same type" );
+
+ if( CV_MAT_TYPE( result->type ) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "output image should have 32f type" );
+
+ if( img->rows < templ->rows || img->cols < templ->cols )
+ {
+ CvMat* t;
+ CV_SWAP( img, templ, t );
+ }
+
+ if( result->rows != img->rows - templ->rows + 1 ||
+ result->cols != img->cols - templ->cols + 1 )
+ CV_ERROR( CV_StsUnmatchedSizes, "output image should be (W - w + 1)x(H - h + 1)" );
+
+ if( method < CV_TM_SQDIFF || method > CV_TM_CCOEFF_NORMED )
+ CV_ERROR( CV_StsBadArg, "unknown comparison method" );
+
+ depth = CV_MAT_DEPTH(img->type);
+ cn = CV_MAT_CN(img->type);
+
+ if( is_normed && cn == 1 && templ->rows > 8 && templ->cols > 8 &&
+ img->rows > templ->cols && img->cols > templ->cols )
+ {
+ CvTemplMatchIPPFunc ipp_func =
+ depth == CV_8U ?
+ (method == CV_TM_SQDIFF_NORMED ? (CvTemplMatchIPPFunc)icvSqrDistanceValid_Norm_8u32f_C1R_p :
+ method == CV_TM_CCORR_NORMED ? (CvTemplMatchIPPFunc)icvCrossCorrValid_Norm_8u32f_C1R_p :
+ (CvTemplMatchIPPFunc)icvCrossCorrValid_NormLevel_8u32f_C1R_p) :
+ (method == CV_TM_SQDIFF_NORMED ? (CvTemplMatchIPPFunc)icvSqrDistanceValid_Norm_32f_C1R_p :
+ method == CV_TM_CCORR_NORMED ? (CvTemplMatchIPPFunc)icvCrossCorrValid_Norm_32f_C1R_p :
+ (CvTemplMatchIPPFunc)icvCrossCorrValid_NormLevel_32f_C1R_p);
+
+ if( ipp_func )
+ {
+ CvSize img_size = cvGetMatSize(img), templ_size = cvGetMatSize(templ);
+
+ IPPI_CALL( ipp_func( img->data.ptr, img->step ? img->step : CV_STUB_STEP,
+ img_size, templ->data.ptr,
+ templ->step ? templ->step : CV_STUB_STEP,
+ templ_size, result->data.ptr,
+ result->step ? result->step : CV_STUB_STEP ));
+ for( i = 0; i < result->rows; i++ )
+ {
+ float* rrow = (float*)(result->data.ptr + i*result->step);
+ for( j = 0; j < result->cols; j++ )
+ {
+ if( fabs(rrow[j]) > 1. )
+ rrow[j] = rrow[j] < 0 ? -1.f : 1.f;
+ }
+ }
+ EXIT;
+ }
+ }
+
+ CV_CALL( icvCrossCorr( img, templ, result ));
+
+ if( method == CV_TM_CCORR )
+ EXIT;
+
+ inv_area = 1./((double)templ->rows * templ->cols);
+
+ CV_CALL( sum = cvCreateMat( img->rows + 1, img->cols + 1,
+ CV_MAKETYPE( CV_64F, cn )));
+ if( method == CV_TM_CCOEFF )
+ {
+ CV_CALL( cvIntegral( img, sum, 0, 0 ));
+ CV_CALL( templ_mean = cvAvg( templ ));
+ q0 = q1 = q2 = q3 = 0;
+ }
+ else
+ {
+ CvScalar _templ_sdv = cvScalarAll(0);
+ CV_CALL( sqsum = cvCreateMat( img->rows + 1, img->cols + 1,
+ CV_MAKETYPE( CV_64F, cn )));
+ CV_CALL( cvIntegral( img, sum, sqsum, 0 ));
+ CV_CALL( cvAvgSdv( templ, &templ_mean, &_templ_sdv ));
+
+ templ_norm = CV_SQR(_templ_sdv.val[0]) + CV_SQR(_templ_sdv.val[1]) +
+ CV_SQR(_templ_sdv.val[2]) + CV_SQR(_templ_sdv.val[3]);
+
+ if( templ_norm < DBL_EPSILON && method == CV_TM_CCOEFF_NORMED )
+ {
+ cvSet( result, cvScalarAll(1.) );
+ EXIT;
+ }
+
+ templ_sum2 = templ_norm +
+ CV_SQR(templ_mean.val[0]) + CV_SQR(templ_mean.val[1]) +
+ CV_SQR(templ_mean.val[2]) + CV_SQR(templ_mean.val[3]);
+
+ if( num_type != 1 )
+ {
+ templ_mean = cvScalarAll(0);
+ templ_norm = templ_sum2;
+ }
+
+ templ_sum2 /= inv_area;
+ templ_norm = sqrt(templ_norm);
+ templ_norm /= sqrt(inv_area); // care of accuracy here
+
+ q0 = (double*)sqsum->data.ptr;
+ q1 = q0 + templ->cols*cn;
+ q2 = (double*)(sqsum->data.ptr + templ->rows*sqsum->step);
+ q3 = q2 + templ->cols*cn;
+ }
+
+ p0 = (double*)sum->data.ptr;
+ p1 = p0 + templ->cols*cn;
+ p2 = (double*)(sum->data.ptr + templ->rows*sum->step);
+ p3 = p2 + templ->cols*cn;
+
+ sum_step = sum ? sum->step / sizeof(double) : 0;
+ sqsum_step = sqsum ? sqsum->step / sizeof(double) : 0;
+
+ for( i = 0; i < result->rows; i++ )
+ {
+ float* rrow = (float*)(result->data.ptr + i*result->step);
+ idx = i * sum_step;
+ idx2 = i * sqsum_step;
+
+ for( j = 0; j < result->cols; j++, idx += cn, idx2 += cn )
+ {
+ double num = rrow[j], t;
+ double wnd_mean2 = 0, wnd_sum2 = 0;
+
+ if( num_type == 1 )
+ {
+ for( k = 0; k < cn; k++ )
+ {
+ t = p0[idx+k] - p1[idx+k] - p2[idx+k] + p3[idx+k];
+ wnd_mean2 += CV_SQR(t);
+ num -= t*templ_mean.val[k];
+ }
+
+ wnd_mean2 *= inv_area;
+ }
+
+ if( is_normed || num_type == 2 )
+ {
+ for( k = 0; k < cn; k++ )
+ {
+ t = q0[idx2+k] - q1[idx2+k] - q2[idx2+k] + q3[idx2+k];
+ wnd_sum2 += t;
+ }
+
+ if( num_type == 2 )
+ num = wnd_sum2 - 2*num + templ_sum2;
+ }
+
+ if( is_normed )
+ {
+ t = sqrt(MAX(wnd_sum2 - wnd_mean2,0))*templ_norm;
+ if( t > DBL_EPSILON )
+ {
+ num /= t;
+ if( fabs(num) > 1. )
+ num = num > 0 ? 1 : -1;
+ }
+ else
+ num = method != CV_TM_SQDIFF_NORMED || num < DBL_EPSILON ? 0 : 1;
+ }
+
+ rrow[j] = (float)num;
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &sum );
+ cvReleaseMat( &sqsum );
+}
+
+/* End of file. */
diff --git a/cv/src/cvthresh.cpp b/cv/src/cvthresh.cpp
new file mode 100644
index 0000000..52ea622
--- /dev/null
+++ b/cv/src/cvthresh.cpp
@@ -0,0 +1,495 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+static CvStatus CV_STDCALL
+icvThresh_8u_C1R( const uchar* src, int src_step, uchar* dst, int dst_step,
+ CvSize roi, uchar thresh, uchar maxval, int type )
+{
+ int i, j;
+ uchar tab[256];
+
+ switch( type )
+ {
+ case CV_THRESH_BINARY:
+ for( i = 0; i <= thresh; i++ )
+ tab[i] = 0;
+ for( ; i < 256; i++ )
+ tab[i] = maxval;
+ break;
+ case CV_THRESH_BINARY_INV:
+ for( i = 0; i <= thresh; i++ )
+ tab[i] = maxval;
+ for( ; i < 256; i++ )
+ tab[i] = 0;
+ break;
+ case CV_THRESH_TRUNC:
+ for( i = 0; i <= thresh; i++ )
+ tab[i] = (uchar)i;
+ for( ; i < 256; i++ )
+ tab[i] = thresh;
+ break;
+ case CV_THRESH_TOZERO:
+ for( i = 0; i <= thresh; i++ )
+ tab[i] = 0;
+ for( ; i < 256; i++ )
+ tab[i] = (uchar)i;
+ break;
+ case CV_THRESH_TOZERO_INV:
+ for( i = 0; i <= thresh; i++ )
+ tab[i] = (uchar)i;
+ for( ; i < 256; i++ )
+ tab[i] = 0;
+ break;
+ default:
+ return CV_BADFLAG_ERR;
+ }
+
+ for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+ {
+ for( j = 0; j <= roi.width - 4; j += 4 )
+ {
+ uchar t0 = tab[src[j]];
+ uchar t1 = tab[src[j+1]];
+
+ dst[j] = t0;
+ dst[j+1] = t1;
+
+ t0 = tab[src[j+2]];
+ t1 = tab[src[j+3]];
+
+ dst[j+2] = t0;
+ dst[j+3] = t1;
+ }
+
+ for( ; j < roi.width; j++ )
+ dst[j] = tab[src[j]];
+ }
+
+ return CV_NO_ERR;
+}
+
+
+static CvStatus CV_STDCALL
+icvThresh_32f_C1R( const float *src, int src_step, float *dst, int dst_step,
+ CvSize roi, float thresh, float maxval, int type )
+{
+ int i, j;
+ const int* isrc = (const int*)src;
+ int* idst = (int*)dst;
+ Cv32suf v;
+ int iThresh, iMax;
+
+ v.f = thresh; iThresh = CV_TOGGLE_FLT(v.i);
+ v.f = maxval; iMax = v.i;
+
+ src_step /= sizeof(src[0]);
+ dst_step /= sizeof(dst[0]);
+
+ switch( type )
+ {
+ case CV_THRESH_BINARY:
+ for( i = 0; i < roi.height; i++, isrc += src_step, idst += dst_step )
+ {
+ for( j = 0; j < roi.width; j++ )
+ {
+ int temp = isrc[j];
+ idst[j] = ((CV_TOGGLE_FLT(temp) <= iThresh) - 1) & iMax;
+ }
+ }
+ break;
+
+ case CV_THRESH_BINARY_INV:
+ for( i = 0; i < roi.height; i++, isrc += src_step, idst += dst_step )
+ {
+ for( j = 0; j < roi.width; j++ )
+ {
+ int temp = isrc[j];
+ idst[j] = ((CV_TOGGLE_FLT(temp) > iThresh) - 1) & iMax;
+ }
+ }
+ break;
+
+ case CV_THRESH_TRUNC:
+ for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+ {
+ for( j = 0; j < roi.width; j++ )
+ {
+ float temp = src[j];
+
+ if( temp > thresh )
+ temp = thresh;
+ dst[j] = temp;
+ }
+ }
+ break;
+
+ case CV_THRESH_TOZERO:
+ for( i = 0; i < roi.height; i++, isrc += src_step, idst += dst_step )
+ {
+ for( j = 0; j < roi.width; j++ )
+ {
+ int temp = isrc[j];
+ idst[j] = ((CV_TOGGLE_FLT( temp ) <= iThresh) - 1) & temp;
+ }
+ }
+ break;
+
+ case CV_THRESH_TOZERO_INV:
+ for( i = 0; i < roi.height; i++, isrc += src_step, idst += dst_step )
+ {
+ for( j = 0; j < roi.width; j++ )
+ {
+ int temp = isrc[j];
+ idst[j] = ((CV_TOGGLE_FLT( temp ) > iThresh) - 1) & temp;
+ }
+ }
+ break;
+
+ default:
+ return CV_BADFLAG_ERR;
+ }
+
+ return CV_OK;
+}
+
+
+static double
+icvGetThreshVal_Otsu( const CvHistogram* hist )
+{
+ double max_val = 0;
+
+ CV_FUNCNAME( "icvGetThreshVal_Otsu" );
+
+ __BEGIN__;
+
+ int i, count;
+ const float* h;
+ double sum = 0, mu = 0;
+ bool uniform = false;
+ double low = 0, high = 0, delta = 0;
+ float* nu_thresh = 0;
+ double mu1 = 0, q1 = 0;
+ double max_sigma = 0;
+
+ if( !CV_IS_HIST(hist) || CV_IS_SPARSE_HIST(hist) || hist->mat.dims != 1 )
+ CV_ERROR( CV_StsBadArg,
+ "The histogram in Otsu method must be a valid dense 1D histogram" );
+
+ count = hist->mat.dim[0].size;
+ h = (float*)cvPtr1D( hist->bins, 0 );
+
+ if( !CV_HIST_HAS_RANGES(hist) || CV_IS_UNIFORM_HIST(hist) )
+ {
+ if( CV_HIST_HAS_RANGES(hist) )
+ {
+ low = hist->thresh[0][0];
+ high = hist->thresh[0][1];
+ }
+ else
+ {
+ low = 0;
+ high = count;
+ }
+
+ delta = (high-low)/count;
+ low += delta*0.5;
+ uniform = true;
+ }
+ else
+ nu_thresh = hist->thresh2[0];
+
+ for( i = 0; i < count; i++ )
+ {
+ sum += h[i];
+ if( uniform )
+ mu += (i*delta + low)*h[i];
+ else
+ mu += (nu_thresh[i*2] + nu_thresh[i*2+1])*0.5*h[i];
+ }
+
+ sum = fabs(sum) > FLT_EPSILON ? 1./sum : 0;
+ mu *= sum;
+
+ mu1 = 0;
+ q1 = 0;
+
+ for( i = 0; i < count; i++ )
+ {
+ double p_i, q2, mu2, val_i, sigma;
+
+ p_i = h[i]*sum;
+ mu1 *= q1;
+ q1 += p_i;
+ q2 = 1. - q1;
+
+ if( MIN(q1,q2) < FLT_EPSILON || MAX(q1,q2) > 1. - FLT_EPSILON )
+ continue;
+
+ if( uniform )
+ val_i = i*delta + low;
+ else
+ val_i = (nu_thresh[i*2] + nu_thresh[i*2+1])*0.5;
+
+ mu1 = (mu1 + val_i*p_i)/q1;
+ mu2 = (mu - q1*mu1)/q2;
+ sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2);
+ if( sigma > max_sigma )
+ {
+ max_sigma = sigma;
+ max_val = val_i;
+ }
+ }
+
+ __END__;
+
+ return max_val;
+}
+
+
+icvAndC_8u_C1R_t icvAndC_8u_C1R_p = 0;
+icvCompareC_8u_C1R_cv_t icvCompareC_8u_C1R_cv_p = 0;
+icvThreshold_GTVal_8u_C1R_t icvThreshold_GTVal_8u_C1R_p = 0;
+icvThreshold_GTVal_32f_C1R_t icvThreshold_GTVal_32f_C1R_p = 0;
+icvThreshold_LTVal_8u_C1R_t icvThreshold_LTVal_8u_C1R_p = 0;
+icvThreshold_LTVal_32f_C1R_t icvThreshold_LTVal_32f_C1R_p = 0;
+
+CV_IMPL double
+cvThreshold( const void* srcarr, void* dstarr, double thresh, double maxval, int type )
+{
+ CvHistogram* hist = 0;
+
+ CV_FUNCNAME( "cvThreshold" );
+
+ __BEGIN__;
+
+ CvSize roi;
+ int src_step, dst_step;
+ CvMat src_stub, *src = (CvMat*)srcarr;
+ CvMat dst_stub, *dst = (CvMat*)dstarr;
+ CvMat src0, dst0;
+ int coi1 = 0, coi2 = 0;
+ int ithresh, imaxval, cn;
+ bool use_otsu;
+
+ CV_CALL( src = cvGetMat( src, &src_stub, &coi1 ));
+ CV_CALL( dst = cvGetMat( dst, &dst_stub, &coi2 ));
+
+ if( coi1 + coi2 )
+ CV_ERROR( CV_BadCOI, "COI is not supported by the function" );
+
+ if( !CV_ARE_CNS_EQ( src, dst ) )
+ CV_ERROR( CV_StsUnmatchedFormats, "Both arrays must have equal number of channels" );
+
+ cn = CV_MAT_CN(src->type);
+ if( cn > 1 )
+ {
+ src = cvReshape( src, &src0, 1 );
+ dst = cvReshape( dst, &dst0, 1 );
+ }
+
+ use_otsu = (type & ~CV_THRESH_MASK) == CV_THRESH_OTSU;
+ type &= CV_THRESH_MASK;
+
+ if( use_otsu )
+ {
+ float _ranges[] = { 0, 256 };
+ float* ranges = _ranges;
+ int hist_size = 256;
+ void* srcarr0 = src;
+
+ if( CV_MAT_TYPE(src->type) != CV_8UC1 )
+ CV_ERROR( CV_StsNotImplemented, "Otsu method can only be used with 8uC1 images" );
+
+ CV_CALL( hist = cvCreateHist( 1, &hist_size, CV_HIST_ARRAY, &ranges ));
+ cvCalcArrHist( &srcarr0, hist );
+ thresh = cvFloor(icvGetThreshVal_Otsu( hist ));
+ }
+
+ if( !CV_ARE_DEPTHS_EQ( src, dst ) )
+ {
+ if( CV_MAT_TYPE(dst->type) != CV_8UC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "In case of different types destination should be 8uC1" );
+
+ if( type != CV_THRESH_BINARY && type != CV_THRESH_BINARY_INV )
+ CV_ERROR( CV_StsBadArg,
+ "In case of different types only CV_THRESH_BINARY "
+ "and CV_THRESH_BINARY_INV thresholding types are supported" );
+
+ if( maxval < 0 )
+ {
+ CV_CALL( cvSetZero( dst ));
+ }
+ else
+ {
+ CV_CALL( cvCmpS( src, thresh, dst, type == CV_THRESH_BINARY ? CV_CMP_GT : CV_CMP_LE ));
+ if( maxval < 255 )
+ CV_CALL( cvAndS( dst, cvScalarAll( maxval ), dst ));
+ }
+ EXIT;
+ }
+
+ if( !CV_ARE_SIZES_EQ( src, dst ) )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ roi = cvGetMatSize( src );
+ if( CV_IS_MAT_CONT( src->type & dst->type ))
+ {
+ roi.width *= roi.height;
+ roi.height = 1;
+ src_step = dst_step = CV_STUB_STEP;
+ }
+ else
+ {
+ src_step = src->step;
+ dst_step = dst->step;
+ }
+
+ switch( CV_MAT_DEPTH(src->type) )
+ {
+ case CV_8U:
+
+ ithresh = cvFloor(thresh);
+ imaxval = cvRound(maxval);
+ if( type == CV_THRESH_TRUNC )
+ imaxval = ithresh;
+ imaxval = CV_CAST_8U(imaxval);
+
+ if( ithresh < 0 || ithresh >= 255 )
+ {
+ if( type == CV_THRESH_BINARY || type == CV_THRESH_BINARY_INV ||
+ ((type == CV_THRESH_TRUNC || type == CV_THRESH_TOZERO_INV) && ithresh < 0) ||
+ (type == CV_THRESH_TOZERO && ithresh >= 255) )
+ {
+ int v = type == CV_THRESH_BINARY ? (ithresh >= 255 ? 0 : imaxval) :
+ type == CV_THRESH_BINARY_INV ? (ithresh >= 255 ? imaxval : 0) :
+ type == CV_THRESH_TRUNC ? imaxval : 0;
+
+ cvSet( dst, cvScalarAll(v) );
+ EXIT;
+ }
+ else
+ {
+ cvCopy( src, dst );
+ EXIT;
+ }
+ }
+
+ if( type == CV_THRESH_BINARY || type == CV_THRESH_BINARY_INV )
+ {
+ if( icvCompareC_8u_C1R_cv_p && icvAndC_8u_C1R_p )
+ {
+ IPPI_CALL( icvCompareC_8u_C1R_cv_p( src->data.ptr, src_step,
+ (uchar)ithresh, dst->data.ptr, dst_step, roi,
+ type == CV_THRESH_BINARY ? cvCmpGreater : cvCmpLessEq ));
+
+ if( imaxval < 255 )
+ IPPI_CALL( icvAndC_8u_C1R_p( dst->data.ptr, dst_step,
+ (uchar)imaxval, dst->data.ptr, dst_step, roi ));
+ EXIT;
+ }
+ }
+ else if( type == CV_THRESH_TRUNC || type == CV_THRESH_TOZERO_INV )
+ {
+ if( icvThreshold_GTVal_8u_C1R_p )
+ {
+ IPPI_CALL( icvThreshold_GTVal_8u_C1R_p( src->data.ptr, src_step,
+ dst->data.ptr, dst_step, roi, (uchar)ithresh,
+ (uchar)(type == CV_THRESH_TRUNC ? ithresh : 0) ));
+ EXIT;
+ }
+ }
+ else
+ {
+ assert( type == CV_THRESH_TOZERO );
+ if( icvThreshold_LTVal_8u_C1R_p )
+ {
+ ithresh = cvFloor(thresh+1.);
+ ithresh = CV_CAST_8U(ithresh);
+ IPPI_CALL( icvThreshold_LTVal_8u_C1R_p( src->data.ptr, src_step,
+ dst->data.ptr, dst_step, roi, (uchar)ithresh, 0 ));
+ EXIT;
+ }
+ }
+
+ icvThresh_8u_C1R( src->data.ptr, src_step,
+ dst->data.ptr, dst_step, roi,
+ (uchar)ithresh, (uchar)imaxval, type );
+ break;
+ case CV_32F:
+
+ if( type == CV_THRESH_TRUNC || type == CV_THRESH_TOZERO_INV )
+ {
+ if( icvThreshold_GTVal_32f_C1R_p )
+ {
+ IPPI_CALL( icvThreshold_GTVal_32f_C1R_p( src->data.fl, src_step,
+ dst->data.fl, dst_step, roi, (float)thresh,
+ type == CV_THRESH_TRUNC ? (float)thresh : 0 ));
+ EXIT;
+ }
+ }
+ else if( type == CV_THRESH_TOZERO )
+ {
+ if( icvThreshold_LTVal_32f_C1R_p )
+ {
+ IPPI_CALL( icvThreshold_LTVal_32f_C1R_p( src->data.fl, src_step,
+ dst->data.fl, dst_step, roi, (float)(thresh*(1 + FLT_EPSILON)), 0 ));
+ EXIT;
+ }
+ }
+
+ icvThresh_32f_C1R( src->data.fl, src_step, dst->data.fl, dst_step, roi,
+ (float)thresh, (float)maxval, type );
+ break;
+ default:
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ }
+
+ __END__;
+
+ if( hist )
+ cvReleaseHist( &hist );
+
+ return thresh;
+}
+
+/* End of file. */
diff --git a/cv/src/cvundistort.cpp b/cv/src/cvundistort.cpp
new file mode 100644
index 0000000..a84bcf7
--- /dev/null
+++ b/cv/src/cvundistort.cpp
@@ -0,0 +1,491 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+static CvStatus
+icvUnDistort_8u_CnR( const uchar* src, int srcstep,
+ uchar* dst, int dststep, CvSize size,
+ const float* intrinsic_matrix,
+ const float* dist_coeffs, int cn )
+{
+ int u, v, i;
+ float u0 = intrinsic_matrix[2], v0 = intrinsic_matrix[5];
+ float x0 = (size.width-1)*0.5f, y0 = (size.height-1)*0.5f;
+ float fx = intrinsic_matrix[0], fy = intrinsic_matrix[4];
+ float ifx = 1.f/fx, ify = 1.f/fy;
+ float k1 = dist_coeffs[0], k2 = dist_coeffs[1], k3 = dist_coeffs[4];
+ float p1 = dist_coeffs[2], p2 = dist_coeffs[3];
+
+ srcstep /= sizeof(src[0]);
+ dststep /= sizeof(dst[0]);
+
+ for( v = 0; v < size.height; v++, dst += dststep )
+ {
+ float y = (v - v0)*ify, y2 = y*y;
+
+ for( u = 0; u < size.width; u++ )
+ {
+ float x = (u - u0)*ifx, x2 = x*x, r2 = x2 + y2, _2xy = 2*x*y;
+ float kr = 1 + ((k3*r2 + k2)*r2 + k1)*r2;
+ float _x = fx*(x*kr + p1*_2xy + p2*(r2 + 2*x2)) + x0;
+ float _y = fy*(y*kr + p1*(r2 + 2*y2) + p2*_2xy) + y0;
+ int ix = cvFloor(_x), iy = cvFloor(_y);
+
+ if( (unsigned)iy < (unsigned)(size.height - 1) &&
+ (unsigned)ix < (unsigned)(size.width - 1) )
+ {
+ const uchar* ptr = src + iy*srcstep + ix*cn;
+ _x -= ix; _y -= iy;
+ for( i = 0; i < cn; i++ )
+ {
+ float t0 = CV_8TO32F(ptr[i]), t1 = CV_8TO32F(ptr[i+srcstep]);
+ t0 += _x*(CV_8TO32F(ptr[i+cn]) - t0);
+ t1 += _x*(CV_8TO32F(ptr[i + srcstep + cn]) - t1);
+ dst[u*cn + i] = (uchar)cvRound(t0 + _y*(t1 - t0));
+ }
+ }
+ else
+ {
+ for( i = 0; i < cn; i++ )
+ dst[u*cn + i] = 0;
+ }
+
+ }
+ }
+
+ return CV_OK;
+}
+
+
+icvUndistortGetSize_t icvUndistortGetSize_p = 0;
+icvCreateMapCameraUndistort_32f_C1R_t icvCreateMapCameraUndistort_32f_C1R_p = 0;
+icvUndistortRadial_8u_C1R_t icvUndistortRadial_8u_C1R_p = 0;
+icvUndistortRadial_8u_C3R_t icvUndistortRadial_8u_C3R_p = 0;
+
+typedef CvStatus (CV_STDCALL * CvUndistortRadialIPPFunc)
+ ( const void* pSrc, int srcStep, void* pDst, int dstStep, CvSize roiSize,
+ float fx, float fy, float cx, float cy, float k1, float k2, uchar *pBuffer );
+
+CV_IMPL void
+cvUndistort2( const CvArr* _src, CvArr* _dst, const CvMat* A, const CvMat* dist_coeffs )
+{
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvUndistort2" );
+
+ __BEGIN__;
+
+ float a[9], k[5]={0,0,0,0,0};
+ int coi1 = 0, coi2 = 0;
+ CvMat srcstub, *src = (CvMat*)_src;
+ CvMat dststub, *dst = (CvMat*)_dst;
+ CvMat _a = cvMat( 3, 3, CV_32F, a ), _k;
+ int cn, src_step, dst_step;
+ CvSize size;
+
+ if( !inittab )
+ {
+ icvInitLinearCoeffTab();
+ icvInitCubicCoeffTab();
+ inittab = 1;
+ }
+
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "The function does not support COI" );
+
+ if( CV_MAT_DEPTH(src->type) != CV_8U )
+ CV_ERROR( CV_StsUnsupportedFormat, "Only 8-bit images are supported" );
+
+ if( src->data.ptr == dst->data.ptr )
+ CV_ERROR( CV_StsNotImplemented, "In-place undistortion is not implemented" );
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( !CV_IS_MAT(A) || A->rows != 3 || A->cols != 3 ||
+ (CV_MAT_TYPE(A->type) != CV_32FC1 && CV_MAT_TYPE(A->type) != CV_64FC1) )
+ CV_ERROR( CV_StsBadArg, "Intrinsic matrix must be a valid 3x3 floating-point matrix" );
+
+ if( !CV_IS_MAT(dist_coeffs) || (dist_coeffs->rows != 1 && dist_coeffs->cols != 1) ||
+ (dist_coeffs->rows*dist_coeffs->cols*CV_MAT_CN(dist_coeffs->type) != 4 &&
+ dist_coeffs->rows*dist_coeffs->cols*CV_MAT_CN(dist_coeffs->type) != 5) ||
+ (CV_MAT_DEPTH(dist_coeffs->type) != CV_64F &&
+ CV_MAT_DEPTH(dist_coeffs->type) != CV_32F) )
+ CV_ERROR( CV_StsBadArg,
+ "Distortion coefficients must be 1x4, 4x1, 1x5 or 5x1 floating-point vector" );
+
+ cvConvert( A, &_a );
+ _k = cvMat( dist_coeffs->rows, dist_coeffs->cols,
+ CV_MAKETYPE(CV_32F, CV_MAT_CN(dist_coeffs->type)), k );
+ cvConvert( dist_coeffs, &_k );
+
+ cn = CV_MAT_CN(src->type);
+ size = cvGetMatSize(src);
+ src_step = src->step ? src->step : CV_STUB_STEP;
+ dst_step = dst->step ? dst->step : CV_STUB_STEP;
+
+ icvUnDistort_8u_CnR( src->data.ptr, src_step,
+ dst->data.ptr, dst_step, size, a, k, cn );
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvInitUndistortMap( const CvMat* A, const CvMat* dist_coeffs,
+ CvArr* mapxarr, CvArr* mapyarr )
+{
+ CV_FUNCNAME( "cvInitUndistortMap" );
+
+ __BEGIN__;
+
+ float a[9], k[5]={0,0,0,0,0};
+ int coi1 = 0, coi2 = 0;
+ CvMat mapxstub, *_mapx = (CvMat*)mapxarr;
+ CvMat mapystub, *_mapy = (CvMat*)mapyarr;
+ CvMat _a = cvMat( 3, 3, CV_32F, a ), _k;
+ int u, v;
+ float u0, v0, fx, fy, ifx, ify, x0, y0, k1, k2, k3, p1, p2;
+ CvSize size;
+
+ CV_CALL( _mapx = cvGetMat( _mapx, &mapxstub, &coi1 ));
+ CV_CALL( _mapy = cvGetMat( _mapy, &mapystub, &coi2 ));
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "The function does not support COI" );
+
+ if( CV_MAT_TYPE(_mapx->type) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Both maps must have 32fC1 type" );
+
+ if( !CV_ARE_TYPES_EQ( _mapx, _mapy ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( !CV_ARE_SIZES_EQ( _mapx, _mapy ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ size = cvGetMatSize(_mapx);
+
+ if( !CV_IS_MAT(A) || A->rows != 3 || A->cols != 3 ||
+ (CV_MAT_TYPE(A->type) != CV_32FC1 && CV_MAT_TYPE(A->type) != CV_64FC1) )
+ CV_ERROR( CV_StsBadArg, "Intrinsic matrix must be a valid 3x3 floating-point matrix" );
+
+ if( !CV_IS_MAT(dist_coeffs) || (dist_coeffs->rows != 1 && dist_coeffs->cols != 1) ||
+ (dist_coeffs->rows*dist_coeffs->cols*CV_MAT_CN(dist_coeffs->type) != 4 &&
+ dist_coeffs->rows*dist_coeffs->cols*CV_MAT_CN(dist_coeffs->type) != 5) ||
+ (CV_MAT_DEPTH(dist_coeffs->type) != CV_64F &&
+ CV_MAT_DEPTH(dist_coeffs->type) != CV_32F) )
+ CV_ERROR( CV_StsBadArg,
+ "Distortion coefficients must be 1x4, 4x1, 1x5 or 5x1 floating-point vector" );
+
+ cvConvert( A, &_a );
+ _k = cvMat( dist_coeffs->rows, dist_coeffs->cols,
+ CV_MAKETYPE(CV_32F, CV_MAT_CN(dist_coeffs->type)), k );
+ cvConvert( dist_coeffs, &_k );
+
+ u0 = a[2]; v0 = a[5];
+ fx = a[0]; fy = a[4];
+ ifx = 1.f/fx; ify = 1.f/fy;
+ k1 = k[0]; k2 = k[1]; k3 = k[4];
+ p1 = k[2]; p2 = k[3];
+ x0 = (size.width-1)*0.5f;
+ y0 = (size.height-1)*0.5f;
+
+ for( v = 0; v < size.height; v++ )
+ {
+ float* mapx = (float*)(_mapx->data.ptr + _mapx->step*v);
+ float* mapy = (float*)(_mapy->data.ptr + _mapy->step*v);
+ float y = (v - v0)*ify, y2 = y*y;
+
+ for( u = 0; u < size.width; u++ )
+ {
+ float x = (u - u0)*ifx, x2 = x*x, r2 = x2 + y2, _2xy = 2*x*y;
+ double kr = 1 + ((k3*r2 + k2)*r2 + k1)*r2;
+ double _x = fx*(x*kr + p1*_2xy + p2*(r2 + 2*x2)) + x0;
+ double _y = fy*(y*kr + p1*(r2 + 2*y2) + p2*_2xy) + y0;
+ mapx[u] = (float)_x;
+ mapy[u] = (float)_y;
+ }
+ }
+
+ __END__;
+}
+
+
+void
+cvInitUndistortRectifyMap( const CvMat* A, const CvMat* distCoeffs,
+ const CvMat *R, const CvMat* Ar, CvArr* mapxarr, CvArr* mapyarr )
+{
+ CV_FUNCNAME( "cvInitUndistortMap" );
+
+ __BEGIN__;
+
+ double a[9], ar[9], r[9], ir[9], k[5]={0,0,0,0,0};
+ int coi1 = 0, coi2 = 0;
+ CvMat mapxstub, *_mapx = (CvMat*)mapxarr;
+ CvMat mapystub, *_mapy = (CvMat*)mapyarr;
+ CvMat _a = cvMat( 3, 3, CV_64F, a );
+ CvMat _k = cvMat( 4, 1, CV_64F, k );
+ CvMat _ar = cvMat( 3, 3, CV_64F, ar );
+ CvMat _r = cvMat( 3, 3, CV_64F, r );
+ CvMat _ir = cvMat( 3, 3, CV_64F, ir );
+ int i, j;
+ double fx, fy, u0, v0, k1, k2, k3, p1, p2;
+ CvSize size;
+
+ CV_CALL( _mapx = cvGetMat( _mapx, &mapxstub, &coi1 ));
+ CV_CALL( _mapy = cvGetMat( _mapy, &mapystub, &coi2 ));
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "The function does not support COI" );
+
+ if( CV_MAT_TYPE(_mapx->type) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Both maps must have 32fC1 type" );
+
+ if( !CV_ARE_TYPES_EQ( _mapx, _mapy ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( !CV_ARE_SIZES_EQ( _mapx, _mapy ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( A )
+ {
+ if( !CV_IS_MAT(A) || A->rows != 3 || A->cols != 3 ||
+ (CV_MAT_TYPE(A->type) != CV_32FC1 && CV_MAT_TYPE(A->type) != CV_64FC1) )
+ CV_ERROR( CV_StsBadArg, "Intrinsic matrix must be a valid 3x3 floating-point matrix" );
+ cvConvert( A, &_a );
+ }
+ else
+ cvSetIdentity( &_a );
+
+ if( Ar )
+ {
+ CvMat Ar33;
+ if( !CV_IS_MAT(Ar) || Ar->rows != 3 || (Ar->cols != 3 && Ar->cols != 4) ||
+ (CV_MAT_TYPE(Ar->type) != CV_32FC1 && CV_MAT_TYPE(Ar->type) != CV_64FC1) )
+ CV_ERROR( CV_StsBadArg, "The new intrinsic matrix must be a valid 3x3 floating-point matrix" );
+ cvGetCols( Ar, &Ar33, 0, 3 );
+ cvConvert( &Ar33, &_ar );
+ }
+ else
+ cvSetIdentity( &_ar );
+
+ if( !CV_IS_MAT(R) || R->rows != 3 || R->cols != 3 ||
+ (CV_MAT_TYPE(R->type) != CV_32FC1 && CV_MAT_TYPE(R->type) != CV_64FC1) )
+ CV_ERROR( CV_StsBadArg, "Rotaion/homography matrix must be a valid 3x3 floating-point matrix" );
+
+ if( distCoeffs )
+ {
+ CV_ASSERT( CV_IS_MAT(distCoeffs) &&
+ (distCoeffs->rows == 1 || distCoeffs->cols == 1) &&
+ (distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) == 4 ||
+ distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) == 5) &&
+ (CV_MAT_DEPTH(distCoeffs->type) == CV_64F ||
+ CV_MAT_DEPTH(distCoeffs->type) == CV_32F) );
+ _k = cvMat( distCoeffs->rows, distCoeffs->cols,
+ CV_MAKETYPE(CV_64F, CV_MAT_CN(distCoeffs->type)), k );
+ cvConvert( distCoeffs, &_k );
+ }
+ else
+ cvZero( &_k );
+
+ cvConvert( R, &_r ); // rectification matrix
+ cvMatMul( &_ar, &_r, &_r ); // Ar*R
+ cvInvert( &_r, &_ir ); // inverse: R^-1*Ar^-1
+
+ u0 = a[2]; v0 = a[5];
+ fx = a[0]; fy = a[4];
+ k1 = k[0]; k2 = k[1]; k3 = k[4];
+ p1 = k[2]; p2 = k[3];
+
+ size = cvGetMatSize(_mapx);
+
+ for( i = 0; i < size.height; i++ )
+ {
+ float* mapx = (float*)(_mapx->data.ptr + _mapx->step*i);
+ float* mapy = (float*)(_mapy->data.ptr + _mapy->step*i);
+ double _x = i*ir[1] + ir[2], _y = i*ir[4] + ir[5], _w = i*ir[7] + ir[8];
+
+ for( j = 0; j < size.width; j++, _x += ir[0], _y += ir[3], _w += ir[6] )
+ {
+ double w = 1./_w, x = _x*w, y = _y*w;
+ double x2 = x*x, y2 = y*y;
+ double r2 = x2 + y2, _2xy = 2*x*y;
+ double kr = 1 + ((k3*r2 + k2)*r2 + k1)*r2;
+ double u = fx*(x*kr + p1*_2xy + p2*(r2 + 2*x2)) + u0;
+ double v = fy*(y*kr + p1*(r2 + 2*y2) + p2*_2xy) + v0;
+ mapx[j] = (float)u;
+ mapy[j] = (float)v;
+ }
+ }
+
+ __END__;
+}
+
+
+void
+cvUndistortPoints( const CvMat* _src, CvMat* _dst, const CvMat* _cameraMatrix,
+ const CvMat* _distCoeffs,
+ const CvMat* _R, const CvMat* _P )
+{
+ CV_FUNCNAME( "cvUndistortPoints" );
+
+ __BEGIN__;
+
+ double A[3][3], RR[3][3], k[5]={0,0,0,0,0}, fx, fy, ifx, ify, cx, cy;
+ CvMat _A=cvMat(3, 3, CV_64F, A), _Dk;
+ CvMat _RR=cvMat(3, 3, CV_64F, RR);
+ const CvPoint2D32f* srcf;
+ const CvPoint2D64f* srcd;
+ CvPoint2D32f* dstf;
+ CvPoint2D64f* dstd;
+ int stype, dtype;
+ int sstep, dstep;
+ int i, j, n;
+
+ CV_ASSERT( CV_IS_MAT(_src) && CV_IS_MAT(_dst) &&
+ (_src->rows == 1 || _src->cols == 1) &&
+ (_dst->rows == 1 || _dst->cols == 1) &&
+ CV_ARE_SIZES_EQ(_src, _dst) &&
+ (CV_MAT_TYPE(_src->type) == CV_32FC2 || CV_MAT_TYPE(_src->type) == CV_64FC2) &&
+ (CV_MAT_TYPE(_dst->type) == CV_32FC2 || CV_MAT_TYPE(_dst->type) == CV_64FC2));
+
+ CV_ASSERT( CV_IS_MAT(_cameraMatrix) && CV_IS_MAT(_distCoeffs) &&
+ _cameraMatrix->rows == 3 && _cameraMatrix->cols == 3 &&
+ (_distCoeffs->rows == 1 || _distCoeffs->cols == 1) &&
+ (_distCoeffs->rows*_distCoeffs->cols == 4 ||
+ _distCoeffs->rows*_distCoeffs->cols == 5) );
+ _Dk = cvMat( _distCoeffs->rows, _distCoeffs->cols,
+ CV_MAKETYPE(CV_64F,CV_MAT_CN(_distCoeffs->type)), k);
+ cvConvert( _cameraMatrix, &_A );
+ cvConvert( _distCoeffs, &_Dk );
+
+ if( _R )
+ {
+ CV_ASSERT( CV_IS_MAT(_R) && _R->rows == 3 && _R->cols == 3 );
+ cvConvert( _R, &_RR );
+ }
+ else
+ cvSetIdentity(&_RR);
+
+ if( _P )
+ {
+ double PP[3][3];
+ CvMat _P3x3, _PP=cvMat(3, 3, CV_64F, PP);
+ CV_ASSERT( CV_IS_MAT(_P) && _P->rows == 3 && (_P->cols == 3 || _P->cols == 4));
+ cvConvert( cvGetCols(_P, &_P3x3, 0, 3), &_PP );
+ cvMatMul( &_PP, &_RR, &_RR );
+ }
+
+ srcf = (const CvPoint2D32f*)_src->data.ptr;
+ srcd = (const CvPoint2D64f*)_src->data.ptr;
+ dstf = (CvPoint2D32f*)_dst->data.ptr;
+ dstd = (CvPoint2D64f*)_dst->data.ptr;
+ stype = CV_MAT_TYPE(_src->type);
+ dtype = CV_MAT_TYPE(_dst->type);
+ sstep = _src->rows == 1 ? 1 : _src->step/CV_ELEM_SIZE(stype);
+ dstep = _dst->rows == 1 ? 1 : _dst->step/CV_ELEM_SIZE(dtype);
+
+ n = _src->rows + _src->cols - 1;
+
+ fx = A[0][0];
+ fy = A[1][1];
+ ifx = 1./fx;
+ ify = 1./fy;
+ cx = A[0][2];
+ cy = A[1][2];
+
+ for( i = 0; i < n; i++ )
+ {
+ double x, y, x0, y0;
+ if( stype == CV_32FC2 )
+ {
+ x = srcf[i*sstep].x;
+ y = srcf[i*sstep].y;
+ }
+ else
+ {
+ x = srcd[i*sstep].x;
+ y = srcd[i*sstep].y;
+ }
+
+ x0 = x = (x - cx)*ifx;
+ y0 = y = (y - cy)*ify;
+
+ // compensate distortion iteratively
+ for( j = 0; j < 5; j++ )
+ {
+ double r2 = x*x + y*y;
+ double icdist = 1./(1 + ((k[4]*r2 + k[1])*r2 + k[0])*r2);
+ double deltaX = 2*k[2]*x*y + k[3]*(r2 + 2*x*x);
+ double deltaY = k[2]*(r2 + 2*y*y) + 2*k[3]*x*y;
+ x = (x0 - deltaX)*icdist;
+ y = (y0 - deltaY)*icdist;
+ }
+
+ double xx = RR[0][0]*x + RR[0][1]*y + RR[0][2];
+ double yy = RR[1][0]*x + RR[1][1]*y + RR[1][2];
+ double ww = 1./(RR[2][0]*x + RR[2][1]*y + RR[2][2]);
+ x = xx*ww;
+ y = yy*ww;
+
+ if( dtype == CV_32FC2 )
+ {
+ dstf[i*dstep].x = (float)x;
+ dstf[i*dstep].y = (float)y;
+ }
+ else
+ {
+ dstd[i*dstep].x = x;
+ dstd[i*dstep].y = y;
+ }
+ }
+
+ __END__;
+}
+
+/* End of file */
diff --git a/cv/src/cvutils.cpp b/cv/src/cvutils.cpp
new file mode 100644
index 0000000..c88b309
--- /dev/null
+++ b/cv/src/cvutils.cpp
@@ -0,0 +1,540 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cv.h"
+
+CV_IMPL CvSeq* cvPointSeqFromMat( int seq_kind, const CvArr* arr,
+ CvContour* contour_header, CvSeqBlock* block )
+{
+ CvSeq* contour = 0;
+
+ CV_FUNCNAME( "cvPointSeqFromMat" );
+
+ assert( arr != 0 && contour_header != 0 && block != 0 );
+
+ __BEGIN__;
+
+ int eltype;
+ CvMat* mat = (CvMat*)arr;
+
+ if( !CV_IS_MAT( mat ))
+ CV_ERROR( CV_StsBadArg, "Input array is not a valid matrix" );
+
+ eltype = CV_MAT_TYPE( mat->type );
+ if( eltype != CV_32SC2 && eltype != CV_32FC2 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "The matrix can not be converted to point sequence because of "
+ "inappropriate element type" );
+
+ if( (mat->width != 1 && mat->height != 1) || !CV_IS_MAT_CONT(mat->type))
+ CV_ERROR( CV_StsBadArg,
+ "The matrix converted to point sequence must be "
+ "1-dimensional and continuous" );
+
+ CV_CALL( cvMakeSeqHeaderForArray(
+ (seq_kind & (CV_SEQ_KIND_MASK|CV_SEQ_FLAG_CLOSED)) | eltype,
+ sizeof(CvContour), CV_ELEM_SIZE(eltype), mat->data.ptr,
+ mat->width*mat->height, (CvSeq*)contour_header, block ));
+
+ contour = (CvSeq*)contour_header;
+
+ __END__;
+
+ return contour;
+}
+
+
+typedef CvStatus (CV_STDCALL * CvCopyNonConstBorderFunc)(
+ const void*, int, CvSize, void*, int, CvSize, int, int );
+
+typedef CvStatus (CV_STDCALL * CvCopyNonConstBorderFuncI)(
+ const void*, int, CvSize, CvSize, int, int );
+
+icvCopyReplicateBorder_8u_C1R_t icvCopyReplicateBorder_8u_C1R_p = 0;
+icvCopyReplicateBorder_16s_C1R_t icvCopyReplicateBorder_16s_C1R_p = 0;
+icvCopyReplicateBorder_8u_C3R_t icvCopyReplicateBorder_8u_C3R_p = 0;
+icvCopyReplicateBorder_32s_C1R_t icvCopyReplicateBorder_32s_C1R_p = 0;
+icvCopyReplicateBorder_16s_C3R_t icvCopyReplicateBorder_16s_C3R_p = 0;
+icvCopyReplicateBorder_16s_C4R_t icvCopyReplicateBorder_16s_C4R_p = 0;
+icvCopyReplicateBorder_32s_C3R_t icvCopyReplicateBorder_32s_C3R_p = 0;
+icvCopyReplicateBorder_32s_C4R_t icvCopyReplicateBorder_32s_C4R_p = 0;
+
+icvCopyReplicateBorder_8u_C1IR_t icvCopyReplicateBorder_8u_C1IR_p = 0;
+icvCopyReplicateBorder_16s_C1IR_t icvCopyReplicateBorder_16s_C1IR_p = 0;
+icvCopyReplicateBorder_8u_C3IR_t icvCopyReplicateBorder_8u_C3IR_p = 0;
+icvCopyReplicateBorder_32s_C1IR_t icvCopyReplicateBorder_32s_C1IR_p = 0;
+icvCopyReplicateBorder_16s_C3IR_t icvCopyReplicateBorder_16s_C3IR_p = 0;
+icvCopyReplicateBorder_16s_C4IR_t icvCopyReplicateBorder_16s_C4IR_p = 0;
+icvCopyReplicateBorder_32s_C3IR_t icvCopyReplicateBorder_32s_C3IR_p = 0;
+icvCopyReplicateBorder_32s_C4IR_t icvCopyReplicateBorder_32s_C4IR_p = 0;
+
+
+CvStatus CV_STDCALL
+icvCopyReplicateBorder_8u( const uchar* src, int srcstep, CvSize srcroi,
+ uchar* dst, int dststep, CvSize dstroi,
+ int top, int left, int cn, const uchar* )
+{
+ const int isz = (int)sizeof(int);
+ int i, j;
+
+ if( srcstep == dststep && dst + dststep*top + left*cn == src &&
+ icvCopyReplicateBorder_8u_C1IR_p )
+ {
+ CvCopyNonConstBorderFuncI ifunc =
+ cn == 1 ? icvCopyReplicateBorder_8u_C1IR_p :
+ cn == 2 ? icvCopyReplicateBorder_16s_C1IR_p :
+ cn == 3 ? icvCopyReplicateBorder_8u_C3IR_p :
+ cn == 4 ? icvCopyReplicateBorder_32s_C1IR_p :
+ cn == 6 ? icvCopyReplicateBorder_16s_C3IR_p :
+ cn == 8 ? icvCopyReplicateBorder_16s_C4IR_p :
+ cn == 12 ? icvCopyReplicateBorder_32s_C3IR_p :
+ cn == 16 ? icvCopyReplicateBorder_32s_C4IR_p : 0;
+
+ if( ifunc )
+ return ifunc( src, srcstep, srcroi, dstroi, top, left );
+ }
+ else if( icvCopyReplicateBorder_8u_C1R_p )
+ {
+ CvCopyNonConstBorderFunc func =
+ cn == 1 ? icvCopyReplicateBorder_8u_C1R_p :
+ cn == 2 ? icvCopyReplicateBorder_16s_C1R_p :
+ cn == 3 ? icvCopyReplicateBorder_8u_C3R_p :
+ cn == 4 ? icvCopyReplicateBorder_32s_C1R_p :
+ cn == 6 ? icvCopyReplicateBorder_16s_C3R_p :
+ cn == 8 ? icvCopyReplicateBorder_16s_C4R_p :
+ cn == 12 ? icvCopyReplicateBorder_32s_C3R_p :
+ cn == 16 ? icvCopyReplicateBorder_32s_C4R_p : 0;
+
+ if( func )
+ return func( src, srcstep, srcroi, dst, dststep, dstroi, top, left );
+ }
+
+ if( (cn | srcstep | dststep | (size_t)src | (size_t)dst) % isz == 0 )
+ {
+ const int* isrc = (const int*)src;
+ int* idst = (int*)dst;
+
+ cn /= isz;
+ srcstep /= isz;
+ dststep /= isz;
+
+ srcroi.width *= cn;
+ dstroi.width *= cn;
+ left *= cn;
+
+ for( i = 0; i < dstroi.height; i++, idst += dststep )
+ {
+ if( idst + left != isrc )
+ for( j = 0; j < srcroi.width; j++ )
+ idst[j + left] = isrc[j];
+ for( j = left - 1; j >= 0; j-- )
+ idst[j] = idst[j + cn];
+ for( j = left+srcroi.width; j < dstroi.width; j++ )
+ idst[j] = idst[j - cn];
+ if( i >= top && i < top + srcroi.height - 1 )
+ isrc += srcstep;
+ }
+ }
+ else
+ {
+ srcroi.width *= cn;
+ dstroi.width *= cn;
+ left *= cn;
+
+ for( i = 0; i < dstroi.height; i++, dst += dststep )
+ {
+ if( dst + left != src )
+ for( j = 0; j < srcroi.width; j++ )
+ dst[j + left] = src[j];
+ for( j = left - 1; j >= 0; j-- )
+ dst[j] = dst[j + cn];
+ for( j = left+srcroi.width; j < dstroi.width; j++ )
+ dst[j] = dst[j - cn];
+ if( i >= top && i < top + srcroi.height - 1 )
+ src += srcstep;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvCopyReflect101Border_8u( const uchar* src, int srcstep, CvSize srcroi,
+ uchar* dst, int dststep, CvSize dstroi,
+ int top, int left, int cn )
+{
+ const int isz = (int)sizeof(int);
+ int i, j, k, t, dj, tab_size, int_mode = 0;
+ const int* isrc = (const int*)src;
+ int* idst = (int*)dst, *tab;
+
+ if( (cn | srcstep | dststep | (size_t)src | (size_t)dst) % isz == 0 )
+ {
+ cn /= isz;
+ srcstep /= isz;
+ dststep /= isz;
+
+ int_mode = 1;
+ }
+
+ srcroi.width *= cn;
+ dstroi.width *= cn;
+ left *= cn;
+
+ tab_size = dstroi.width - srcroi.width;
+ tab = (int*)cvStackAlloc( tab_size*sizeof(tab[0]) );
+
+ if( srcroi.width == 1 )
+ {
+ for( k = 0; k < cn; k++ )
+ for( i = 0; i < tab_size; i += cn )
+ tab[i + k] = k + left;
+ }
+ else
+ {
+ j = dj = cn;
+ for( i = left - cn; i >= 0; i -= cn )
+ {
+ for( k = 0; k < cn; k++ )
+ tab[i + k] = j + k + left;
+ if( (unsigned)(j += dj) >= (unsigned)srcroi.width )
+ j -= 2*dj, dj = -dj;
+ }
+
+ j = srcroi.width - cn*2;
+ dj = -cn;
+ for( i = left; i < tab_size; i += cn )
+ {
+ for( k = 0; k < cn; k++ )
+ tab[i + k] = j + k + left;
+ if( (unsigned)(j += dj) >= (unsigned)srcroi.width )
+ j -= 2*dj, dj = -dj;
+ }
+ }
+
+ if( int_mode )
+ {
+ idst += top*dststep;
+ for( i = 0; i < srcroi.height; i++, isrc += srcstep, idst += dststep )
+ {
+ if( idst + left != isrc )
+ for( j = 0; j < srcroi.width; j++ )
+ idst[j + left] = isrc[j];
+ for( j = 0; j < left; j++ )
+ {
+ k = tab[j];
+ idst[j] = idst[k];
+ }
+ for( ; j < tab_size; j++ )
+ {
+ k = tab[j];
+ idst[j + srcroi.width] = idst[k];
+ }
+ }
+ isrc -= srcroi.height*srcstep;
+ idst -= (top - srcroi.height)*dststep;
+ }
+ else
+ {
+ dst += top*dststep;
+ for( i = 0; i < srcroi.height; i++, src += srcstep, dst += dststep )
+ {
+ if( dst + left != src )
+ for( j = 0; j < srcroi.width; j++ )
+ dst[j + left] = src[j];
+ for( j = 0; j < left; j++ )
+ {
+ k = tab[j];
+ dst[j] = dst[k];
+ }
+ for( ; j < tab_size; j++ )
+ {
+ k = tab[j];
+ dst[j + srcroi.width] = dst[k];
+ }
+ }
+ src -= srcroi.height*srcstep;
+ dst -= (top - srcroi.height)*dststep;
+ }
+
+ for( t = 0; t < 2; t++ )
+ {
+ int i1, i2, di;
+ if( t == 0 )
+ i1 = top-1, i2 = 0, di = -1, j = 1, dj = 1;
+ else
+ i1 = top+srcroi.height, i2=dstroi.height, di = 1, j = srcroi.height-2, dj = -1;
+
+ for( i = i1; i != i2; i += di )
+ {
+ if( int_mode )
+ {
+ const int* s = idst + i*dststep;
+ int* d = idst + (j+top)*dststep;
+ for( k = 0; k < dstroi.width; k++ )
+ d[k] = s[k];
+ }
+ else
+ {
+ const uchar* s = dst + i*dststep;
+ uchar* d = dst + (j+top)*dststep;
+ for( k = 0; k < dstroi.width; k++ )
+ d[k] = s[k];
+ }
+
+ if( (unsigned)(j += dj) >= (unsigned)srcroi.height )
+ j -= 2*dj, dj = -dj;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvCopyConstBorder_8u( const uchar* src, int srcstep, CvSize srcroi,
+ uchar* dst, int dststep, CvSize dstroi,
+ int top, int left, int cn, const uchar* value )
+{
+ const int isz = (int)sizeof(int);
+ int i, j, k;
+ if( (cn | srcstep | dststep | (size_t)src | (size_t)dst | (size_t)value) % isz == 0 )
+ {
+ const int* isrc = (const int*)src;
+ int* idst = (int*)dst;
+ const int* ivalue = (const int*)value;
+ int v0 = ivalue[0];
+
+ cn /= isz;
+ srcstep /= isz;
+ dststep /= isz;
+
+ srcroi.width *= cn;
+ dstroi.width *= cn;
+ left *= cn;
+
+ for( j = 1; j < cn; j++ )
+ if( ivalue[j] != ivalue[0] )
+ break;
+
+ if( j == cn )
+ cn = 1;
+
+ if( dstroi.width <= 0 )
+ return CV_OK;
+
+ for( i = 0; i < dstroi.height; i++, idst += dststep )
+ {
+ if( i < top || i >= top + srcroi.height )
+ {
+ if( cn == 1 )
+ {
+ for( j = 0; j < dstroi.width; j++ )
+ idst[j] = v0;
+ }
+ else
+ {
+ for( j = 0; j < cn; j++ )
+ idst[j] = ivalue[j];
+ for( ; j < dstroi.width; j++ )
+ idst[j] = idst[j - cn];
+ }
+ continue;
+ }
+
+ if( cn == 1 )
+ {
+ for( j = 0; j < left; j++ )
+ idst[j] = v0;
+ for( j = srcroi.width + left; j < dstroi.width; j++ )
+ idst[j] = v0;
+ }
+ else
+ {
+ for( k = 0; k < cn; k++ )
+ {
+ for( j = 0; j < left; j += cn )
+ idst[j+k] = ivalue[k];
+ for( j = srcroi.width + left; j < dstroi.width; j += cn )
+ idst[j+k] = ivalue[k];
+ }
+ }
+
+ if( idst + left != isrc )
+ for( j = 0; j < srcroi.width; j++ )
+ idst[j + left] = isrc[j];
+ isrc += srcstep;
+ }
+ }
+ else
+ {
+ uchar v0 = value[0];
+
+ srcroi.width *= cn;
+ dstroi.width *= cn;
+ left *= cn;
+
+ for( j = 1; j < cn; j++ )
+ if( value[j] != value[0] )
+ break;
+
+ if( j == cn )
+ cn = 1;
+
+ if( dstroi.width <= 0 )
+ return CV_OK;
+
+ for( i = 0; i < dstroi.height; i++, dst += dststep )
+ {
+ if( i < top || i >= top + srcroi.height )
+ {
+ if( cn == 1 )
+ {
+ for( j = 0; j < dstroi.width; j++ )
+ dst[j] = v0;
+ }
+ else
+ {
+ for( j = 0; j < cn; j++ )
+ dst[j] = value[j];
+ for( ; j < dstroi.width; j++ )
+ dst[j] = dst[j - cn];
+ }
+ continue;
+ }
+
+ if( cn == 1 )
+ {
+ for( j = 0; j < left; j++ )
+ dst[j] = v0;
+ for( j = srcroi.width + left; j < dstroi.width; j++ )
+ dst[j] = v0;
+ }
+ else
+ {
+ for( k = 0; k < cn; k++ )
+ {
+ for( j = 0; j < left; j += cn )
+ dst[j+k] = value[k];
+ for( j = srcroi.width + left; j < dstroi.width; j += cn )
+ dst[j+k] = value[k];
+ }
+ }
+
+ if( dst + left != src )
+ for( j = 0; j < srcroi.width; j++ )
+ dst[j + left] = src[j];
+ src += srcstep;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+CV_IMPL void
+cvCopyMakeBorder( const CvArr* srcarr, CvArr* dstarr, CvPoint offset,
+ int bordertype, CvScalar value )
+{
+ CV_FUNCNAME( "cvCopyMakeBorder" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize srcsize, dstsize;
+ int srcstep, dststep;
+ int pix_size, type;
+
+ if( !CV_IS_MAT(src) )
+ CV_CALL( src = cvGetMat( src, &srcstub ));
+
+ if( !CV_IS_MAT(dst) )
+ CV_CALL( dst = cvGetMat( dst, &dststub ));
+
+ if( offset.x < 0 || offset.y < 0 )
+ CV_ERROR( CV_StsOutOfRange, "Offset (left/top border width) is negative" );
+
+ if( src->rows + offset.y > dst->rows || src->cols + offset.x > dst->cols )
+ CV_ERROR( CV_StsBadSize, "Source array is too big or destination array is too small" );
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ type = CV_MAT_TYPE(src->type);
+ pix_size = CV_ELEM_SIZE(type);
+ srcsize = cvGetMatSize(src);
+ dstsize = cvGetMatSize(dst);
+ srcstep = src->step;
+ dststep = dst->step;
+ if( srcstep == 0 )
+ srcstep = CV_STUB_STEP;
+ if( dststep == 0 )
+ dststep = CV_STUB_STEP;
+
+ if( bordertype == IPL_BORDER_REPLICATE )
+ {
+ icvCopyReplicateBorder_8u( src->data.ptr, srcstep, srcsize,
+ dst->data.ptr, dststep, dstsize,
+ offset.y, offset.x, pix_size );
+ }
+ else if( bordertype == IPL_BORDER_REFLECT_101 )
+ {
+ icvCopyReflect101Border_8u( src->data.ptr, srcstep, srcsize,
+ dst->data.ptr, dststep, dstsize,
+ offset.y, offset.x, pix_size );
+ }
+ else if( bordertype == IPL_BORDER_CONSTANT )
+ {
+ double buf[4];
+ cvScalarToRawData( &value, buf, src->type, 0 );
+ icvCopyConstBorder_8u( src->data.ptr, srcstep, srcsize,
+ dst->data.ptr, dststep, dstsize,
+ offset.y, offset.x, pix_size, (uchar*)buf );
+ }
+ else
+ CV_ERROR( CV_StsBadFlag, "Unknown/unsupported border type" );
+
+ __END__;
+}
+
+/* End of file. */
diff --git a/cv/src/mycvHaarDetectObjects.cpp b/cv/src/mycvHaarDetectObjects.cpp
new file mode 100644
index 0000000..18b946c
--- /dev/null
+++ b/cv/src/mycvHaarDetectObjects.cpp
@@ -0,0 +1,1572 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/* Haar features calculation */
+
+#include "_cv.h"
+#include <stdio.h>
+
+/* these settings affect the quality of detection: change with care */
+#define CV_ADJUST_FEATURES 1
+#define CV_ADJUST_WEIGHTS 1
+
+typedef int sumtype;
+typedef double sqsumtype;
+
+typedef struct MyCvHidHaarFeature
+ {
+ struct
+ {
+ sumtype *p0, *p1, *p2, *p3;
+ int weight;
+ }
+ rect[CV_HAAR_FEATURE_MAX];
+ }
+ MyCvHidHaarFeature;
+
+
+typedef struct MyCvHidHaarTreeNode
+ {
+ MyCvHidHaarFeature feature;
+ int threshold;
+ int left;
+ int right;
+ }
+ MyCvHidHaarTreeNode;
+
+
+typedef struct MyCvHidHaarClassifier
+ {
+ int count;
+ //CvHaarFeature* orig_feature;
+ MyCvHidHaarTreeNode* node;
+ float* alpha;
+ }
+ MyCvHidHaarClassifier;
+
+
+typedef struct MyCvHidHaarStageClassifier
+ {
+ int count;
+ float threshold;
+ MyCvHidHaarClassifier* classifier;
+ int two_rects;
+
+ struct MyCvHidHaarStageClassifier* next;
+ struct MyCvHidHaarStageClassifier* child;
+ struct MyCvHidHaarStageClassifier* parent;
+ }
+ MyCvHidHaarStageClassifier;
+
+
+struct MyCvHidHaarClassifierCascade
+{
+ int count;
+ int is_stump_based;
+ int has_tilted_features;
+ int is_tree;
+ double inv_window_area;
+ CvMat sum, sqsum, tilted;
+ MyCvHidHaarStageClassifier* stage_classifier;
+ sqsumtype *pq0, *pq1, *pq2, *pq3;
+ sumtype *p0, *p1, *p2, *p3;
+
+ void** ipp_stages;
+};
+
+
+const int icv_object_win_border = 1;
+const float icv_stage_threshold_bias = 0.0001f;
+
+static int myis_equal( const void* _r1, const void* _r2, void* )
+{
+ const CvRect* r1 = (const CvRect*)_r1;
+ const CvRect* r2 = (const CvRect*)_r2;
+ int distance = cvRound(r1->width*0.2);
+
+ return r2->x <= r1->x + distance &&
+ r2->x >= r1->x - distance &&
+ r2->y <= r1->y + distance &&
+ r2->y >= r1->y - distance &&
+ r2->width <= cvRound( r1->width * 1.2 ) &&
+ cvRound( r2->width * 1.2 ) >= r1->width;
+}
+
+static void
+myicvReleaseHidHaarClassifierCascade( MyCvHidHaarClassifierCascade** _cascade )
+{
+ if( _cascade && *_cascade )
+ {
+ /*CvHidHaarClassifierCascade* cascade = *_cascade;
+ if( cascade->ipp_stages && icvHaarClassifierFree_32f_p )
+ {
+ int i;
+ for( i = 0; i < cascade->count; i++ )
+ {
+ if( cascade->ipp_stages[i] )
+ icvHaarClassifierFree_32f_p( cascade->ipp_stages[i] );
+ }
+ }
+ cvFree( &cascade->ipp_stages );*/
+ cvFree( _cascade );
+ }
+}
+
+/* create more efficient internal representation of haar classifier cascade */
+static MyCvHidHaarClassifierCascade*
+myicvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade )
+{
+ CvRect* ipp_features = 0;
+ float *ipp_weights = 0, *ipp_thresholds = 0, *ipp_val1 = 0, *ipp_val2 = 0;
+ int* ipp_counts = 0;
+
+ MyCvHidHaarClassifierCascade* out = 0;
+
+ CV_FUNCNAME( "icvCreateHidHaarClassifierCascade" );
+
+ __BEGIN__;
+
+ int i, j, k, l;
+ int datasize;
+ int total_classifiers = 0;
+ int total_nodes = 0;
+ char errorstr[100];
+ MyCvHidHaarClassifier* haar_classifier_ptr;
+ MyCvHidHaarTreeNode* haar_node_ptr;
+ CvSize orig_window_size;
+ int has_tilted_features = 0;
+ int max_count = 0;
+
+ if( !CV_IS_HAAR_CLASSIFIER(cascade) )
+ CV_ERROR( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier pointer" );
+
+ if( cascade->hid_cascade )
+ CV_ERROR( CV_StsError, "hid_cascade has been already created" );
+
+ if( !cascade->stage_classifier )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( cascade->count <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "Negative number of cascade stages" );
+
+ orig_window_size = cascade->orig_window_size;
+
+ /* check input structure correctness and calculate total memory size needed for
+ internal representation of the classifier cascade */
+ for( i = 0; i < cascade->count; i++ )
+ {
+ CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
+
+ if( !stage_classifier->classifier ||
+ stage_classifier->count <= 0 )
+ {
+ sprintf( errorstr, "header of the stage classifier #%d is invalid "
+ "(has null pointers or non-positive classfier count)", i );
+ CV_ERROR( CV_StsError, errorstr );
+ }
+
+ max_count = MAX( max_count, stage_classifier->count );
+ total_classifiers += stage_classifier->count;
+
+ for( j = 0; j < stage_classifier->count; j++ )
+ {
+ CvHaarClassifier* classifier = stage_classifier->classifier + j;
+
+ total_nodes += classifier->count;
+ for( l = 0; l < classifier->count; l++ )
+ {
+ for( k = 0; k < CV_HAAR_FEATURE_MAX; k++ )
+ {
+ if( classifier->haar_feature[l].rect[k].r.width )
+ {
+ CvRect r = classifier->haar_feature[l].rect[k].r;
+ int tilted = classifier->haar_feature[l].tilted;
+ has_tilted_features |= tilted != 0;
+ if( r.width < 0 || r.height < 0 || r.y < 0 ||
+ r.x + r.width > orig_window_size.width
+ ||
+ (!tilted &&
+ (r.x < 0 || r.y + r.height > orig_window_size.height))
+ ||
+ (tilted && (r.x - r.height < 0 ||
+ r.y + r.width + r.height > orig_window_size.height)))
+ {
+ sprintf( errorstr, "rectangle #%d of the classifier #%d of "
+ "the stage classifier #%d is not inside "
+ "the reference (original) cascade window", k, j, i );
+ CV_ERROR( CV_StsNullPtr, errorstr );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // this is an upper boundary for the whole hidden cascade size
+ datasize = sizeof(MyCvHidHaarClassifierCascade) +
+ sizeof(MyCvHidHaarStageClassifier)*cascade->count +
+ sizeof(MyCvHidHaarClassifier) * total_classifiers +
+ sizeof(MyCvHidHaarTreeNode) * total_nodes +
+ sizeof(void*)*(total_nodes + total_classifiers);
+
+ CV_CALL( out = (MyCvHidHaarClassifierCascade*)cvAlloc( datasize ));
+ memset( out, 0, sizeof(*out) );
+
+ /* init header */
+ out->count = cascade->count;
+ out->stage_classifier = (MyCvHidHaarStageClassifier*)(out + 1);
+ haar_classifier_ptr = (MyCvHidHaarClassifier*)(out->stage_classifier + cascade->count);
+ haar_node_ptr = (MyCvHidHaarTreeNode*)(haar_classifier_ptr + total_classifiers);
+
+ out->is_stump_based = 1;
+ out->has_tilted_features = has_tilted_features;
+ out->is_tree = 0;
+
+ /* initialize internal representation */
+ for( i = 0; i < cascade->count; i++ )
+ {
+ CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
+ MyCvHidHaarStageClassifier* hid_stage_classifier = out->stage_classifier + i;
+
+ hid_stage_classifier->count = stage_classifier->count;
+ hid_stage_classifier->threshold = stage_classifier->threshold - icv_stage_threshold_bias;
+ hid_stage_classifier->classifier = haar_classifier_ptr;
+ hid_stage_classifier->two_rects = 1;
+ haar_classifier_ptr += stage_classifier->count;
+
+ hid_stage_classifier->parent = (stage_classifier->parent == -1)
+ ? NULL : out->stage_classifier + stage_classifier->parent;
+ hid_stage_classifier->next = (stage_classifier->next == -1)
+ ? NULL : out->stage_classifier + stage_classifier->next;
+ hid_stage_classifier->child = (stage_classifier->child == -1)
+ ? NULL : out->stage_classifier + stage_classifier->child;
+
+ out->is_tree |= hid_stage_classifier->next != NULL;
+
+ for( j = 0; j < stage_classifier->count; j++ )
+ {
+ CvHaarClassifier* classifier = stage_classifier->classifier + j;
+ MyCvHidHaarClassifier* hid_classifier = hid_stage_classifier->classifier + j;
+ int node_count = classifier->count;
+ float* alpha_ptr = (float*)(haar_node_ptr + node_count);
+
+ hid_classifier->count = node_count;
+ hid_classifier->node = haar_node_ptr;
+ hid_classifier->alpha = alpha_ptr;
+
+ for( l = 0; l < node_count; l++ )
+ {
+ MyCvHidHaarTreeNode* node = hid_classifier->node + l;
+ CvHaarFeature* feature = classifier->haar_feature + l;
+ memset( node, -1, sizeof(*node) );
+ node->threshold = (int)((classifier->threshold[l]) * 65536.0);
+ node->left = classifier->left[l];
+ node->right = classifier->right[l];
+
+ if( fabs(feature->rect[2].weight) < DBL_EPSILON ||
+ feature->rect[2].r.width == 0 ||
+ feature->rect[2].r.height == 0 )
+ memset( &(node->feature.rect[2]), 0, sizeof(node->feature.rect[2]) );
+ else
+ hid_stage_classifier->two_rects = 0;
+ }
+
+ memcpy( alpha_ptr, classifier->alpha, (node_count+1)*sizeof(alpha_ptr[0]));
+ haar_node_ptr =
+ (MyCvHidHaarTreeNode*)cvAlignPtr(alpha_ptr+node_count+1, sizeof(void*));
+
+ out->is_stump_based &= node_count == 1;
+ }
+ }
+
+ /*{
+ int can_use_ipp = icvHaarClassifierInitAlloc_32f_p != 0 &&
+ icvHaarClassifierFree_32f_p != 0 &&
+ icvApplyHaarClassifier_32f_C1R_p != 0 &&
+ icvRectStdDev_32f_C1R_p != 0 &&
+ !out->has_tilted_features && !out->is_tree && out->is_stump_based;
+
+ if( can_use_ipp )
+ {
+ int ipp_datasize = cascade->count*sizeof(out->ipp_stages[0]);
+ float ipp_weight_scale=(float)(1./((orig_window_size.width-icv_object_win_border*2)*
+ (orig_window_size.height-icv_object_win_border*2)));
+
+ CV_CALL( out->ipp_stages = (void**)cvAlloc( ipp_datasize ));
+ memset( out->ipp_stages, 0, ipp_datasize );
+
+ CV_CALL( ipp_features = (CvRect*)cvAlloc( max_count*3*sizeof(ipp_features[0]) ));
+ CV_CALL( ipp_weights = (float*)cvAlloc( max_count*3*sizeof(ipp_weights[0]) ));
+ CV_CALL( ipp_thresholds = (float*)cvAlloc( max_count*sizeof(ipp_thresholds[0]) ));
+ CV_CALL( ipp_val1 = (float*)cvAlloc( max_count*sizeof(ipp_val1[0]) ));
+ CV_CALL( ipp_val2 = (float*)cvAlloc( max_count*sizeof(ipp_val2[0]) ));
+ CV_CALL( ipp_counts = (int*)cvAlloc( max_count*sizeof(ipp_counts[0]) ));
+
+ for( i = 0; i < cascade->count; i++ )
+ {
+ CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
+ for( j = 0, k = 0; j < stage_classifier->count; j++ )
+ {
+ CvHaarClassifier* classifier = stage_classifier->classifier + j;
+ int rect_count = 2 + (classifier->haar_feature->rect[2].r.width != 0);
+
+ ipp_thresholds[j] = classifier->threshold[0];
+ ipp_val1[j] = classifier->alpha[0];
+ ipp_val2[j] = classifier->alpha[1];
+ ipp_counts[j] = rect_count;
+
+ for( l = 0; l < rect_count; l++, k++ )
+ {
+ ipp_features[k] = classifier->haar_feature->rect[l].r;
+ //ipp_features[k].y = orig_window_size.height - ipp_features[k].y - ipp_features[k].height;
+ ipp_weights[k] = classifier->haar_feature->rect[l].weight*ipp_weight_scale;
+ }
+ }
+
+ if( icvHaarClassifierInitAlloc_32f_p( &out->ipp_stages[i],
+ ipp_features, ipp_weights, ipp_thresholds,
+ ipp_val1, ipp_val2, ipp_counts, stage_classifier->count ) < 0 )
+ break;
+ }
+
+ if( i < cascade->count )
+ {
+ for( j = 0; j < i; j++ )
+ if( icvHaarClassifierFree_32f_p && out->ipp_stages[i] )
+ icvHaarClassifierFree_32f_p( out->ipp_stages[i] );
+ cvFree( &out->ipp_stages );
+ }
+ }
+ }*/
+
+ cascade->hid_cascade = (CvHidHaarClassifierCascade*)out;
+ assert( (char*)haar_node_ptr - (char*)out <= datasize );
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ myicvReleaseHidHaarClassifierCascade( &out );
+
+ cvFree( &ipp_features );
+ cvFree( &ipp_weights );
+ cvFree( &ipp_thresholds );
+ cvFree( &ipp_val1 );
+ cvFree( &ipp_val2 );
+ cvFree( &ipp_counts );
+
+ return out;
+}
+
+#define calc_sum(rect,offset) \
+((rect).p0[offset] - (rect).p1[offset] - (rect).p2[offset] + (rect).p3[offset])
+
+
+CV_INLINE
+double myicvEvalHidHaarClassifier( MyCvHidHaarClassifier* classifier,
+ double variance_norm_factor,
+ size_t p_offset )
+{
+ int idx = 0;
+ do
+ {
+ MyCvHidHaarTreeNode* node = classifier->node + idx;
+ double t = node->threshold * variance_norm_factor;
+
+ double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
+ sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
+
+ if( node->feature.rect[2].p0 )
+ sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight;
+
+ idx = sum < t ? node->left : node->right;
+ }
+ while( idx > 0 );
+ return classifier->alpha[-idx];
+}
+
+/*********************** Special integer sqrt **************************/
+
+int
+isqrt(int x)
+{
+ /*
+ * Logically, these are unsigned. We need the sign bit to test
+ * whether (op - res - one) underflowed.
+ */
+
+ register int op, res, one;
+
+ op = x;
+ res = 0;
+
+ /* "one" starts at the highest power of four <= than the argument. */
+
+ one = 1 << 30; /* second-to-top bit set */
+ while (one > op) one >>= 2;
+
+ while (one != 0) {
+ if (op >= res + one) {
+ op = op - (res + one);
+ res = res + 2 * one;
+ }
+ res /= 2;
+ one /= 4;
+ }
+ return(res);
+}
+
+#define NEXT(n, i) (((n) + (i)/(n)) >> 1)
+
+unsigned int isqrt1(int number) {
+ unsigned int n = 1;
+ unsigned int n1 = NEXT(n, number);
+
+ while(abs(n1 - n) > 1) {
+ n = n1;
+ n1 = NEXT(n, number);
+ }
+ while((n1*n1) > number) {
+ n1 -= 1;
+ }
+ return n1;
+}
+/***********************************************************************/
+
+CV_IMPL int
+mycvRunHaarClassifierCascade( CvHaarClassifierCascade* _cascade,
+ CvPoint pt, int start_stage )
+{
+ int result = -1;
+ CV_FUNCNAME("mycvRunHaarClassifierCascade");
+
+ __BEGIN__;
+
+ int p_offset, pq_offset;
+ int pq0, pq1, pq2, pq3;
+ int i, j;
+ double mean;
+ int variance_norm_factor;
+ MyCvHidHaarClassifierCascade* cascade;
+
+ if( !CV_IS_HAAR_CLASSIFIER(_cascade) )
+ CV_ERROR( !_cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid cascade pointer" );
+
+ cascade = (MyCvHidHaarClassifierCascade*)_cascade->hid_cascade;
+ if( !cascade )
+ CV_ERROR( CV_StsNullPtr, "Hidden cascade has not been created.\n"
+ "Use cvSetImagesForHaarClassifierCascade" );
+
+ if( pt.x < 0 || pt.y < 0 ||
+ pt.x + _cascade->real_window_size.width >= cascade->sum.width-2 ||
+ pt.y + _cascade->real_window_size.height >= cascade->sum.height-2 )
+ EXIT;
+
+ p_offset = pt.y * (cascade->sum.step/sizeof(sumtype)) + pt.x;
+ pq_offset = pt.y * (cascade->sqsum.step/sizeof(sqsumtype)) + pt.x;
+ mean = calc_sum(*cascade,p_offset) * cascade->inv_window_area;
+ pq0 = cascade->pq0[pq_offset];
+ pq1 = cascade->pq1[pq_offset];
+ pq2 = cascade->pq2[pq_offset];
+ pq3 = cascade->pq3[pq_offset];
+ variance_norm_factor = pq0 - pq1 - pq2 + pq3;
+ variance_norm_factor = variance_norm_factor * cascade->inv_window_area - mean * mean;
+ if( variance_norm_factor >= 0. )
+ variance_norm_factor = sqrt(variance_norm_factor);
+ else
+ variance_norm_factor = 1.;
+
+// if( cascade->is_tree )
+// {
+// MyCvHidHaarStageClassifier* ptr;
+// assert( start_stage == 0 );
+//
+// result = 1;
+// ptr = cascade->stage_classifier;
+//
+// while( ptr )
+// {
+// double stage_sum = 0;
+//
+// for( j = 0; j < ptr->count; j++ )
+// {
+// stage_sum += myicvEvalHidHaarClassifier( ptr->classifier + j,
+// variance_norm_factor, p_offset );
+// }
+//
+// if( stage_sum >= ptr->threshold )
+// {
+// ptr = ptr->child;
+// }
+// else
+// {
+// while( ptr && ptr->next == NULL ) ptr = ptr->parent;
+// if( ptr == NULL )
+// {
+// result = 0;
+// EXIT;
+// }
+// ptr = ptr->next;
+// }
+// }
+// }
+// else if( cascade->is_stump_based )
+ {
+ for( i = start_stage; i < cascade->count; i++ )
+ {
+ double stage_sum = 0;
+
+ if( cascade->stage_classifier[i].two_rects )
+ {
+ for( j = 0; j < cascade->stage_classifier[i].count; j++ )
+ {
+ MyCvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
+ MyCvHidHaarTreeNode* node = classifier->node;
+ int t = node->threshold * variance_norm_factor;
+ int sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
+ sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
+ stage_sum += classifier->alpha[sum >= t];
+ }
+ }
+ else
+ {
+ for( j = 0; j < cascade->stage_classifier[i].count; j++ )
+ {
+ MyCvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
+ MyCvHidHaarTreeNode* node = classifier->node;
+ int t = node->threshold * variance_norm_factor;
+ int sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
+ sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
+ if( node->feature.rect[2].p0 )
+ sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight;
+
+ stage_sum += classifier->alpha[sum >= t];
+ }
+ }
+
+ if( stage_sum < cascade->stage_classifier[i].threshold )
+ {
+ result = -i;
+ EXIT;
+ }
+ }
+ }
+// else
+// {
+// for( i = start_stage; i < cascade->count; i++ )
+// {
+// double stage_sum = 0;
+//
+// for( j = 0; j < cascade->stage_classifier[i].count; j++ )
+// {
+// stage_sum += myicvEvalHidHaarClassifier(
+// cascade->stage_classifier[i].classifier + j,
+// variance_norm_factor, p_offset );
+// }
+//
+// if( stage_sum < cascade->stage_classifier[i].threshold )
+// {
+// result = -i;
+// EXIT;
+// }
+// }
+// }
+
+ result = 1;
+
+ __END__;
+
+ return result;
+}
+
+#define sum_elem_ptr(sum,row,col) \
+((sumtype*)CV_MAT_ELEM_PTR_FAST((sum),(row),(col),sizeof(sumtype)))
+
+#define sqsum_elem_ptr(sqsum,row,col) \
+((sqsumtype*)CV_MAT_ELEM_PTR_FAST((sqsum),(row),(col),sizeof(sqsumtype)))
+
+
+CV_IMPL void
+mycvSetImagesForHaarClassifierCascade( CvHaarClassifierCascade* _cascade,
+ const CvArr* _sum,
+ const CvArr* _sqsum,
+ const CvArr* _tilted_sum,
+ double scale )
+{
+ CV_FUNCNAME("cvSetImagesForHaarClassifierCascade");
+
+ __BEGIN__;
+
+ CvMat sum_stub, *sum = (CvMat*)_sum;
+ CvMat sqsum_stub, *sqsum = (CvMat*)_sqsum;
+ CvMat tilted_stub, *tilted = (CvMat*)_tilted_sum;
+ MyCvHidHaarClassifierCascade* cascade;
+ int coi0 = 0, coi1 = 0;
+ int i;
+ CvRect equ_rect;
+ double weight_scale;
+
+ if( !CV_IS_HAAR_CLASSIFIER(_cascade) )
+ CV_ERROR( !_cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier pointer" );
+
+ if( scale <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "Scale must be positive" );
+
+ CV_CALL( sum = cvGetMat( sum, &sum_stub, &coi0 ));
+ CV_CALL( sqsum = cvGetMat( sqsum, &sqsum_stub, &coi1 ));
+
+ if( coi0 || coi1 )
+ CV_ERROR( CV_BadCOI, "COI is not supported" );
+
+ if( !CV_ARE_SIZES_EQ( sum, sqsum ))
+ CV_ERROR( CV_StsUnmatchedSizes, "All integral images must have the same size" );
+
+ if( CV_MAT_TYPE(sqsum->type) != CV_64FC1 ||
+ CV_MAT_TYPE(sum->type) != CV_32SC1 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Only (32s, 64f, 32s) combination of (sum,sqsum,tilted_sum) formats is allowed" );
+
+ if( !_cascade->hid_cascade )
+ CV_CALL( myicvCreateHidHaarClassifierCascade(_cascade) );
+
+ cascade = (MyCvHidHaarClassifierCascade*)_cascade->hid_cascade;
+
+ if( cascade->has_tilted_features )
+ {
+ CV_CALL( tilted = cvGetMat( tilted, &tilted_stub, &coi1 ));
+
+ if( CV_MAT_TYPE(tilted->type) != CV_32SC1 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Only (32s, 64f, 32s) combination of (sum,sqsum,tilted_sum) formats is allowed" );
+
+ if( sum->step != tilted->step )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Sum and tilted_sum must have the same stride (step, widthStep)" );
+
+ if( !CV_ARE_SIZES_EQ( sum, tilted ))
+ CV_ERROR( CV_StsUnmatchedSizes, "All integral images must have the same size" );
+ cascade->tilted = *tilted;
+ }
+
+ _cascade->scale = scale;
+ _cascade->real_window_size.width = cvRound( _cascade->orig_window_size.width * scale );
+ _cascade->real_window_size.height = cvRound( _cascade->orig_window_size.height * scale );
+
+ cascade->sum = *sum;
+ cascade->sqsum = *sqsum;
+
+ equ_rect.x = equ_rect.y = cvRound(scale);
+ equ_rect.width = cvRound((_cascade->orig_window_size.width-2)*scale);
+ equ_rect.height = cvRound((_cascade->orig_window_size.height-2)*scale);
+ weight_scale = 1./(equ_rect.width*equ_rect.height);
+ cascade->inv_window_area = weight_scale;
+
+ cascade->p0 = sum_elem_ptr(*sum, equ_rect.y, equ_rect.x);
+ cascade->p1 = sum_elem_ptr(*sum, equ_rect.y, equ_rect.x + equ_rect.width );
+ cascade->p2 = sum_elem_ptr(*sum, equ_rect.y + equ_rect.height, equ_rect.x );
+ cascade->p3 = sum_elem_ptr(*sum, equ_rect.y + equ_rect.height,
+ equ_rect.x + equ_rect.width );
+
+ cascade->pq0 = sqsum_elem_ptr(*sqsum, equ_rect.y, equ_rect.x);
+ cascade->pq1 = sqsum_elem_ptr(*sqsum, equ_rect.y, equ_rect.x + equ_rect.width );
+ cascade->pq2 = sqsum_elem_ptr(*sqsum, equ_rect.y + equ_rect.height, equ_rect.x );
+ cascade->pq3 = sqsum_elem_ptr(*sqsum, equ_rect.y + equ_rect.height,
+ equ_rect.x + equ_rect.width );
+
+ /* init pointers in haar features according to real window size and
+ given image pointers */
+ {
+#ifdef _OPENMP
+ int max_threads = cvGetNumThreads();
+#pragma omp parallel for num_threads(max_threads) schedule(dynamic)
+#endif // _OPENMP
+ for( i = 0; i < _cascade->count; i++ )
+ {
+ int j, k, l;
+ for( j = 0; j < cascade->stage_classifier[i].count; j++ )
+ {
+ for( l = 0; l < cascade->stage_classifier[i].classifier[j].count; l++ )
+ {
+ CvHaarFeature* feature =
+ &_cascade->stage_classifier[i].classifier[j].haar_feature[l];
+ /* CvHidHaarClassifier* classifier =
+ cascade->stage_classifier[i].classifier + j; */
+ MyCvHidHaarFeature* hidfeature =
+ &cascade->stage_classifier[i].classifier[j].node[l].feature;
+ double sum0 = 0, area0 = 0;
+ CvRect r[3];
+#if CV_ADJUST_FEATURES
+ int base_w = -1, base_h = -1;
+ int new_base_w = 0, new_base_h = 0;
+ int kx, ky;
+ int flagx = 0, flagy = 0;
+ int x0 = 0, y0 = 0;
+#endif
+ int nr;
+
+ /* align blocks */
+ for( k = 0; k < CV_HAAR_FEATURE_MAX; k++ )
+ {
+ if( !hidfeature->rect[k].p0 )
+ break;
+#if CV_ADJUST_FEATURES
+ r[k] = feature->rect[k].r;
+ base_w = (int)CV_IMIN( (unsigned)base_w, (unsigned)(r[k].width-1) );
+ base_w = (int)CV_IMIN( (unsigned)base_w, (unsigned)(r[k].x - r[0].x-1) );
+ base_h = (int)CV_IMIN( (unsigned)base_h, (unsigned)(r[k].height-1) );
+ base_h = (int)CV_IMIN( (unsigned)base_h, (unsigned)(r[k].y - r[0].y-1) );
+#endif
+ }
+
+ nr = k;
+
+#if CV_ADJUST_FEATURES
+ base_w += 1;
+ base_h += 1;
+ kx = r[0].width / base_w;
+ ky = r[0].height / base_h;
+
+ if( kx <= 0 )
+ {
+ flagx = 1;
+ new_base_w = cvRound( r[0].width * scale ) / kx;
+ x0 = cvRound( r[0].x * scale );
+ }
+
+ if( ky <= 0 )
+ {
+ flagy = 1;
+ new_base_h = cvRound( r[0].height * scale ) / ky;
+ y0 = cvRound( r[0].y * scale );
+ }
+#endif
+
+ float tmpweight[3] = {0};
+
+ for( k = 0; k < nr; k++ )
+ {
+ CvRect tr;
+ double correction_ratio;
+
+#if CV_ADJUST_FEATURES
+ if( flagx )
+ {
+ tr.x = (r[k].x - r[0].x) * new_base_w / base_w + x0;
+ tr.width = r[k].width * new_base_w / base_w;
+ }
+ else
+#endif
+ {
+ tr.x = cvRound( r[k].x * scale );
+ tr.width = cvRound( r[k].width * scale );
+ }
+
+#if CV_ADJUST_FEATURES
+ if( flagy )
+ {
+ tr.y = (r[k].y - r[0].y) * new_base_h / base_h + y0;
+ tr.height = r[k].height * new_base_h / base_h;
+ }
+ else
+#endif
+ {
+ tr.y = cvRound( r[k].y * scale );
+ tr.height = cvRound( r[k].height * scale );
+ }
+
+#if CV_ADJUST_WEIGHTS
+ {
+ // RAINER START
+ const float orig_feature_size = (float)(feature->rect[k].r.width)*feature->rect[k].r.height;
+ const float orig_norm_size = (float)(_cascade->orig_window_size.width)*(_cascade->orig_window_size.height);
+ const float feature_size = float(tr.width*tr.height);
+ //const float normSize = float(equ_rect.width*equ_rect.height);
+ float target_ratio = orig_feature_size / orig_norm_size;
+ //float isRatio = featureSize / normSize;
+ //correctionRatio = targetRatio / isRatio / normSize;
+ correction_ratio = target_ratio / feature_size;
+ // RAINER END
+ }
+#else
+ correction_ratio = weight_scale * (!feature->tilted ? 1 : 0.5);
+#endif
+
+ if( !feature->tilted )
+ {
+ hidfeature->rect[k].p0 = sum_elem_ptr(*sum, tr.y, tr.x);
+ hidfeature->rect[k].p1 = sum_elem_ptr(*sum, tr.y, tr.x + tr.width);
+ hidfeature->rect[k].p2 = sum_elem_ptr(*sum, tr.y + tr.height, tr.x);
+ hidfeature->rect[k].p3 = sum_elem_ptr(*sum, tr.y + tr.height, tr.x + tr.width);
+ }
+ else
+ {
+ hidfeature->rect[k].p2 = sum_elem_ptr(*tilted, tr.y + tr.width, tr.x + tr.width);
+ hidfeature->rect[k].p3 = sum_elem_ptr(*tilted, tr.y + tr.width + tr.height,
+ tr.x + tr.width - tr.height);
+ hidfeature->rect[k].p0 = sum_elem_ptr(*tilted, tr.y, tr.x);
+ hidfeature->rect[k].p1 = sum_elem_ptr(*tilted, tr.y + tr.height, tr.x - tr.height);
+ }
+
+// hidfeature->rect[k].weight = (float)(feature->rect[k].weight * correction_ratio);
+ tmpweight[k] = (float)(feature->rect[k].weight * correction_ratio);
+
+ if( k == 0 )
+ area0 = tr.width * tr.height;
+ else
+// sum0 += hidfeature->rect[k].weight * tr.width * tr.height;
+ sum0 += tmpweight[k] * tr.width * tr.height;
+ }
+
+ tmpweight[0] = (float)(-sum0/area0);
+
+ for(int ii = 0; ii < nr; hidfeature->rect[ii].weight = (int)(tmpweight[ii] * 65536.0), ii++);
+ } /* l */
+ } /* j */
+ }
+ }
+
+ __END__;
+}
+
+CvMat *temp = 0, *sum = 0, *sqsum = 0;
+double tickFreqTimes1000 = ((double)cvGetTickFrequency()*1000.);
+
+CV_IMPL CvSeq*
+mycvHaarDetectObjects( const CvArr* _img,
+ CvHaarClassifierCascade* cascade,
+ CvMemStorage* storage, double scale_factor,
+ int min_neighbors, int flags, CvSize min_size )
+{
+ int split_stage = 2;
+
+ CvMat stub, *img = (CvMat*)_img;
+ CvMat *tilted = 0, *norm_img = 0, *sumcanny = 0, *img_small = 0;
+ CvSeq* result_seq = 0;
+ CvMemStorage* temp_storage = 0;
+ CvAvgComp* comps = 0;
+ CvSeq* seq_thread[CV_MAX_THREADS] = {0};
+ int i, max_threads = 0;
+ double t1;
+
+ CV_FUNCNAME( "cvHaarDetectObjects" );
+
+ __BEGIN__;
+
+ double t = (double)cvGetTickCount();
+
+ CvSeq *seq = 0, *seq2 = 0, *idx_seq = 0, *big_seq = 0;
+ CvAvgComp result_comp = {{0,0,0,0},0};
+ double factor;
+ int npass = 2, coi;
+ bool do_canny_pruning = (flags & CV_HAAR_DO_CANNY_PRUNING) != 0;
+ bool find_biggest_object = (flags & CV_HAAR_FIND_BIGGEST_OBJECT) != 0;
+ bool rough_search = (flags & CV_HAAR_DO_ROUGH_SEARCH) != 0;
+
+ if( !CV_IS_HAAR_CLASSIFIER(cascade) )
+ CV_ERROR( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier cascade" );
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "Null storage pointer" );
+
+ CV_CALL( img = cvGetMat( img, &stub, &coi ));
+ if( coi )
+ CV_ERROR( CV_BadCOI, "COI is not supported" );
+
+ if( CV_MAT_DEPTH(img->type) != CV_8U )
+ CV_ERROR( CV_StsUnsupportedFormat, "Only 8-bit images are supported" );
+
+ if( scale_factor <= 1 )
+ CV_ERROR( CV_StsOutOfRange, "scale factor must be > 1" );
+
+ if( find_biggest_object )
+ flags &= ~CV_HAAR_SCALE_IMAGE;
+
+ if(!temp) {
+ CV_CALL( temp = cvCreateMat( img->rows, img->cols, CV_8UC1 ));
+ }
+ if(!sum) {
+ CV_CALL( sum = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 ));
+ }
+ if(!sqsum) {
+ CV_CALL( sqsum = cvCreateMat( img->rows + 1, img->cols + 1, CV_64FC1 ));
+ }
+ CV_CALL( temp_storage = cvCreateChildMemStorage( storage ));
+
+ if( !cascade->hid_cascade )
+ CV_CALL( myicvCreateHidHaarClassifierCascade(cascade) );
+
+ if( ((MyCvHidHaarClassifierCascade*)cascade->hid_cascade)->has_tilted_features )
+ tilted = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 );
+
+ seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvRect), temp_storage );
+ seq2 = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), temp_storage );
+ result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), storage );
+
+ max_threads = cvGetNumThreads();
+ if( max_threads > 1 )
+ for( i = 0; i < max_threads; i++ )
+ {
+ CvMemStorage* temp_storage_thread;
+ CV_CALL( temp_storage_thread = cvCreateMemStorage(0));
+ CV_CALL( seq_thread[i] = cvCreateSeq( 0, sizeof(CvSeq),
+ sizeof(CvRect), temp_storage_thread ));
+ }
+ else
+ seq_thread[0] = seq;
+
+ if( CV_MAT_CN(img->type) > 1 )
+ {
+ cvCvtColor( img, temp, CV_BGR2GRAY );
+ img = temp;
+ }
+
+ if( flags & CV_HAAR_FIND_BIGGEST_OBJECT )
+ flags &= ~(CV_HAAR_SCALE_IMAGE|CV_HAAR_DO_CANNY_PRUNING);
+
+// if( flags & CV_HAAR_SCALE_IMAGE )
+// {
+// CvSize win_size0 = cascade->orig_window_size;
+// /*int use_ipp = cascade->hid_cascade->ipp_stages != 0 &&
+// icvApplyHaarClassifier_32f_C1R_p != 0;
+//
+// if( use_ipp )
+// CV_CALL( norm_img = cvCreateMat( img->rows, img->cols, CV_32FC1 ));*/
+// CV_CALL( img_small = cvCreateMat( img->rows + 1, img->cols + 1, CV_8UC1 ));
+//
+// for( factor = 1; ; factor *= scale_factor )
+// {
+// int strip_count, strip_size;
+// int ystep = factor > 2. ? 1 : 2;
+// CvSize win_size = { cvRound(win_size0.width*factor),
+// cvRound(win_size0.height*factor) };
+// CvSize sz = { cvRound( img->cols/factor ), cvRound( img->rows/factor ) };
+// CvSize sz1 = { sz.width - win_size0.width, sz.height - win_size0.height };
+// /*CvRect equ_rect = { icv_object_win_border, icv_object_win_border,
+// win_size0.width - icv_object_win_border*2,
+// win_size0.height - icv_object_win_border*2 };*/
+// CvMat img1, sum1, sqsum1, norm1, tilted1, mask1;
+// CvMat* _tilted = 0;
+//
+// if( sz1.width <= 0 || sz1.height <= 0 )
+// break;
+// if( win_size.width < min_size.width || win_size.height < min_size.height )
+// continue;
+//
+// img1 = cvMat( sz.height, sz.width, CV_8UC1, img_small->data.ptr );
+// sum1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, sum->data.ptr );
+// sqsum1 = cvMat( sz.height+1, sz.width+1, CV_64FC1, sqsum->data.ptr );
+// if( tilted )
+// {
+// tilted1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, tilted->data.ptr );
+// _tilted = &tilted1;
+// }
+// norm1 = cvMat( sz1.height, sz1.width, CV_32FC1, norm_img ? norm_img->data.ptr : 0 );
+// mask1 = cvMat( sz1.height, sz1.width, CV_8UC1, temp->data.ptr );
+//
+// cvResize( img, &img1, CV_INTER_LINEAR );
+// cvIntegral( &img1, &sum1, &sqsum1, _tilted );
+//
+// if( max_threads > 1 )
+// {
+// strip_count = MAX(MIN(sz1.height/ystep, max_threads*3), 1);
+// strip_size = (sz1.height + strip_count - 1)/strip_count;
+// strip_size = (strip_size / ystep)*ystep;
+// }
+// else
+// {
+// strip_count = 1;
+// strip_size = sz1.height;
+// }
+//
+// //if( !use_ipp )
+// cvSetImagesForHaarClassifierCascade( cascade, &sum1, &sqsum1, 0, 1. );
+// /*else
+// {
+// for( i = 0; i <= sz.height; i++ )
+// {
+// const int* isum = (int*)(sum1.data.ptr + sum1.step*i);
+// float* fsum = (float*)isum;
+// const int FLT_DELTA = -(1 << 24);
+// int j;
+// for( j = 0; j <= sz.width; j++ )
+// fsum[j] = (float)(isum[j] + FLT_DELTA);
+// }
+// }*/
+//
+//#ifdef _OPENMP
+//#pragma omp parallel for num_threads(max_threads) schedule(dynamic)
+//#endif
+// for( i = 0; i < strip_count; i++ )
+// {
+// int thread_id = cvGetThreadNum();
+// int positive = 0;
+// int y1 = i*strip_size, y2 = (i+1)*strip_size/* - ystep + 1*/;
+// CvSize ssz;
+// int x, y;
+// if( i == strip_count - 1 || y2 > sz1.height )
+// y2 = sz1.height;
+// ssz = cvSize(sz1.width, y2 - y1);
+//
+// /*if( use_ipp )
+// {
+// icvRectStdDev_32f_C1R_p(
+// (float*)(sum1.data.ptr + y1*sum1.step), sum1.step,
+// (double*)(sqsum1.data.ptr + y1*sqsum1.step), sqsum1.step,
+// (float*)(norm1.data.ptr + y1*norm1.step), norm1.step, ssz, equ_rect );
+//
+// positive = (ssz.width/ystep)*((ssz.height + ystep-1)/ystep);
+// memset( mask1.data.ptr + y1*mask1.step, ystep == 1, mask1.height*mask1.step);
+//
+// if( ystep > 1 )
+// {
+// for( y = y1, positive = 0; y < y2; y += ystep )
+// for( x = 0; x < ssz.width; x += ystep )
+// mask1.data.ptr[mask1.step*y + x] = (uchar)1;
+// }
+//
+// for( int j = 0; j < cascade->count; j++ )
+// {
+// if( icvApplyHaarClassifier_32f_C1R_p(
+// (float*)(sum1.data.ptr + y1*sum1.step), sum1.step,
+// (float*)(norm1.data.ptr + y1*norm1.step), norm1.step,
+// mask1.data.ptr + y1*mask1.step, mask1.step, ssz, &positive,
+// cascade->hid_cascade->stage_classifier[j].threshold,
+// cascade->hid_cascade->ipp_stages[j]) < 0 )
+// {
+// positive = 0;
+// break;
+// }
+// if( positive <= 0 )
+// break;
+// }
+// }
+// else*/
+// {
+// for( y = y1, positive = 0; y < y2; y += ystep )
+// for( x = 0; x < ssz.width; x += ystep )
+// {
+// mask1.data.ptr[mask1.step*y + x] =
+// mycvRunHaarClassifierCascade( cascade, cvPoint(x,y), 0 ) > 0;
+// positive += mask1.data.ptr[mask1.step*y + x];
+// }
+// }
+//
+// if( positive > 0 )
+// {
+// for( y = y1; y < y2; y += ystep )
+// for( x = 0; x < ssz.width; x += ystep )
+// if( mask1.data.ptr[mask1.step*y + x] != 0 )
+// {
+// CvRect obj_rect = { cvRound(x*factor), cvRound(y*factor),
+// win_size.width, win_size.height };
+// cvSeqPush( seq_thread[thread_id], &obj_rect );
+// }
+// }
+// }
+//
+// // gather the results
+// if( max_threads > 1 )
+// for( i = 0; i < max_threads; i++ )
+// {
+// CvSeq* s = seq_thread[i];
+// int j, total = s->total;
+// CvSeqBlock* b = s->first;
+// for( j = 0; j < total; j += b->count, b = b->next )
+// cvSeqPushMulti( seq, b->data, b->count );
+// }
+// }
+// }
+// else
+ t1 = (double)cvGetTickCount();
+// printf( "init time = %gms\n", (t1 - t)/tickFreqTimes1000);
+ t = t1;
+
+ {
+ int n_factors = 0;
+ CvRect scan_roi_rect = {0,0,0,0};
+ bool is_found = false, scan_roi = false;
+
+ cvIntegral( img, sum, sqsum, tilted );
+
+// if( do_canny_pruning )
+// {
+// sumcanny = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 );
+// cvCanny( img, temp, 0, 50, 3 );
+// cvIntegral( temp, sumcanny );
+// }
+
+ if( (unsigned)split_stage >= (unsigned)cascade->count ||
+ ((MyCvHidHaarClassifierCascade*)cascade->hid_cascade)->is_tree )
+ {
+ split_stage = cascade->count;
+ npass = 1;
+ }
+
+ for( n_factors = 0, factor = 1;
+ factor*cascade->orig_window_size.width < img->cols - 10 &&
+ factor*cascade->orig_window_size.height < img->rows - 10;
+ n_factors++, factor *= scale_factor )
+ ;
+
+ if( find_biggest_object )
+ {
+ scale_factor = 1./scale_factor;
+ factor *= scale_factor;
+ big_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvRect), temp_storage );
+ }
+ else
+ factor = 1;
+
+ for( ; n_factors-- > 0 && !is_found; factor *= scale_factor )
+ {
+ const double ystep = MAX( 2, factor );
+ CvSize win_size = { cvRound( cascade->orig_window_size.width * factor ),
+ cvRound( cascade->orig_window_size.height * factor )};
+ CvRect equ_rect = { 0, 0, 0, 0 };
+ int *p0 = 0, *p1 = 0, *p2 = 0, *p3 = 0;
+ int *pq0 = 0, *pq1 = 0, *pq2 = 0, *pq3 = 0;
+ int pass, stage_offset = 0;
+ int start_x = 0, start_y = 0;
+ int end_x = cvRound((img->cols - win_size.width) / ystep);
+ int end_y = cvRound((img->rows - win_size.height) / ystep);
+
+ if( win_size.width < min_size.width || win_size.height < min_size.height )
+ {
+ if( find_biggest_object )
+ break;
+ continue;
+ }
+
+ mycvSetImagesForHaarClassifierCascade( cascade, sum, sqsum, tilted, factor );
+ cvZero( temp );
+
+// if( do_canny_pruning )
+// {
+// equ_rect.x = cvRound(win_size.width*0.15);
+// equ_rect.y = cvRound(win_size.height*0.15);
+// equ_rect.width = cvRound(win_size.width*0.7);
+// equ_rect.height = cvRound(win_size.height*0.7);
+//
+// p0 = (int*)(sumcanny->data.ptr + equ_rect.y*sumcanny->step) + equ_rect.x;
+// p1 = (int*)(sumcanny->data.ptr + equ_rect.y*sumcanny->step)
+// + equ_rect.x + equ_rect.width;
+// p2 = (int*)(sumcanny->data.ptr + (equ_rect.y + equ_rect.height)*sumcanny->step) + equ_rect.x;
+// p3 = (int*)(sumcanny->data.ptr + (equ_rect.y + equ_rect.height)*sumcanny->step)
+// + equ_rect.x + equ_rect.width;
+//
+// pq0 = (int*)(sum->data.ptr + equ_rect.y*sum->step) + equ_rect.x;
+// pq1 = (int*)(sum->data.ptr + equ_rect.y*sum->step)
+// + equ_rect.x + equ_rect.width;
+// pq2 = (int*)(sum->data.ptr + (equ_rect.y + equ_rect.height)*sum->step) + equ_rect.x;
+// pq3 = (int*)(sum->data.ptr + (equ_rect.y + equ_rect.height)*sum->step)
+// + equ_rect.x + equ_rect.width;
+// }
+
+ if( scan_roi )
+ {
+ //adjust start_height and stop_height
+ start_y = cvRound(scan_roi_rect.y / ystep);
+ end_y = cvRound((scan_roi_rect.y + scan_roi_rect.height - win_size.height) / ystep);
+
+ start_x = cvRound(scan_roi_rect.x / ystep);
+ end_x = cvRound((scan_roi_rect.x + scan_roi_rect.width - win_size.width) / ystep);
+ }
+
+ ((MyCvHidHaarClassifierCascade*)cascade->hid_cascade)->count = split_stage;
+
+ for( pass = 0; pass < npass; pass++ )
+ {
+#ifdef _OPENMP
+#pragma omp parallel for num_threads(max_threads) schedule(dynamic)
+#endif
+ for( int _iy = start_y; _iy < end_y; _iy++ )
+ {
+ int thread_id = cvGetThreadNum();
+ int iy = cvRound(_iy*ystep);
+ int _ix, _xstep = 1;
+ uchar* mask_row = temp->data.ptr + temp->step * iy;
+
+ for( _ix = start_x; _ix < end_x; _ix += _xstep )
+ {
+ int ix = cvRound(_ix*ystep); // it really should be ystep
+
+ if( pass == 0 )
+ {
+ int result;
+ _xstep = 2;
+
+// if( do_canny_pruning )
+// {
+// int offset;
+// int s, sq;
+//
+// offset = iy*(sum->step/sizeof(p0[0])) + ix;
+// s = p0[offset] - p1[offset] - p2[offset] + p3[offset];
+// sq = pq0[offset] - pq1[offset] - pq2[offset] + pq3[offset];
+// if( s < 100 || sq < 20 )
+// continue;
+// }
+
+ result = mycvRunHaarClassifierCascade( cascade, cvPoint(ix,iy), 0 );
+ if( result > 0 )
+ {
+ if( pass < npass - 1 )
+ mask_row[ix] = 1;
+ else
+ {
+ CvRect rect = cvRect(ix,iy,win_size.width,win_size.height);
+ cvSeqPush( seq_thread[thread_id], &rect );
+ }
+ }
+ if( result < 0 )
+ _xstep = 1;
+ }
+ else if( mask_row[ix] )
+ {
+ int result = mycvRunHaarClassifierCascade( cascade, cvPoint(ix,iy),
+ stage_offset );
+ if( result > 0 )
+ {
+ if( pass == npass - 1 )
+ {
+ CvRect rect = cvRect(ix,iy,win_size.width,win_size.height);
+ cvSeqPush( seq_thread[thread_id], &rect );
+ }
+ }
+ else
+ mask_row[ix] = 0;
+ }
+ }
+ }
+ stage_offset = ((MyCvHidHaarClassifierCascade*)cascade->hid_cascade)->count;
+ ((MyCvHidHaarClassifierCascade*)cascade->hid_cascade)->count = cascade->count;
+ }
+
+ // gather the results
+ if( max_threads > 1 )
+ for( i = 0; i < max_threads; i++ )
+ {
+ CvSeq* s = seq_thread[i];
+ int j, total = s->total;
+ CvSeqBlock* b = s->first;
+ for( j = 0; j < total; j += b->count, b = b->next )
+ cvSeqPushMulti( seq, b->data, b->count );
+ }
+
+ if( find_biggest_object )
+ {
+ CvSeq* bseq = min_neighbors > 0 ? big_seq : seq;
+
+ if( min_neighbors > 0 && !scan_roi )
+ {
+ // group retrieved rectangles in order to filter out noise
+ int ncomp = cvSeqPartition( seq, 0, &idx_seq, myis_equal, 0 );
+ CV_CALL( comps = (CvAvgComp*)cvAlloc( (ncomp+1)*sizeof(comps[0])));
+ memset( comps, 0, (ncomp+1)*sizeof(comps[0]));
+
+#if VERY_ROUGH_SEARCH
+ if( rough_search )
+ {
+ for( i = 0; i < seq->total; i++ )
+ {
+ CvRect r1 = *(CvRect*)cvGetSeqElem( seq, i );
+ int idx = *(int*)cvGetSeqElem( idx_seq, i );
+ assert( (unsigned)idx < (unsigned)ncomp );
+
+ comps[idx].neighbors++;
+ comps[idx].rect.x += r1.x;
+ comps[idx].rect.y += r1.y;
+ comps[idx].rect.width += r1.width;
+ comps[idx].rect.height += r1.height;
+ }
+
+ // calculate average bounding box
+ for( i = 0; i < ncomp; i++ )
+ {
+ int n = comps[i].neighbors;
+ if( n >= min_neighbors )
+ {
+ CvAvgComp comp;
+ comp.rect.x = (comps[i].rect.x*2 + n)/(2*n);
+ comp.rect.y = (comps[i].rect.y*2 + n)/(2*n);
+ comp.rect.width = (comps[i].rect.width*2 + n)/(2*n);
+ comp.rect.height = (comps[i].rect.height*2 + n)/(2*n);
+ comp.neighbors = n;
+ cvSeqPush( bseq, &comp );
+ }
+ }
+ }
+ else
+#endif
+ {
+ for( i = 0 ; i <= ncomp; i++ )
+ comps[i].rect.x = comps[i].rect.y = INT_MAX;
+
+ // count number of neighbors
+ for( i = 0; i < seq->total; i++ )
+ {
+ CvRect r1 = *(CvRect*)cvGetSeqElem( seq, i );
+ int idx = *(int*)cvGetSeqElem( idx_seq, i );
+ assert( (unsigned)idx < (unsigned)ncomp );
+
+ comps[idx].neighbors++;
+
+ // rect.width and rect.height will store coordinate of right-bottom corner
+ comps[idx].rect.x = MIN(comps[idx].rect.x, r1.x);
+ comps[idx].rect.y = MIN(comps[idx].rect.y, r1.y);
+ comps[idx].rect.width = MAX(comps[idx].rect.width, r1.x+r1.width-1);
+ comps[idx].rect.height = MAX(comps[idx].rect.height, r1.y+r1.height-1);
+ }
+
+ // calculate enclosing box
+ for( i = 0; i < ncomp; i++ )
+ {
+ int n = comps[i].neighbors;
+ if( n >= min_neighbors )
+ {
+ CvAvgComp comp;
+ int t;
+ double min_scale = rough_search ? 0.6 : 0.4;
+ comp.rect.x = comps[i].rect.x;
+ comp.rect.y = comps[i].rect.y;
+ comp.rect.width = comps[i].rect.width - comps[i].rect.x + 1;
+ comp.rect.height = comps[i].rect.height - comps[i].rect.y + 1;
+
+ // update min_size
+ t = cvRound( comp.rect.width*min_scale );
+ min_size.width = MAX( min_size.width, t );
+
+ t = cvRound( comp.rect.height*min_scale );
+ min_size.height = MAX( min_size.height, t );
+
+ //expand the box by 20% because we could miss some neighbours
+ //see 'is_equal' function
+#if 1
+ int offset = cvRound(comp.rect.width * 0.2);
+ int right = MIN( img->cols-1, comp.rect.x+comp.rect.width-1 + offset );
+ int bottom = MIN( img->rows-1, comp.rect.y+comp.rect.height-1 + offset);
+ comp.rect.x = MAX( comp.rect.x - offset, 0 );
+ comp.rect.y = MAX( comp.rect.y - offset, 0 );
+ comp.rect.width = right - comp.rect.x + 1;
+ comp.rect.height = bottom - comp.rect.y + 1;
+#endif
+
+ comp.neighbors = n;
+ cvSeqPush( bseq, &comp );
+ }
+ }
+ }
+
+ cvFree( &comps );
+ }
+
+ // extract the biggest rect
+ if( bseq->total > 0 )
+ {
+ int max_area = 0;
+ for( i = 0; i < bseq->total; i++ )
+ {
+ CvAvgComp* comp = (CvAvgComp*)cvGetSeqElem( bseq, i );
+ int area = comp->rect.width * comp->rect.height;
+ if( max_area < area )
+ {
+ max_area = area;
+ result_comp.rect = comp->rect;
+ result_comp.neighbors = bseq == seq ? 1 : comp->neighbors;
+ }
+ }
+
+ //Prepare information for further scanning inside the biggest rectangle
+
+#if VERY_ROUGH_SEARCH
+ // change scan ranges to roi in case of required
+ if( !rough_search && !scan_roi )
+ {
+ scan_roi = true;
+ scan_roi_rect = result_comp.rect;
+ cvClearSeq(bseq);
+ }
+ else if( rough_search )
+ is_found = true;
+#else
+ if( !scan_roi )
+ {
+ scan_roi = true;
+ scan_roi_rect = result_comp.rect;
+ cvClearSeq(bseq);
+ }
+#endif
+ }
+ }
+ }
+ }
+
+// t1 = (double)cvGetTickCount();
+// printf( "factors time = %gms\n", (t1 - t)/tickFreqTimes1000);
+// t = t1;
+
+ if( min_neighbors == 0 && !find_biggest_object )
+ {
+ for( i = 0; i < seq->total; i++ )
+ {
+ CvRect* rect = (CvRect*)cvGetSeqElem( seq, i );
+ CvAvgComp comp;
+ comp.rect = *rect;
+ comp.neighbors = 1;
+ cvSeqPush( result_seq, &comp );
+ }
+ }
+
+ if( min_neighbors != 0
+#if VERY_ROUGH_SEARCH
+ && (!find_biggest_object || !rough_search)
+#endif
+ )
+ {
+ // group retrieved rectangles in order to filter out noise
+ int ncomp = cvSeqPartition( seq, 0, &idx_seq, myis_equal, 0 );
+ CV_CALL( comps = (CvAvgComp*)cvAlloc( (ncomp+1)*sizeof(comps[0])));
+ memset( comps, 0, (ncomp+1)*sizeof(comps[0]));
+
+ // count number of neighbors
+ for( i = 0; i < seq->total; i++ )
+ {
+ CvRect r1 = *(CvRect*)cvGetSeqElem( seq, i );
+ int idx = *(int*)cvGetSeqElem( idx_seq, i );
+ assert( (unsigned)idx < (unsigned)ncomp );
+
+ comps[idx].neighbors++;
+
+ comps[idx].rect.x += r1.x;
+ comps[idx].rect.y += r1.y;
+ comps[idx].rect.width += r1.width;
+ comps[idx].rect.height += r1.height;
+ }
+
+ // calculate average bounding box
+ for( i = 0; i < ncomp; i++ )
+ {
+ int n = comps[i].neighbors;
+ if( n >= min_neighbors )
+ {
+ CvAvgComp comp;
+ comp.rect.x = (comps[i].rect.x*2 + n)/(2*n);
+ comp.rect.y = (comps[i].rect.y*2 + n)/(2*n);
+ comp.rect.width = (comps[i].rect.width*2 + n)/(2*n);
+ comp.rect.height = (comps[i].rect.height*2 + n)/(2*n);
+ comp.neighbors = comps[i].neighbors;
+
+ cvSeqPush( seq2, &comp );
+ }
+ }
+
+ if( !find_biggest_object )
+ {
+ // filter out small face rectangles inside large face rectangles
+ for( i = 0; i < seq2->total; i++ )
+ {
+ CvAvgComp r1 = *(CvAvgComp*)cvGetSeqElem( seq2, i );
+ int j, flag = 1;
+
+ for( j = 0; j < seq2->total; j++ )
+ {
+ CvAvgComp r2 = *(CvAvgComp*)cvGetSeqElem( seq2, j );
+ int distance = cvRound( r2.rect.width * 0.2 );
+
+ if( i != j &&
+ r1.rect.x >= r2.rect.x - distance &&
+ r1.rect.y >= r2.rect.y - distance &&
+ r1.rect.x + r1.rect.width <= r2.rect.x + r2.rect.width + distance &&
+ r1.rect.y + r1.rect.height <= r2.rect.y + r2.rect.height + distance &&
+ (r2.neighbors > MAX( 3, r1.neighbors ) || r1.neighbors < 3) )
+ {
+ flag = 0;
+ break;
+ }
+ }
+
+ if( flag )
+ cvSeqPush( result_seq, &r1 );
+ }
+ }
+ else
+ {
+ int max_area = 0;
+ for( i = 0; i < seq2->total; i++ )
+ {
+ CvAvgComp* comp = (CvAvgComp*)cvGetSeqElem( seq2, i );
+ int area = comp->rect.width * comp->rect.height;
+ if( max_area < area )
+ {
+ max_area = area;
+ result_comp = *comp;
+ }
+ }
+ }
+ }
+
+ t1 = (double)cvGetTickCount();
+// printf( "results eval time = %gms\n", (t1 - t)/tickFreqTimes1000);
+ t = t1;
+
+ if( find_biggest_object && result_comp.rect.width > 0 )
+ cvSeqPush( result_seq, &result_comp );
+
+ __END__;
+
+ if( max_threads > 1 )
+ for( i = 0; i < max_threads; i++ )
+ {
+ if( seq_thread[i] )
+ cvReleaseMemStorage( &seq_thread[i]->storage );
+ }
+
+ cvReleaseMemStorage( &temp_storage );
+ cvReleaseMat( &sum );
+ cvReleaseMat( &sqsum );
+ cvReleaseMat( &tilted );
+ cvReleaseMat( &temp );
+ cvReleaseMat( &sumcanny );
+ cvReleaseMat( &norm_img );
+ cvReleaseMat( &img_small );
+ cvFree( &comps );
+
+ return result_seq;
+}
diff --git a/cvaux/include/cvaux.h b/cvaux/include/cvaux.h
new file mode 100644
index 0000000..e102dc8
--- /dev/null
+++ b/cvaux/include/cvaux.h
@@ -0,0 +1,1574 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __CVAUX__H__
+#define __CVAUX__H__
+
+#include "cv.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+CVAPI(CvSeq*) cvSegmentImage( const CvArr* srcarr, CvArr* dstarr,
+ double canny_threshold,
+ double ffill_threshold,
+ CvMemStorage* storage );
+
+/****************************************************************************************\
+* Eigen objects *
+\****************************************************************************************/
+
+typedef int (CV_CDECL * CvCallback)(int index, void* buffer, void* user_data);
+typedef union
+{
+ CvCallback callback;
+ void* data;
+}
+CvInput;
+
+#define CV_EIGOBJ_NO_CALLBACK 0
+#define CV_EIGOBJ_INPUT_CALLBACK 1
+#define CV_EIGOBJ_OUTPUT_CALLBACK 2
+#define CV_EIGOBJ_BOTH_CALLBACK 3
+
+/* Calculates covariation matrix of a set of arrays */
+CVAPI(void) cvCalcCovarMatrixEx( int nObjects, void* input, int ioFlags,
+ int ioBufSize, uchar* buffer, void* userData,
+ IplImage* avg, float* covarMatrix );
+
+/* Calculates eigen values and vectors of covariation matrix of a set of
+ arrays */
+CVAPI(void) cvCalcEigenObjects( int nObjects, void* input, void* output,
+ int ioFlags, int ioBufSize, void* userData,
+ CvTermCriteria* calcLimit, IplImage* avg,
+ float* eigVals );
+
+/* Calculates dot product (obj - avg) * eigObj (i.e. projects image to eigen vector) */
+CVAPI(double) cvCalcDecompCoeff( IplImage* obj, IplImage* eigObj, IplImage* avg );
+
+/* Projects image to eigen space (finds all decomposion coefficients */
+CVAPI(void) cvEigenDecomposite( IplImage* obj, int nEigObjs, void* eigInput,
+ int ioFlags, void* userData, IplImage* avg,
+ float* coeffs );
+
+/* Projects original objects used to calculate eigen space basis to that space */
+CVAPI(void) cvEigenProjection( void* eigInput, int nEigObjs, int ioFlags,
+ void* userData, float* coeffs, IplImage* avg,
+ IplImage* proj );
+
+/****************************************************************************************\
+* 1D/2D HMM *
+\****************************************************************************************/
+
+typedef struct CvImgObsInfo
+{
+ int obs_x;
+ int obs_y;
+ int obs_size;
+ float* obs;//consequtive observations
+
+ int* state;/* arr of pairs superstate/state to which observation belong */
+ int* mix; /* number of mixture to which observation belong */
+
+}
+CvImgObsInfo;/*struct for 1 image*/
+
+typedef CvImgObsInfo Cv1DObsInfo;
+
+typedef struct CvEHMMState
+{
+ int num_mix; /*number of mixtures in this state*/
+ float* mu; /*mean vectors corresponding to each mixture*/
+ float* inv_var; /* square root of inversed variances corresp. to each mixture*/
+ float* log_var_val; /* sum of 0.5 (LN2PI + ln(variance[i]) ) for i=1,n */
+ float* weight; /*array of mixture weights. Summ of all weights in state is 1. */
+
+}
+CvEHMMState;
+
+typedef struct CvEHMM
+{
+ int level; /* 0 - lowest(i.e its states are real states), ..... */
+ int num_states; /* number of HMM states */
+ float* transP;/*transition probab. matrices for states */
+ float** obsProb; /* if level == 0 - array of brob matrices corresponding to hmm
+ if level == 1 - martix of matrices */
+ union
+ {
+ CvEHMMState* state; /* if level == 0 points to real states array,
+ if not - points to embedded hmms */
+ struct CvEHMM* ehmm; /* pointer to an embedded model or NULL, if it is a leaf */
+ } u;
+
+}
+CvEHMM;
+
+/*CVAPI(int) icvCreate1DHMM( CvEHMM** this_hmm,
+ int state_number, int* num_mix, int obs_size );
+
+CVAPI(int) icvRelease1DHMM( CvEHMM** phmm );
+
+CVAPI(int) icvUniform1DSegm( Cv1DObsInfo* obs_info, CvEHMM* hmm );
+
+CVAPI(int) icvInit1DMixSegm( Cv1DObsInfo** obs_info_array, int num_img, CvEHMM* hmm);
+
+CVAPI(int) icvEstimate1DHMMStateParams( CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm);
+
+CVAPI(int) icvEstimate1DObsProb( CvImgObsInfo* obs_info, CvEHMM* hmm );
+
+CVAPI(int) icvEstimate1DTransProb( Cv1DObsInfo** obs_info_array,
+ int num_seq,
+ CvEHMM* hmm );
+
+CVAPI(float) icvViterbi( Cv1DObsInfo* obs_info, CvEHMM* hmm);
+
+CVAPI(int) icv1DMixSegmL2( CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm );*/
+
+/*********************************** Embedded HMMs *************************************/
+
+/* Creates 2D HMM */
+CVAPI(CvEHMM*) cvCreate2DHMM( int* stateNumber, int* numMix, int obsSize );
+
+/* Releases HMM */
+CVAPI(void) cvRelease2DHMM( CvEHMM** hmm );
+
+#define CV_COUNT_OBS(roi, win, delta, numObs ) \
+{ \
+ (numObs)->width =((roi)->width -(win)->width +(delta)->width)/(delta)->width; \
+ (numObs)->height =((roi)->height -(win)->height +(delta)->height)/(delta)->height;\
+}
+
+/* Creates storage for observation vectors */
+CVAPI(CvImgObsInfo*) cvCreateObsInfo( CvSize numObs, int obsSize );
+
+/* Releases storage for observation vectors */
+CVAPI(void) cvReleaseObsInfo( CvImgObsInfo** obs_info );
+
+
+/* The function takes an image on input and and returns the sequnce of observations
+ to be used with an embedded HMM; Each observation is top-left block of DCT
+ coefficient matrix */
+CVAPI(void) cvImgToObs_DCT( const CvArr* arr, float* obs, CvSize dctSize,
+ CvSize obsSize, CvSize delta );
+
+
+/* Uniformly segments all observation vectors extracted from image */
+CVAPI(void) cvUniformImgSegm( CvImgObsInfo* obs_info, CvEHMM* ehmm );
+
+/* Does mixture segmentation of the states of embedded HMM */
+CVAPI(void) cvInitMixSegm( CvImgObsInfo** obs_info_array,
+ int num_img, CvEHMM* hmm );
+
+/* Function calculates means, variances, weights of every Gaussian mixture
+ of every low-level state of embedded HMM */
+CVAPI(void) cvEstimateHMMStateParams( CvImgObsInfo** obs_info_array,
+ int num_img, CvEHMM* hmm );
+
+/* Function computes transition probability matrices of embedded HMM
+ given observations segmentation */
+CVAPI(void) cvEstimateTransProb( CvImgObsInfo** obs_info_array,
+ int num_img, CvEHMM* hmm );
+
+/* Function computes probabilities of appearing observations at any state
+ (i.e. computes P(obs|state) for every pair(obs,state)) */
+CVAPI(void) cvEstimateObsProb( CvImgObsInfo* obs_info,
+ CvEHMM* hmm );
+
+/* Runs Viterbi algorithm for embedded HMM */
+CVAPI(float) cvEViterbi( CvImgObsInfo* obs_info, CvEHMM* hmm );
+
+
+/* Function clusters observation vectors from several images
+ given observations segmentation.
+ Euclidean distance used for clustering vectors.
+ Centers of clusters are given means of every mixture */
+CVAPI(void) cvMixSegmL2( CvImgObsInfo** obs_info_array,
+ int num_img, CvEHMM* hmm );
+
+/****************************************************************************************\
+* A few functions from old stereo gesture recognition demosions *
+\****************************************************************************************/
+
+/* Creates hand mask image given several points on the hand */
+CVAPI(void) cvCreateHandMask( CvSeq* hand_points,
+ IplImage *img_mask, CvRect *roi);
+
+/* Finds hand region in range image data */
+CVAPI(void) cvFindHandRegion (CvPoint3D32f* points, int count,
+ CvSeq* indexs,
+ float* line, CvSize2D32f size, int flag,
+ CvPoint3D32f* center,
+ CvMemStorage* storage, CvSeq **numbers);
+
+/* Finds hand region in range image data (advanced version) */
+CVAPI(void) cvFindHandRegionA( CvPoint3D32f* points, int count,
+ CvSeq* indexs,
+ float* line, CvSize2D32f size, int jc,
+ CvPoint3D32f* center,
+ CvMemStorage* storage, CvSeq **numbers);
+
+/****************************************************************************************\
+* Additional operations on Subdivisions *
+\****************************************************************************************/
+
+// paints voronoi diagram: just demo function
+CVAPI(void) icvDrawMosaic( CvSubdiv2D* subdiv, IplImage* src, IplImage* dst );
+
+// checks planar subdivision for correctness. It is not an absolute check,
+// but it verifies some relations between quad-edges
+CVAPI(int) icvSubdiv2DCheck( CvSubdiv2D* subdiv );
+
+// returns squared distance between two 2D points with floating-point coordinates.
+CV_INLINE double icvSqDist2D32f( CvPoint2D32f pt1, CvPoint2D32f pt2 )
+{
+ double dx = pt1.x - pt2.x;
+ double dy = pt1.y - pt2.y;
+
+ return dx*dx + dy*dy;
+}
+
+
+/****************************************************************************************\
+* More operations on sequences *
+\****************************************************************************************/
+
+/*****************************************************************************************/
+
+#define CV_CURRENT_INT( reader ) (*((int *)(reader).ptr))
+#define CV_PREV_INT( reader ) (*((int *)(reader).prev_elem))
+
+#define CV_GRAPH_WEIGHTED_VERTEX_FIELDS() CV_GRAPH_VERTEX_FIELDS()\
+ float weight;
+
+#define CV_GRAPH_WEIGHTED_EDGE_FIELDS() CV_GRAPH_EDGE_FIELDS()
+
+typedef struct CvGraphWeightedVtx
+{
+ CV_GRAPH_WEIGHTED_VERTEX_FIELDS()
+}
+CvGraphWeightedVtx;
+
+typedef struct CvGraphWeightedEdge
+{
+ CV_GRAPH_WEIGHTED_EDGE_FIELDS()
+}
+CvGraphWeightedEdge;
+
+typedef enum CvGraphWeightType
+{
+ CV_NOT_WEIGHTED,
+ CV_WEIGHTED_VTX,
+ CV_WEIGHTED_EDGE,
+ CV_WEIGHTED_ALL
+} CvGraphWeightType;
+
+
+/*****************************************************************************************/
+
+
+/*******************************Stereo correspondence*************************************/
+
+typedef struct CvCliqueFinder
+{
+ CvGraph* graph;
+ int** adj_matr;
+ int N; //graph size
+
+ // stacks, counters etc/
+ int k; //stack size
+ int* current_comp;
+ int** All;
+
+ int* ne;
+ int* ce;
+ int* fixp; //node with minimal disconnections
+ int* nod;
+ int* s; //for selected candidate
+ int status;
+ int best_score;
+ int weighted;
+ int weighted_edges;
+ float best_weight;
+ float* edge_weights;
+ float* vertex_weights;
+ float* cur_weight;
+ float* cand_weight;
+
+} CvCliqueFinder;
+
+#define CLIQUE_TIME_OFF 2
+#define CLIQUE_FOUND 1
+#define CLIQUE_END 0
+
+/*CVAPI(void) cvStartFindCliques( CvGraph* graph, CvCliqueFinder* finder, int reverse,
+ int weighted CV_DEFAULT(0), int weighted_edges CV_DEFAULT(0));
+CVAPI(int) cvFindNextMaximalClique( CvCliqueFinder* finder, int* clock_rest CV_DEFAULT(0) );
+CVAPI(void) cvEndFindCliques( CvCliqueFinder* finder );
+
+CVAPI(void) cvBronKerbosch( CvGraph* graph );*/
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+//
+// Name: cvSubgraphWeight
+// Purpose: finds weight of subgraph in a graph
+// Context:
+// Parameters:
+// graph - input graph.
+// subgraph - sequence of pairwise different ints. These are indices of vertices of subgraph.
+// weight_type - describes the way we measure weight.
+// one of the following:
+// CV_NOT_WEIGHTED - weight of a clique is simply its size
+// CV_WEIGHTED_VTX - weight of a clique is the sum of weights of its vertices
+// CV_WEIGHTED_EDGE - the same but edges
+// CV_WEIGHTED_ALL - the same but both edges and vertices
+// weight_vtx - optional vector of floats, with size = graph->total.
+// If weight_type is either CV_WEIGHTED_VTX or CV_WEIGHTED_ALL
+// weights of vertices must be provided. If weight_vtx not zero
+// these weights considered to be here, otherwise function assumes
+// that vertices of graph are inherited from CvGraphWeightedVtx.
+// weight_edge - optional matrix of floats, of width and height = graph->total.
+// If weight_type is either CV_WEIGHTED_EDGE or CV_WEIGHTED_ALL
+// weights of edges ought to be supplied. If weight_edge is not zero
+// function finds them here, otherwise function expects
+// edges of graph to be inherited from CvGraphWeightedEdge.
+// If this parameter is not zero structure of the graph is determined from matrix
+// rather than from CvGraphEdge's. In particular, elements corresponding to
+// absent edges should be zero.
+// Returns:
+// weight of subgraph.
+// Notes:
+//F*/
+/*CVAPI(float) cvSubgraphWeight( CvGraph *graph, CvSeq *subgraph,
+ CvGraphWeightType weight_type CV_DEFAULT(CV_NOT_WEIGHTED),
+ CvVect32f weight_vtx CV_DEFAULT(0),
+ CvMatr32f weight_edge CV_DEFAULT(0) );*/
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+//
+// Name: cvFindCliqueEx
+// Purpose: tries to find clique with maximum possible weight in a graph
+// Context:
+// Parameters:
+// graph - input graph.
+// storage - memory storage to be used by the result.
+// is_complementary - optional flag showing whether function should seek for clique
+// in complementary graph.
+// weight_type - describes our notion about weight.
+// one of the following:
+// CV_NOT_WEIGHTED - weight of a clique is simply its size
+// CV_WEIGHTED_VTX - weight of a clique is the sum of weights of its vertices
+// CV_WEIGHTED_EDGE - the same but edges
+// CV_WEIGHTED_ALL - the same but both edges and vertices
+// weight_vtx - optional vector of floats, with size = graph->total.
+// If weight_type is either CV_WEIGHTED_VTX or CV_WEIGHTED_ALL
+// weights of vertices must be provided. If weight_vtx not zero
+// these weights considered to be here, otherwise function assumes
+// that vertices of graph are inherited from CvGraphWeightedVtx.
+// weight_edge - optional matrix of floats, of width and height = graph->total.
+// If weight_type is either CV_WEIGHTED_EDGE or CV_WEIGHTED_ALL
+// weights of edges ought to be supplied. If weight_edge is not zero
+// function finds them here, otherwise function expects
+// edges of graph to be inherited from CvGraphWeightedEdge.
+// Note that in case of CV_WEIGHTED_EDGE or CV_WEIGHTED_ALL
+// nonzero is_complementary implies nonzero weight_edge.
+// start_clique - optional sequence of pairwise different ints. They are indices of
+// vertices that shall be present in the output clique.
+// subgraph_of_ban - optional sequence of (maybe equal) ints. They are indices of
+// vertices that shall not be present in the output clique.
+// clique_weight_ptr - optional output parameter. Weight of found clique stored here.
+// num_generations - optional number of generations in evolutionary part of algorithm,
+// zero forces to return first found clique.
+// quality - optional parameter determining degree of required quality/speed tradeoff.
+// Must be in the range from 0 to 9.
+// 0 is fast and dirty, 9 is slow but hopefully yields good clique.
+// Returns:
+// sequence of pairwise different ints.
+// These are indices of vertices that form found clique.
+// Notes:
+// in cases of CV_WEIGHTED_EDGE and CV_WEIGHTED_ALL weights should be nonnegative.
+// start_clique has a priority over subgraph_of_ban.
+//F*/
+/*CVAPI(CvSeq*) cvFindCliqueEx( CvGraph *graph, CvMemStorage *storage,
+ int is_complementary CV_DEFAULT(0),
+ CvGraphWeightType weight_type CV_DEFAULT(CV_NOT_WEIGHTED),
+ CvVect32f weight_vtx CV_DEFAULT(0),
+ CvMatr32f weight_edge CV_DEFAULT(0),
+ CvSeq *start_clique CV_DEFAULT(0),
+ CvSeq *subgraph_of_ban CV_DEFAULT(0),
+ float *clique_weight_ptr CV_DEFAULT(0),
+ int num_generations CV_DEFAULT(3),
+ int quality CV_DEFAULT(2) );*/
+
+
+#define CV_UNDEF_SC_PARAM 12345 //default value of parameters
+
+#define CV_IDP_BIRCHFIELD_PARAM1 25
+#define CV_IDP_BIRCHFIELD_PARAM2 5
+#define CV_IDP_BIRCHFIELD_PARAM3 12
+#define CV_IDP_BIRCHFIELD_PARAM4 15
+#define CV_IDP_BIRCHFIELD_PARAM5 25
+
+
+#define CV_DISPARITY_BIRCHFIELD 0
+
+
+/*F///////////////////////////////////////////////////////////////////////////
+//
+// Name: cvFindStereoCorrespondence
+// Purpose: find stereo correspondence on stereo-pair
+// Context:
+// Parameters:
+// leftImage - left image of stereo-pair (format 8uC1).
+// rightImage - right image of stereo-pair (format 8uC1).
+// mode - mode of correspondence retrieval (now CV_DISPARITY_BIRCHFIELD only)
+// dispImage - destination disparity image
+// maxDisparity - maximal disparity
+// param1, param2, param3, param4, param5 - parameters of algorithm
+// Returns:
+// Notes:
+// Images must be rectified.
+// All images must have format 8uC1.
+//F*/
+CVAPI(void)
+cvFindStereoCorrespondence(
+ const CvArr* leftImage, const CvArr* rightImage,
+ int mode,
+ CvArr* dispImage,
+ int maxDisparity,
+ double param1 CV_DEFAULT(CV_UNDEF_SC_PARAM),
+ double param2 CV_DEFAULT(CV_UNDEF_SC_PARAM),
+ double param3 CV_DEFAULT(CV_UNDEF_SC_PARAM),
+ double param4 CV_DEFAULT(CV_UNDEF_SC_PARAM),
+ double param5 CV_DEFAULT(CV_UNDEF_SC_PARAM) );
+
+/*****************************************************************************************/
+/************ Epiline functions *******************/
+
+
+
+typedef struct CvStereoLineCoeff
+{
+ double Xcoef;
+ double XcoefA;
+ double XcoefB;
+ double XcoefAB;
+
+ double Ycoef;
+ double YcoefA;
+ double YcoefB;
+ double YcoefAB;
+
+ double Zcoef;
+ double ZcoefA;
+ double ZcoefB;
+ double ZcoefAB;
+}CvStereoLineCoeff;
+
+
+typedef struct CvCamera
+{
+ float imgSize[2]; /* size of the camera view, used during calibration */
+ float matrix[9]; /* intinsic camera parameters: [ fx 0 cx; 0 fy cy; 0 0 1 ] */
+ float distortion[4]; /* distortion coefficients - two coefficients for radial distortion
+ and another two for tangential: [ k1 k2 p1 p2 ] */
+ float rotMatr[9];
+ float transVect[3]; /* rotation matrix and transition vector relatively
+ to some reference point in the space. */
+}
+CvCamera;
+
+typedef struct CvStereoCamera
+{
+ CvCamera* camera[2]; /* two individual camera parameters */
+ float fundMatr[9]; /* fundamental matrix */
+
+ /* New part for stereo */
+ CvPoint3D32f epipole[2];
+ CvPoint2D32f quad[2][4]; /* coordinates of destination quadrangle after
+ epipolar geometry rectification */
+ double coeffs[2][3][3];/* coefficients for transformation */
+ CvPoint2D32f border[2][4];
+ CvSize warpSize;
+ CvStereoLineCoeff* lineCoeffs;
+ int needSwapCameras;/* flag set to 1 if need to swap cameras for good reconstruction */
+ float rotMatrix[9];
+ float transVector[3];
+}
+CvStereoCamera;
+
+
+typedef struct CvContourOrientation
+{
+ float egvals[2];
+ float egvects[4];
+
+ float max, min; // minimum and maximum projections
+ int imax, imin;
+} CvContourOrientation;
+
+#define CV_CAMERA_TO_WARP 1
+#define CV_WARP_TO_CAMERA 2
+
+CVAPI(int) icvConvertWarpCoordinates(double coeffs[3][3],
+ CvPoint2D32f* cameraPoint,
+ CvPoint2D32f* warpPoint,
+ int direction);
+
+CVAPI(int) icvGetSymPoint3D( CvPoint3D64f pointCorner,
+ CvPoint3D64f point1,
+ CvPoint3D64f point2,
+ CvPoint3D64f *pointSym2);
+
+CVAPI(void) icvGetPieceLength3D(CvPoint3D64f point1,CvPoint3D64f point2,double* dist);
+
+CVAPI(int) icvCompute3DPoint( double alpha,double betta,
+ CvStereoLineCoeff* coeffs,
+ CvPoint3D64f* point);
+
+CVAPI(int) icvCreateConvertMatrVect( CvMatr64d rotMatr1,
+ CvMatr64d transVect1,
+ CvMatr64d rotMatr2,
+ CvMatr64d transVect2,
+ CvMatr64d convRotMatr,
+ CvMatr64d convTransVect);
+
+CVAPI(int) icvConvertPointSystem(CvPoint3D64f M2,
+ CvPoint3D64f* M1,
+ CvMatr64d rotMatr,
+ CvMatr64d transVect
+ );
+
+CVAPI(int) icvComputeCoeffForStereo( CvStereoCamera* stereoCamera);
+
+CVAPI(int) icvGetCrossPieceVector(CvPoint2D32f p1_start,CvPoint2D32f p1_end,CvPoint2D32f v2_start,CvPoint2D32f v2_end,CvPoint2D32f *cross);
+CVAPI(int) icvGetCrossLineDirect(CvPoint2D32f p1,CvPoint2D32f p2,float a,float b,float c,CvPoint2D32f* cross);
+CVAPI(float) icvDefinePointPosition(CvPoint2D32f point1,CvPoint2D32f point2,CvPoint2D32f point);
+CVAPI(int) icvStereoCalibration( int numImages,
+ int* nums,
+ CvSize imageSize,
+ CvPoint2D32f* imagePoints1,
+ CvPoint2D32f* imagePoints2,
+ CvPoint3D32f* objectPoints,
+ CvStereoCamera* stereoparams
+ );
+
+
+CVAPI(int) icvComputeRestStereoParams(CvStereoCamera *stereoparams);
+
+CVAPI(void) cvComputePerspectiveMap( const double coeffs[3][3], CvArr* rectMapX, CvArr* rectMapY );
+
+CVAPI(int) icvComCoeffForLine( CvPoint2D64f point1,
+ CvPoint2D64f point2,
+ CvPoint2D64f point3,
+ CvPoint2D64f point4,
+ CvMatr64d camMatr1,
+ CvMatr64d rotMatr1,
+ CvMatr64d transVect1,
+ CvMatr64d camMatr2,
+ CvMatr64d rotMatr2,
+ CvMatr64d transVect2,
+ CvStereoLineCoeff* coeffs,
+ int* needSwapCameras);
+
+CVAPI(int) icvGetDirectionForPoint( CvPoint2D64f point,
+ CvMatr64d camMatr,
+ CvPoint3D64f* direct);
+
+CVAPI(int) icvGetCrossLines(CvPoint3D64f point11,CvPoint3D64f point12,
+ CvPoint3D64f point21,CvPoint3D64f point22,
+ CvPoint3D64f* midPoint);
+
+CVAPI(int) icvComputeStereoLineCoeffs( CvPoint3D64f pointA,
+ CvPoint3D64f pointB,
+ CvPoint3D64f pointCam1,
+ double gamma,
+ CvStereoLineCoeff* coeffs);
+
+/*CVAPI(int) icvComputeFundMatrEpipoles ( CvMatr64d camMatr1,
+ CvMatr64d rotMatr1,
+ CvVect64d transVect1,
+ CvMatr64d camMatr2,
+ CvMatr64d rotMatr2,
+ CvVect64d transVect2,
+ CvPoint2D64f* epipole1,
+ CvPoint2D64f* epipole2,
+ CvMatr64d fundMatr);*/
+
+CVAPI(int) icvGetAngleLine( CvPoint2D64f startPoint, CvSize imageSize,CvPoint2D64f *point1,CvPoint2D64f *point2);
+
+CVAPI(void) icvGetCoefForPiece( CvPoint2D64f p_start,CvPoint2D64f p_end,
+ double *a,double *b,double *c,
+ int* result);
+
+/*CVAPI(void) icvGetCommonArea( CvSize imageSize,
+ CvPoint2D64f epipole1,CvPoint2D64f epipole2,
+ CvMatr64d fundMatr,
+ CvVect64d coeff11,CvVect64d coeff12,
+ CvVect64d coeff21,CvVect64d coeff22,
+ int* result);*/
+
+CVAPI(void) icvComputeeInfiniteProject1(CvMatr64d rotMatr,
+ CvMatr64d camMatr1,
+ CvMatr64d camMatr2,
+ CvPoint2D32f point1,
+ CvPoint2D32f *point2);
+
+CVAPI(void) icvComputeeInfiniteProject2(CvMatr64d rotMatr,
+ CvMatr64d camMatr1,
+ CvMatr64d camMatr2,
+ CvPoint2D32f* point1,
+ CvPoint2D32f point2);
+
+CVAPI(void) icvGetCrossDirectDirect( CvVect64d direct1,CvVect64d direct2,
+ CvPoint2D64f *cross,int* result);
+
+CVAPI(void) icvGetCrossPieceDirect( CvPoint2D64f p_start,CvPoint2D64f p_end,
+ double a,double b,double c,
+ CvPoint2D64f *cross,int* result);
+
+CVAPI(void) icvGetCrossPiecePiece( CvPoint2D64f p1_start,CvPoint2D64f p1_end,
+ CvPoint2D64f p2_start,CvPoint2D64f p2_end,
+ CvPoint2D64f* cross,
+ int* result);
+
+CVAPI(void) icvGetPieceLength(CvPoint2D64f point1,CvPoint2D64f point2,double* dist);
+
+CVAPI(void) icvGetCrossRectDirect( CvSize imageSize,
+ double a,double b,double c,
+ CvPoint2D64f *start,CvPoint2D64f *end,
+ int* result);
+
+CVAPI(void) icvProjectPointToImage( CvPoint3D64f point,
+ CvMatr64d camMatr,CvMatr64d rotMatr,CvVect64d transVect,
+ CvPoint2D64f* projPoint);
+
+CVAPI(void) icvGetQuadsTransform( CvSize imageSize,
+ CvMatr64d camMatr1,
+ CvMatr64d rotMatr1,
+ CvVect64d transVect1,
+ CvMatr64d camMatr2,
+ CvMatr64d rotMatr2,
+ CvVect64d transVect2,
+ CvSize* warpSize,
+ double quad1[4][2],
+ double quad2[4][2],
+ CvMatr64d fundMatr,
+ CvPoint3D64f* epipole1,
+ CvPoint3D64f* epipole2
+ );
+
+CVAPI(void) icvGetQuadsTransformStruct( CvStereoCamera* stereoCamera);
+
+CVAPI(void) icvComputeStereoParamsForCameras(CvStereoCamera* stereoCamera);
+
+CVAPI(void) icvGetCutPiece( CvVect64d areaLineCoef1,CvVect64d areaLineCoef2,
+ CvPoint2D64f epipole,
+ CvSize imageSize,
+ CvPoint2D64f* point11,CvPoint2D64f* point12,
+ CvPoint2D64f* point21,CvPoint2D64f* point22,
+ int* result);
+
+CVAPI(void) icvGetMiddleAnglePoint( CvPoint2D64f basePoint,
+ CvPoint2D64f point1,CvPoint2D64f point2,
+ CvPoint2D64f* midPoint);
+
+CVAPI(void) icvGetNormalDirect(CvVect64d direct,CvPoint2D64f point,CvVect64d normDirect);
+
+CVAPI(double) icvGetVect(CvPoint2D64f basePoint,CvPoint2D64f point1,CvPoint2D64f point2);
+
+CVAPI(void) icvProjectPointToDirect( CvPoint2D64f point,CvVect64d lineCoeff,
+ CvPoint2D64f* projectPoint);
+
+CVAPI(void) icvGetDistanceFromPointToDirect( CvPoint2D64f point,CvVect64d lineCoef,double*dist);
+
+CVAPI(IplImage*) icvCreateIsometricImage( IplImage* src, IplImage* dst,
+ int desired_depth, int desired_num_channels );
+
+CVAPI(void) cvDeInterlace( const CvArr* frame, CvArr* fieldEven, CvArr* fieldOdd );
+
+/*CVAPI(int) icvSelectBestRt( int numImages,
+ int* numPoints,
+ CvSize imageSize,
+ CvPoint2D32f* imagePoints1,
+ CvPoint2D32f* imagePoints2,
+ CvPoint3D32f* objectPoints,
+
+ CvMatr32f cameraMatrix1,
+ CvVect32f distortion1,
+ CvMatr32f rotMatrs1,
+ CvVect32f transVects1,
+
+ CvMatr32f cameraMatrix2,
+ CvVect32f distortion2,
+ CvMatr32f rotMatrs2,
+ CvVect32f transVects2,
+
+ CvMatr32f bestRotMatr,
+ CvVect32f bestTransVect
+ );*/
+
+/****************************************************************************************\
+* Contour Morphing *
+\****************************************************************************************/
+
+/* finds correspondence between two contours */
+CvSeq* cvCalcContoursCorrespondence( const CvSeq* contour1,
+ const CvSeq* contour2,
+ CvMemStorage* storage);
+
+/* morphs contours using the pre-calculated correspondence:
+ alpha=0 ~ contour1, alpha=1 ~ contour2 */
+CvSeq* cvMorphContours( const CvSeq* contour1, const CvSeq* contour2,
+ CvSeq* corr, double alpha,
+ CvMemStorage* storage );
+
+/****************************************************************************************\
+* Texture Descriptors *
+\****************************************************************************************/
+
+#define CV_GLCM_OPTIMIZATION_NONE -2
+#define CV_GLCM_OPTIMIZATION_LUT -1
+#define CV_GLCM_OPTIMIZATION_HISTOGRAM 0
+
+#define CV_GLCMDESC_OPTIMIZATION_ALLOWDOUBLENEST 10
+#define CV_GLCMDESC_OPTIMIZATION_ALLOWTRIPLENEST 11
+#define CV_GLCMDESC_OPTIMIZATION_HISTOGRAM 4
+
+#define CV_GLCMDESC_ENTROPY 0
+#define CV_GLCMDESC_ENERGY 1
+#define CV_GLCMDESC_HOMOGENITY 2
+#define CV_GLCMDESC_CONTRAST 3
+#define CV_GLCMDESC_CLUSTERTENDENCY 4
+#define CV_GLCMDESC_CLUSTERSHADE 5
+#define CV_GLCMDESC_CORRELATION 6
+#define CV_GLCMDESC_CORRELATIONINFO1 7
+#define CV_GLCMDESC_CORRELATIONINFO2 8
+#define CV_GLCMDESC_MAXIMUMPROBABILITY 9
+
+#define CV_GLCM_ALL 0
+#define CV_GLCM_GLCM 1
+#define CV_GLCM_DESC 2
+
+typedef struct CvGLCM CvGLCM;
+
+CVAPI(CvGLCM*) cvCreateGLCM( const IplImage* srcImage,
+ int stepMagnitude,
+ const int* stepDirections CV_DEFAULT(0),
+ int numStepDirections CV_DEFAULT(0),
+ int optimizationType CV_DEFAULT(CV_GLCM_OPTIMIZATION_NONE));
+
+CVAPI(void) cvReleaseGLCM( CvGLCM** GLCM, int flag CV_DEFAULT(CV_GLCM_ALL));
+
+CVAPI(void) cvCreateGLCMDescriptors( CvGLCM* destGLCM,
+ int descriptorOptimizationType
+ CV_DEFAULT(CV_GLCMDESC_OPTIMIZATION_ALLOWDOUBLENEST));
+
+CVAPI(double) cvGetGLCMDescriptor( CvGLCM* GLCM, int step, int descriptor );
+
+CVAPI(void) cvGetGLCMDescriptorStatistics( CvGLCM* GLCM, int descriptor,
+ double* average, double* standardDeviation );
+
+CVAPI(IplImage*) cvCreateGLCMImage( CvGLCM* GLCM, int step );
+
+/****************************************************************************************\
+* Face eyes&mouth tracking *
+\****************************************************************************************/
+
+
+typedef struct CvFaceTracker CvFaceTracker;
+
+#define CV_NUM_FACE_ELEMENTS 3
+enum CV_FACE_ELEMENTS
+{
+ CV_FACE_MOUTH = 0,
+ CV_FACE_LEFT_EYE = 1,
+ CV_FACE_RIGHT_EYE = 2
+};
+
+CVAPI(CvFaceTracker*) cvInitFaceTracker(CvFaceTracker* pFaceTracking, const IplImage* imgGray,
+ CvRect* pRects, int nRects);
+CVAPI(int) cvTrackFace( CvFaceTracker* pFaceTracker, IplImage* imgGray,
+ CvRect* pRects, int nRects,
+ CvPoint* ptRotate, double* dbAngleRotate);
+CVAPI(void) cvReleaseFaceTracker(CvFaceTracker** ppFaceTracker);
+
+
+typedef struct CvFace
+{
+ CvRect MouthRect;
+ CvRect LeftEyeRect;
+ CvRect RightEyeRect;
+} CvFaceData;
+
+CvSeq * cvFindFace(IplImage * Image,CvMemStorage* storage);
+CvSeq * cvPostBoostingFindFace(IplImage * Image,CvMemStorage* storage);
+
+
+/****************************************************************************************\
+* 3D Tracker *
+\****************************************************************************************/
+
+typedef unsigned char CvBool;
+
+typedef struct
+{
+ int id;
+ CvPoint2D32f p; // pgruebele: So we do not loose precision, this needs to be float
+} Cv3dTracker2dTrackedObject;
+
+CV_INLINE Cv3dTracker2dTrackedObject cv3dTracker2dTrackedObject(int id, CvPoint2D32f p)
+{
+ Cv3dTracker2dTrackedObject r;
+ r.id = id;
+ r.p = p;
+ return r;
+}
+
+typedef struct
+{
+ int id;
+ CvPoint3D32f p; // location of the tracked object
+} Cv3dTrackerTrackedObject;
+
+CV_INLINE Cv3dTrackerTrackedObject cv3dTrackerTrackedObject(int id, CvPoint3D32f p)
+{
+ Cv3dTrackerTrackedObject r;
+ r.id = id;
+ r.p = p;
+ return r;
+}
+
+typedef struct
+{
+ CvBool valid;
+ float mat[4][4]; /* maps camera coordinates to world coordinates */
+ CvPoint2D32f principal_point; /* copied from intrinsics so this structure */
+ /* has all the info we need */
+} Cv3dTrackerCameraInfo;
+
+typedef struct
+{
+ CvPoint2D32f principal_point;
+ float focal_length[2];
+ float distortion[4];
+} Cv3dTrackerCameraIntrinsics;
+
+CVAPI(CvBool) cv3dTrackerCalibrateCameras(int num_cameras,
+ const Cv3dTrackerCameraIntrinsics camera_intrinsics[], /* size is num_cameras */
+ CvSize etalon_size,
+ float square_size,
+ IplImage *samples[], /* size is num_cameras */
+ Cv3dTrackerCameraInfo camera_info[]); /* size is num_cameras */
+
+CVAPI(int) cv3dTrackerLocateObjects(int num_cameras, int num_objects,
+ const Cv3dTrackerCameraInfo camera_info[], /* size is num_cameras */
+ const Cv3dTracker2dTrackedObject tracking_info[], /* size is num_objects*num_cameras */
+ Cv3dTrackerTrackedObject tracked_objects[]); /* size is num_objects */
+/****************************************************************************************
+ tracking_info is a rectangular array; one row per camera, num_objects elements per row.
+ The id field of any unused slots must be -1. Ids need not be ordered or consecutive. On
+ completion, the return value is the number of objects located; i.e., the number of objects
+ visible by more than one camera. The id field of any unused slots in tracked objects is
+ set to -1.
+****************************************************************************************/
+
+
+/****************************************************************************************\
+* Skeletons and Linear-Contour Models *
+\****************************************************************************************/
+
+typedef enum CvLeeParameters
+{
+ CV_LEE_INT = 0,
+ CV_LEE_FLOAT = 1,
+ CV_LEE_DOUBLE = 2,
+ CV_LEE_AUTO = -1,
+ CV_LEE_ERODE = 0,
+ CV_LEE_ZOOM = 1,
+ CV_LEE_NON = 2
+} CvLeeParameters;
+
+#define CV_NEXT_VORONOISITE2D( SITE ) ((SITE)->edge[0]->site[((SITE)->edge[0]->site[0] == (SITE))])
+#define CV_PREV_VORONOISITE2D( SITE ) ((SITE)->edge[1]->site[((SITE)->edge[1]->site[0] == (SITE))])
+#define CV_FIRST_VORONOIEDGE2D( SITE ) ((SITE)->edge[0])
+#define CV_LAST_VORONOIEDGE2D( SITE ) ((SITE)->edge[1])
+#define CV_NEXT_VORONOIEDGE2D( EDGE, SITE ) ((EDGE)->next[(EDGE)->site[0] != (SITE)])
+#define CV_PREV_VORONOIEDGE2D( EDGE, SITE ) ((EDGE)->next[2 + ((EDGE)->site[0] != (SITE))])
+#define CV_VORONOIEDGE2D_BEGINNODE( EDGE, SITE ) ((EDGE)->node[((EDGE)->site[0] != (SITE))])
+#define CV_VORONOIEDGE2D_ENDNODE( EDGE, SITE ) ((EDGE)->node[((EDGE)->site[0] == (SITE))])
+#define CV_TWIN_VORONOISITE2D( SITE, EDGE ) ( (EDGE)->site[((EDGE)->site[0] == (SITE))])
+
+#define CV_VORONOISITE2D_FIELDS() \
+ struct CvVoronoiNode2D *node[2]; \
+ struct CvVoronoiEdge2D *edge[2];
+
+typedef struct CvVoronoiSite2D
+{
+ CV_VORONOISITE2D_FIELDS()
+ struct CvVoronoiSite2D *next[2];
+} CvVoronoiSite2D;
+
+#define CV_VORONOIEDGE2D_FIELDS() \
+ struct CvVoronoiNode2D *node[2]; \
+ struct CvVoronoiSite2D *site[2]; \
+ struct CvVoronoiEdge2D *next[4];
+
+typedef struct CvVoronoiEdge2D
+{
+ CV_VORONOIEDGE2D_FIELDS()
+} CvVoronoiEdge2D;
+
+#define CV_VORONOINODE2D_FIELDS() \
+ CV_SET_ELEM_FIELDS(CvVoronoiNode2D) \
+ CvPoint2D32f pt; \
+ float radius;
+
+typedef struct CvVoronoiNode2D
+{
+ CV_VORONOINODE2D_FIELDS()
+} CvVoronoiNode2D;
+
+#define CV_VORONOIDIAGRAM2D_FIELDS() \
+ CV_GRAPH_FIELDS() \
+ CvSet *sites;
+
+typedef struct CvVoronoiDiagram2D
+{
+ CV_VORONOIDIAGRAM2D_FIELDS()
+} CvVoronoiDiagram2D;
+
+/* Computes Voronoi Diagram for given polygons with holes */
+CVAPI(int) cvVoronoiDiagramFromContour(CvSeq* ContourSeq,
+ CvVoronoiDiagram2D** VoronoiDiagram,
+ CvMemStorage* VoronoiStorage,
+ CvLeeParameters contour_type CV_DEFAULT(CV_LEE_INT),
+ int contour_orientation CV_DEFAULT(-1),
+ int attempt_number CV_DEFAULT(10));
+
+/* Computes Voronoi Diagram for domains in given image */
+CVAPI(int) cvVoronoiDiagramFromImage(IplImage* pImage,
+ CvSeq** ContourSeq,
+ CvVoronoiDiagram2D** VoronoiDiagram,
+ CvMemStorage* VoronoiStorage,
+ CvLeeParameters regularization_method CV_DEFAULT(CV_LEE_NON),
+ float approx_precision CV_DEFAULT(CV_LEE_AUTO));
+
+/* Deallocates the storage */
+CVAPI(void) cvReleaseVoronoiStorage(CvVoronoiDiagram2D* VoronoiDiagram,
+ CvMemStorage** pVoronoiStorage);
+
+/*********************** Linear-Contour Model ****************************/
+
+struct CvLCMEdge;
+struct CvLCMNode;
+
+typedef struct CvLCMEdge
+{
+ CV_GRAPH_EDGE_FIELDS()
+ CvSeq* chain;
+ float width;
+ int index1;
+ int index2;
+} CvLCMEdge;
+
+typedef struct CvLCMNode
+{
+ CV_GRAPH_VERTEX_FIELDS()
+ CvContour* contour;
+} CvLCMNode;
+
+
+/* Computes hybrid model from Voronoi Diagram */
+CVAPI(CvGraph*) cvLinearContorModelFromVoronoiDiagram(CvVoronoiDiagram2D* VoronoiDiagram,
+ float maxWidth);
+
+/* Releases hybrid model storage */
+CVAPI(int) cvReleaseLinearContorModelStorage(CvGraph** Graph);
+
+
+/* two stereo-related functions */
+
+CVAPI(void) cvInitPerspectiveTransform( CvSize size, const CvPoint2D32f vertex[4], double matrix[3][3],
+ CvArr* rectMap );
+
+/*CVAPI(void) cvInitStereoRectification( CvStereoCamera* params,
+ CvArr* rectMap1, CvArr* rectMap2,
+ int do_undistortion );*/
+
+/*************************** View Morphing Functions ************************/
+
+/* The order of the function corresponds to the order they should appear in
+ the view morphing pipeline */
+
+/* Finds ending points of scanlines on left and right images of stereo-pair */
+CVAPI(void) cvMakeScanlines( const CvMatrix3* matrix, CvSize img_size,
+ int* scanlines1, int* scanlines2,
+ int* lengths1, int* lengths2,
+ int* line_count );
+
+/* Grab pixel values from scanlines and stores them sequentially
+ (some sort of perspective image transform) */
+CVAPI(void) cvPreWarpImage( int line_count,
+ IplImage* img,
+ uchar* dst,
+ int* dst_nums,
+ int* scanlines);
+
+/* Approximate each grabbed scanline by a sequence of runs
+ (lossy run-length compression) */
+CVAPI(void) cvFindRuns( int line_count,
+ uchar* prewarp1,
+ uchar* prewarp2,
+ int* line_lengths1,
+ int* line_lengths2,
+ int* runs1,
+ int* runs2,
+ int* num_runs1,
+ int* num_runs2);
+
+/* Compares two sets of compressed scanlines */
+CVAPI(void) cvDynamicCorrespondMulti( int line_count,
+ int* first,
+ int* first_runs,
+ int* second,
+ int* second_runs,
+ int* first_corr,
+ int* second_corr);
+
+/* Finds scanline ending coordinates for some intermediate "virtual" camera position */
+CVAPI(void) cvMakeAlphaScanlines( int* scanlines1,
+ int* scanlines2,
+ int* scanlinesA,
+ int* lengths,
+ int line_count,
+ float alpha);
+
+/* Blends data of the left and right image scanlines to get
+ pixel values of "virtual" image scanlines */
+CVAPI(void) cvMorphEpilinesMulti( int line_count,
+ uchar* first_pix,
+ int* first_num,
+ uchar* second_pix,
+ int* second_num,
+ uchar* dst_pix,
+ int* dst_num,
+ float alpha,
+ int* first,
+ int* first_runs,
+ int* second,
+ int* second_runs,
+ int* first_corr,
+ int* second_corr);
+
+/* Does reverse warping of the morphing result to make
+ it fill the destination image rectangle */
+CVAPI(void) cvPostWarpImage( int line_count,
+ uchar* src,
+ int* src_nums,
+ IplImage* img,
+ int* scanlines);
+
+/* Deletes Moire (missed pixels that appear due to discretization) */
+CVAPI(void) cvDeleteMoire( IplImage* img );
+
+
+/****************************************************************************************\
+* Background/foreground segmentation *
+\****************************************************************************************/
+
+/* We discriminate between foreground and background pixels
+ * by building and maintaining a model of the background.
+ * Any pixel which does not fit this model is then deemed
+ * to be foreground.
+ *
+ * At present we support two core background models,
+ * one of which has two variations:
+ *
+ * o CV_BG_MODEL_FGD: latest and greatest algorithm, described in
+ *
+ * Foreground Object Detection from Videos Containing Complex Background.
+ * Liyuan Li, Weimin Huang, Irene Y.H. Gu, and Qi Tian.
+ * ACM MM2003 9p
+ *
+ * o CV_BG_MODEL_FGD_SIMPLE:
+ * A code comment describes this as a simplified version of the above,
+ * but the code is in fact currently identical
+ *
+ * o CV_BG_MODEL_MOG: "Mixture of Gaussians", older algorithm, described in
+ *
+ * Moving target classification and tracking from real-time video.
+ * A Lipton, H Fujijoshi, R Patil
+ * Proceedings IEEE Workshop on Application of Computer Vision pp 8-14 1998
+ *
+ * Learning patterns of activity using real-time tracking
+ * C Stauffer and W Grimson August 2000
+ * IEEE Transactions on Pattern Analysis and Machine Intelligence 22(8):747-757
+ */
+
+
+#define CV_BG_MODEL_FGD 0
+#define CV_BG_MODEL_MOG 1 /* "Mixture of Gaussians". */
+#define CV_BG_MODEL_FGD_SIMPLE 2
+
+struct CvBGStatModel;
+
+typedef void (CV_CDECL * CvReleaseBGStatModel)( struct CvBGStatModel** bg_model );
+typedef int (CV_CDECL * CvUpdateBGStatModel)( IplImage* curr_frame, struct CvBGStatModel* bg_model );
+
+#define CV_BG_STAT_MODEL_FIELDS() \
+ int type; /*type of BG model*/ \
+ CvReleaseBGStatModel release; \
+ CvUpdateBGStatModel update; \
+ IplImage* background; /*8UC3 reference background image*/ \
+ IplImage* foreground; /*8UC1 foreground image*/ \
+ IplImage** layers; /*8UC3 reference background image, can be null */ \
+ int layer_count; /* can be zero */ \
+ CvMemStorage* storage; /*storage for “foreground_regions”*/ \
+ CvSeq* foreground_regions /*foreground object contours*/
+
+typedef struct CvBGStatModel
+{
+ CV_BG_STAT_MODEL_FIELDS();
+}
+CvBGStatModel;
+
+//
+
+// Releases memory used by BGStatModel
+CV_INLINE void cvReleaseBGStatModel( CvBGStatModel** bg_model )
+{
+ if( bg_model && *bg_model && (*bg_model)->release )
+ (*bg_model)->release( bg_model );
+}
+
+// Updates statistical model and returns number of found foreground regions
+CV_INLINE int cvUpdateBGStatModel( IplImage* current_frame, CvBGStatModel* bg_model )
+{
+ return bg_model && bg_model->update ? bg_model->update( current_frame, bg_model ) : 0;
+}
+
+// Performs FG post-processing using segmentation
+// (all pixels of a region will be classified as foreground if majority of pixels of the region are FG).
+// parameters:
+// segments - pointer to result of segmentation (for example MeanShiftSegmentation)
+// bg_model - pointer to CvBGStatModel structure
+CVAPI(void) cvRefineForegroundMaskBySegm( CvSeq* segments, CvBGStatModel* bg_model );
+
+/* Common use change detection function */
+CVAPI(int) cvChangeDetection( IplImage* prev_frame,
+ IplImage* curr_frame,
+ IplImage* change_mask );
+
+/*
+ Interface of ACM MM2003 algorithm
+*/
+
+/* Default parameters of foreground detection algorithm: */
+#define CV_BGFG_FGD_LC 128
+#define CV_BGFG_FGD_N1C 15
+#define CV_BGFG_FGD_N2C 25
+
+#define CV_BGFG_FGD_LCC 64
+#define CV_BGFG_FGD_N1CC 25
+#define CV_BGFG_FGD_N2CC 40
+
+/* Background reference image update parameter: */
+#define CV_BGFG_FGD_ALPHA_1 0.1f
+
+/* stat model update parameter
+ * 0.002f ~ 1K frame(~45sec), 0.005 ~ 18sec (if 25fps and absolutely static BG)
+ */
+#define CV_BGFG_FGD_ALPHA_2 0.005f
+
+/* start value for alpha parameter (to fast initiate statistic model) */
+#define CV_BGFG_FGD_ALPHA_3 0.1f
+
+#define CV_BGFG_FGD_DELTA 2
+
+#define CV_BGFG_FGD_T 0.9f
+
+#define CV_BGFG_FGD_MINAREA 15.f
+
+#define CV_BGFG_FGD_BG_UPDATE_TRESH 0.5f
+
+/* See the above-referenced Li/Huang/Gu/Tian paper
+ * for a full description of these background-model
+ * tuning parameters.
+ *
+ * Nomenclature: 'c' == "color", a three-component red/green/blue vector.
+ * We use histograms of these to model the range of
+ * colors we've seen at a given background pixel.
+ *
+ * 'cc' == "color co-occurrence", a six-component vector giving
+ * RGB color for both this frame and preceding frame.
+ * We use histograms of these to model the range of
+ * color CHANGES we've seen at a given background pixel.
+ */
+typedef struct CvFGDStatModelParams
+{
+ int Lc; /* Quantized levels per 'color' component. Power of two, typically 32, 64 or 128. */
+ int N1c; /* Number of color vectors used to model normal background color variation at a given pixel. */
+ int N2c; /* Number of color vectors retained at given pixel. Must be > N1c, typically ~ 5/3 of N1c. */
+ /* Used to allow the first N1c vectors to adapt over time to changing background. */
+
+ int Lcc; /* Quantized levels per 'color co-occurrence' component. Power of two, typically 16, 32 or 64. */
+ int N1cc; /* Number of color co-occurrence vectors used to model normal background color variation at a given pixel. */
+ int N2cc; /* Number of color co-occurrence vectors retained at given pixel. Must be > N1cc, typically ~ 5/3 of N1cc. */
+ /* Used to allow the first N1cc vectors to adapt over time to changing background. */
+
+ int is_obj_without_holes;/* If TRUE we ignore holes within foreground blobs. Defaults to TRUE. */
+ int perform_morphing; /* Number of erode-dilate-erode foreground-blob cleanup iterations. */
+ /* These erase one-pixel junk blobs and merge almost-touching blobs. Default value is 1. */
+
+ float alpha1; /* How quickly we forget old background pixel values seen. Typically set to 0.1 */
+ float alpha2; /* "Controls speed of feature learning". Depends on T. Typical value circa 0.005. */
+ float alpha3; /* Alternate to alpha2, used (e.g.) for quicker initial convergence. Typical value 0.1. */
+
+ float delta; /* Affects color and color co-occurrence quantization, typically set to 2. */
+ float T; /* "A percentage value which determines when new features can be recognized as new background." (Typically 0.9).*/
+ float minArea; /* Discard foreground blobs whose bounding box is smaller than this threshold. */
+}
+CvFGDStatModelParams;
+
+typedef struct CvBGPixelCStatTable
+{
+ float Pv, Pvb;
+ uchar v[3];
+}
+CvBGPixelCStatTable;
+
+typedef struct CvBGPixelCCStatTable
+{
+ float Pv, Pvb;
+ uchar v[6];
+}
+CvBGPixelCCStatTable;
+
+typedef struct CvBGPixelStat
+{
+ float Pbc;
+ float Pbcc;
+ CvBGPixelCStatTable* ctable;
+ CvBGPixelCCStatTable* cctable;
+ uchar is_trained_st_model;
+ uchar is_trained_dyn_model;
+}
+CvBGPixelStat;
+
+
+typedef struct CvFGDStatModel
+{
+ CV_BG_STAT_MODEL_FIELDS();
+ CvBGPixelStat* pixel_stat;
+ IplImage* Ftd;
+ IplImage* Fbd;
+ IplImage* prev_frame;
+ CvFGDStatModelParams params;
+}
+CvFGDStatModel;
+
+/* Creates FGD model */
+CVAPI(CvBGStatModel*) cvCreateFGDStatModel( IplImage* first_frame,
+ CvFGDStatModelParams* parameters CV_DEFAULT(NULL));
+
+/*
+ Interface of Gaussian mixture algorithm
+
+ "An improved adaptive background mixture model for real-time tracking with shadow detection"
+ P. KadewTraKuPong and R. Bowden,
+ Proc. 2nd European Workshp on Advanced Video-Based Surveillance Systems, 2001."
+ http://personal.ee.surrey.ac.uk/Personal/R.Bowden/publications/avbs01/avbs01.pdf
+*/
+
+/* Note: "MOG" == "Mixture Of Gaussians": */
+
+#define CV_BGFG_MOG_MAX_NGAUSSIANS 500
+
+/* default parameters of gaussian background detection algorithm */
+#define CV_BGFG_MOG_BACKGROUND_THRESHOLD 0.7 /* threshold sum of weights for background test */
+#define CV_BGFG_MOG_STD_THRESHOLD 2.5 /* lambda=2.5 is 99% */
+#define CV_BGFG_MOG_WINDOW_SIZE 200 /* Learning rate; alpha = 1/CV_GBG_WINDOW_SIZE */
+#define CV_BGFG_MOG_NGAUSSIANS 5 /* = K = number of Gaussians in mixture */
+#define CV_BGFG_MOG_WEIGHT_INIT 0.05
+#define CV_BGFG_MOG_SIGMA_INIT 30
+#define CV_BGFG_MOG_MINAREA 15.f
+
+
+#define CV_BGFG_MOG_NCOLORS 3
+
+typedef struct CvGaussBGStatModelParams
+{
+ int win_size; /* = 1/alpha */
+ int n_gauss;
+ double bg_threshold, std_threshold, minArea;
+ double weight_init, variance_init;
+}CvGaussBGStatModelParams;
+
+typedef struct CvGaussBGValues
+{
+ int match_sum;
+ double weight;
+ double variance[CV_BGFG_MOG_NCOLORS];
+ double mean[CV_BGFG_MOG_NCOLORS];
+}
+CvGaussBGValues;
+
+typedef struct CvGaussBGPoint
+{
+ CvGaussBGValues* g_values;
+}
+CvGaussBGPoint;
+
+
+typedef struct CvGaussBGModel
+{
+ CV_BG_STAT_MODEL_FIELDS();
+ CvGaussBGStatModelParams params;
+ CvGaussBGPoint* g_point;
+ int countFrames;
+}
+CvGaussBGModel;
+
+
+/* Creates Gaussian mixture background model */
+CVAPI(CvBGStatModel*) cvCreateGaussianBGModel( IplImage* first_frame,
+ CvGaussBGStatModelParams* parameters CV_DEFAULT(NULL));
+
+
+typedef struct CvBGCodeBookElem
+{
+ struct CvBGCodeBookElem* next;
+ int tLastUpdate;
+ int stale;
+ uchar boxMin[3];
+ uchar boxMax[3];
+ uchar learnMin[3];
+ uchar learnMax[3];
+}
+CvBGCodeBookElem;
+
+typedef struct CvBGCodeBookModel
+{
+ CvSize size;
+ int t;
+ uchar cbBounds[3];
+ uchar modMin[3];
+ uchar modMax[3];
+ CvBGCodeBookElem** cbmap;
+ CvMemStorage* storage;
+ CvBGCodeBookElem* freeList;
+}
+CvBGCodeBookModel;
+
+CVAPI(CvBGCodeBookModel*) cvCreateBGCodeBookModel();
+CVAPI(void) cvReleaseBGCodeBookModel( CvBGCodeBookModel** model );
+
+CVAPI(void) cvBGCodeBookUpdate( CvBGCodeBookModel* model, const CvArr* image,
+ CvRect roi CV_DEFAULT(cvRect(0,0,0,0)),
+ const CvArr* mask CV_DEFAULT(0) );
+
+CVAPI(int) cvBGCodeBookDiff( const CvBGCodeBookModel* model, const CvArr* image,
+ CvArr* fgmask, CvRect roi CV_DEFAULT(cvRect(0,0,0,0)) );
+
+CVAPI(void) cvBGCodeBookClearStale( CvBGCodeBookModel* model, int staleThresh,
+ CvRect roi CV_DEFAULT(cvRect(0,0,0,0)),
+ const CvArr* mask CV_DEFAULT(0) );
+
+CVAPI(CvSeq*) cvSegmentFGMask( CvArr *fgmask, int poly1Hull0 CV_DEFAULT(1),
+ float perimScale CV_DEFAULT(4.f),
+ CvMemStorage* storage CV_DEFAULT(0),
+ CvPoint offset CV_DEFAULT(cvPoint(0,0)));
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+
+/****************************************************************************************\
+* Calibration engine *
+\****************************************************************************************/
+
+typedef enum CvCalibEtalonType
+{
+ CV_CALIB_ETALON_USER = -1,
+ CV_CALIB_ETALON_CHESSBOARD = 0,
+ CV_CALIB_ETALON_CHECKERBOARD = CV_CALIB_ETALON_CHESSBOARD
+}
+CvCalibEtalonType;
+
+class CV_EXPORTS CvCalibFilter
+{
+public:
+ /* Constructor & destructor */
+ CvCalibFilter();
+ virtual ~CvCalibFilter();
+
+ /* Sets etalon type - one for all cameras.
+ etalonParams is used in case of pre-defined etalons (such as chessboard).
+ Number of elements in etalonParams is determined by etalonType.
+ E.g., if etalon type is CV_ETALON_TYPE_CHESSBOARD then:
+ etalonParams[0] is number of squares per one side of etalon
+ etalonParams[1] is number of squares per another side of etalon
+ etalonParams[2] is linear size of squares in the board in arbitrary units.
+ pointCount & points are used in case of
+ CV_CALIB_ETALON_USER (user-defined) etalon. */
+ virtual bool
+ SetEtalon( CvCalibEtalonType etalonType, double* etalonParams,
+ int pointCount = 0, CvPoint2D32f* points = 0 );
+
+ /* Retrieves etalon parameters/or and points */
+ virtual CvCalibEtalonType
+ GetEtalon( int* paramCount = 0, const double** etalonParams = 0,
+ int* pointCount = 0, const CvPoint2D32f** etalonPoints = 0 ) const;
+
+ /* Sets number of cameras calibrated simultaneously. It is equal to 1 initially */
+ virtual void SetCameraCount( int cameraCount );
+
+ /* Retrieves number of cameras */
+ int GetCameraCount() const { return cameraCount; }
+
+ /* Starts cameras calibration */
+ virtual bool SetFrames( int totalFrames );
+
+ /* Stops cameras calibration */
+ virtual void Stop( bool calibrate = false );
+
+ /* Retrieves number of cameras */
+ bool IsCalibrated() const { return isCalibrated; }
+
+ /* Feeds another serie of snapshots (one per each camera) to filter.
+ Etalon points on these images are found automatically.
+ If the function can't locate points, it returns false */
+ virtual bool FindEtalon( IplImage** imgs );
+
+ /* The same but takes matrices */
+ virtual bool FindEtalon( CvMat** imgs );
+
+ /* Lower-level function for feeding filter with already found etalon points.
+ Array of point arrays for each camera is passed. */
+ virtual bool Push( const CvPoint2D32f** points = 0 );
+
+ /* Returns total number of accepted frames and, optionally,
+ total number of frames to collect */
+ virtual int GetFrameCount( int* framesTotal = 0 ) const;
+
+ /* Retrieves camera parameters for specified camera.
+ If camera is not calibrated the function returns 0 */
+ virtual const CvCamera* GetCameraParams( int idx = 0 ) const;
+
+ virtual const CvStereoCamera* GetStereoParams() const;
+
+ /* Sets camera parameters for all cameras */
+ virtual bool SetCameraParams( CvCamera* params );
+
+ /* Saves all camera parameters to file */
+ virtual bool SaveCameraParams( const char* filename );
+
+ /* Loads all camera parameters from file */
+ virtual bool LoadCameraParams( const char* filename );
+
+ /* Undistorts images using camera parameters. Some of src pointers can be NULL. */
+ virtual bool Undistort( IplImage** src, IplImage** dst );
+
+ /* Undistorts images using camera parameters. Some of src pointers can be NULL. */
+ virtual bool Undistort( CvMat** src, CvMat** dst );
+
+ /* Returns array of etalon points detected/partally detected
+ on the latest frame for idx-th camera */
+ virtual bool GetLatestPoints( int idx, CvPoint2D32f** pts,
+ int* count, bool* found );
+
+ /* Draw the latest detected/partially detected etalon */
+ virtual void DrawPoints( IplImage** dst );
+
+ /* Draw the latest detected/partially detected etalon */
+ virtual void DrawPoints( CvMat** dst );
+
+ virtual bool Rectify( IplImage** srcarr, IplImage** dstarr );
+ virtual bool Rectify( CvMat** srcarr, CvMat** dstarr );
+
+protected:
+
+ enum { MAX_CAMERAS = 3 };
+
+ /* etalon data */
+ CvCalibEtalonType etalonType;
+ int etalonParamCount;
+ double* etalonParams;
+ int etalonPointCount;
+ CvPoint2D32f* etalonPoints;
+ CvSize imgSize;
+ CvMat* grayImg;
+ CvMat* tempImg;
+ CvMemStorage* storage;
+
+ /* camera data */
+ int cameraCount;
+ CvCamera cameraParams[MAX_CAMERAS];
+ CvStereoCamera stereo;
+ CvPoint2D32f* points[MAX_CAMERAS];
+ CvMat* undistMap[MAX_CAMERAS][2];
+ CvMat* undistImg;
+ int latestCounts[MAX_CAMERAS];
+ CvPoint2D32f* latestPoints[MAX_CAMERAS];
+ CvMat* rectMap[MAX_CAMERAS][2];
+
+ /* Added by Valery */
+ //CvStereoCamera stereoParams;
+
+ int maxPoints;
+ int framesTotal;
+ int framesAccepted;
+ bool isCalibrated;
+};
+
+#include "cvaux.hpp"
+#include "cvvidsurv.hpp"
+/*#include "cvmat.hpp"*/
+#endif
+
+#endif
+
+/* End of file. */
diff --git a/cvaux/include/cvaux.hpp b/cvaux/include/cvaux.hpp
new file mode 100644
index 0000000..37ae897
--- /dev/null
+++ b/cvaux/include/cvaux.hpp
@@ -0,0 +1,144 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __CVAUX_HPP__
+#define __CVAUX_HPP__
+
+#ifdef __cplusplus
+
+/****************************************************************************************\
+* Image class *
+\****************************************************************************************/
+
+class CV_EXPORTS CvCamShiftTracker
+{
+public:
+
+ CvCamShiftTracker();
+ virtual ~CvCamShiftTracker();
+
+ /**** Characteristics of the object that are calculated by track_object method *****/
+ float get_orientation() const // orientation of the object in degrees
+ { return m_box.angle; }
+ float get_length() const // the larger linear size of the object
+ { return m_box.size.height; }
+ float get_width() const // the smaller linear size of the object
+ { return m_box.size.width; }
+ CvPoint2D32f get_center() const // center of the object
+ { return m_box.center; }
+ CvRect get_window() const // bounding rectangle for the object
+ { return m_comp.rect; }
+
+ /*********************** Tracking parameters ************************/
+ int get_threshold() const // thresholding value that applied to back project
+ { return m_threshold; }
+
+ int get_hist_dims( int* dims = 0 ) const // returns number of histogram dimensions and sets
+ { return m_hist ? cvGetDims( m_hist->bins, dims ) : 0; }
+
+ int get_min_ch_val( int channel ) const // get the minimum allowed value of the specified channel
+ { return m_min_ch_val[channel]; }
+
+ int get_max_ch_val( int channel ) const // get the maximum allowed value of the specified channel
+ { return m_max_ch_val[channel]; }
+
+ // set initial object rectangle (must be called before initial calculation of the histogram)
+ bool set_window( CvRect window)
+ { m_comp.rect = window; return true; }
+
+ bool set_threshold( int threshold ) // threshold applied to the histogram bins
+ { m_threshold = threshold; return true; }
+
+ bool set_hist_bin_range( int dim, int min_val, int max_val );
+
+ bool set_hist_dims( int c_dims, int* dims );// set the histogram parameters
+
+ bool set_min_ch_val( int channel, int val ) // set the minimum allowed value of the specified channel
+ { m_min_ch_val[channel] = val; return true; }
+ bool set_max_ch_val( int channel, int val ) // set the maximum allowed value of the specified channel
+ { m_max_ch_val[channel] = val; return true; }
+
+ /************************ The processing methods *********************************/
+ // update object position
+ virtual bool track_object( const IplImage* cur_frame );
+
+ // update object histogram
+ virtual bool update_histogram( const IplImage* cur_frame );
+
+ // reset histogram
+ virtual void reset_histogram();
+
+ /************************ Retrieving internal data *******************************/
+ // get back project image
+ virtual IplImage* get_back_project()
+ { return m_back_project; }
+
+ float query( int* bin ) const
+ { return m_hist ? (float)cvGetRealND(m_hist->bins, bin) : 0.f; }
+
+protected:
+
+ // internal method for color conversion: fills m_color_planes group
+ virtual void color_transform( const IplImage* img );
+
+ CvHistogram* m_hist;
+
+ CvBox2D m_box;
+ CvConnectedComp m_comp;
+
+ float m_hist_ranges_data[CV_MAX_DIM][2];
+ float* m_hist_ranges[CV_MAX_DIM];
+
+ int m_min_ch_val[CV_MAX_DIM];
+ int m_max_ch_val[CV_MAX_DIM];
+ int m_threshold;
+
+ IplImage* m_color_planes[CV_MAX_DIM];
+ IplImage* m_back_project;
+ IplImage* m_temp;
+ IplImage* m_mask;
+};
+
+#endif /* __cplusplus */
+
+#endif /* __CVAUX_HPP__ */
+
+/* End of file. */
diff --git a/cvaux/include/cvmat.hpp b/cvaux/include/cvmat.hpp
new file mode 100644
index 0000000..5defb59
--- /dev/null
+++ b/cvaux/include/cvmat.hpp
@@ -0,0 +1,2326 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _CVMAT_HPP_
+#define _CVMAT_HPP_
+
+#if 0 && (defined __cplusplus && (_MSC_VER>=1200 || defined __BORLANDC__ || defined __GNUC__))
+
+#if _MSC_VER >= 1200
+#pragma warning( disable: 4710 ) /* suppress "function ... is not inlined" */
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#undef min
+#undef max
+
+/****************************************************************************************\
+* C++ - like operations on CvScalar *
+\****************************************************************************************/
+
+inline CvScalar& operator += ( CvScalar& a, const CvScalar& b )
+{
+ double t0 = a.val[0] + b.val[0];
+ double t1 = a.val[1] + b.val[1];
+ a.val[0] = t0;
+ a.val[1] = t1;
+
+ t0 = a.val[2] + b.val[2];
+ t1 = a.val[3] + b.val[3];
+ a.val[2] = t0;
+ a.val[3] = t1;
+
+ return a;
+}
+
+
+inline CvScalar& operator -= ( CvScalar& a, const CvScalar& b )
+{
+ double t0 = a.val[0] - b.val[0];
+ double t1 = a.val[1] - b.val[1];
+ a.val[0] = t0;
+ a.val[1] = t1;
+
+ t0 = a.val[2] - b.val[2];
+ t1 = a.val[3] - b.val[3];
+ a.val[2] = t0;
+ a.val[3] = t1;
+
+ return a;
+}
+
+
+inline CvScalar& operator *= ( CvScalar& a, double b )
+{
+ double t0 = a.val[0] * b;
+ double t1 = a.val[1] * b;
+ a.val[0] = t0;
+ a.val[1] = t1;
+
+ t0 = a.val[2] * b;
+ t1 = a.val[3] * b;
+ a.val[2] = t0;
+ a.val[3] = t1;
+
+ return a;
+}
+
+
+inline CvScalar& operator /= ( CvScalar& a, double b )
+{
+ double inv_b = 1./b;
+ double t0 = a.val[0] * inv_b;
+ double t1 = a.val[1] * inv_b;
+ a.val[0] = t0;
+ a.val[1] = t1;
+
+ t0 = a.val[2] * inv_b;
+ t1 = a.val[3] * inv_b;
+ a.val[2] = t0;
+ a.val[3] = t1;
+
+ return a;
+}
+
+
+inline CvScalar& operator *= ( CvScalar& a, const CvScalar& b )
+{
+ double t0 = a.val[0]*b.val[0] - a.val[1]*b.val[1] -
+ a.val[2]*b.val[2] - a.val[3]*b.val[3];
+
+ double t1 = a.val[0]*b.val[1] + a.val[1]*b.val[0] +
+ a.val[2]*b.val[3] - a.val[3]*b.val[2];
+
+ double t2 = a.val[0]*b.val[2] - a.val[1]*b.val[3] +
+ a.val[2]*b.val[0] + a.val[3]*b.val[1];
+
+ double t3 = a.val[0]*b.val[3] + a.val[1]*b.val[2] -
+ a.val[2]*b.val[1] + a.val[3]*b.val[0];
+
+ a.val[0] = t0;
+ a.val[1] = t1;
+ a.val[2] = t2;
+ a.val[3] = t3;
+
+ return a;
+}
+
+
+inline CvScalar& operator /= ( CvScalar& a, const CvScalar& b )
+{
+ double inv_d = -1./(b.val[0]*b.val[0] + b.val[1]*b.val[1] +
+ b.val[2]*b.val[2] + b.val[3]*b.val[3]);
+ return a *= cvScalar( b.val[0] * -inv_d, b.val[1] * inv_d,
+ b.val[2] * inv_d, b.val[3] * inv_d );
+}
+
+
+inline CvScalar& operator += ( CvScalar& a, double b )
+{
+ a.val[0] += b;
+ return a;
+}
+
+
+inline CvScalar& operator -= ( CvScalar& a, double b )
+{
+ a.val[0] -= b;
+ return a;
+}
+
+
+inline CvScalar operator + ( const CvScalar& a, const CvScalar& b )
+{
+ return cvScalar( a.val[0] + b.val[0], a.val[1] + b.val[1],
+ a.val[2] + b.val[2], a.val[3] + b.val[3] );
+}
+
+
+inline CvScalar operator - ( const CvScalar& a, const CvScalar& b )
+{
+ return cvScalar( a.val[0] - b.val[0], a.val[1] - b.val[1],
+ a.val[2] - b.val[2], a.val[3] - b.val[3] );
+}
+
+
+inline CvScalar operator + ( const CvScalar& a, double b )
+{
+ return cvScalar( a.val[0] + b, a.val[1], a.val[2], a.val[3] );
+}
+
+
+inline CvScalar operator - ( const CvScalar& a, double b )
+{
+ return cvScalar( a.val[0] - b, a.val[1], a.val[2], a.val[3] );
+}
+
+
+inline CvScalar operator + ( double a, const CvScalar& b )
+{
+ return cvScalar( a + b.val[0], b.val[1], b.val[2], b.val[3] );
+}
+
+
+inline CvScalar operator - ( double a, const CvScalar& b )
+{
+ return cvScalar( a - b.val[0], -b.val[1], -b.val[2], -b.val[3] );
+}
+
+
+inline CvScalar operator - ( const CvScalar& b )
+{
+ return cvScalar( -b.val[0], -b.val[1], -b.val[2], -b.val[3] );
+}
+
+
+inline CvScalar operator * ( const CvScalar& a, const CvScalar& b )
+{
+ CvScalar c = a;
+
+ return (c *= b);
+}
+
+
+inline CvScalar operator * ( const CvScalar& a, double b )
+{
+ return cvScalar( a.val[0]*b, a.val[1]*b, a.val[2]*b, a.val[3]*b );
+}
+
+
+inline CvScalar operator * ( double a, const CvScalar& b )
+{
+ return cvScalar( b.val[0]*a, b.val[1]*a, b.val[2]*a, b.val[3]*a );
+}
+
+
+inline CvScalar operator / ( const CvScalar& a, const CvScalar& b )
+{
+ CvScalar c = a;
+ return (c /= b);
+}
+
+
+inline CvScalar operator / ( const CvScalar& a, double b )
+{
+ double inv_b = 1./b;
+ return cvScalar( a.val[0]*inv_b, a.val[1]*inv_b,
+ a.val[2]*inv_b, a.val[3]*inv_b );
+}
+
+
+inline CvScalar operator / ( double a, const CvScalar& b )
+{
+ double inv_d = -a/(b.val[0]*b.val[0] + b.val[1]*b.val[1] +
+ b.val[2]*b.val[2] + b.val[3]*b.val[3]);
+ return cvScalar( b.val[0] * -inv_d, b.val[1] * inv_d,
+ b.val[2] * inv_d, b.val[3] * inv_d );
+}
+
+
+inline CvScalar& operator &= ( CvScalar& a, const CvScalar& b )
+{
+ int t0 = cvRound(a.val[0]) & cvRound(b.val[0]);
+ int t1 = cvRound(a.val[1]) & cvRound(b.val[1]);
+ a.val[0] = t0;
+ a.val[1] = t1;
+
+ t0 = cvRound(a.val[2]) & cvRound(b.val[2]);
+ t1 = cvRound(a.val[3]) & cvRound(b.val[3]);
+ a.val[2] = t0;
+ a.val[3] = t1;
+
+ return a;
+}
+
+
+inline CvScalar& operator |= ( CvScalar& a, const CvScalar& b )
+{
+ int t0 = cvRound(a.val[0]) | cvRound(b.val[0]);
+ int t1 = cvRound(a.val[1]) | cvRound(b.val[1]);
+ a.val[0] = t0;
+ a.val[1] = t1;
+
+ t0 = cvRound(a.val[2]) | cvRound(b.val[2]);
+ t1 = cvRound(a.val[3]) | cvRound(b.val[3]);
+ a.val[2] = t0;
+ a.val[3] = t1;
+
+ return a;
+}
+
+
+inline CvScalar& operator ^= ( CvScalar& a, const CvScalar& b )
+{
+ int t0 = cvRound(a.val[0]) ^ cvRound(b.val[0]);
+ int t1 = cvRound(a.val[1]) ^ cvRound(b.val[1]);
+ a.val[0] = t0;
+ a.val[1] = t1;
+
+ t0 = cvRound(a.val[2]) ^ cvRound(b.val[2]);
+ t1 = cvRound(a.val[3]) ^ cvRound(b.val[3]);
+ a.val[2] = t0;
+ a.val[3] = t1;
+
+ return a;
+}
+
+
+inline CvScalar operator & ( const CvScalar& a, const CvScalar& b )
+{
+ CvScalar c = a;
+ return (c &= b);
+}
+
+
+inline CvScalar operator | ( const CvScalar& a, const CvScalar& b )
+{
+ CvScalar c = a;
+ return (c |= b);
+}
+
+
+inline CvScalar operator ^ ( const CvScalar& a, const CvScalar& b )
+{
+ CvScalar c = a;
+ return (c ^= b);
+}
+
+
+inline CvScalar operator ~ ( const CvScalar& a )
+{
+ return cvScalar( ~cvRound(a.val[0]), ~cvRound(a.val[1]),
+ ~cvRound(a.val[2]), ~cvRound(a.val[3]));
+}
+
+
+/****************************************************************************************\
+* C++ Matrix Class *
+\****************************************************************************************/
+
+struct _CvMATConstElem_;
+struct _CvMATElem_;
+struct _CvMATElemCn_;
+
+struct _CvMAT_T_;
+struct _CvMAT_MUL_;
+struct _CvMAT_INV_;
+struct _CvMAT_SCALE_;
+struct _CvMAT_SCALE_SHIFT_;
+struct _CvMAT_ADD_;
+struct _CvMAT_ADD_EX_;
+struct _CvMAT_MUL_ADD_;
+struct _CvMAT_LOGIC_;
+struct _CvMAT_UN_LOGIC_;
+struct _CvMAT_NOT_;
+struct _CvMAT_CVT_;
+struct _CvMAT_COPY_;
+struct _CvMAT_DOT_OP_;
+struct _CvMAT_SOLVE_;
+struct _CvMAT_CMP_;
+
+class CV_EXPORTS CvMAT : public CvMat
+{
+protected:
+
+public:
+ /* helper methods for retrieving/setting matrix elements */
+ static double get( const uchar* ptr, int type, int coi = 0 );
+ static void set( uchar* ptr, int type, int coi, double d );
+ static void set( uchar* ptr, int type, int coi, int i );
+ static void set( uchar* ptr, int type, double d );
+ static void set( uchar* ptr, int type, int i );
+
+ /******************* constructors ********************/
+ /* empty */
+ explicit CvMAT();
+
+ /* creation */
+ explicit CvMAT( int rows, int cols, int type, void* data, int step = CV_AUTOSTEP );
+ explicit CvMAT( int rows, int type, void* data, int step = CV_AUTOSTEP );
+ explicit CvMAT( int rows, int cols, int type );
+ explicit CvMAT( int rows, int type );
+
+ /* extracting part of an existing matrix */
+ explicit CvMAT( const CvMat& mat, CvRect rect ); /* submatrix */
+ explicit CvMAT( const CvMat& mat, int k, int i ); /* submatrix:
+ k == 0 - i-th row
+ k > 0 - i-th column
+ k < 0 - i-th diagonal */
+ /* copying */
+ CvMAT( const CvMat& mat );
+ CvMAT( const CvMAT& mat );
+ CvMAT( const IplImage& img );
+
+ /* CvMAT b = op(a1,a2,...) */
+ explicit CvMAT( const _CvMAT_T_& mat_t );
+ explicit CvMAT( const _CvMAT_INV_& inv_mat );
+ explicit CvMAT( const _CvMAT_ADD_& mat_add );
+ explicit CvMAT( const _CvMAT_ADD_EX_& mat_add );
+ explicit CvMAT( const _CvMAT_SCALE_& scale_mat );
+ explicit CvMAT( const _CvMAT_SCALE_SHIFT_& scale_shift_mat );
+ explicit CvMAT( const _CvMAT_MUL_& mmul );
+ explicit CvMAT( const _CvMAT_MUL_ADD_& mmuladd );
+ explicit CvMAT( const _CvMAT_LOGIC_& mat_logic );
+ explicit CvMAT( const _CvMAT_UN_LOGIC_& mat_logic );
+ explicit CvMAT( const _CvMAT_NOT_& not_mat );
+ explicit CvMAT( const _CvMAT_COPY_& mat_copy );
+ explicit CvMAT( const _CvMAT_CVT_& mat_copy );
+ explicit CvMAT( const _CvMAT_DOT_OP_& dot_mul );
+ explicit CvMAT( const _CvMAT_SOLVE_& solve_mat );
+ explicit CvMAT( const _CvMAT_CMP_& cmp_mat );
+
+ /* desctructor */
+ ~CvMAT();
+
+ /* copying and filling with a constant */
+ CvMAT& operator = ( const CvMAT& mat );
+ CvMAT& operator = ( const CvMat& mat );
+ CvMAT& operator = ( const IplImage& img );
+ CvMAT& operator = ( double fillval );
+ CvMAT& operator = ( const CvScalar& fillval );
+
+ /* b = op(a1, a2,...) */
+ CvMAT& operator = ( const _CvMAT_T_& mat_t );
+ CvMAT& operator = ( const _CvMAT_INV_& inv_mat );
+ CvMAT& operator = ( const _CvMAT_ADD_& mat_add );
+ CvMAT& operator = ( const _CvMAT_ADD_EX_& mat_add );
+ CvMAT& operator = ( const _CvMAT_SCALE_& scale_mat );
+ CvMAT& operator = ( const _CvMAT_SCALE_SHIFT_& scale_shift_mat );
+ CvMAT& operator = ( const _CvMAT_MUL_& mmul );
+ CvMAT& operator = ( const _CvMAT_MUL_ADD_& mmuladd );
+ CvMAT& operator = ( const _CvMAT_LOGIC_& mat_logic );
+ CvMAT& operator = ( const _CvMAT_UN_LOGIC_& mat_logic );
+ CvMAT& operator = ( const _CvMAT_NOT_& not_mat );
+ CvMAT& operator = ( const _CvMAT_DOT_OP_& dot_mul );
+ CvMAT& operator = ( const _CvMAT_SOLVE_& solve_mat );
+ CvMAT& operator = ( const _CvMAT_CMP_& cmp_mat );
+ CvMAT& operator = ( const _CvMAT_CVT_& mat_cvt );
+
+ /* copy matrix data, not only matrix header */
+ CvMAT& operator = ( const _CvMAT_COPY_& mat_copy );
+
+ /* augmented assignments */
+ CvMAT& operator += ( const CvMat& mat );
+ CvMAT& operator += ( double val );
+ CvMAT& operator += ( const CvScalar& val );
+ CvMAT& operator += ( const _CvMAT_SCALE_& scale_mat );
+ CvMAT& operator += ( const _CvMAT_SCALE_SHIFT_& scale_mat );
+ CvMAT& operator += ( const _CvMAT_MUL_& mmul );
+
+ CvMAT& operator -= ( const CvMat& mat );
+ CvMAT& operator -= ( double val );
+ CvMAT& operator -= ( const CvScalar& val );
+ CvMAT& operator -= ( const _CvMAT_SCALE_& scale_mat );
+ CvMAT& operator -= ( const _CvMAT_SCALE_SHIFT_& scale_mat );
+ CvMAT& operator -= ( const _CvMAT_MUL_& mmul );
+
+ CvMAT& operator *= ( const CvMat& mat );
+ CvMAT& operator *= ( double val );
+ CvMAT& operator *= ( const CvScalar& val );
+ CvMAT& operator *= ( const _CvMAT_SCALE_& scale_mat );
+ CvMAT& operator *= ( const _CvMAT_SCALE_SHIFT_& scale_mat );
+
+ CvMAT& operator &= ( const CvMat& mat );
+ CvMAT& operator &= ( double val );
+ CvMAT& operator &= ( const CvScalar& val );
+
+ CvMAT& operator |= ( const CvMat& mat );
+ CvMAT& operator |= ( double val );
+ CvMAT& operator |= ( const CvScalar& val );
+
+ CvMAT& operator ^= ( const CvMat& mat );
+ CvMAT& operator ^= ( double val );
+ CvMAT& operator ^= ( const CvScalar& val );
+
+ /* various scalar charactertics */
+ double norm( int norm_type = CV_L2 ) const;
+ double norm( CvMat& mat, int norm_type = CV_L2 ) const;
+ CvScalar sum() const;
+
+ double det() const;
+ double trace() const;
+
+ _CvMAT_T_ t() const; /* transposition */
+ _CvMAT_INV_ inv(int method = 0) const;
+ /* inversion using one of the following methods:
+ method = 0 - Gaussian elimination,
+ method = 1 - SVD */
+
+ _CvMAT_DOT_OP_ mul( const CvMAT& mat ) const;
+ _CvMAT_DOT_OP_ mul( const _CvMAT_SCALE_& mat ) const;
+
+ _CvMAT_DOT_OP_ div( const CvMAT& mat ) const;
+ _CvMAT_DOT_OP_ div( const _CvMAT_SCALE_& mat ) const;
+
+ _CvMAT_DOT_OP_ min( const CvMAT& mat ) const;
+ _CvMAT_DOT_OP_ max( const CvMAT& mat ) const;
+ _CvMAT_DOT_OP_ min( double value ) const;
+ _CvMAT_DOT_OP_ max( double value ) const;
+ double min( CvPoint* minloc = 0 ) const;
+ double max( CvPoint* maxloc = 0 ) const;
+
+ _CvMAT_DOT_OP_ abs() const;
+
+ /* accessing matrix elements */
+ _CvMATElem_ operator ()( int row );
+ _CvMATConstElem_ operator ()( int row ) const;
+
+ _CvMATElem_ operator ()( int row, int col );
+ _CvMATConstElem_ operator ()( int row, int col ) const;
+
+ _CvMATElem_ operator ()( CvPoint loc );
+ _CvMATConstElem_ operator ()( CvPoint loc ) const;
+
+ _CvMATElemCn_ operator()( int row, int col, int coi );
+ double operator()( int row, int col, int coi ) const;
+
+ _CvMATElemCn_ operator()( CvPoint pt, int coi );
+ double operator()( CvPoint pt, int coi ) const;
+
+ void* ptr( int row );
+ const void* ptr( int row ) const;
+
+ void* ptr( int row, int col );
+ const void* ptr( int row, int col ) const;
+
+ void* ptr( CvPoint pt );
+ const void* ptr( CvPoint pt ) const;
+
+ /* accessing matrix parts */
+ CvMAT row( int row ) const;
+ CvMAT rowrange( int row1, int row2 ) const;
+ CvMAT col( int col ) const;
+ CvMAT colrange( int col1, int col2 ) const;
+ CvMAT rect( CvRect rect ) const;
+ CvMAT diag( int diag = 0 ) const;
+
+ _CvMAT_COPY_ clone() const;
+
+ /* convert matrix */
+ _CvMAT_CVT_ cvt( int newdepth = -1, double scale = 1,
+ double shift = 0 ) const;
+
+ /* matrix transformation */
+ void reshape( int newcn, int newrows = 0 );
+ void flipX();
+ void flipY();
+ void flipXY();
+
+ /* matrix I/O: use dynamically linked runtime libraries */
+ void write( const char* name = 0, FILE* f = 0, const char* fmt = 0 );
+ void read( char** name = 0, FILE* f = 0 );
+
+ /* decrease matrix data reference counter and clear data pointer */
+ void release();
+protected:
+
+ void create( int rows, int cols, int type );
+};
+
+
+/* !!! Internal Use Only !!! */
+/* proxies for matrix elements */
+
+/* const_A(i,j) */
+struct CV_EXPORTS _CvMATConstElem_
+{
+ explicit _CvMATConstElem_( const uchar* ptr, int type );
+ operator CvScalar () const;
+ double operator ()( int coi = 0 ) const;
+
+ uchar* ptr;
+ int type;
+};
+
+
+/* A(i,j,cn) or A(i,j)(cn) */
+struct CV_EXPORTS _CvMATElemCn_
+{
+ explicit _CvMATElemCn_( uchar* ptr, int type, int coi );
+ operator double() const;
+
+ _CvMATElemCn_& operator = ( const _CvMATConstElem_& elem );
+ _CvMATElemCn_& operator = ( const _CvMATElemCn_& elem );
+ _CvMATElemCn_& operator = ( const CvScalar& scalar );
+ _CvMATElemCn_& operator = ( double d );
+ _CvMATElemCn_& operator = ( float f );
+ _CvMATElemCn_& operator = ( int i );
+
+ uchar* ptr;
+ int type;
+};
+
+
+/* A(i,j) */
+struct CV_EXPORTS _CvMATElem_ : public _CvMATConstElem_
+{
+ explicit _CvMATElem_( uchar* ptr, int type );
+ _CvMATElemCn_ operator ()( int coi = 0 );
+
+ _CvMATElem_& operator = ( const _CvMATConstElem_& elem );
+ _CvMATElem_& operator = ( const _CvMATElem_& elem );
+ _CvMATElem_& operator = ( const _CvMATElemCn_& elem );
+ _CvMATElem_& operator = ( const CvScalar& val );
+ _CvMATElem_& operator = ( double d );
+ _CvMATElem_& operator = ( float f );
+ _CvMATElem_& operator = ( int i );
+};
+
+
+struct CV_EXPORTS _CvMAT_BASE_OP_
+{
+ _CvMAT_BASE_OP_() {};
+ virtual operator CvMAT() const = 0;
+
+ _CvMAT_DOT_OP_ mul( const CvMAT& a ) const;
+ _CvMAT_DOT_OP_ mul( const _CvMAT_SCALE_& a ) const;
+
+ _CvMAT_DOT_OP_ div( const CvMAT& a ) const;
+ _CvMAT_DOT_OP_ div( const _CvMAT_SCALE_& a ) const;
+
+ _CvMAT_DOT_OP_ max( const CvMAT& a ) const;
+ _CvMAT_DOT_OP_ min( const CvMAT& a ) const;
+
+ _CvMAT_DOT_OP_ max( double value ) const;
+ _CvMAT_DOT_OP_ min( double value ) const;
+
+ double max( CvPoint* maxloc = 0 ) const;
+ double min( CvPoint* minloc = 0 ) const;
+
+ _CvMAT_DOT_OP_ abs() const;
+
+ _CvMAT_INV_ inv( int method = 0 ) const;
+ _CvMAT_T_ t() const;
+
+ CvMAT row( int row ) const;
+ CvMAT rowrange( int row1, int row2 ) const;
+ CvMAT col( int col ) const;
+ CvMAT colrange( int col1, int col2 ) const;
+ CvMAT rect( CvRect rect ) const;
+ CvMAT diag( int diag = 0 ) const;
+ _CvMAT_CVT_ cvt( int newdepth = -1, double scale = 1, double shift = 0 ) const;
+
+ double norm( int norm_type = CV_L2 ) const;
+ double det() const;
+ double trace() const;
+ CvScalar sum() const;
+};
+
+
+/* (A^t)*alpha */
+struct CV_EXPORTS _CvMAT_T_ : public _CvMAT_BASE_OP_
+{
+ explicit _CvMAT_T_( const CvMAT* a );
+ explicit _CvMAT_T_( const CvMAT* a, double alpha );
+
+ double det() const;
+ double norm( int normType = CV_L2 ) const;
+ operator CvMAT() const;
+
+ CvMAT a;
+ double alpha;
+};
+
+
+/* inv(A) */
+struct CV_EXPORTS _CvMAT_INV_ : public _CvMAT_BASE_OP_
+{
+ explicit _CvMAT_INV_( const CvMAT* mat, int method );
+ operator CvMAT() const;
+
+ CvMAT a;
+ int method;
+};
+
+
+/* (A^ta)*(B^tb)*alpha */
+struct CV_EXPORTS _CvMAT_MUL_ : public _CvMAT_BASE_OP_
+{
+ explicit _CvMAT_MUL_( const CvMAT* a, const CvMAT* b, int t_ab );
+ explicit _CvMAT_MUL_( const CvMAT* a, const CvMAT* b,
+ double alpha, int t_abc );
+ operator CvMAT() const;
+
+ double alpha;
+ CvMAT* a;
+ CvMAT* b;
+ int t_ab; /* (t_ab & 1) = ta, (t_ab & 2) = tb */
+};
+
+
+/* (A^ta)*(B^tb)*alpha + (C^tc)*beta */
+struct CV_EXPORTS _CvMAT_MUL_ADD_ : public _CvMAT_BASE_OP_
+{
+ explicit _CvMAT_MUL_ADD_( const CvMAT* a, const CvMAT* b,
+ const CvMAT* c, int t_abc );
+ explicit _CvMAT_MUL_ADD_( const CvMAT* a, const CvMAT* b, double alpha,
+ const CvMAT* c, double beta, int t_abc );
+ operator CvMAT() const;
+
+ double alpha, beta;
+ CvMAT* a;
+ CvMAT* b;
+ CvMAT* c;
+ int t_abc; /* (t_abc & 1) = ta, (t_abc & 2) = tb, (t_abc & 4) = tc */
+};
+
+
+/* A + B*beta */
+struct CV_EXPORTS _CvMAT_ADD_ : public _CvMAT_BASE_OP_
+{
+ explicit _CvMAT_ADD_( const CvMAT* a, const CvMAT* b, double beta = 1 );
+ operator CvMAT() const;
+
+ double norm( int norm_type = CV_L2 ) const;
+ _CvMAT_DOT_OP_ abs() const;
+
+ double beta;
+ CvMAT* a;
+ CvMAT* b;
+};
+
+
+/* A*alpha + B*beta + gamma */
+struct CV_EXPORTS _CvMAT_ADD_EX_ : public _CvMAT_BASE_OP_
+{
+ explicit _CvMAT_ADD_EX_( const CvMAT* a, double alpha,
+ const CvMAT* b, double beta, double gamma = 0 );
+ operator CvMAT() const;
+
+ double alpha, beta, gamma;
+ CvMAT* a;
+ CvMAT* b;
+};
+
+
+/* A*alpha */
+struct CV_EXPORTS _CvMAT_SCALE_ : public _CvMAT_BASE_OP_
+{
+ explicit _CvMAT_SCALE_( const CvMAT* a, double alpha );
+ operator CvMAT() const;
+
+ _CvMAT_DOT_OP_ mul( const CvMAT& a ) const;
+ _CvMAT_DOT_OP_ mul( const _CvMAT_SCALE_& a ) const;
+
+ _CvMAT_DOT_OP_ div( const CvMAT& a ) const;
+ _CvMAT_DOT_OP_ div( const _CvMAT_SCALE_& a ) const;
+
+ double alpha;
+ CvMAT* a;
+};
+
+
+/* A*alpha + beta */
+struct CV_EXPORTS _CvMAT_SCALE_SHIFT_ : public _CvMAT_BASE_OP_
+{
+ explicit _CvMAT_SCALE_SHIFT_( const CvMAT* a, double alpha, double beta );
+ operator CvMAT() const;
+
+ _CvMAT_DOT_OP_ abs() const;
+
+ double alpha, beta;
+ CvMAT* a;
+};
+
+
+/* (A & B), (A | B) or (A ^ B) */
+struct CV_EXPORTS _CvMAT_LOGIC_ : public _CvMAT_BASE_OP_
+{
+ enum Op { AND = 0, OR = 1, XOR = 2 };
+ explicit _CvMAT_LOGIC_( const CvMAT* a, const CvMAT* b, Op op, int flags = 0 );
+ operator CvMAT() const;
+
+ CvMAT* a;
+ CvMAT* b;
+ Op op;
+ int flags;
+};
+
+
+/* (A & scalar), (A | scalar) or (A ^ scalar) */
+struct CV_EXPORTS _CvMAT_UN_LOGIC_ : public _CvMAT_BASE_OP_
+{
+ explicit _CvMAT_UN_LOGIC_( const CvMAT* a, double alpha,
+ _CvMAT_LOGIC_::Op op, int flags = 0 );
+ operator CvMAT() const;
+
+ CvMAT* a;
+ double alpha;
+ _CvMAT_LOGIC_::Op op;
+ int flags;
+};
+
+
+/* ~A */
+struct CV_EXPORTS _CvMAT_NOT_ : public _CvMAT_BASE_OP_
+{
+ explicit _CvMAT_NOT_( const CvMAT* a );
+ operator CvMAT() const;
+
+ CvMAT* a;
+};
+
+
+/* conversion of data type */
+struct CV_EXPORTS _CvMAT_CVT_ : public _CvMAT_BASE_OP_
+{
+ explicit _CvMAT_CVT_( const CvMAT* a, int newdepth = -1,
+ double scale = 1, double shift = 0 );
+ operator CvMAT() const;
+
+ CvMAT a;
+ int newdepth;
+ double scale, shift;
+};
+
+
+/* conversion of data type */
+struct CV_EXPORTS _CvMAT_COPY_
+{
+ explicit _CvMAT_COPY_( const CvMAT* a );
+ operator CvMAT() const;
+ CvMAT* a;
+};
+
+
+/* a.op(b), where op = mul, div, min, max ... */
+struct CV_EXPORTS _CvMAT_DOT_OP_ : public _CvMAT_BASE_OP_
+{
+ explicit _CvMAT_DOT_OP_( const CvMAT* a, const CvMAT* b,
+ int op, double alpha = 1 );
+ operator CvMAT() const;
+
+ CvMAT a; /* keep the left operand copy */
+ CvMAT* b;
+ double alpha;
+ int op;
+};
+
+
+/* A.inv()*B or A.pinv()*B */
+struct CV_EXPORTS _CvMAT_SOLVE_ : public _CvMAT_BASE_OP_
+{
+ explicit _CvMAT_SOLVE_( const CvMAT* a, const CvMAT* b, int method );
+ operator CvMAT() const;
+
+ CvMAT* a;
+ CvMAT* b;
+ int method;
+};
+
+
+/* A <=> B */
+struct CV_EXPORTS _CvMAT_CMP_ : public _CvMAT_BASE_OP_
+{
+ explicit _CvMAT_CMP_( const CvMAT* a, const CvMAT* b, int cmp_op );
+ explicit _CvMAT_CMP_( const CvMAT* a, double alpha, int cmp_op );
+ operator CvMAT() const;
+
+ CvMAT* a;
+ CvMAT* b;
+ double alpha;
+ int cmp_op;
+};
+
+
+/************************* _CvMATConstElem_ inline methods ******************************/
+
+inline _CvMATConstElem_::_CvMATConstElem_(const uchar* p, int t) : ptr((uchar*)p), type(t)
+{}
+
+
+inline _CvMATConstElem_::operator CvScalar() const
+{
+ CvScalar scalar;
+ cvRawDataToScalar( ptr, type, &scalar );
+
+ return scalar;
+}
+
+
+inline double _CvMATConstElem_::operator ()( int coi ) const
+{ return CvMAT::get( ptr, type, coi ); }
+
+
+inline _CvMATElemCn_::_CvMATElemCn_( uchar* p, int t, int coi ) :
+ ptr(p), type(CV_MAT_DEPTH(t))
+{
+ if( coi )
+ {
+ assert( (unsigned)coi < (unsigned)CV_MAT_CN(t) );
+ ptr += coi * CV_ELEM_SIZE(type);
+ }
+}
+
+
+inline _CvMATElemCn_::operator double() const
+{ return CvMAT::get( ptr, type ); }
+
+
+inline _CvMATElemCn_& _CvMATElemCn_::operator = ( const _CvMATConstElem_& elem )
+{
+ if( type == elem.type )
+ memcpy( ptr, elem.ptr, CV_ELEM_SIZE(type) );
+ else
+ {
+ assert( CV_MAT_CN(elem.type) == 1 );
+ CvMAT::set( ptr, type, 0, elem(0));
+ }
+
+ return *this;
+}
+
+
+inline _CvMATElemCn_& _CvMATElemCn_::operator = ( const _CvMATElemCn_& elem )
+{
+ if( type == elem.type )
+ memcpy( ptr, elem.ptr, CV_ELEM_SIZE(type) );
+ else
+ CvMAT::set( ptr, type, 0, (double)elem );
+ return *this;
+}
+
+
+inline _CvMATElemCn_& _CvMATElemCn_::operator = ( const CvScalar& scalar )
+{
+ CvMAT::set( ptr, type, 0, scalar.val[0] );
+ return *this;
+}
+
+
+inline _CvMATElemCn_& _CvMATElemCn_::operator = ( double d )
+{
+ CvMAT::set( ptr, type, 0, d );
+ return *this;
+}
+
+
+inline _CvMATElemCn_& _CvMATElemCn_::operator = ( float f )
+{
+ CvMAT::set( ptr, type, 0, (double)f );
+ return *this;
+}
+
+
+inline _CvMATElemCn_& _CvMATElemCn_::operator = ( int i )
+{
+ CvMAT::set( ptr, type, 0, i );
+ return *this;
+}
+
+
+inline _CvMATElem_::_CvMATElem_( uchar* p, int t ) : _CvMATConstElem_( (const uchar*)p, t )
+{}
+
+
+inline _CvMATElemCn_ _CvMATElem_::operator ()( int coi )
+{ return _CvMATElemCn_( ptr, type, coi ); }
+
+
+inline _CvMATElem_& _CvMATElem_::operator = ( const _CvMATConstElem_& elem )
+{
+ if( type == elem.type )
+ memcpy( ptr, elem.ptr, CV_ELEM_SIZE(type) );
+ else
+ {
+ assert( CV_MAT_CN( type ^ elem.type ) == 0 );
+ CvScalar sc = (CvScalar)elem;
+ cvScalarToRawData( &sc, ptr, type, 0 );
+ }
+
+ return *this;
+}
+
+
+inline _CvMATElem_& _CvMATElem_::operator = ( const _CvMATElem_& elem )
+{
+ *this = (const _CvMATConstElem_&)elem;
+ return *this;
+}
+
+
+inline _CvMATElem_& _CvMATElem_::operator = ( const _CvMATElemCn_& elem )
+{
+ if( type == elem.type )
+ memcpy( ptr, elem.ptr, CV_ELEM_SIZE(type) );
+ else
+ CvMAT::set( ptr, type, (double)elem );
+
+ return *this;
+}
+
+
+inline _CvMATElem_& _CvMATElem_::operator = ( const CvScalar& scalar )
+{
+ cvScalarToRawData( &scalar, ptr, type, 0 );
+ return *this;
+}
+
+
+inline _CvMATElem_& _CvMATElem_::operator = ( double d )
+{
+ CvMAT::set( ptr, type, d );
+ return *this;
+}
+
+
+inline _CvMATElem_& _CvMATElem_::operator = ( float f )
+{
+ CvMAT::set( ptr, type, (double)f );
+ return *this;
+}
+
+
+inline _CvMATElem_& _CvMATElem_::operator = ( int i )
+{
+ CvMAT::set( ptr, type, i );
+ return *this;
+}
+
+
+/********************************** CvMAT inline methods ********************************/
+
+inline CvMAT::CvMAT()
+{
+ memset( this, 0, sizeof(*this));
+}
+
+
+inline CvMAT::CvMAT( int rows, int cols, int type, void* data, int step )
+{
+ cvInitMatHeader( this, rows, cols, type, data, step );
+}
+
+
+inline CvMAT::CvMAT( int rows, int type, void* data, int step )
+{
+ cvInitMatHeader( this, rows, 1, type, data, step );
+}
+
+
+inline void CvMAT::create( int rows, int cols, int type )
+{
+ int step = cols*CV_ELEM_SIZE(type), total_size = step*rows;
+ this->rows = rows;
+ this->cols = cols;
+ this->step = rows == 1 ? 0 : step;
+ this->type = CV_MAT_MAGIC_VAL | (type & CV_MAT_TYPE_MASK) | CV_MAT_CONT_FLAG;
+ refcount = (int*)cvAlloc((size_t)total_size + 8);
+ data.ptr = (uchar*)(((size_t)(refcount + 1) + 7) & -8);
+ *refcount = 1;
+}
+
+
+inline CvMAT::CvMAT( int rows, int cols, int type )
+{
+ create( rows, cols, type );
+}
+
+
+inline CvMAT::CvMAT( int rows, int type )
+{
+ create( rows, 1, type );
+}
+
+
+inline CvMAT::CvMAT( const CvMat& mat )
+{
+ memcpy( this, &mat, sizeof(mat));
+ if( refcount )
+ (*refcount)++;
+}
+
+
+inline CvMAT::CvMAT( const CvMAT& mat )
+{
+ memcpy( this, &mat, sizeof(mat));
+ if( refcount )
+ (*refcount)++;
+}
+
+
+inline CvMAT::CvMAT( const IplImage& img )
+{
+ cvGetMat( &img, this );
+}
+
+
+inline void CvMAT::release()
+{
+ data.ptr = NULL;
+ if( refcount != NULL && --*refcount == 0 )
+ cvFree( (void**)&refcount );
+ refcount = 0;
+}
+
+
+inline CvMAT::~CvMAT()
+{
+ release();
+}
+
+
+inline CvMAT& CvMAT::operator = ( const CvMAT& mat )
+{
+ if( this != &mat )
+ {
+ release();
+ memcpy( this, &mat, sizeof(mat));
+ if( refcount )
+ (*refcount)++;
+ }
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator = ( const CvMat& mat )
+{
+ *this = (const CvMAT&)mat;
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator = ( const IplImage& img )
+{
+ release();
+ cvGetMat( &img, this );
+
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator = ( double fillval )
+{
+ cvFillImage( this, fillval );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator = ( const CvScalar& fillval )
+{
+ cvSet( this, fillval );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator += ( const CvMat& mat )
+{
+ cvAdd( this, &mat, this );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator += ( double val )
+{
+ cvAddS( this, cvScalar(val), this );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator += ( const CvScalar& val )
+{
+ cvAddS( this, val, this );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator -= ( const CvMat& mat )
+{
+ cvSub( this, &mat, this );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator -= ( double val )
+{
+ cvSubS( this, cvScalar(val), this );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator -= ( const CvScalar& val )
+{
+ cvSubS( this, val, this );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator *= ( const CvMat& mat )
+{
+ cvMul( this, &mat, this );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator *= ( double val )
+{
+ cvScale( this, this, val, 0 );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator *= ( const CvScalar& val )
+{
+ cvScaleAdd( this, val, 0, this );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator &= ( const CvMat& mat )
+{
+ cvAnd( this, &mat, this );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator &= ( double val )
+{
+ cvAndS( this, cvScalarAll(val), this );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator &= ( const CvScalar& val )
+{
+ cvAndS( this, val, this );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator |= ( const CvMat& mat )
+{
+ cvOr( this, &mat, this );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator |= ( double val )
+{
+ cvOrS( this, cvScalarAll(val), this );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator |= ( const CvScalar& val )
+{
+ cvOrS( this, val, this );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator ^= ( const CvMat& mat )
+{
+ cvXor( this, &mat, this );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator ^= ( double val )
+{
+ cvXorS( this, cvScalarAll(val), this );
+ return *this;
+}
+
+
+inline CvMAT& CvMAT::operator ^= ( const CvScalar& val )
+{
+ cvXorS( this, val, this );
+ return *this;
+}
+
+
+inline double CvMAT::norm( int normType ) const
+{ return cvNorm( this, 0, normType ); }
+
+
+inline double CvMAT::min( CvPoint* minloc ) const
+{
+ double t;
+ cvMinMaxLoc( this, &t, 0, minloc, 0, 0 );
+ return t;
+}
+
+inline double CvMAT::max( CvPoint* maxloc ) const
+{
+ double t;
+ cvMinMaxLoc( this, 0, &t, 0, maxloc, 0 );
+ return t;
+}
+
+
+inline double CvMAT::norm( CvMat& mat, int normType ) const
+{ return cvNorm( this, &mat, normType ); }
+
+
+inline CvScalar CvMAT::sum() const
+{ return cvSum( this ); }
+
+
+inline double CvMAT::det() const
+{ return cvDet( this ); }
+
+
+inline void CvMAT::reshape( int newcn, int newrows )
+{ cvReshape( this, this, newcn, newrows ); }
+
+
+inline void CvMAT::flipX()
+{ cvFlip( this, this, 1 ); }
+
+
+inline void CvMAT::flipY()
+{ cvFlip( this, this, 0 ); }
+
+
+inline void CvMAT::flipXY()
+{ cvFlip( this, this, -1 ); }
+
+
+inline _CvMATElem_ CvMAT::operator ()( int row )
+{ return _CvMATElem_( CV_MAT_ELEM_PTR( *this, row, 0 ), type ); }
+
+
+inline _CvMATConstElem_ CvMAT::operator ()( int row ) const
+{ return _CvMATConstElem_( CV_MAT_ELEM_PTR( *this, row, 0 ), type ); }
+
+
+inline _CvMATElem_ CvMAT::operator ()( int row, int col )
+{ return _CvMATElem_( CV_MAT_ELEM_PTR( *this, row, col ), type ); }
+
+
+inline _CvMATConstElem_ CvMAT::operator ()( int row, int col ) const
+{ return _CvMATConstElem_( CV_MAT_ELEM_PTR( *this, row, col ), type ); }
+
+
+inline _CvMATElemCn_ CvMAT::operator()( int row, int col, int coi )
+{ return _CvMATElemCn_( CV_MAT_ELEM_PTR( *this, row, col ), type, coi ); }
+
+
+inline _CvMATElemCn_ CvMAT::operator()( CvPoint pt, int coi )
+{ return _CvMATElemCn_( CV_MAT_ELEM_PTR( *this, pt.y, pt.x ), type, coi ); }
+
+
+inline double CvMAT::operator()( int row, int col, int coi ) const
+{ return get( CV_MAT_ELEM_PTR( *this, row, col ), type, coi ); }
+
+
+inline _CvMATElem_ CvMAT::operator ()( CvPoint pt )
+{ return _CvMATElem_( CV_MAT_ELEM_PTR( *this, pt.y, pt.x ), type ); }
+
+
+inline _CvMATConstElem_ CvMAT::operator ()( CvPoint pt ) const
+{ return _CvMATConstElem_( CV_MAT_ELEM_PTR( *this, pt.y, pt.x ), type ); }
+
+
+inline double CvMAT::operator()( CvPoint pt, int coi ) const
+{ return get( CV_MAT_ELEM_PTR( *this, pt.y, pt.x ), type, coi ); }
+
+
+inline void* CvMAT::ptr( int row )
+{ return CV_MAT_ELEM_PTR( *this, row, 0 ); }
+
+
+inline const void* CvMAT::ptr( int row ) const
+{ return (const void*)CV_MAT_ELEM_PTR( *this, row, 0 ); }
+
+
+inline void* CvMAT::ptr( int row, int col )
+{ return CV_MAT_ELEM_PTR( *this, row, col ); }
+
+
+inline const void* CvMAT::ptr( int row, int col ) const
+{ return (const void*)CV_MAT_ELEM_PTR( *this, row, col ); }
+
+
+inline void* CvMAT::ptr( CvPoint pt )
+{ return CV_MAT_ELEM_PTR( *this, pt.y, pt.x ); }
+
+
+inline const void* CvMAT::ptr( CvPoint pt ) const
+{ return (const void*)CV_MAT_ELEM_PTR( *this, pt.y, pt.x ); }
+
+
+inline _CvMAT_INV_ CvMAT::inv( int method ) const
+{ return _CvMAT_INV_( this, method ); }
+
+
+inline _CvMAT_T_ CvMAT::t() const
+{ return _CvMAT_T_( this ); }
+
+
+inline _CvMAT_COPY_ CvMAT::clone() const
+{ return _CvMAT_COPY_( this ); }
+
+inline _CvMAT_CVT_ CvMAT::cvt( int newdepth, double scale, double shift ) const
+{ return _CvMAT_CVT_( this, newdepth, scale, shift ); }
+
+
+inline CvMAT::CvMAT( const CvMat& mat, CvRect rect )
+{
+ type = 0;
+ cvGetSubArr( &mat, this, rect );
+ cvIncRefData( this );
+}
+
+
+/* submatrix:
+ k == 0 - i-th row
+ k > 0 - i-th column
+ k < 0 - i-th diagonal */
+inline CvMAT::CvMAT( const CvMat& mat, int k, int i )
+{
+ type = 0;
+ if( k == 0 )
+ cvGetRow( &mat, this, i );
+ else if( k > 0 )
+ cvGetCol( &mat, this, i );
+ else
+ cvGetDiag( &mat, this, i );
+ cvIncRefData( this );
+}
+
+
+inline CvMAT CvMAT::row( int r ) const
+{ return CvMAT( *this, 0, r ); }
+
+
+inline CvMAT CvMAT::col( int c ) const
+{ return CvMAT( *this, 1, c ); }
+
+
+inline CvMAT CvMAT::diag( int d ) const
+{ return CvMAT( *this, -1, d ); }
+
+
+inline CvMAT CvMAT::rect( CvRect rect ) const
+{ return CvMAT( *this, rect ); }
+
+inline CvMAT CvMAT::rowrange( int row1, int row2 ) const
+{
+ assert( 0 <= row1 && row1 < row2 && row2 <= height );
+ return CvMAT( *this, cvRect( 0, row1, width, row2 - row1 ));
+}
+
+inline CvMAT CvMAT::colrange( int col1, int col2 ) const
+{
+ assert( 0 <= col1 && col1 < col2 && col2 <= width );
+ return CvMAT( *this, cvRect( col1, 0, col2 - col1, height ));
+}
+
+inline _CvMAT_DOT_OP_ CvMAT::mul( const CvMAT& mat ) const
+{ return _CvMAT_DOT_OP_( this, &mat, '*' ); }
+
+inline _CvMAT_DOT_OP_ CvMAT::mul( const _CvMAT_SCALE_& mat ) const
+{ return _CvMAT_DOT_OP_( this, mat.a, '*', mat.alpha ); }
+
+inline _CvMAT_DOT_OP_ CvMAT::div( const CvMAT& mat ) const
+{ return _CvMAT_DOT_OP_( this, &mat, '/' ); }
+
+inline _CvMAT_DOT_OP_ CvMAT::div( const _CvMAT_SCALE_& mat ) const
+{ return _CvMAT_DOT_OP_( this, mat.a, '/', 1./mat.alpha ); }
+
+inline _CvMAT_DOT_OP_ CvMAT::min( const CvMAT& mat ) const
+{ return _CvMAT_DOT_OP_( this, &mat, 'm' ); }
+
+inline _CvMAT_DOT_OP_ CvMAT::max( const CvMAT& mat ) const
+{ return _CvMAT_DOT_OP_( this, &mat, 'M' ); }
+
+inline _CvMAT_DOT_OP_ CvMAT::min( double value ) const
+{ return _CvMAT_DOT_OP_( this, 0, 'm', value ); }
+
+inline _CvMAT_DOT_OP_ CvMAT::max( double value ) const
+{ return _CvMAT_DOT_OP_( this, 0, 'M', value ); }
+
+inline _CvMAT_DOT_OP_ CvMAT::abs() const
+{ return _CvMAT_DOT_OP_( this, 0, 'a', 0 ); }
+
+/****************************************************************************************\
+* binary operations (+,-,*) *
+\****************************************************************************************/
+
+/*
+* PART I. Scaling, shifting, addition/subtraction operations
+*/
+
+/* (mat2^t) = (mat1^t) * scalar */
+inline _CvMAT_T_ operator * ( const _CvMAT_T_& a, double alpha )
+{ return _CvMAT_T_( &a.a, a.alpha*alpha ); }
+
+/* (mat2^t) = scalar * (mat1^t) */
+inline _CvMAT_T_ operator * ( double alpha, const _CvMAT_T_& a )
+{ return _CvMAT_T_( &a.a, a.alpha*alpha ); }
+
+/* -(mat^t) */
+inline _CvMAT_T_ operator - ( const _CvMAT_T_& a )
+{ return _CvMAT_T_( &a.a, -a.alpha ); }
+
+/* mat_scaled = mat * scalar */
+inline _CvMAT_SCALE_ operator * ( const CvMAT& a, double alpha )
+{ return _CvMAT_SCALE_( &a, alpha ); }
+
+/* mat_scaled = scalar * mat */
+inline _CvMAT_SCALE_ operator * ( double alpha, const CvMAT& a )
+{ return _CvMAT_SCALE_( &a, alpha ); }
+
+/* mat_scaled2 = mat_scaled1 * scalar */
+inline _CvMAT_SCALE_ operator * ( const _CvMAT_SCALE_& a, double alpha )
+{ return _CvMAT_SCALE_( a.a, a.alpha*alpha ); }
+
+/* mat_scaled2 = scalar * mat_scaled1 */
+inline _CvMAT_SCALE_ operator * ( double alpha, const _CvMAT_SCALE_& a )
+{ return _CvMAT_SCALE_( a.a, a.alpha*alpha ); }
+
+/* -mat_scaled */
+inline _CvMAT_SCALE_ operator - ( const _CvMAT_SCALE_& a )
+{ return _CvMAT_SCALE_( a.a, -a.alpha ); }
+
+
+/* mat_scaled_shifted = mat + scalar */
+inline _CvMAT_SCALE_SHIFT_ operator + ( const CvMAT& a, double beta )
+{ return _CvMAT_SCALE_SHIFT_( &a, 1, beta ); }
+
+/* mat_scaled_shifted = scalar + mat */
+inline _CvMAT_SCALE_SHIFT_ operator + ( double beta, const CvMAT& a )
+{ return _CvMAT_SCALE_SHIFT_( &a, 1, beta ); }
+
+/* mat_scaled_shifted = mat - scalar */
+inline _CvMAT_SCALE_SHIFT_ operator - ( const CvMAT& a, double beta )
+{ return _CvMAT_SCALE_SHIFT_( &a, 1, -beta ); }
+
+/* mat_scaled_shifted = scalar - mat */
+inline _CvMAT_SCALE_SHIFT_ operator - ( double beta, const CvMAT& a )
+{ return _CvMAT_SCALE_SHIFT_( &a, -1, beta ); }
+
+/* mat_scaled_shifted = mat_scaled + scalar */
+inline _CvMAT_SCALE_SHIFT_ operator + ( const _CvMAT_SCALE_& a, double beta )
+{ return _CvMAT_SCALE_SHIFT_( a.a, a.alpha, beta ); }
+
+/* mat_scaled_shifted = scalar + mat_scaled */
+inline _CvMAT_SCALE_SHIFT_ operator + ( double beta, const _CvMAT_SCALE_& a )
+{ return _CvMAT_SCALE_SHIFT_( a.a, a.alpha, beta ); }
+
+/* mat_scaled_shifted = mat_scaled - scalar */
+inline _CvMAT_SCALE_SHIFT_ operator - ( const _CvMAT_SCALE_& a, double beta )
+{ return _CvMAT_SCALE_SHIFT_( a.a, a.alpha, -beta ); }
+
+/* mat_scaled_shifted = scalar - mat_scaled */
+inline _CvMAT_SCALE_SHIFT_ operator - ( double beta, const _CvMAT_SCALE_& a )
+{ return _CvMAT_SCALE_SHIFT_( a.a, -a.alpha, beta ); }
+
+/* mat_scaled_shifted2 = mat_scaled_shifted1 + scalar */
+inline _CvMAT_SCALE_SHIFT_ operator + ( const _CvMAT_SCALE_SHIFT_& a, double beta )
+{ return _CvMAT_SCALE_SHIFT_( a.a, a.alpha, a.beta + beta ); }
+
+/* mat_scaled_shifted2 = scalar + mat_scaled_shifted1 */
+inline _CvMAT_SCALE_SHIFT_ operator + ( double beta, const _CvMAT_SCALE_SHIFT_& a )
+{ return _CvMAT_SCALE_SHIFT_( a.a, a.alpha, a.beta + beta ); }
+
+/* mat_scaled_shifted2 = mat_scaled_shifted1 - scalar */
+inline _CvMAT_SCALE_SHIFT_ operator - ( const _CvMAT_SCALE_SHIFT_& a, double beta )
+{ return _CvMAT_SCALE_SHIFT_( a.a, a.alpha, a.beta - beta ); }
+
+/* mat_scaled_shifted2 = scalar - mat_scaled_shifted1 */
+inline _CvMAT_SCALE_SHIFT_ operator - ( double beta, const _CvMAT_SCALE_SHIFT_& a )
+{ return _CvMAT_SCALE_SHIFT_( a.a, -a.alpha, beta - a.beta ); }
+
+/* mat_scaled_shifted2 = mat_scaled_shifted1 * scalar */
+inline _CvMAT_SCALE_SHIFT_ operator * ( const _CvMAT_SCALE_SHIFT_& a, double alpha )
+{ return _CvMAT_SCALE_SHIFT_( a.a, a.alpha*alpha, a.beta*alpha ); }
+
+/* mat_scaled_shifted2 = scalar * mat_scaled_shifted1 */
+inline _CvMAT_SCALE_SHIFT_ operator * ( double alpha, const _CvMAT_SCALE_SHIFT_& a )
+{ return _CvMAT_SCALE_SHIFT_( a.a, a.alpha*alpha, a.beta*alpha ); }
+
+/* -mat_scaled_shifted */
+inline _CvMAT_SCALE_SHIFT_ operator - ( const _CvMAT_SCALE_SHIFT_& a )
+{ return _CvMAT_SCALE_SHIFT_( a.a, -a.alpha, -a.beta ); }
+
+
+/* -mat1 */
+inline _CvMAT_SCALE_ operator - ( const CvMAT& a )
+{ return _CvMAT_SCALE_( &a, -1 ); }
+
+/* mat_add = mat1 + mat2 */
+inline _CvMAT_ADD_ operator + ( const CvMAT& a, const CvMAT& b )
+{ return _CvMAT_ADD_( &a, &b ); }
+
+/* mat_add = mat1 - mat2 */
+inline _CvMAT_ADD_ operator - ( const CvMAT& a, const CvMAT& b )
+{ return _CvMAT_ADD_( &a, &b, -1 ); }
+
+/* mat_add = mat_scaled1 + mat2 */
+inline _CvMAT_ADD_ operator + ( const _CvMAT_SCALE_& a, const CvMAT& b )
+{ return _CvMAT_ADD_( &b, a.a, a.alpha ); }
+
+/* mat_add = mat1 + mat_scaled2 */
+inline _CvMAT_ADD_ operator + ( const CvMAT& b, const _CvMAT_SCALE_& a )
+{ return _CvMAT_ADD_( &b, a.a, a.alpha ); }
+
+/* -mat_add */
+inline _CvMAT_ADD_EX_ operator - ( const _CvMAT_ADD_& a )
+{ return _CvMAT_ADD_EX_( a.a, -1, a.b, -a.beta ); }
+
+/* mat_add = mat_scaled1 - mat2 */
+inline _CvMAT_ADD_EX_ operator - ( const _CvMAT_SCALE_& a, const CvMAT& b )
+{ return _CvMAT_ADD_EX_( a.a, a.alpha, &b, -1 ); }
+
+/* mat_add = mat1 - mat_scaled2 */
+inline _CvMAT_ADD_ operator - ( const CvMAT& b, const _CvMAT_SCALE_& a )
+{ return _CvMAT_ADD_( &b, a.a, -a.alpha ); }
+
+/* mat_add = mat_scaled_shifted1 + mat2 */
+inline _CvMAT_ADD_EX_ operator + ( const _CvMAT_SCALE_SHIFT_& a, const CvMAT& b )
+{ return _CvMAT_ADD_EX_( a.a, a.alpha, &b, 1, a.beta ); }
+
+/* mat_add = mat1 + mat_scaled_shifted2 */
+inline _CvMAT_ADD_EX_ operator + ( const CvMAT& b, const _CvMAT_SCALE_SHIFT_& a )
+{ return _CvMAT_ADD_EX_( a.a, a.alpha, &b, 1, a.beta ); }
+
+/* mat_add = mat_scaled_shifted1 - mat2 */
+inline _CvMAT_ADD_EX_ operator - ( const _CvMAT_SCALE_SHIFT_& a, const CvMAT& b )
+{ return _CvMAT_ADD_EX_( a.a, a.alpha, &b, -1, a.beta ); }
+
+/* mat_add = mat1 - mat_scaled_shifted2 */
+inline _CvMAT_ADD_EX_ operator - ( const CvMAT& b, const _CvMAT_SCALE_SHIFT_& a )
+{ return _CvMAT_ADD_EX_( a.a, -a.alpha, &b, 1, -a.beta ); }
+
+/* mat_add = mat_scaled_shifted1 + mat_scaled2 */
+inline _CvMAT_ADD_EX_ operator + ( const _CvMAT_SCALE_SHIFT_& a, const _CvMAT_SCALE_& b )
+{ return _CvMAT_ADD_EX_( a.a, a.alpha, b.a, b.alpha, a.beta ); }
+
+/* mat_add = mat_scaled1 + mat_scaled_shifted2 */
+inline _CvMAT_ADD_EX_ operator + ( const _CvMAT_SCALE_& b, const _CvMAT_SCALE_SHIFT_& a )
+{ return _CvMAT_ADD_EX_( a.a, a.alpha, b.a, b.alpha, a.beta ); }
+
+/* mat_add = mat_scaled_shifted1 - mat_scaled2 */
+inline _CvMAT_ADD_EX_ operator - ( const _CvMAT_SCALE_SHIFT_& a, const _CvMAT_SCALE_& b )
+{ return _CvMAT_ADD_EX_( a.a, a.alpha, b.a, -b.alpha, a.beta ); }
+
+/* mat_add = mat_scaled1 - mat_scaled_shifted2 */
+inline _CvMAT_ADD_EX_ operator - ( const _CvMAT_SCALE_& b, const _CvMAT_SCALE_SHIFT_& a )
+{ return _CvMAT_ADD_EX_( a.a, -a.alpha, b.a, b.alpha, -a.beta ); }
+
+/* mat_add = mat_scaled1 + mat_scaled2 */
+inline _CvMAT_ADD_EX_ operator + ( const _CvMAT_SCALE_& a, const _CvMAT_SCALE_& b )
+{ return _CvMAT_ADD_EX_( a.a, a.alpha, b.a, b.alpha ); }
+
+/* mat_add = mat_scaled1 - mat_scaled2 */
+inline _CvMAT_ADD_EX_ operator - ( const _CvMAT_SCALE_& a, const _CvMAT_SCALE_& b )
+{ return _CvMAT_ADD_EX_( a.a, a.alpha, b.a, -b.alpha ); }
+
+/* mat_add = mat_scaled_shifted1 + mat_scaled_shifted2 */
+inline _CvMAT_ADD_EX_ operator + ( const _CvMAT_SCALE_SHIFT_& a,
+ const _CvMAT_SCALE_SHIFT_& b )
+{ return _CvMAT_ADD_EX_( a.a, a.alpha, b.a, b.alpha, a.beta + b.beta ); }
+
+/* mat_add = mat_scaled_shifted1 - mat_scaled_shifted2 */
+inline _CvMAT_ADD_EX_ operator - ( const _CvMAT_SCALE_SHIFT_& a,
+ const _CvMAT_SCALE_SHIFT_& b )
+{ return _CvMAT_ADD_EX_( a.a, a.alpha, b.a, -b.alpha, a.beta - b.beta ); }
+
+/* mat_add2 = mat_add1 + scalar */
+inline _CvMAT_ADD_EX_ operator + ( const _CvMAT_ADD_EX_& a, double gamma )
+{ return _CvMAT_ADD_EX_( a.a, a.alpha, a.b, a.beta, a.gamma + gamma ); }
+
+/* mat_add2 = scalar + mat_add1 */
+inline _CvMAT_ADD_EX_ operator + ( double gamma, const _CvMAT_ADD_EX_& a )
+{ return _CvMAT_ADD_EX_( a.a, a.alpha, a.b, a.beta, a.gamma + gamma ); }
+
+/* mat_add2 = mat_add1 - scalar */
+inline _CvMAT_ADD_EX_ operator - ( const _CvMAT_ADD_EX_& a, double gamma )
+{ return _CvMAT_ADD_EX_( a.a, a.alpha, a.b, a.beta, a.gamma - gamma ); }
+
+/* mat_add2 = scalar - mat_add1 */
+inline _CvMAT_ADD_EX_ operator - ( double gamma, const _CvMAT_ADD_EX_& a )
+{ return _CvMAT_ADD_EX_( a.a, -a.alpha, a.b, -a.beta, gamma - a.gamma ); }
+
+/* mat_add2 = mat_add1 * scalar */
+inline _CvMAT_ADD_EX_ operator * ( const _CvMAT_ADD_EX_& a, double alpha )
+{ return _CvMAT_ADD_EX_( a.a, a.alpha*alpha, a.b, a.beta*alpha, a.gamma*alpha ); }
+
+/* mat_add2 = scalar * mat_add1 */
+inline _CvMAT_ADD_EX_ operator * ( double alpha, const _CvMAT_ADD_EX_& a )
+{ return _CvMAT_ADD_EX_( a.a, a.alpha*alpha, a.b, a.beta*alpha, a.gamma*alpha ); }
+
+/* mat_add2 = mat_add1 + scalar */
+inline _CvMAT_ADD_EX_ operator + ( const _CvMAT_ADD_& a, double gamma )
+{ return _CvMAT_ADD_EX_( a.a, 1, a.b, a.beta, gamma ); }
+
+/* mat_add2 = scalar + mat_add1 */
+inline _CvMAT_ADD_EX_ operator + ( double gamma, const _CvMAT_ADD_& a )
+{ return _CvMAT_ADD_EX_( a.a, 1, a.b, a.beta, gamma ); }
+
+/* mat_add2 = mat_add1 - scalar */
+inline _CvMAT_ADD_EX_ operator - ( const _CvMAT_ADD_& a, double gamma )
+{ return _CvMAT_ADD_EX_( a.a, 1, a.b, a.beta, -gamma ); }
+
+/* mat_add2 = scalar - mat_add1 */
+inline _CvMAT_ADD_EX_ operator - ( double gamma, const _CvMAT_ADD_& a )
+{ return _CvMAT_ADD_EX_( a.a, -1, a.b, -a.beta, gamma ); }
+
+/* mat_add2 = mat_add1 * scalar */
+inline _CvMAT_ADD_EX_ operator * ( const _CvMAT_ADD_& a, double alpha )
+{ return _CvMAT_ADD_EX_( a.a, alpha, a.b, a.beta*alpha, 0 ); }
+
+/* mat_add2 = scalar * mat_add1 */
+inline _CvMAT_ADD_EX_ operator * ( double alpha, const _CvMAT_ADD_& a )
+{ return _CvMAT_ADD_EX_( a.a, alpha, a.b, a.beta*alpha, 0 ); }
+
+/* -mat_add_ex */
+inline _CvMAT_ADD_EX_ operator - ( const _CvMAT_ADD_EX_& a )
+{ return _CvMAT_ADD_EX_( a.a, -a.alpha, a.b, -a.beta, -a.gamma ); }
+
+
+/*
+* PART II. Matrix multiplication.
+*/
+
+/* mmul = mat1 * mat2 */
+inline _CvMAT_MUL_ operator * ( const CvMAT& a, const CvMAT& b )
+{ return _CvMAT_MUL_( &a, &b, 0 ); }
+
+/* mmul = (mat1^t) * mat2 */
+inline _CvMAT_MUL_ operator * ( const _CvMAT_T_& a, const CvMAT& b )
+{ return _CvMAT_MUL_( &a.a, &b, a.alpha, 1 ); }
+
+/* mmul = mat1 * (mat2^t) */
+inline _CvMAT_MUL_ operator * ( const CvMAT& b, const _CvMAT_T_& a )
+{ return _CvMAT_MUL_( &b, &a.a, a.alpha, 2 ); }
+
+/* mmul = (mat1^t) * (mat2^t) */
+inline _CvMAT_MUL_ operator * ( const _CvMAT_T_& a, const _CvMAT_T_& b )
+{ return _CvMAT_MUL_( &a.a, &b.a, a.alpha*b.alpha, 3 ); }
+
+/* mmul = mat_scaled1 * mat2 */
+inline _CvMAT_MUL_ operator * ( const _CvMAT_SCALE_& a, const CvMAT& b )
+{ return _CvMAT_MUL_( a.a, &b, a.alpha, 0 ); }
+
+/* mmul = mat1 * mat_scaled2 */
+inline _CvMAT_MUL_ operator * ( const CvMAT& b, const _CvMAT_SCALE_& a )
+{ return _CvMAT_MUL_( &b, a.a, a.alpha, 0 ); }
+
+/* mmul = (mat1^t) * mat_scaled1 */
+inline _CvMAT_MUL_ operator * ( const _CvMAT_T_& a, const _CvMAT_SCALE_& b )
+{ return _CvMAT_MUL_( &a.a, b.a, a.alpha*b.alpha, 1 ); }
+
+/* mmul = mat_scaled1 * (mat2^t) */
+inline _CvMAT_MUL_ operator * ( const _CvMAT_SCALE_& b, const _CvMAT_T_& a )
+{ return _CvMAT_MUL_( b.a, &a.a, a.alpha*b.alpha, 2 ); }
+
+/* mmul = mat_scaled1 * mat_scaled2 */
+inline _CvMAT_MUL_ operator * ( const _CvMAT_SCALE_& a, const _CvMAT_SCALE_& b )
+{ return _CvMAT_MUL_( a.a, b.a, a.alpha*b.alpha, 0 ); }
+
+/* mmul2 = mmul1 * scalar */
+inline _CvMAT_MUL_ operator * ( const _CvMAT_MUL_& a, double alpha )
+{ return _CvMAT_MUL_( a.a, a.b, a.alpha*alpha, a.t_ab ); }
+
+/* mmul2 = scalar * mmul1 */
+inline _CvMAT_MUL_ operator * ( double alpha, const _CvMAT_MUL_& a )
+{ return _CvMAT_MUL_( a.a, a.b, a.alpha*alpha, a.t_ab ); }
+
+/* -mmul */
+inline _CvMAT_MUL_ operator - ( const _CvMAT_MUL_& a )
+{ return _CvMAT_MUL_( a.a, a.b, -a.alpha, a.t_ab ); }
+
+/* mmuladd = mmul + mat */
+inline _CvMAT_MUL_ADD_ operator + ( const _CvMAT_MUL_& a, const CvMAT& b )
+{ return _CvMAT_MUL_ADD_( a.a, a.b, a.alpha, &b, 1, a.t_ab ); }
+
+/* !!! Comment this off because of ambigous conversion error !!!
+ mmuladd = mat + mmul */
+/* inline _CvMAT_MUL_ADD_ operator + ( const CvMAT& b, const _CvMAT_MUL_& a )
+{ return _CvMAT_MUL_ADD_( a.a, a.b, a.alpha, &b, 1, a.t_ab ); }*/
+
+/* mmuladd = mmul - mat */
+inline _CvMAT_MUL_ADD_ operator - ( const _CvMAT_MUL_& a, const CvMAT& b )
+{ return _CvMAT_MUL_ADD_( a.a, a.b, a.alpha, &b, -1, a.t_ab ); }
+
+/* !!! Comment this off because of ambigous conversion error !!!
+ mmuladd = mat - mmul */
+/*inline _CvMAT_MUL_ADD_ operator - ( const CvMAT& b, const _CvMAT_MUL_& a )
+{ return _CvMAT_MUL_ADD_( a.a, a.b, -a.alpha, &b, 1, a.t_ab ); }*/
+
+/* mmuladd = mmul + mat_scaled */
+inline _CvMAT_MUL_ADD_ operator + ( const _CvMAT_MUL_& a, const _CvMAT_SCALE_& b )
+{ return _CvMAT_MUL_ADD_( a.a, a.b, a.alpha, b.a, b.alpha, a.t_ab ); }
+
+/* mmuladd = mat_scaled + mmul */
+inline _CvMAT_MUL_ADD_ operator + ( const _CvMAT_SCALE_& b, const _CvMAT_MUL_& a )
+{ return _CvMAT_MUL_ADD_( a.a, a.b, a.alpha, b.a, b.alpha, a.t_ab ); }
+
+/* mmuladd = mmul - mat_scaled */
+inline _CvMAT_MUL_ADD_ operator - ( const _CvMAT_MUL_& a, const _CvMAT_SCALE_& b )
+{ return _CvMAT_MUL_ADD_( a.a, a.b, a.alpha, b.a, -b.alpha, a.t_ab ); }
+
+/* mmuladd = mat_scaled - mmul */
+inline _CvMAT_MUL_ADD_ operator - ( const _CvMAT_SCALE_& b, const _CvMAT_MUL_& a )
+{ return _CvMAT_MUL_ADD_( a.a, a.b, -a.alpha, b.a, b.alpha, a.t_ab ); }
+
+/* mmuladd = mmul + (mat^t) */
+inline _CvMAT_MUL_ADD_ operator + ( const _CvMAT_MUL_& a, const _CvMAT_T_& b )
+{ return _CvMAT_MUL_ADD_( a.a, a.b, a.alpha, &b.a, b.alpha, a.t_ab + 4 ); }
+
+/* mmuladd = (mat^t) + mmul */
+inline _CvMAT_MUL_ADD_ operator + ( const _CvMAT_T_& b, const _CvMAT_MUL_& a )
+{ return _CvMAT_MUL_ADD_( a.a, a.b, a.alpha, &b.a, b.alpha, a.t_ab + 4 ); }
+
+/* mmuladd = mmul - (mat^t) */
+inline _CvMAT_MUL_ADD_ operator - ( const _CvMAT_MUL_& a, const _CvMAT_T_& b )
+{ return _CvMAT_MUL_ADD_( a.a, a.b, a.alpha, &b.a, -b.alpha, a.t_ab + 4 ); }
+
+/* mmuladd = (mat^t) - mmul */
+inline _CvMAT_MUL_ADD_ operator - ( const _CvMAT_T_& b, const _CvMAT_MUL_& a )
+{ return _CvMAT_MUL_ADD_( a.a, a.b, -a.alpha, &b.a, b.alpha, a.t_ab + 4 ); }
+
+
+/* mmuladd = mat_scaled_shifted * mat */
+inline _CvMAT_MUL_ADD_ operator * ( const _CvMAT_SCALE_SHIFT_& a, const CvMAT& b )
+{ return _CvMAT_MUL_ADD_( a.a, &b, a.alpha, &b, a.beta, 0 ); }
+
+/* mmuladd = mat * mat_scaled_shifted */
+inline _CvMAT_MUL_ADD_ operator * ( const CvMAT& b, const _CvMAT_SCALE_SHIFT_& a )
+{ return _CvMAT_MUL_ADD_( &b, a.a, a.alpha, &b, a.beta, 0 ); }
+
+/* mmuladd = mat_scaled_shifted * mat_scaled */
+inline _CvMAT_MUL_ADD_ operator * ( const _CvMAT_SCALE_SHIFT_& a, const _CvMAT_SCALE_& b )
+{ return _CvMAT_MUL_ADD_( a.a, b.a, a.alpha*b.alpha, b.a, a.beta*b.alpha, 0 ); }
+
+/* mmuladd = mat_scaled * mat_scaled_shifted */
+inline _CvMAT_MUL_ADD_ operator * ( const _CvMAT_SCALE_& b, const _CvMAT_SCALE_SHIFT_& a )
+{ return _CvMAT_MUL_ADD_( b.a, a.a, a.alpha*b.alpha, b.a, a.beta*b.alpha, 0 ); }
+
+/* mmuladd = mat_scaled_shifted * (mat^t) */
+inline _CvMAT_MUL_ADD_ operator * ( const _CvMAT_SCALE_SHIFT_& a, const _CvMAT_T_& b )
+{ return _CvMAT_MUL_ADD_( a.a, &b.a, a.alpha*b.alpha, &b.a, a.beta*b.alpha, 6 ); }
+
+/* mmuladd = (mat^t) * mat_scaled_shifted */
+inline _CvMAT_MUL_ADD_ operator * ( const _CvMAT_T_& b, const _CvMAT_SCALE_SHIFT_& a )
+{ return _CvMAT_MUL_ADD_( &b.a, a.a, a.alpha*b.alpha, &b.a, a.beta*b.alpha, 5 ); }
+
+/* mmuladd2 = mmuladd1 * scalar */
+inline _CvMAT_MUL_ADD_ operator * ( const _CvMAT_MUL_ADD_& a, double alpha )
+{ return _CvMAT_MUL_ADD_( a.a, a.b, a.alpha*alpha, a.c, a.beta*alpha, a.t_abc ); }
+
+/* mmuladd2 = scalar * mmuladd1 */
+inline _CvMAT_MUL_ADD_ operator * ( double alpha, const _CvMAT_MUL_ADD_& a )
+{ return _CvMAT_MUL_ADD_( a.a, a.b, a.alpha*alpha, a.c, a.beta*alpha, a.t_abc ); }
+
+/* -mmuladd */
+inline _CvMAT_MUL_ADD_ operator - ( const _CvMAT_MUL_ADD_& a )
+{ return _CvMAT_MUL_ADD_( a.a, a.b, -a.alpha, a.c, -a.beta, a.t_abc ); }
+
+/* inv(a)*b, i.e. solve a*x = b */
+inline _CvMAT_SOLVE_ operator * ( const _CvMAT_INV_& a, const CvMAT& b )
+{ return _CvMAT_SOLVE_( &a.a, &b, a.method ); }
+
+
+/*
+* PART III. Logical operations
+*/
+inline _CvMAT_NOT_ operator ~ ( const CvMAT& a )
+{ return _CvMAT_NOT_(&a); }
+
+inline _CvMAT_LOGIC_ operator & ( const CvMAT& a, const CvMAT& b )
+{ return _CvMAT_LOGIC_( &a, &b, _CvMAT_LOGIC_::AND, 0 ); }
+
+inline _CvMAT_LOGIC_ operator & ( const _CvMAT_NOT_& a, const CvMAT& b )
+{ return _CvMAT_LOGIC_( a.a, &b, _CvMAT_LOGIC_::AND, 1 ); }
+
+inline _CvMAT_LOGIC_ operator & ( const CvMAT& a, const _CvMAT_NOT_& b )
+{ return _CvMAT_LOGIC_( &a, b.a, _CvMAT_LOGIC_::AND, 2 ); }
+
+inline _CvMAT_LOGIC_ operator & ( const _CvMAT_NOT_& a, const _CvMAT_NOT_& b )
+{ return _CvMAT_LOGIC_( a.a, b.a, _CvMAT_LOGIC_::AND, 3 ); }
+
+
+inline _CvMAT_LOGIC_ operator | ( const CvMAT& a, const CvMAT& b )
+{ return _CvMAT_LOGIC_( &a, &b, _CvMAT_LOGIC_::OR, 0 ); }
+
+inline _CvMAT_LOGIC_ operator | ( const _CvMAT_NOT_& a, const CvMAT& b )
+{ return _CvMAT_LOGIC_( a.a, &b, _CvMAT_LOGIC_::OR, 1 ); }
+
+inline _CvMAT_LOGIC_ operator | ( const CvMAT& a, const _CvMAT_NOT_& b )
+{ return _CvMAT_LOGIC_( &a, b.a, _CvMAT_LOGIC_::OR, 2 ); }
+
+inline _CvMAT_LOGIC_ operator | ( const _CvMAT_NOT_& a, const _CvMAT_NOT_& b )
+{ return _CvMAT_LOGIC_( a.a, b.a, _CvMAT_LOGIC_::OR, 3 ); }
+
+
+inline _CvMAT_LOGIC_ operator ^ ( const CvMAT& a, const CvMAT& b )
+{ return _CvMAT_LOGIC_( &a, &b, _CvMAT_LOGIC_::XOR, 0 ); }
+
+inline _CvMAT_LOGIC_ operator ^ ( const _CvMAT_NOT_& a, const CvMAT& b )
+{ return _CvMAT_LOGIC_( a.a, &b, _CvMAT_LOGIC_::XOR, 1 ); }
+
+inline _CvMAT_LOGIC_ operator ^ ( const CvMAT& a, const _CvMAT_NOT_& b )
+{ return _CvMAT_LOGIC_( &a, b.a, _CvMAT_LOGIC_::XOR, 2 ); }
+
+inline _CvMAT_LOGIC_ operator ^ ( const _CvMAT_NOT_& a, const _CvMAT_NOT_& b )
+{ return _CvMAT_LOGIC_( a.a, b.a, _CvMAT_LOGIC_::XOR, 3 ); }
+
+
+inline _CvMAT_UN_LOGIC_ operator & ( const CvMAT& a, double alpha )
+{ return _CvMAT_UN_LOGIC_( &a, alpha, _CvMAT_LOGIC_::AND, 0 ); }
+
+inline _CvMAT_UN_LOGIC_ operator & ( double alpha, const CvMAT& a )
+{ return _CvMAT_UN_LOGIC_( &a, alpha, _CvMAT_LOGIC_::AND, 0 ); }
+
+inline _CvMAT_UN_LOGIC_ operator & ( const _CvMAT_NOT_& a, double alpha )
+{ return _CvMAT_UN_LOGIC_( a.a, alpha, _CvMAT_LOGIC_::AND, 1 ); }
+
+inline _CvMAT_UN_LOGIC_ operator & ( double alpha, const _CvMAT_NOT_& a )
+{ return _CvMAT_UN_LOGIC_( a.a, alpha, _CvMAT_LOGIC_::AND, 1 ); }
+
+
+inline _CvMAT_UN_LOGIC_ operator | ( const CvMAT& a, double alpha )
+{ return _CvMAT_UN_LOGIC_( &a, alpha, _CvMAT_LOGIC_::OR, 0 ); }
+
+inline _CvMAT_UN_LOGIC_ operator | ( double alpha, const CvMAT& a )
+{ return _CvMAT_UN_LOGIC_( &a, alpha, _CvMAT_LOGIC_::OR, 0 ); }
+
+inline _CvMAT_UN_LOGIC_ operator | ( const _CvMAT_NOT_& a, double alpha )
+{ return _CvMAT_UN_LOGIC_( a.a, alpha, _CvMAT_LOGIC_::OR, 1 ); }
+
+inline _CvMAT_UN_LOGIC_ operator | ( double alpha, const _CvMAT_NOT_& a )
+{ return _CvMAT_UN_LOGIC_( a.a, alpha, _CvMAT_LOGIC_::OR, 1 ); }
+
+
+inline _CvMAT_UN_LOGIC_ operator ^ ( const CvMAT& a, double alpha )
+{ return _CvMAT_UN_LOGIC_( &a, alpha, _CvMAT_LOGIC_::XOR, 0 ); }
+
+inline _CvMAT_UN_LOGIC_ operator ^ ( double alpha, const CvMAT& a )
+{ return _CvMAT_UN_LOGIC_( &a, alpha, _CvMAT_LOGIC_::XOR, 0 ); }
+
+inline _CvMAT_UN_LOGIC_ operator ^ ( const _CvMAT_NOT_& a, double alpha )
+{ return _CvMAT_UN_LOGIC_( a.a, alpha, _CvMAT_LOGIC_::XOR, 1 ); }
+
+inline _CvMAT_UN_LOGIC_ operator ^ ( double alpha, const _CvMAT_NOT_& a )
+{ return _CvMAT_UN_LOGIC_( a.a, alpha, _CvMAT_LOGIC_::XOR, 1 ); }
+
+
+/*
+* PART IV. Comparison operations
+*/
+inline _CvMAT_CMP_ operator > ( const CvMAT& a, const CvMAT& b )
+{ return _CvMAT_CMP_( &a, &b, CV_CMP_GT ); }
+
+inline _CvMAT_CMP_ operator >= ( const CvMAT& a, const CvMAT& b )
+{ return _CvMAT_CMP_( &a, &b, CV_CMP_GE ); }
+
+inline _CvMAT_CMP_ operator < ( const CvMAT& a, const CvMAT& b )
+{ return _CvMAT_CMP_( &a, &b, CV_CMP_LT ); }
+
+inline _CvMAT_CMP_ operator <= ( const CvMAT& a, const CvMAT& b )
+{ return _CvMAT_CMP_( &a, &b, CV_CMP_LE ); }
+
+inline _CvMAT_CMP_ operator == ( const CvMAT& a, const CvMAT& b )
+{ return _CvMAT_CMP_( &a, &b, CV_CMP_EQ ); }
+
+inline _CvMAT_CMP_ operator != ( const CvMAT& a, const CvMAT& b )
+{ return _CvMAT_CMP_( &a, &b, CV_CMP_NE ); }
+
+
+inline _CvMAT_CMP_ operator > ( const CvMAT& a, double alpha )
+{ return _CvMAT_CMP_( &a, alpha, CV_CMP_GT ); }
+
+inline _CvMAT_CMP_ operator > ( double alpha, const CvMAT& a )
+{ return _CvMAT_CMP_( &a, alpha, CV_CMP_LT ); }
+
+inline _CvMAT_CMP_ operator >= ( const CvMAT& a, double alpha )
+{ return _CvMAT_CMP_( &a, alpha, CV_CMP_GE ); }
+
+inline _CvMAT_CMP_ operator >= ( double alpha, const CvMAT& a )
+{ return _CvMAT_CMP_( &a, alpha, CV_CMP_LE ); }
+
+inline _CvMAT_CMP_ operator < ( const CvMAT& a, double alpha )
+{ return _CvMAT_CMP_( &a, alpha, CV_CMP_LT ); }
+
+inline _CvMAT_CMP_ operator < ( double alpha, const CvMAT& a )
+{ return _CvMAT_CMP_( &a, alpha, CV_CMP_GT ); }
+
+inline _CvMAT_CMP_ operator <= ( const CvMAT& a, double alpha )
+{ return _CvMAT_CMP_( &a, alpha, CV_CMP_LE ); }
+
+inline _CvMAT_CMP_ operator <= ( double alpha, const CvMAT& a )
+{ return _CvMAT_CMP_( &a, alpha, CV_CMP_GE ); }
+
+inline _CvMAT_CMP_ operator == ( const CvMAT& a, double alpha )
+{ return _CvMAT_CMP_( &a, alpha, CV_CMP_EQ ); }
+
+inline _CvMAT_CMP_ operator == ( double alpha, const CvMAT& a )
+{ return _CvMAT_CMP_( &a, alpha, CV_CMP_EQ ); }
+
+inline _CvMAT_CMP_ operator != ( const CvMAT& a, double alpha )
+{ return _CvMAT_CMP_( &a, alpha, CV_CMP_NE ); }
+
+inline _CvMAT_CMP_ operator != ( double alpha, const CvMAT& a )
+{ return _CvMAT_CMP_( &a, alpha, CV_CMP_NE ); }
+
+
+/*
+* PART V. Speedup for some augmented assignments to CvMAT
+*/
+
+inline CvMAT& CvMAT::operator += ( const _CvMAT_SCALE_& scale_mat )
+{ return (*this = *this + scale_mat); }
+
+inline CvMAT& CvMAT::operator += ( const _CvMAT_SCALE_SHIFT_& scale_mat )
+{ return (*this = *this + scale_mat); }
+
+inline CvMAT& CvMAT::operator += ( const _CvMAT_MUL_& mmul )
+{ return (*this = mmul + *this); }
+
+inline CvMAT& CvMAT::operator -= ( const _CvMAT_SCALE_& scale_mat )
+{ return (*this = *this - scale_mat); }
+
+inline CvMAT& CvMAT::operator -= ( const _CvMAT_SCALE_SHIFT_& scale_mat )
+{ return (*this = *this - scale_mat); }
+
+inline CvMAT& CvMAT::operator -= ( const _CvMAT_MUL_& mmul )
+{ return (*this = -mmul + *this); }
+
+inline CvMAT& CvMAT::operator *= ( const _CvMAT_SCALE_& scale_mat )
+{ return (*this = *this * scale_mat); }
+
+inline CvMAT& CvMAT::operator *= ( const _CvMAT_SCALE_SHIFT_& scale_mat )
+{ return (*this = *this * scale_mat); }
+
+/****************************************************************************************\
+* misc. operations on temporary matrices (+,-,*) *
+\****************************************************************************************/
+
+/*
+* the base proxy class implementation
+*/
+
+/* a.*b */
+inline _CvMAT_DOT_OP_ _CvMAT_BASE_OP_::mul( const CvMAT& a ) const
+{ return ((CvMAT)*this).mul(a); }
+
+/* a.*b*alpha */
+inline _CvMAT_DOT_OP_ _CvMAT_BASE_OP_::mul( const _CvMAT_SCALE_& a ) const
+{ return ((CvMAT)*this).mul(a); }
+
+/* a./b */
+inline _CvMAT_DOT_OP_ _CvMAT_BASE_OP_::div( const CvMAT& a ) const
+{ return ((CvMAT)*this).div(a); }
+
+/* a./(b*alpha) */
+inline _CvMAT_DOT_OP_ _CvMAT_BASE_OP_::div( const _CvMAT_SCALE_& a ) const
+{ return ((CvMAT)*this).div(a); }
+
+/* a.max(b) */
+inline _CvMAT_DOT_OP_ _CvMAT_BASE_OP_::min( const CvMAT& a ) const
+{ return ((CvMAT)*this).min(a); }
+
+/* a.min(b) */
+inline _CvMAT_DOT_OP_ _CvMAT_BASE_OP_::max( const CvMAT& a ) const
+{ return ((CvMAT)*this).max(a); }
+
+/* a.max(alpha) */
+inline _CvMAT_DOT_OP_ _CvMAT_BASE_OP_::min( double alpha ) const
+{ return ((CvMAT)*this).min(alpha); }
+
+/* a.min(alpha) */
+inline _CvMAT_DOT_OP_ _CvMAT_BASE_OP_::max( double alpha ) const
+{ return ((CvMAT)*this).max(alpha); }
+
+
+inline _CvMAT_INV_ _CvMAT_BASE_OP_::inv( int method ) const
+{ return ((CvMAT)*this).inv(method); }
+
+inline _CvMAT_T_ _CvMAT_BASE_OP_::t() const
+{ return ((CvMAT)*this).t(); }
+
+inline _CvMAT_CVT_ _CvMAT_BASE_OP_::cvt( int newdepth, double scale, double shift ) const
+{ return ((CvMAT)*this).cvt( newdepth, scale, shift ); }
+
+inline CvMAT _CvMAT_BASE_OP_::row( int r ) const
+{ return CvMAT((CvMAT)*this, 0, r ); }
+
+inline CvMAT _CvMAT_BASE_OP_::rowrange( int row1, int row2 ) const
+{
+ CvMAT m = (CvMAT)*this;
+ assert( 0 <= row1 && row1 < row2 && row2 <= m.height );
+ return CvMAT( m, cvRect( 0, row1, m.width, row2 - row1 ));
+}
+
+inline CvMAT _CvMAT_BASE_OP_::col( int c ) const
+{ return CvMAT( (CvMAT)*this, 1, c ); }
+
+inline CvMAT _CvMAT_BASE_OP_::colrange( int col1, int col2 ) const
+{
+ CvMAT m = (CvMAT)*this;
+ assert( 0 <= col1 && col1 < col2 && col2 <= m.width );
+ return CvMAT( m, cvRect( col1, 0, col2 - col1, m.height ));
+}
+
+inline CvMAT _CvMAT_BASE_OP_::rect( CvRect r ) const
+{ return CvMAT( (CvMAT)*this, r ); }
+
+inline CvMAT _CvMAT_BASE_OP_::diag( int d ) const
+{ return CvMAT( (CvMAT)*this, -1, d ); }
+
+inline double _CvMAT_BASE_OP_::det() const
+{ return ((CvMAT)*this).det(); }
+
+inline double _CvMAT_BASE_OP_::norm( int norm_type ) const
+{ return ((CvMAT)*this).norm( norm_type ); }
+
+inline CvScalar _CvMAT_BASE_OP_::sum() const
+{ return ((CvMAT)*this).sum(); }
+
+inline double _CvMAT_BASE_OP_::min( CvPoint* minloc ) const
+{ return ((CvMAT)*this).min( minloc ); }
+
+inline double _CvMAT_BASE_OP_::max( CvPoint* maxloc ) const
+{ return ((CvMAT)*this).max( maxloc ); }
+
+
+/****************************************************************************************/
+/* proxy classes implementation. */
+/* part I. constructors */
+/****************************************************************************************/
+
+/* constructors */
+inline _CvMAT_COPY_::_CvMAT_COPY_( const CvMAT* _a ) : a((CvMAT*)_a) {}
+
+inline _CvMAT_CVT_::_CvMAT_CVT_( const CvMAT* _a, int _newdepth,
+ double _scale, double _shift ) :
+ a(*(CvMAT*)_a), newdepth(_newdepth), scale(_scale), shift(_shift) {}
+
+inline _CvMAT_T_::_CvMAT_T_( const CvMAT* _a ) : a(*(CvMAT*)_a), alpha(1) {}
+
+
+inline _CvMAT_T_::_CvMAT_T_( const CvMAT* _a, double _alpha ) :
+ a(*(CvMAT*)_a), alpha(_alpha) {}
+
+
+inline _CvMAT_INV_::_CvMAT_INV_( const CvMAT* _a, int _method ) :
+ a(*(CvMAT*)_a), method(_method) {}
+
+
+inline _CvMAT_MUL_::_CvMAT_MUL_( const CvMAT* _a, const CvMAT* _b, int _t_ab ) :
+ a((CvMAT*)_a), b((CvMAT*)_b), alpha(1), t_ab(_t_ab) {}
+
+
+inline _CvMAT_MUL_::_CvMAT_MUL_( const CvMAT* _a, const CvMAT* _b,
+ double _alpha, int _t_ab ) :
+ a((CvMAT*)_a), b((CvMAT*)_b), alpha(_alpha), t_ab(_t_ab) {}
+
+
+inline _CvMAT_MUL_ADD_::_CvMAT_MUL_ADD_( const CvMAT* _a, const CvMAT* _b,
+ const CvMAT* _c, int _t_abc ) :
+ a((CvMAT*)_a), b((CvMAT*)_b), c((CvMAT*)_c), t_abc(_t_abc) {}
+
+
+inline _CvMAT_MUL_ADD_::_CvMAT_MUL_ADD_( const CvMAT* _a, const CvMAT* _b, double _alpha,
+ const CvMAT* _c, double _beta, int _t_abc ) :
+ a((CvMAT*)_a), b((CvMAT*)_b), alpha(_alpha),
+ c((CvMAT*)_c), beta(_beta), t_abc(_t_abc) {}
+
+
+inline _CvMAT_ADD_::_CvMAT_ADD_( const CvMAT* _a, const CvMAT* _b, double _beta ) :
+ a((CvMAT*)_a), b((CvMAT*)_b), beta(_beta) {}
+
+
+inline _CvMAT_ADD_EX_::_CvMAT_ADD_EX_( const CvMAT* _a, double _alpha,
+ const CvMAT* _b, double _beta, double _gamma ) :
+ a((CvMAT*)_a), alpha(_alpha), b((CvMAT*)_b), beta(_beta), gamma(_gamma) {}
+
+
+inline _CvMAT_SCALE_::_CvMAT_SCALE_( const CvMAT* _a, double _alpha ) :
+ a((CvMAT*)_a), alpha(_alpha) {}
+
+
+inline _CvMAT_SCALE_SHIFT_::_CvMAT_SCALE_SHIFT_( const CvMAT* _a,
+ double _alpha, double _beta ) :
+ a((CvMAT*)_a), alpha(_alpha), beta(_beta) {}
+
+
+inline _CvMAT_LOGIC_::_CvMAT_LOGIC_( const CvMAT* _a, const CvMAT* _b,
+ _CvMAT_LOGIC_::Op _op, int _flags ) :
+ a((CvMAT*)_a), b((CvMAT*)_b), op(_op), flags(_flags) {}
+
+
+inline _CvMAT_UN_LOGIC_::_CvMAT_UN_LOGIC_( const CvMAT* _a, double _alpha,
+ _CvMAT_LOGIC_::Op _op, int _flags ) :
+ a((CvMAT*)_a), alpha(_alpha), op(_op), flags(_flags) {}
+
+
+inline _CvMAT_NOT_::_CvMAT_NOT_( const CvMAT* _a ) :
+ a((CvMAT*)_a) {}
+
+
+inline _CvMAT_DOT_OP_::_CvMAT_DOT_OP_( const CvMAT* _a, const CvMAT* _b,
+ int _op, double _alpha ) :
+ a(*_a), b((CvMAT*)_b), op(_op), alpha(_alpha) {}
+
+
+inline _CvMAT_SOLVE_::_CvMAT_SOLVE_( const CvMAT* _a, const CvMAT* _b, int _method ) :
+ a((CvMAT*)_a), b((CvMAT*)_b), method(_method) {}
+
+inline _CvMAT_CMP_::_CvMAT_CMP_( const CvMAT* _a, const CvMAT* _b, int _cmp_op ) :
+ a((CvMAT*)_a), b((CvMAT*)_b), alpha(0), cmp_op(_cmp_op) {}
+
+inline _CvMAT_CMP_::_CvMAT_CMP_( const CvMAT* _a, double _alpha, int _cmp_op ) :
+ a((CvMAT*)_a), b(0), alpha(_alpha), cmp_op(_cmp_op) {}
+
+/****************************************************************************************/
+/* proxy classes implementation. */
+/* part II. conversion to CvMAT */
+/****************************************************************************************/
+
+inline _CvMAT_T_::operator CvMAT() const
+{ return CvMAT( *this ); }
+
+inline _CvMAT_INV_::operator CvMAT() const
+{ return CvMAT( *this ); }
+
+inline _CvMAT_MUL_::operator CvMAT() const
+{ return CvMAT( *this ); }
+
+inline _CvMAT_SCALE_::operator CvMAT() const
+{ return CvMAT( *this ); }
+
+inline _CvMAT_SCALE_SHIFT_::operator CvMAT() const
+{ return CvMAT( *this ); }
+
+inline _CvMAT_ADD_::operator CvMAT() const
+{ return CvMAT( *this ); }
+
+inline _CvMAT_ADD_EX_::operator CvMAT() const
+{ return CvMAT( *this ); }
+
+inline _CvMAT_MUL_ADD_::operator CvMAT() const
+{ return CvMAT( *this ); }
+
+inline _CvMAT_LOGIC_::operator CvMAT() const
+{ return CvMAT( *this ); }
+
+inline _CvMAT_UN_LOGIC_::operator CvMAT() const
+{ return CvMAT( *this ); }
+
+inline _CvMAT_NOT_::operator CvMAT() const
+{ return CvMAT( *this ); }
+
+inline _CvMAT_DOT_OP_::operator CvMAT() const
+{ return CvMAT( *this ); }
+
+inline _CvMAT_SOLVE_::operator CvMAT() const
+{ return CvMAT( *this ); }
+
+inline _CvMAT_CMP_::operator CvMAT() const
+{ return CvMAT( *this ); }
+
+inline _CvMAT_CVT_::operator CvMAT() const
+{ return CvMAT(*this); }
+
+inline _CvMAT_COPY_::operator CvMAT() const
+{ return *a; }
+
+/****************************************************************************************/
+/* proxy classes implementation. */
+/* part III. custom overrided methods */
+/****************************************************************************************/
+
+inline _CvMAT_DOT_OP_ _CvMAT_SCALE_::mul( const CvMAT& mat ) const
+{ return _CvMAT_DOT_OP_( a, &mat, '*', alpha ); }
+
+inline _CvMAT_DOT_OP_ _CvMAT_SCALE_::mul( const _CvMAT_SCALE_& mat ) const
+{ return _CvMAT_DOT_OP_( a, mat.a, '*', alpha*mat.alpha ); }
+
+inline _CvMAT_DOT_OP_ _CvMAT_SCALE_::div( const CvMAT& mat ) const
+{ return _CvMAT_DOT_OP_( a, &mat, '/', alpha ); }
+
+inline _CvMAT_DOT_OP_ _CvMAT_SCALE_::div( const _CvMAT_SCALE_& mat ) const
+{ return _CvMAT_DOT_OP_( a, mat.a, '/', alpha/mat.alpha ); }
+
+inline _CvMAT_DOT_OP_ operator * ( const _CvMAT_DOT_OP_& dot_op, double alpha )
+{ return _CvMAT_DOT_OP_( &dot_op.a, dot_op.b, dot_op.op, dot_op.alpha * alpha ); }
+
+inline _CvMAT_DOT_OP_ operator * ( double alpha, const _CvMAT_DOT_OP_& dot_op )
+{ return _CvMAT_DOT_OP_( &dot_op.a, dot_op.b, dot_op.op, dot_op.alpha * alpha ); }
+
+inline _CvMAT_DOT_OP_ operator / ( double alpha, const CvMAT& mat )
+{ return _CvMAT_DOT_OP_( &mat, 0, '/', alpha ); }
+
+inline _CvMAT_DOT_OP_ operator / ( double alpha, const _CvMAT_SCALE_& mat )
+{ return _CvMAT_DOT_OP_( mat.a, 0, '/', alpha/mat.alpha ); }
+
+
+inline double _CvMAT_T_::det() const
+{ return a.det(); }
+
+inline double _CvMAT_T_::norm( int norm_type ) const
+{ return a.norm( norm_type ); }
+
+inline double _CvMAT_ADD_::norm( int norm_type ) const
+{
+ if( beta == -1 )
+ return cvNorm( a, b, norm_type );
+ else
+ return ((CvMAT)*this).norm( norm_type );
+}
+
+inline _CvMAT_DOT_OP_ _CvMAT_ADD_::abs() const
+{
+ if( beta == -1 )
+ return _CvMAT_DOT_OP_( a, b, 'a', 0 );
+ else
+ return ((CvMAT)*this).abs();
+}
+
+inline _CvMAT_DOT_OP_ _CvMAT_SCALE_SHIFT_::abs() const
+{
+ if( alpha == 1 )
+ return _CvMAT_DOT_OP_( a, 0, 'a', -beta );
+ else
+ return ((CvMAT)*this).abs();
+}
+
+#endif /* __cplusplus */
+
+#endif /*_CVMAT_HPP_*/
+
diff --git a/cvaux/include/cvvidsurv.hpp b/cvaux/include/cvvidsurv.hpp
new file mode 100644
index 0000000..373565d
--- /dev/null
+++ b/cvaux/include/cvvidsurv.hpp
@@ -0,0 +1,1324 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+
+#ifndef __CVVIDEOSURVEILLANCE_H__
+#define __CVVIDEOSURVEILLANCE_H__
+
+/* Turn off the functionality until cvaux/src/Makefile.am gets updated: */
+//#if _MSC_VER >= 1200
+
+#include <stdio.h>
+
+#if _MSC_VER >= 1200 || defined __BORLANDC__
+#define cv_stricmp stricmp
+#define cv_strnicmp strnicmp
+#elif defined __GNUC__
+#define cv_stricmp strcasecmp
+#define cv_strnicmp strncasecmp
+#else
+#error Do not know how to make case-insensitive string comparison on this platform
+#endif
+
+//struct DefParam;
+struct CvDefParam
+{
+ struct CvDefParam* next;
+ char* pName;
+ char* pComment;
+ double* pDouble;
+ double Double;
+ float* pFloat;
+ float Float;
+ int* pInt;
+ int Int;
+ char** pStr;
+ char* Str;
+};
+
+class CV_EXPORTS CvVSModule
+{
+private: /* Internal data: */
+ CvDefParam* m_pParamList;
+ char* m_pModuleTypeName;
+ char* m_pModuleName;
+ char* m_pNickName;
+protected:
+ int m_Wnd;
+public: /* Constructor and destructor: */
+ CvVSModule()
+ {
+ m_pNickName = NULL;
+ m_pParamList = NULL;
+ m_pModuleTypeName = NULL;
+ m_pModuleName = NULL;
+ m_Wnd = 0;
+ AddParam("DebugWnd",&m_Wnd);
+ }
+ virtual ~CvVSModule()
+ {
+ CvDefParam* p = m_pParamList;
+ for(;p;)
+ {
+ CvDefParam* pf = p;
+ p=p->next;
+ FreeParam(&pf);
+ }
+ m_pParamList=NULL;
+ if(m_pModuleTypeName)free(m_pModuleTypeName);
+ if(m_pModuleName)free(m_pModuleName);
+ }
+private: /* Internal functions: */
+ void FreeParam(CvDefParam** pp)
+ {
+ CvDefParam* p = pp[0];
+ if(p->Str)free(p->Str);
+ if(p->pName)free(p->pName);
+ if(p->pComment)free(p->pComment);
+ cvFree((void**)pp);
+ }
+ CvDefParam* NewParam(const char* name)
+ {
+ CvDefParam* pNew = (CvDefParam*)cvAlloc(sizeof(CvDefParam));
+ memset(pNew,0,sizeof(CvDefParam));
+ pNew->pName = strdup(name);
+ if(m_pParamList==NULL)
+ {
+ m_pParamList = pNew;
+ }
+ else
+ {
+ CvDefParam* p = m_pParamList;
+ for(;p->next;p=p->next);
+ p->next = pNew;
+ }
+ return pNew;
+ };
+
+ CvDefParam* GetParamPtr(int index)
+ {
+ CvDefParam* p = m_pParamList;
+ for(;index>0 && p;index--,p=p->next);
+ return p;
+ }
+ CvDefParam* GetParamPtr(const char* name)
+ {
+ CvDefParam* p = m_pParamList;
+ for(;p;p=p->next)
+ {
+ if(cv_stricmp(p->pName,name)==0) break;
+ }
+ return p;
+ }
+protected: /* INTERNAL INTERFACE */
+ int IsParam(const char* name)
+ {
+ return GetParamPtr(name)?1:0;
+ };
+ void AddParam(const char* name, double* pAddr)
+ {
+ NewParam(name)->pDouble = pAddr;
+ };
+ void AddParam(const char* name, float* pAddr)
+ {
+ NewParam(name)->pFloat=pAddr;
+ };
+ void AddParam(const char* name, int* pAddr)
+ {
+ NewParam(name)->pInt=pAddr;
+ };
+ void AddParam(const char* name, char** pAddr)
+ {
+ CvDefParam* pP = NewParam(name);
+ char* p = pAddr?pAddr[0]:NULL;
+ pP->pStr = pAddr?pAddr:&(pP->Str);
+ if(p)
+ {
+ pP->Str = strdup(p);
+ pP->pStr[0] = pP->Str;
+ }
+ };
+ void AddParam(const char* name)
+ {
+ CvDefParam* p = NewParam(name);
+ p->pDouble = &p->Double;
+ };
+ void CommentParam(const char* name, const char* pComment)
+ {
+ CvDefParam* p = GetParamPtr(name);
+ if(p)p->pComment = pComment ? strdup(pComment) : 0;
+ };
+ void SetTypeName(const char* name){m_pModuleTypeName = strdup(name);}
+ void SetModuleName(const char* name){m_pModuleName = strdup(name);}
+ void DelParam(const char* name)
+ {
+ CvDefParam* p = m_pParamList;
+ CvDefParam* pPrev = NULL;
+ for(;p;p=p->next)
+ {
+ if(cv_stricmp(p->pName,name)==0) break;
+ pPrev = p;
+ }
+ if(p)
+ {
+ if(pPrev)
+ {
+ pPrev->next = p->next;
+ }
+ else
+ {
+ m_pParamList = p->next;
+ }
+ FreeParam(&p);
+ }
+ }/* DelParam */
+
+public: /* EXTERNAL INTERFACE */
+ char* GetParamName(int index)
+ {
+ CvDefParam* p = GetParamPtr(index);
+ return p?p->pName:NULL;
+ }
+ char* GetParamComment(const char* name)
+ {
+ CvDefParam* p = GetParamPtr(name);
+ if(p && p->pComment) return p->pComment;
+ return NULL;
+ }
+ double GetParam(const char* name)
+ {
+ CvDefParam* p = GetParamPtr(name);
+ if(p)
+ {
+ if(p->pDouble) return p->pDouble[0];
+ if(p->pFloat) return p->pFloat[0];
+ if(p->pInt) return p->pInt[0];
+ }
+ return 0;
+ };
+
+ const char* GetParamStr(const char* name)
+ {
+ CvDefParam* p = GetParamPtr(name);
+ return p?p->Str:NULL;
+ }
+ void SetParam(const char* name, double val)
+ {
+ CvDefParam* p = m_pParamList;
+ for(;p;p=p->next)
+ {
+ if(cv_stricmp(p->pName,name) != 0) continue;
+ if(p->pDouble)p->pDouble[0] = val;
+ if(p->pFloat)p->pFloat[0] = (float)val;
+ if(p->pInt)p->pInt[0] = cvRound(val);
+ }
+ }
+ void SetParamStr(const char* name, const char* str)
+ {
+ CvDefParam* p = m_pParamList;
+ for(; p; p=p->next)
+ {
+ if(cv_stricmp(p->pName,name) != 0) continue;
+ if(p->pStr)
+ {
+ if(p->Str)free(p->Str);
+ p->Str = NULL;
+ if(str)p->Str = strdup(str);
+ p->pStr[0] = p->Str;
+ }
+ }
+ /* Convert to double and set: */
+ if(str) SetParam(name,atof(str));
+ }
+ void TransferParamsFromChild(CvVSModule* pM, char* prefix = NULL)
+ {
+ char tmp[1024];
+ char* FN = NULL;
+ int i;
+ for(i=0;;++i)
+ {
+ char* N = pM->GetParamName(i);
+ if(N == NULL) break;
+ FN = N;
+ if(prefix)
+ {
+ strcpy(tmp,prefix);
+ strcat(tmp,"_");
+ FN = strcat(tmp,N);
+ }
+
+ if(!IsParam(FN))
+ {
+ if(pM->GetParamStr(N))
+ {
+ AddParam(FN,(char**)NULL);
+ }
+ else
+ {
+ AddParam(FN);
+ }
+ }
+ if(pM->GetParamStr(N))
+ {
+ const char* val = pM->GetParamStr(N);
+ SetParamStr(FN,val);
+ }
+ else
+ {
+ double val = pM->GetParam(N);
+ SetParam(FN,val);
+ }
+ CommentParam(FN, pM->GetParamComment(N));
+ }/* transfer next param */
+ }/* Transfer params */
+
+ void TransferParamsToChild(CvVSModule* pM, char* prefix = NULL)
+ {
+ char tmp[1024];
+ int i;
+ for(i=0;;++i)
+ {
+ char* N = pM->GetParamName(i);
+ if(N == NULL) break;
+ if(prefix)
+ {
+ strcpy(tmp,prefix);
+ strcat(tmp,"_");
+ strcat(tmp,N);
+ }
+ else
+ {
+ strcpy(tmp,N);
+ }
+
+ if(IsParam(tmp))
+ {
+ if(GetParamStr(tmp))
+ pM->SetParamStr(N,GetParamStr(tmp));
+ else
+ pM->SetParam(N,GetParam(tmp));
+ }
+ }/* Transfer next parameter */
+ pM->ParamUpdate();
+ }/* Transfer params */
+
+ virtual void ParamUpdate(){};
+ const char* GetTypeName()
+ {
+ return m_pModuleTypeName;
+ }
+ int IsModuleTypeName(const char* name)
+ {
+ return m_pModuleTypeName?(cv_stricmp(m_pModuleTypeName,name)==0):0;
+ }
+ char* GetModuleName()
+ {
+ return m_pModuleName;
+ }
+ int IsModuleName(const char* name)
+ {
+ return m_pModuleName?(cv_stricmp(m_pModuleName,name)==0):0;
+ }
+ void SetNickName(const char* pStr)
+ {
+ if(m_pNickName)
+ free(m_pNickName);
+
+ m_pNickName = NULL;
+
+ if(pStr)
+ m_pNickName = strdup(pStr);
+ }
+ const char* GetNickName()
+ {
+ return m_pNickName ? m_pNickName : "unknown";
+ }
+ virtual void SaveState(CvFileStorage*){};
+ virtual void LoadState(CvFileStorage*, CvFileNode*){};
+
+ virtual void Release() = 0;
+};/* CvVMModule */
+void inline cvWriteStruct(CvFileStorage* fs, const char* name, void* addr, char* desc, int num=1)
+{
+ cvStartWriteStruct(fs,name,CV_NODE_SEQ|CV_NODE_FLOW);
+ cvWriteRawData(fs,addr,num,desc);
+ cvEndWriteStruct(fs);
+}
+void inline cvReadStructByName(CvFileStorage* fs, CvFileNode* node, const char* name, void* addr, char* desc)
+{
+ CvFileNode* pSeqNode = cvGetFileNodeByName(fs, node, name);
+ if(pSeqNode==NULL)
+ {
+ printf("WARNING!!! Can't read structure %s\n",name);
+ }
+ else
+ {
+ if(CV_NODE_IS_SEQ(pSeqNode->tag))
+ {
+ cvReadRawData( fs, pSeqNode, addr, desc );
+ }
+ else
+ {
+ printf("WARNING!!! Structure %s is not sequence and can not be read\n",name);
+ }
+ }
+}
+
+
+/* FOREGROUND DETECTOR INTERFACE */
+class CV_EXPORTS CvFGDetector: public CvVSModule
+{
+public:
+ virtual IplImage* GetMask() = 0;
+ /* Process current image: */
+ virtual void Process(IplImage* pImg) = 0;
+ /* Release foreground detector: */
+ virtual void Release() = 0;
+};
+inline void cvReleaseFGDetector(CvFGDetector** ppT )
+{
+ ppT[0]->Release();
+ ppT[0] = 0;
+}
+/* FOREGROUND DETECTOR INTERFACE */
+
+CV_EXPORTS CvFGDetector* cvCreateFGDetectorBase(int type, void *param);
+
+
+/* BLOB STRUCTURE*/
+struct CvBlob
+{
+ float x,y; /* blob position */
+ float w,h; /* blob sizes */
+ int ID; /* blob ID */
+};
+
+inline CvBlob cvBlob(float x,float y, float w, float h)
+{
+ CvBlob B = {x,y,w,h,0};
+ return B;
+}
+#define CV_BLOB_MINW 5
+#define CV_BLOB_MINH 5
+#define CV_BLOB_ID(pB) (((CvBlob*)(pB))->ID)
+#define CV_BLOB_CENTER(pB) cvPoint2D32f(((CvBlob*)(pB))->x,((CvBlob*)(pB))->y)
+#define CV_BLOB_X(pB) (((CvBlob*)(pB))->x)
+#define CV_BLOB_Y(pB) (((CvBlob*)(pB))->y)
+#define CV_BLOB_WX(pB) (((CvBlob*)(pB))->w)
+#define CV_BLOB_WY(pB) (((CvBlob*)(pB))->h)
+#define CV_BLOB_RX(pB) (0.5f*CV_BLOB_WX(pB))
+#define CV_BLOB_RY(pB) (0.5f*CV_BLOB_WY(pB))
+#define CV_BLOB_RECT(pB) cvRect(cvRound(((CvBlob*)(pB))->x-CV_BLOB_RX(pB)),cvRound(((CvBlob*)(pB))->y-CV_BLOB_RY(pB)),cvRound(CV_BLOB_WX(pB)),cvRound(CV_BLOB_WY(pB)))
+/* END BLOB STRUCTURE*/
+
+
+/* simple BLOBLIST */
+class CV_EXPORTS CvBlobSeq
+{
+public:
+ CvBlobSeq(int BlobSize = sizeof(CvBlob))
+ {
+ m_pMem = cvCreateMemStorage();
+ m_pSeq = cvCreateSeq(0,sizeof(CvSeq),BlobSize,m_pMem);
+ strcpy(m_pElemFormat,"ffffi");
+ }
+ virtual ~CvBlobSeq()
+ {
+ cvReleaseMemStorage(&m_pMem);
+ };
+ virtual CvBlob* GetBlob(int BlobIndex)
+ {
+ return (CvBlob*)cvGetSeqElem(m_pSeq,BlobIndex);
+ };
+ virtual CvBlob* GetBlobByID(int BlobID)
+ {
+ int i;
+ for(i=0; i<m_pSeq->total; ++i)
+ if(BlobID == CV_BLOB_ID(GetBlob(i)))
+ return GetBlob(i);
+ return NULL;
+ };
+ virtual void DelBlob(int BlobIndex)
+ {
+ cvSeqRemove(m_pSeq,BlobIndex);
+ };
+ virtual void DelBlobByID(int BlobID)
+ {
+ int i;
+ for(i=0; i<m_pSeq->total; ++i)
+ {
+ if(BlobID == CV_BLOB_ID(GetBlob(i)))
+ {
+ DelBlob(i);
+ return;
+ }
+ }
+ };
+ virtual void Clear()
+ {
+ cvClearSeq(m_pSeq);
+ };
+ virtual void AddBlob(CvBlob* pB)
+ {
+ cvSeqPush(m_pSeq,pB);
+ };
+ virtual int GetBlobNum()
+ {
+ return m_pSeq->total;
+ };
+ virtual void Write(CvFileStorage* fs, const char* name)
+ {
+ const char* attr[] = {"dt",m_pElemFormat,NULL};
+ if(fs)
+ {
+ cvWrite(fs,name,m_pSeq,cvAttrList(attr,NULL));
+ }
+ }
+ virtual void Load(CvFileStorage* fs, CvFileNode* node)
+ {
+ if(fs==NULL) return;
+ CvSeq* pSeq = (CvSeq*)cvRead(fs, node);
+ if(pSeq)
+ {
+ int i;
+ cvClearSeq(m_pSeq);
+ for(i=0;i<pSeq->total;++i)
+ {
+ void* pB = cvGetSeqElem( pSeq, i );
+ cvSeqPush( m_pSeq, pB );
+ }
+ }
+ }
+ void AddFormat(char* str){strcat(m_pElemFormat,str);}
+protected:
+ CvMemStorage* m_pMem;
+ CvSeq* m_pSeq;
+ char m_pElemFormat[1024];
+};
+/* simple BLOBLIST */
+
+
+/* simple TRACKLIST */
+struct CvBlobTrack
+{
+ int TrackID;
+ int StartFrame;
+ CvBlobSeq* pBlobSeq;
+};
+
+class CV_EXPORTS CvBlobTrackSeq
+{
+public:
+ CvBlobTrackSeq(int TrackSize = sizeof(CvBlobTrack))
+ {
+ m_pMem = cvCreateMemStorage();
+ m_pSeq = cvCreateSeq(0,sizeof(CvSeq),TrackSize,m_pMem);
+ }
+ virtual ~CvBlobTrackSeq()
+ {
+ Clear();
+ cvReleaseMemStorage(&m_pMem);
+ };
+ virtual CvBlobTrack* GetBlobTrack(int TrackIndex)
+ {
+ return (CvBlobTrack*)cvGetSeqElem(m_pSeq,TrackIndex);
+ };
+ virtual CvBlobTrack* GetBlobTrackByID(int TrackID)
+ {
+ int i;
+ for(i=0; i<m_pSeq->total; ++i)
+ {
+ CvBlobTrack* pP = GetBlobTrack(i);
+ if(pP && pP->TrackID == TrackID)
+ return pP;
+ }
+ return NULL;
+ };
+ virtual void DelBlobTrack(int TrackIndex)
+ {
+ CvBlobTrack* pP = GetBlobTrack(TrackIndex);
+ if(pP && pP->pBlobSeq) delete pP->pBlobSeq;
+ cvSeqRemove(m_pSeq,TrackIndex);
+ };
+ virtual void DelBlobTrackByID(int TrackID)
+ {
+ int i;
+ for(i=0; i<m_pSeq->total; ++i)
+ {
+ CvBlobTrack* pP = GetBlobTrack(i);
+ if(TrackID == pP->TrackID)
+ {
+ DelBlobTrack(i);
+ return;
+ }
+ }
+ };
+ virtual void Clear()
+ {
+ int i;
+ for(i=GetBlobTrackNum();i>0;i--)
+ {
+ DelBlobTrack(i-1);
+ }
+ cvClearSeq(m_pSeq);
+ };
+ virtual void AddBlobTrack(int TrackID, int StartFrame = 0)
+ {
+ CvBlobTrack N;
+ N.TrackID = TrackID;
+ N.StartFrame = StartFrame;
+ N.pBlobSeq = new CvBlobSeq;
+ cvSeqPush(m_pSeq,&N);
+ };
+ virtual int GetBlobTrackNum()
+ {
+ return m_pSeq->total;
+ };
+protected:
+ CvMemStorage* m_pMem;
+ CvSeq* m_pSeq;
+};
+
+/* simple TRACKLIST */
+
+
+/* BLOB DETECTOR INTERFACE */
+class CV_EXPORTS CvBlobDetector: public CvVSModule
+{
+public:
+ /* Try to detect new blob entrance based on foreground mask. */
+ /* pFGMask - image of foreground mask */
+ /* pNewBlob - pointer to CvBlob structure which will be filled if new blob entrance detected */
+ /* pOldBlobList - pointer to blob list which already exist on image */
+ virtual int DetectNewBlob(IplImage* pImg, IplImage* pImgFG, CvBlobSeq* pNewBlobList, CvBlobSeq* pOldBlobList) = 0;
+ /* release blob detector */
+ virtual void Release()=0;
+};
+/* Release any blob detector: */
+inline void cvReleaseBlobDetector(CvBlobDetector** ppBD)
+{
+ ppBD[0]->Release();
+ ppBD[0] = NULL;
+}
+/* END BLOB DETECTOR INTERFACE */
+
+/* Declarations of constructors of implemented modules: */
+CV_EXPORTS CvBlobDetector* cvCreateBlobDetectorSimple();
+CV_EXPORTS CvBlobDetector* cvCreateBlobDetectorCC();
+
+
+struct CV_EXPORTS CvDetectedBlob : public CvBlob
+{
+ float response;
+};
+
+CV_INLINE CvDetectedBlob cvDetectedBlob( float x, float y, float w, float h, int ID = 0, float response = 0.0F )
+{
+ CvDetectedBlob b;
+ b.x = x; b.y = y; b.w = w; b.h = h; b.ID = ID; b.response = response;
+ return b;
+}
+
+
+class CV_EXPORTS CvObjectDetector
+{
+public:
+ CvObjectDetector( const char* /*detector_file_name*/ = 0 ) {};
+
+ ~CvObjectDetector() {};
+
+ /*
+ * Release the current detector and load new detector from file
+ * (if detector_file_name is not 0)
+ * Return true on success:
+ */
+ bool Load( const char* /*detector_file_name*/ = 0 ) { return false; }
+
+ /* Return min detector window size: */
+ CvSize GetMinWindowSize() const { return cvSize(0,0); }
+
+ /* Return max border: */
+ int GetMaxBorderSize() const { return 0; }
+
+ /*
+ * Detect the object on the image and push the detected
+ * blobs into <detected_blob_seq> which must be the sequence of <CvDetectedBlob>s
+ */
+ void Detect( const CvArr* /*img*/, /* out */ CvBlobSeq* /*detected_blob_seq*/ = 0 ) {};
+
+protected:
+ class CvObjectDetectorImpl* impl;
+};
+
+
+CV_INLINE CvRect cvRectIntersection( const CvRect r1, const CvRect r2 )
+{
+ CvRect r = cvRect( MAX(r1.x, r2.x), MAX(r1.y, r2.y), 0, 0 );
+
+ r.width = MIN(r1.x + r1.width, r2.x + r2.width) - r.x;
+ r.height = MIN(r1.y + r1.height, r2.y + r2.height) - r.y;
+
+ return r;
+}
+
+
+/*
+ * CvImageDrawer
+ *
+ * Draw on an image the specified ROIs from the source image and
+ * given blobs as ellipses or rectangles:
+ */
+
+struct CvDrawShape
+{
+ enum {RECT, ELLIPSE} shape;
+ CvScalar color;
+};
+
+/*extern const CvDrawShape icv_shape[] =
+{
+ { CvDrawShape::ELLIPSE, CV_RGB(255,0,0) },
+ { CvDrawShape::ELLIPSE, CV_RGB(0,255,0) },
+ { CvDrawShape::ELLIPSE, CV_RGB(0,0,255) },
+ { CvDrawShape::ELLIPSE, CV_RGB(255,255,0) },
+ { CvDrawShape::ELLIPSE, CV_RGB(0,255,255) },
+ { CvDrawShape::ELLIPSE, CV_RGB(255,0,255) }
+};*/
+
+class CV_EXPORTS CvImageDrawer
+{
+public:
+ CvImageDrawer() : m_image(0) {}
+ ~CvImageDrawer() { cvReleaseImage( &m_image ); }
+ void SetShapes( const CvDrawShape* shapes, int num );
+ /* <blob_seq> must be the sequence of <CvDetectedBlob>s */
+ IplImage* Draw( const CvArr* src, CvBlobSeq* blob_seq = 0, const CvSeq* roi_seq = 0 );
+ IplImage* GetImage() { return m_image; }
+protected:
+ //static const int MAX_SHAPES = sizeof(icv_shape) / sizeof(icv_shape[0]);;
+
+ IplImage* m_image;
+ CvDrawShape m_shape[16];
+};
+
+
+
+/* Trajectory generation module: */
+class CV_EXPORTS CvBlobTrackGen: public CvVSModule
+{
+public:
+ virtual void SetFileName(char* pFileName) = 0;
+ virtual void AddBlob(CvBlob* pBlob) = 0;
+ virtual void Process(IplImage* pImg = NULL, IplImage* pFG = NULL) = 0;
+ virtual void Release() = 0;
+};
+
+inline void cvReleaseBlobTrackGen(CvBlobTrackGen** pBTGen)
+{
+ if(*pBTGen)(*pBTGen)->Release();
+ *pBTGen = 0;
+}
+
+/* Declarations of constructors of implemented modules: */
+CV_EXPORTS CvBlobTrackGen* cvCreateModuleBlobTrackGen1();
+CV_EXPORTS CvBlobTrackGen* cvCreateModuleBlobTrackGenYML();
+
+
+
+/* BLOB TRACKER INTERFACE */
+class CV_EXPORTS CvBlobTracker: public CvVSModule
+{
+public:
+ CvBlobTracker(){SetTypeName("BlobTracker");};
+
+ /* Add new blob to track it and assign to this blob personal ID */
+ /* pBlob - pointer to structure with blob parameters (ID is ignored)*/
+ /* pImg - current image */
+ /* pImgFG - current foreground mask */
+ /* Return pointer to new added blob: */
+ virtual CvBlob* AddBlob(CvBlob* pBlob, IplImage* pImg, IplImage* pImgFG = NULL ) = 0;
+
+ /* Return number of currently tracked blobs: */
+ virtual int GetBlobNum() = 0;
+
+ /* Return pointer to specified by index blob: */
+ virtual CvBlob* GetBlob(int BlobIndex) = 0;
+
+ /* Delete blob by its index: */
+ virtual void DelBlob(int BlobIndex) = 0;
+
+ /* Process current image and track all existed blobs: */
+ virtual void Process(IplImage* pImg, IplImage* pImgFG = NULL) = 0;
+
+ /* Release blob tracker: */
+ virtual void Release() = 0;
+
+
+ /* Process one blob (for multi hypothesis tracing): */
+ virtual void ProcessBlob(int BlobIndex, CvBlob* pBlob, IplImage* /*pImg*/, IplImage* /*pImgFG*/ = NULL)
+ {
+ CvBlob* pB;
+ int ID = 0;
+ assert(pBlob);
+ //pBlob->ID;
+ pB = GetBlob(BlobIndex);
+ if(pB)
+ pBlob[0] = pB[0];
+ pBlob->ID = ID;
+ };
+
+ /* Get confidence/wieght/probability (0-1) for blob: */
+ virtual double GetConfidence(int /*BlobIndex*/, CvBlob* /*pBlob*/, IplImage* /*pImg*/, IplImage* /*pImgFG*/ = NULL)
+ {
+ return 1;
+ };
+
+ virtual double GetConfidenceList(CvBlobSeq* pBlobList, IplImage* pImg, IplImage* pImgFG = NULL)
+ {
+ int b,bN = pBlobList->GetBlobNum();
+ double W = 1;
+ for(b=0;b<bN;++b)
+ {
+ CvBlob* pB = pBlobList->GetBlob(b);
+ int BI = GetBlobIndexByID(pB->ID);
+ W *= GetConfidence(BI,pB,pImg,pImgFG);
+ }
+ return W;
+ };
+
+ virtual void UpdateBlob(int /*BlobIndex*/, CvBlob* /*pBlob*/, IplImage* /*pImg*/, IplImage* /*pImgFG*/ = NULL){};
+
+ /* Update all blob models: */
+ virtual void Update(IplImage* pImg, IplImage* pImgFG = NULL)
+ {
+ int i;
+ for(i=GetBlobNum();i>0;i--)
+ {
+ CvBlob* pB=GetBlob(i-1);
+ UpdateBlob(i-1, pB, pImg, pImgFG);
+ }
+
+ };
+
+ /* Return pointer to blob by its unique ID: */
+ virtual int GetBlobIndexByID(int BlobID)
+ {
+ int i;
+ for(i=GetBlobNum();i>0;i--)
+ {
+ CvBlob* pB=GetBlob(i-1);
+ if(CV_BLOB_ID(pB) == BlobID) return i-1;
+ }
+ return -1;
+ };
+
+ /* Return pointer to blob by its unique ID: */
+ virtual CvBlob* GetBlobByID(int BlobID){return GetBlob(GetBlobIndexByID(BlobID));};
+
+ /* Delete blob by its ID: */
+ virtual void DelBlobByID(int BlobID){DelBlob(GetBlobIndexByID(BlobID));};
+
+ /* Set new parameters for specified (by index) blob: */
+ virtual void SetBlob(int /*BlobIndex*/, CvBlob* /*pBlob*/){};
+
+ /* Set new parameters for specified (by ID) blob: */
+ virtual void SetBlobByID(int BlobID, CvBlob* pBlob)
+ {
+ SetBlob(GetBlobIndexByID(BlobID),pBlob);
+ };
+
+ /* =============== MULTI HYPOTHESIS INTERFACE ================== */
+
+ /* Return number of position hyposetis of currently tracked blob: */
+ virtual int GetBlobHypNum(int /*BlobIdx*/){return 1;};
+
+ /* Return pointer to specified blob hypothesis by index blob: */
+ virtual CvBlob* GetBlobHyp(int BlobIndex, int /*hypothesis*/){return GetBlob(BlobIndex);};
+
+ /* Set new parameters for specified (by index) blob hyp
+ * (can be called several times for each hyp ):
+ */
+ virtual void SetBlobHyp(int /*BlobIndex*/, CvBlob* /*pBlob*/){};
+};
+inline void cvReleaseBlobTracker(CvBlobTracker**ppT )
+{
+ ppT[0]->Release();
+ ppT[0] = 0;
+}
+/* BLOB TRACKER INTERFACE */
+
+/*BLOB TRACKER ONE INTERFACE */
+class CV_EXPORTS CvBlobTrackerOne:public CvVSModule
+{
+public:
+ virtual void Init(CvBlob* pBlobInit, IplImage* pImg, IplImage* pImgFG = NULL) = 0;
+ virtual CvBlob* Process(CvBlob* pBlobPrev, IplImage* pImg, IplImage* pImgFG = NULL) = 0;
+ virtual void Release() = 0;
+
+ /* Non-required methods: */
+ virtual void SkipProcess(CvBlob* /*pBlobPrev*/, IplImage* /*pImg*/, IplImage* /*pImgFG*/ = NULL){};
+ virtual void Update(CvBlob* /*pBlob*/, IplImage* /*pImg*/, IplImage* /*pImgFG*/ = NULL){};
+ virtual void SetCollision(int /*CollisionFlag*/){}; /* call in case of blob collision situation*/
+ virtual double GetConfidence(CvBlob* /*pBlob*/, IplImage* /*pImg*/,
+ IplImage* /*pImgFG*/ = NULL, IplImage* /*pImgUnusedReg*/ = NULL)
+ {
+ return 1;
+ };
+};
+inline void cvReleaseBlobTrackerOne(CvBlobTrackerOne **ppT )
+{
+ ppT[0]->Release();
+ ppT[0] = 0;
+}
+CV_EXPORTS CvBlobTracker* cvCreateBlobTrackerList(CvBlobTrackerOne* (*create)());
+/*BLOB TRACKER ONE INTERFACE */
+
+/* Declarations of constructors of implemented modules: */
+
+/* Some declarations for specific MeanShift tracker: */
+#define PROFILE_EPANECHNIKOV 0
+#define PROFILE_DOG 1
+struct CvBlobTrackerParamMS
+{
+ int noOfSigBits;
+ int appearance_profile;
+ int meanshift_profile;
+ float sigma;
+};
+
+CV_EXPORTS CvBlobTracker* cvCreateBlobTrackerMS1(CvBlobTrackerParamMS* param);
+CV_EXPORTS CvBlobTracker* cvCreateBlobTrackerMS2(CvBlobTrackerParamMS* param);
+CV_EXPORTS CvBlobTracker* cvCreateBlobTrackerMS1ByList();
+
+/* Some declarations for specific Likelihood tracker: */
+struct CvBlobTrackerParamLH
+{
+ int HistType; /* see Prob.h */
+ int ScaleAfter;
+};
+
+/* Without scale optimization: */
+CV_EXPORTS CvBlobTracker* cvCreateBlobTrackerLHR(CvBlobTrackerParamLH* /*param*/ = NULL);
+
+/* With scale optimization: */
+CV_EXPORTS CvBlobTracker* cvCreateBlobTrackerLHRS(CvBlobTrackerParamLH* /*param*/ = NULL);
+
+/* Simple blob tracker based on connected component tracking: */
+CV_EXPORTS CvBlobTracker* cvCreateBlobTrackerCC();
+
+/* Connected component tracking and mean-shift particle filter collion-resolver: */
+CV_EXPORTS CvBlobTracker* cvCreateBlobTrackerCCMSPF();
+
+/* Blob tracker that integrates meanshift and connected components: */
+CV_EXPORTS CvBlobTracker* cvCreateBlobTrackerMSFG();
+CV_EXPORTS CvBlobTracker* cvCreateBlobTrackerMSFGS();
+
+/* Meanshift without connected-components */
+CV_EXPORTS CvBlobTracker* cvCreateBlobTrackerMS();
+
+/* Particle filtering via Bhattacharya coefficient, which */
+/* is roughly the dot-product of two probability densities. */
+/* See: Real-Time Tracking of Non-Rigid Objects using Mean Shift */
+/* Comanicius, Ramesh, Meer, 2000, 8p */
+/* http://citeseer.ist.psu.edu/321441.html */
+CV_EXPORTS CvBlobTracker* cvCreateBlobTrackerMSPF();
+
+/* =========== tracker integrators trackers =============*/
+
+/* Integrator based on Particle Filtering method: */
+//CV_EXPORTS CvBlobTracker* cvCreateBlobTrackerIPF();
+
+/* Rule based integrator: */
+//CV_EXPORTS CvBlobTracker* cvCreateBlobTrackerIRB();
+
+/* Integrator based on data fusion using particle filtering: */
+//CV_EXPORTS CvBlobTracker* cvCreateBlobTrackerIPFDF();
+
+
+
+
+/* Trajectory postprocessing module: */
+class CV_EXPORTS CvBlobTrackPostProc: public CvVSModule
+{
+public:
+ virtual void AddBlob(CvBlob* pBlob) = 0;
+ virtual void Process() = 0;
+ virtual int GetBlobNum() = 0;
+ virtual CvBlob* GetBlob(int index) = 0;
+ virtual void Release() = 0;
+
+ /* Additional functionality: */
+ virtual CvBlob* GetBlobByID(int BlobID)
+ {
+ int i;
+ for(i=GetBlobNum();i>0;i--)
+ {
+ CvBlob* pB=GetBlob(i-1);
+ if(pB->ID==BlobID) return pB;
+ }
+ return NULL;
+ };
+};
+
+inline void cvReleaseBlobTrackPostProc(CvBlobTrackPostProc** pBTPP)
+{
+ if(pBTPP == NULL) return;
+ if(*pBTPP)(*pBTPP)->Release();
+ *pBTPP = 0;
+}
+
+/* Trajectory generation module: */
+class CV_EXPORTS CvBlobTrackPostProcOne: public CvVSModule
+{
+public:
+ virtual CvBlob* Process(CvBlob* pBlob) = 0;
+ virtual void Release() = 0;
+};
+
+/* Create blob tracking post processing module based on simle module: */
+CV_EXPORTS CvBlobTrackPostProc* cvCreateBlobTrackPostProcList(CvBlobTrackPostProcOne* (*create)());
+
+
+/* Declarations of constructors of implemented modules: */
+CV_EXPORTS CvBlobTrackPostProc* cvCreateModuleBlobTrackPostProcKalman();
+CV_EXPORTS CvBlobTrackPostProc* cvCreateModuleBlobTrackPostProcTimeAverRect();
+CV_EXPORTS CvBlobTrackPostProc* cvCreateModuleBlobTrackPostProcTimeAverExp();
+
+
+/* PREDICTORS */
+/* blob PREDICTOR */
+class CvBlobTrackPredictor: public CvVSModule
+{
+public:
+ virtual CvBlob* Predict() = 0;
+ virtual void Update(CvBlob* pBlob) = 0;
+ virtual void Release() = 0;
+};
+CV_EXPORTS CvBlobTrackPredictor* cvCreateModuleBlobTrackPredictKalman();
+
+
+
+/* Trajectory analyser module: */
+class CV_EXPORTS CvBlobTrackAnalysis: public CvVSModule
+{
+public:
+ virtual void AddBlob(CvBlob* pBlob) = 0;
+ virtual void Process(IplImage* pImg, IplImage* pFG) = 0;
+ virtual float GetState(int BlobID) = 0;
+ /* return 0 if trajectory is normal
+ return >0 if trajectory abnormal */
+ virtual char* GetStateDesc(int /*BlobID*/){return NULL;};
+ virtual void SetFileName(char* /*DataBaseName*/){};
+ virtual void Release() = 0;
+};
+
+
+inline void cvReleaseBlobTrackAnalysis(CvBlobTrackAnalysis** pBTPP)
+{
+ if(pBTPP == NULL) return;
+ if(*pBTPP)(*pBTPP)->Release();
+ *pBTPP = 0;
+}
+
+/* Feature-vector generation module: */
+class CV_EXPORTS CvBlobTrackFVGen : public CvVSModule
+{
+public:
+ virtual void AddBlob(CvBlob* pBlob) = 0;
+ virtual void Process(IplImage* pImg, IplImage* pFG) = 0;
+ virtual void Release() = 0;
+ virtual int GetFVSize() = 0;
+ virtual int GetFVNum() = 0;
+ virtual float* GetFV(int index, int* pFVID) = 0; /* Returns pointer to FV, if return 0 then FV not created */
+ virtual float* GetFVVar(){return NULL;}; /* Returns pointer to array of variation of values of FV, if returns 0 then FVVar does not exist. */
+ virtual float* GetFVMin() = 0; /* Returns pointer to array of minimal values of FV, if returns 0 then FVrange does not exist */
+ virtual float* GetFVMax() = 0; /* Returns pointer to array of maximal values of FV, if returns 0 then FVrange does not exist */
+};
+
+
+/* Trajectory Analyser module: */
+class CV_EXPORTS CvBlobTrackAnalysisOne
+{
+public:
+ virtual ~CvBlobTrackAnalysisOne() {};
+ virtual int Process(CvBlob* pBlob, IplImage* pImg, IplImage* pFG) = 0;
+ /* return 0 if trajectory is normal
+ return >0 if trajectory abnormal */
+ virtual void Release() = 0;
+};
+
+/* Create blob tracking post processing module based on simle module: */
+CV_EXPORTS CvBlobTrackAnalysis* cvCreateBlobTrackAnalysisList(CvBlobTrackAnalysisOne* (*create)());
+
+/* Declarations of constructors of implemented modules: */
+
+/* Based on histogram analysis of 2D FV (x,y): */
+CV_EXPORTS CvBlobTrackAnalysis* cvCreateModuleBlobTrackAnalysisHistP();
+
+/* Based on histogram analysis of 4D FV (x,y,vx,vy): */
+CV_EXPORTS CvBlobTrackAnalysis* cvCreateModuleBlobTrackAnalysisHistPV();
+
+/* Based on histogram analysis of 5D FV (x,y,vx,vy,state): */
+CV_EXPORTS CvBlobTrackAnalysis* cvCreateModuleBlobTrackAnalysisHistPVS();
+
+/* Based on histogram analysis of 4D FV (startpos,stoppos): */
+CV_EXPORTS CvBlobTrackAnalysis* cvCreateModuleBlobTrackAnalysisHistSS();
+
+
+
+/* Based on SVM classifier analysis of 2D FV (x,y): */
+//CV_EXPORTS CvBlobTrackAnalysis* cvCreateModuleBlobTrackAnalysisSVMP();
+
+/* Based on SVM classifier analysis of 4D FV (x,y,vx,vy): */
+//CV_EXPORTS CvBlobTrackAnalysis* cvCreateModuleBlobTrackAnalysisSVMPV();
+
+/* Based on SVM classifier analysis of 5D FV (x,y,vx,vy,state): */
+//CV_EXPORTS CvBlobTrackAnalysis* cvCreateModuleBlobTrackAnalysisSVMPVS();
+
+/* Based on SVM classifier analysis of 4D FV (startpos,stoppos): */
+//CV_EXPORTS CvBlobTrackAnalysis* cvCreateModuleBlobTrackAnalysisSVMSS();
+
+/* Track analysis based on distance between tracks: */
+CV_EXPORTS CvBlobTrackAnalysis* cvCreateModuleBlobTrackAnalysisTrackDist();
+
+/* Analyzer based on reation Road and height map: */
+//CV_EXPORTS CvBlobTrackAnalysis* cvCreateModuleBlobTrackAnalysis3DRoadMap();
+
+/* Analyzer that makes OR decision using set of analyzers: */
+CV_EXPORTS CvBlobTrackAnalysis* cvCreateModuleBlobTrackAnalysisIOR();
+
+/* Estimator of human height: */
+class CV_EXPORTS CvBlobTrackAnalysisHeight: public CvBlobTrackAnalysis
+{
+public:
+ virtual double GetHeight(CvBlob* pB) = 0;
+};
+//CV_EXPORTS CvBlobTrackAnalysisHeight* cvCreateModuleBlobTrackAnalysisHeightScale();
+
+
+
+/* AUTO BLOB TRACKER INTERFACE -- pipeline of 3 modules: */
+class CV_EXPORTS CvBlobTrackerAuto: public CvVSModule
+{
+public:
+ virtual void Process(IplImage* pImg, IplImage* pMask = NULL) = 0;
+ virtual CvBlob* GetBlob(int index) = 0;
+ virtual CvBlob* GetBlobByID(int ID) = 0;
+ virtual int GetBlobNum() = 0;
+ virtual IplImage* GetFGMask(){return NULL;};
+ virtual float GetState(int BlobID) = 0;
+ virtual char* GetStateDesc(int BlobID) = 0;
+ /* return 0 if trajectory is normal;
+ * return >0 if trajectory abnormal. */
+ virtual void Release() = 0;
+};
+inline void cvReleaseBlobTrackerAuto(CvBlobTrackerAuto** ppT)
+{
+ ppT[0]->Release();
+ ppT[0] = 0;
+}
+/* END AUTO BLOB TRACKER INTERFACE */
+
+
+/* Constructor functions and data for specific BlobTRackerAuto modules: */
+
+/* Parameters of blobtracker auto ver1: */
+struct CvBlobTrackerAutoParam1
+{
+ int FGTrainFrames; /* Number of frames needed for FG (foreground) detector to train. */
+
+ CvFGDetector* pFG; /* FGDetector module. If this field is NULL the Process FG mask is used. */
+
+ CvBlobDetector* pBD; /* Selected blob detector module. */
+ /* If this field is NULL default blobdetector module will be created. */
+
+ CvBlobTracker* pBT; /* Selected blob tracking module. */
+ /* If this field is NULL default blobtracker module will be created. */
+
+ CvBlobTrackGen* pBTGen; /* Selected blob trajectory generator. */
+ /* If this field is NULL no generator is used. */
+
+ CvBlobTrackPostProc* pBTPP; /* Selected blob trajectory postprocessing module. */
+ /* If this field is NULL no postprocessing is done. */
+
+ int UsePPData;
+
+ CvBlobTrackAnalysis* pBTA; /* Selected blob trajectory analysis module. */
+ /* If this field is NULL no track analysis is done. */
+};
+
+/* Create blob tracker auto ver1: */
+CV_EXPORTS CvBlobTrackerAuto* cvCreateBlobTrackerAuto1(CvBlobTrackerAutoParam1* param = NULL);
+
+/* Simple loader for many auto trackers by its type : */
+inline CvBlobTrackerAuto* cvCreateBlobTrackerAuto(int type, void* param)
+{
+ if(type == 0) return cvCreateBlobTrackerAuto1((CvBlobTrackerAutoParam1*)param);
+ return 0;
+}
+
+
+
+struct CvTracksTimePos
+{
+ int len1,len2;
+ int beg1,beg2;
+ int end1,end2;
+ int comLen; //common length for two tracks
+ int shift1,shift2;
+};
+
+/*CV_EXPORTS int cvCompareTracks( CvBlobTrackSeq *groundTruth,
+ CvBlobTrackSeq *result,
+ FILE *file);*/
+
+
+/* Constructor functions: */
+
+CV_EXPORTS void cvCreateTracks_One(CvBlobTrackSeq *TS);
+CV_EXPORTS void cvCreateTracks_Same(CvBlobTrackSeq *TS1, CvBlobTrackSeq *TS2);
+CV_EXPORTS void cvCreateTracks_AreaErr(CvBlobTrackSeq *TS1, CvBlobTrackSeq *TS2, int addW, int addH);
+
+
+/* HIST API */
+class CV_EXPORTS CvProb
+{
+public:
+ virtual ~CvProb() {};
+
+ /* Calculate probability value: */
+ virtual double Value(int* /*comp*/, int /*x*/ = 0, int /*y*/ = 0){return -1;};
+
+ /* Update histograpp Pnew = (1-W)*Pold + W*Padd*/
+ /* W weight of new added prob */
+ /* comps - matrix of new fetature vectors used to update prob */
+ virtual void AddFeature(float W, int* comps, int x =0, int y = 0) = 0;
+ virtual void Scale(float factor = 0, int x = -1, int y = -1) = 0;
+ virtual void Release() = 0;
+};
+inline void cvReleaseProb(CvProb** ppProb){ppProb[0]->Release();ppProb[0]=NULL;}
+/* HIST API */
+
+/* Some Prob: */
+CV_EXPORTS CvProb* cvCreateProbS(int dim, CvSize size, int sample_num);
+CV_EXPORTS CvProb* cvCreateProbMG(int dim, CvSize size, int sample_num);
+CV_EXPORTS CvProb* cvCreateProbMG2(int dim, CvSize size, int sample_num);
+CV_EXPORTS CvProb* cvCreateProbHist(int dim, CvSize size);
+
+#define CV_BT_HIST_TYPE_S 0
+#define CV_BT_HIST_TYPE_MG 1
+#define CV_BT_HIST_TYPE_MG2 2
+#define CV_BT_HIST_TYPE_H 3
+inline CvProb* cvCreateProb(int type, int dim, CvSize size = cvSize(1,1), void* /*param*/ = NULL)
+{
+ if(type == CV_BT_HIST_TYPE_S) return cvCreateProbS(dim, size, -1);
+ if(type == CV_BT_HIST_TYPE_MG) return cvCreateProbMG(dim, size, -1);
+ if(type == CV_BT_HIST_TYPE_MG2) return cvCreateProbMG2(dim, size, -1);
+ if(type == CV_BT_HIST_TYPE_H) return cvCreateProbHist(dim, size);
+ return NULL;
+}
+
+
+
+/* Noise type definitions: */
+#define CV_NOISE_NONE 0
+#define CV_NOISE_GAUSSIAN 1
+#define CV_NOISE_UNIFORM 2
+#define CV_NOISE_SPECKLE 3
+#define CV_NOISE_SALT_AND_PEPPER 4
+
+/* Add some noise to image: */
+/* pImg - (input) image without noise */
+/* pImg - (output) image with noise */
+/* noise_type - type of added noise */
+/* CV_NOISE_GAUSSIAN - pImg += n , n - is gaussian noise with Ampl standart deviation */
+/* CV_NOISE_UNIFORM - pImg += n , n - is uniform noise with Ampl standart deviation */
+/* CV_NOISE_SPECKLE - pImg += n*pImg , n - is gaussian noise with Ampl standart deviation */
+/* CV_NOISE_SALT_AND_PAPPER - pImg = pImg with blacked and whited pixels,
+ Ampl is density of brocken pixels (0-there are not broken pixels, 1 - all pixels are broken)*/
+/* Ampl - "amplitude" of noise */
+CV_EXPORTS void cvAddNoise(IplImage* pImg, int noise_type, double Ampl, CvRandState* rnd_state = NULL);
+
+/*================== GENERATOR OF TEST VIDEO SEQUENCE ===================== */
+typedef void CvTestSeq;
+
+/* pConfigfile - Name of file (yml or xml) with description of test sequence */
+/* videos - array of names of test videos described in "pConfigfile" file */
+/* numvideos - size of "videos" array */
+CV_EXPORTS CvTestSeq* cvCreateTestSeq(char* pConfigfile, char** videos, int numvideo, float Scale = 1, int noise_type = CV_NOISE_NONE, double noise_ampl = 0);
+CV_EXPORTS void cvReleaseTestSeq(CvTestSeq** ppTestSeq);
+
+/* Generate next frame from test video seq and return pointer to it: */
+CV_EXPORTS IplImage* cvTestSeqQueryFrame(CvTestSeq* pTestSeq);
+
+/* Return pointer to current foreground mask: */
+CV_EXPORTS IplImage* cvTestSeqGetFGMask(CvTestSeq* pTestSeq);
+
+/* Return pointer to current image: */
+CV_EXPORTS IplImage* cvTestSeqGetImage(CvTestSeq* pTestSeq);
+
+/* Return frame size of result test video: */
+CV_EXPORTS CvSize cvTestSeqGetImageSize(CvTestSeq* pTestSeq);
+
+/* Return number of frames result test video: */
+CV_EXPORTS int cvTestSeqFrameNum(CvTestSeq* pTestSeq);
+
+/* Return number of existing objects.
+ * This is general number of any objects.
+ * For example number of trajectories may be equal or less than returned value:
+ */
+CV_EXPORTS int cvTestSeqGetObjectNum(CvTestSeq* pTestSeq);
+
+/* Return 0 if there is not position for current defined on current frame */
+/* Return 1 if there is object position and pPos was filled */
+CV_EXPORTS int cvTestSeqGetObjectPos(CvTestSeq* pTestSeq, int ObjIndex, CvPoint2D32f* pPos);
+CV_EXPORTS int cvTestSeqGetObjectSize(CvTestSeq* pTestSeq, int ObjIndex, CvPoint2D32f* pSize);
+
+/* Add noise to final image: */
+CV_EXPORTS void cvTestSeqAddNoise(CvTestSeq* pTestSeq, int noise_type = CV_NOISE_NONE, double noise_ampl = 0);
+
+/* Add Intensity variation: */
+CV_EXPORTS void cvTestSeqAddIntensityVariation(CvTestSeq* pTestSeq, float DI_per_frame, float MinI, float MaxI);
+CV_EXPORTS void cvTestSeqSetFrame(CvTestSeq* pTestSeq, int n);
+
+#endif
+
+/* End of file. */
diff --git a/cvaux/src/_cvaux.h b/cvaux/src/_cvaux.h
new file mode 100644
index 0000000..65267d9
--- /dev/null
+++ b/cvaux/src/_cvaux.h
@@ -0,0 +1,73 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#ifndef __CVAUX_H__
+#define __CVAUX_H__
+
+#if _MSC_VER >= 1200
+#pragma warning( disable: 4710 4711 4514 4996 ) /* function AAA selected for automatic inline expansion */
+#endif
+
+#include "cvaux.h"
+#include "cxmisc.h"
+#include "_cvmatrix.h"
+
+typedef unsigned short ushort;
+
+CV_INLINE bool operator == (CvSize size1, CvSize size2 );
+CV_INLINE bool operator == (CvSize size1, CvSize size2 )
+{
+ return size1.width == size2.width && size1.height == size2.height;
+}
+
+CV_INLINE bool operator != (CvSize size1, CvSize size2 );
+CV_INLINE bool operator != (CvSize size1, CvSize size2 )
+{
+ return size1.width != size2.width || size1.height != size2.height;
+}
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#endif /* __CVAUX_H__ */
diff --git a/cvaux/src/_cvfacedetection.h b/cvaux/src/_cvfacedetection.h
new file mode 100644
index 0000000..8c41be4
--- /dev/null
+++ b/cvaux/src/_cvfacedetection.h
@@ -0,0 +1,412 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+///////////////////////////////////////////////
+//// Created by Khudyakov V.A. bober@gorodok.net
+// FaceDetection.h: interface for the FaceDetection class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#ifndef _CVFACEDETECTION_H_
+#define _CVFACEDETECTION_H_
+
+#define MAX_LAYERS 64
+
+class FaceFeature
+{
+public:
+ FaceFeature(double dWeight,void * lpContour,bool bIsFeature);
+ FaceFeature();
+ virtual ~FaceFeature();
+ inline bool isFaceFeature();
+ inline void * GetContour();
+ inline double GetWeight();
+ inline void SetContour(void * lpContour);
+ inline void SetWeight(double dWeight);
+ inline void SetFeature(bool bIsFeature);
+private:
+ double m_dWeight;
+ void * m_lpContour;
+ bool m_bIsFaceFeature;
+};//class FaceFeature
+
+inline void FaceFeature::SetFeature(bool bIsFeature)
+{
+ m_bIsFaceFeature = bIsFeature;
+}
+
+inline bool FaceFeature::isFaceFeature()
+{
+ return m_bIsFaceFeature;
+}//inline bool FaceFeature::isFaceFeature()
+
+inline void * FaceFeature::GetContour()
+{
+ return m_lpContour;
+}//inline void * FaceFeature::GetContour()
+
+inline double FaceFeature::GetWeight()
+{
+ return m_dWeight;
+}//inline long FaceFeature::GetWeight()
+
+inline void FaceFeature::SetContour(void * lpContour)
+{
+ m_lpContour = lpContour;
+}//inline void FaceFeature::SetContour(void * lpContour)
+
+inline void FaceFeature::SetWeight(double dWeight)
+{
+ m_dWeight = dWeight;
+}//inline void FaceFeature::SetWeight(double * dWeight)
+
+
+
+class FaceTemplate
+{
+public:
+ FaceTemplate(long lFeatureCount) {m_lFeaturesCount = lFeatureCount; m_lpFeaturesList = new FaceFeature[lFeatureCount];};
+ virtual ~FaceTemplate();
+
+ inline long GetCount();
+ inline FaceFeature * GetFeatures();
+
+protected:
+ FaceFeature * m_lpFeaturesList;
+private:
+ long m_lFeaturesCount;
+};//class FaceTemplate
+
+
+inline long FaceTemplate::GetCount()
+{
+ return m_lFeaturesCount;
+}//inline long FaceTemplate::GetCount()
+
+
+inline FaceFeature * FaceTemplate::GetFeatures()
+{
+ return m_lpFeaturesList;
+}//inline FaceFeature * FaceTemplate::GetFeatures()
+
+////////////
+//class RFaceTemplate
+///////////
+
+class MouthFaceTemplate:public FaceTemplate
+{
+public:
+ inline MouthFaceTemplate(long lNumber,CvRect rect,double dEyeWidth,double dEyeHeight,double dDistanceBetweenEye,double dDistanceEyeAboveMouth);
+ ~MouthFaceTemplate();
+};//class MouthFaceTemplate:public FaceTemplate
+
+
+inline MouthFaceTemplate::MouthFaceTemplate(long lNumber,CvRect rect,double dEyeWidth,double dEyeHeight,
+ double dDistanceBetweenEye,double dDistanceEyeAboveMouth):FaceTemplate(lNumber)
+{
+
+ CvRect MouthRect = rect;
+
+
+ CvRect LeftEyeRect = cvRect(cvRound(rect.x - (dEyeWidth + dDistanceBetweenEye/(double)2 - (double)rect.width/(double)2)),
+ cvRound(rect.y - dDistanceEyeAboveMouth - dEyeHeight),
+ cvRound(dEyeWidth),
+ cvRound(dEyeHeight) );
+
+ CvRect RightEyeRect = cvRect(cvRound(rect.x + (double)rect.width/(double)2 + dDistanceBetweenEye/(double)2),
+ cvRound(rect.y - dDistanceEyeAboveMouth - dEyeHeight),
+ cvRound(dEyeWidth),
+ cvRound(dEyeHeight) );
+
+// CvRect NoseRect = cvRect(cvRound(rect.x + (double)rect.width/(double)4),
+// cvRound(rect.y - (double)rect.width/(double)2 - (double)rect.height/(double)4),
+// cvRound((double)rect.width/(double)2),
+// cvRound((double)rect.width/(double)2) );
+/*
+ CvRect CheenRect = cvRect(rect.x,rect.y + 3*rect.height/2,rect.width,rect.height);
+
+*/
+
+ CvRect * lpMouthRect = new CvRect();
+ *lpMouthRect = MouthRect;
+ m_lpFeaturesList[0].SetContour(lpMouthRect);
+ m_lpFeaturesList[0].SetWeight(1);
+ m_lpFeaturesList[0].SetFeature(false);
+
+
+ CvRect * lpLeftEyeRect = new CvRect();
+ *lpLeftEyeRect = LeftEyeRect;
+ m_lpFeaturesList[1].SetContour(lpLeftEyeRect);
+ m_lpFeaturesList[1].SetWeight(1);
+ m_lpFeaturesList[1].SetFeature(true);
+
+ CvRect * lpRightEyeRect = new CvRect();
+ *lpRightEyeRect = RightEyeRect;
+ m_lpFeaturesList[2].SetContour(lpRightEyeRect);
+ m_lpFeaturesList[2].SetWeight(1);
+ m_lpFeaturesList[2].SetFeature(true);
+
+
+// CvRect * lpNoseRect = new CvRect();
+// *lpNoseRect = NoseRect;
+// m_lpFeaturesList[3].SetContour(lpNoseRect);
+// m_lpFeaturesList[3].SetWeight(0);
+// m_lpFeaturesList[3].SetFeature(true);
+
+/* CvRect * lpCheenRect = new CvRect();
+ *lpCheenRect = CheenRect;
+ m_lpFeaturesList[4].SetContour(lpCheenRect);
+ m_lpFeaturesList[4].SetWeight(1);
+ m_lpFeaturesList[4].SetFeature(false);
+
+*/
+
+}//constructor MouthFaceTemplate(long lNumFeatures,CvRect rect,double dEyeWidth,double dEyeHeight,double dDistanceBetweenEye,double dDistanceEyeAboveMouth);
+
+
+typedef struct CvContourRect
+{
+ int iNumber;
+ int iType;
+ int iFlags;
+ CvSeq *seqContour;
+ int iContourLength;
+ CvRect r;
+ CvPoint pCenter;
+ int iColor;
+} CvContourRect;
+
+class Face
+{
+public:
+ Face(FaceTemplate * lpFaceTemplate);
+ virtual ~Face();
+
+ inline bool isFeature(void * lpElem);
+
+ virtual void Show(IplImage * /*Image*/){};
+ virtual void ShowIdeal(IplImage* /*Image*/){};
+
+ virtual void CreateFace(void * lpData) = 0;
+ virtual bool CheckElem(void * lpCandidat,void * lpIdeal) = 0;
+ virtual double GetWeight() = 0;
+protected:
+ FaceFeature * m_lpIdealFace;//ideal face definition
+ long m_lFaceFeaturesNumber; //total number of diferent face features
+ long * m_lplFaceFeaturesCount;//number of each features fouded for this face
+ FaceFeature ** m_lppFoundedFaceFeatures;//founded features of curen face
+ double m_dWeight;
+};
+
+inline bool Face::isFeature(void * lpElem)
+{
+ for (int i = 0;i < m_lFaceFeaturesNumber;i ++)
+ {
+ void * lpIdeal = m_lpIdealFace[i].GetContour();
+
+ if ( CheckElem( lpElem,lpIdeal) )
+ {
+ if (m_lplFaceFeaturesCount[i] < 3*MAX_LAYERS)
+ {
+ double dWeight = m_lpIdealFace[i].GetWeight();
+ bool bIsFeature = m_lpIdealFace[i].isFaceFeature();
+
+
+ if (bIsFeature)
+ {
+ m_lppFoundedFaceFeatures[i][m_lplFaceFeaturesCount[i]].SetWeight(dWeight);
+ m_lppFoundedFaceFeatures[i][m_lplFaceFeaturesCount[i]].SetContour(lpElem);
+ m_lppFoundedFaceFeatures[i][m_lplFaceFeaturesCount[i]].SetFeature(bIsFeature);
+ m_lplFaceFeaturesCount[i] ++;
+ }
+
+ m_dWeight += dWeight;
+
+ if (bIsFeature)
+ return true;
+ }
+ }
+
+ }
+
+ return false;
+}//inline bool RFace::isFeature(void * lpElem);
+
+
+struct FaceData
+{
+ CvRect LeftEyeRect;
+ CvRect RightEyeRect;
+ CvRect MouthRect;
+ double Error;
+};//struct FaceData
+
+class RFace:public Face
+{
+public:
+ RFace(FaceTemplate * lpFaceTemplate);
+ virtual ~RFace();
+ virtual bool CheckElem(void * lpCandidat,void * lpIdeal);
+ virtual void CreateFace(void * lpData);
+ virtual void Show(IplImage* Image);
+ virtual void ShowIdeal(IplImage* Image);
+ virtual double GetWeight();
+private:
+ bool isPointInRect(CvPoint p,CvRect rect);
+ bool m_bIsGenerated;
+ void ResizeRect(CvRect Rect,CvRect * lpRect,long lDir,long lD);
+ void CalculateError(FaceData * lpFaceData);
+};
+
+
+class ListElem
+{
+public:
+ ListElem();
+ ListElem(Face * pFace,ListElem * pHead);
+ virtual ~ListElem();
+ ListElem * m_pNext;
+ ListElem * m_pPrev;
+ Face * m_pFace;
+};//class ListElem
+
+class List
+{
+public:
+ List();
+ int AddElem(Face * pFace);
+ virtual ~List();
+ Face* GetData();
+ long m_FacesCount;
+private:
+ ListElem * m_pHead;
+ ListElem * m_pCurElem;
+};//class List
+
+
+class FaceDetection
+{
+public:
+ void FindFace(IplImage* img);
+ void CreateResults(CvSeq * lpSeq);
+ FaceDetection();
+ virtual ~FaceDetection();
+ void SetBoosting(bool bBoosting) {m_bBoosting = bBoosting;}
+ bool isPostBoosting() {return m_bBoosting;}
+protected:
+
+ IplImage* m_imgGray;
+ IplImage* m_imgThresh;
+ int m_iNumLayers;
+ CvMemStorage* m_mstgContours;
+ CvSeq* m_seqContours[MAX_LAYERS];
+ CvMemStorage* m_mstgRects;
+ CvSeq* m_seqRects;
+
+ bool m_bBoosting;
+ List * m_pFaceList;
+
+protected:
+ void ResetImage();
+ void FindContours(IplImage* imgGray);
+ void AddContours2Rect(CvSeq* seq, int color, int iLayer);
+ void ThresholdingParam(IplImage* imgGray, int iNumLayers, int& iMinLevel, int& iMaxLevel, int& iStep);
+ void FindCandidats();
+ void PostBoostingFindCandidats(IplImage * FaceImage);
+};
+
+inline void ReallocImage(IplImage** ppImage, CvSize sz, long lChNum)
+{
+ IplImage* pImage;
+ if( ppImage == NULL )
+ return;
+ pImage = *ppImage;
+ if( pImage != NULL )
+ {
+ if (pImage->width != sz.width || pImage->height != sz.height || pImage->nChannels != lChNum)
+ cvReleaseImage( &pImage );
+ }
+ if( pImage == NULL )
+ pImage = cvCreateImage( sz, IPL_DEPTH_8U, lChNum);
+ *ppImage = pImage;
+}
+
+////////////
+//class RFaceTemplate
+///////////
+
+class BoostingFaceTemplate:public FaceTemplate
+{
+public:
+ inline BoostingFaceTemplate(long lNumber,CvRect rect);
+ ~BoostingFaceTemplate() {};
+};//class RFaceTemplate:public FaceTemplate
+
+
+inline BoostingFaceTemplate::BoostingFaceTemplate(long lNumber,CvRect rect):FaceTemplate(lNumber)
+{
+ long EyeWidth = rect.width/5;
+ long EyeHeight = EyeWidth;
+
+ CvRect LeftEyeRect = cvRect(rect.x + EyeWidth,rect.y + rect.height/2 - EyeHeight,EyeWidth,EyeHeight);
+ CvRect RightEyeRect = cvRect(rect.x + 3*EyeWidth,rect.y + rect.height/2 - EyeHeight,EyeWidth,EyeHeight);
+ CvRect MouthRect = cvRect(rect.x + 3*EyeWidth/2,rect.y + 3*rect.height/4 - EyeHeight/2,2*EyeWidth,EyeHeight);
+
+ CvRect * lpMouthRect = new CvRect();
+ *lpMouthRect = MouthRect;
+ m_lpFeaturesList[0].SetContour(lpMouthRect);
+ m_lpFeaturesList[0].SetWeight(1);
+ m_lpFeaturesList[0].SetFeature(true);
+
+ CvRect * lpLeftEyeRect = new CvRect();
+ *lpLeftEyeRect = LeftEyeRect;
+ m_lpFeaturesList[1].SetContour(lpLeftEyeRect);
+ m_lpFeaturesList[1].SetWeight(1);
+ m_lpFeaturesList[1].SetFeature(true);
+
+ CvRect * lpRightEyeRect = new CvRect();
+ *lpRightEyeRect = RightEyeRect;
+ m_lpFeaturesList[2].SetContour(lpRightEyeRect);
+ m_lpFeaturesList[2].SetWeight(1);
+ m_lpFeaturesList[2].SetFeature(true);
+
+}//inline BoostingFaceTemplate::BoostingFaceTemplate(long lNumber,CvRect rect):FaceTemplate(lNumber)
+
+#endif // !defined(AFX_FACEDETECTION_H__55865033_D8E5_4DD5_8925_34C2285BB1BE__INCLUDED_)
diff --git a/cvaux/src/_cvvectrack.h b/cvaux/src/_cvvectrack.h
new file mode 100644
index 0000000..557a3f7
--- /dev/null
+++ b/cvaux/src/_cvvectrack.h
@@ -0,0 +1,163 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+
+#ifndef __CVVECTRACK_H__
+#define __CVVECTRACK_H__
+
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include <stdio.h>
+
+#undef max
+#undef min
+
+#define max(a,b) ((a)<(b) ? (b) : (a))
+#define min(a,b) ((a)>(b) ? (a) : (b))
+
+inline int pow2(int v)
+{
+ return (v*v);
+}
+
+inline int operator == (const CvRect& r1, const CvRect& r2)
+{
+ return (r1.x == r2.x) && (r1.y == r2.y) &&
+ (r1.width == r2.width) && (r1.height == r2.height);
+}
+
+inline int operator != (const CvRect& r1, const CvRect& r2)
+{
+ return !(r1 == r2);
+}
+
+inline
+int CmpPoints(const CvPoint& p1, const CvPoint& p2, int err)
+{
+ /* Simakov: modify __max to max */
+ return (max(abs(p1.x - p2.x), abs(p1.y - p2.y)) < err);
+}
+
+inline
+int PointInRect(const CvPoint& p, const CvRect& r)
+{
+ return ((p.x > r.x) && (p.x < (r.x + r.width)) &&
+ (p.y > r.y) && (p.y < (r.y + r.height)));
+}
+
+inline
+int RectInRect(const CvRect& r1, const CvRect& r2)
+{
+ CvPoint plt = {r1.x, r1.y};
+ CvPoint prb = {r1.x + r1.width, r1.y + r1.height};
+ return (PointInRect(plt, r2) && PointInRect(prb, r2));
+}
+
+inline
+CvRect Increase(const CvRect& r, int decr)
+{
+ CvRect rect;
+ rect.x = r.x * decr;
+ rect.y = r.y * decr;
+ rect.width = r.width * decr;
+ rect.height = r.height * decr;
+ return rect;
+}
+
+inline
+CvPoint Increase(const CvPoint& p, int decr)
+{
+ CvPoint point;
+ point.x = p.x * decr;
+ point.y = p.y * decr;
+ return point;
+}
+
+inline
+void Move(CvRect& r, int dx, int dy)
+{
+ r.x += dx;
+ r.y += dy;
+}
+
+inline
+void Move(CvPoint& p, int dx, int dy)
+{
+ p.x += dx;
+ p.y += dy;
+}
+
+inline
+void Extend(CvRect& r, int d)
+{
+ r.x -= d;
+ r.y -= d;
+ r.width += 2*d;
+ r.height += 2*d;
+}
+
+inline
+CvPoint Center(const CvRect& r)
+{
+ CvPoint p;
+ p.x = r.x + r.width / 2;
+ p.y = r.y + r.height / 2;
+ return p;
+}
+
+inline void ReallocImage(IplImage** ppImage, CvSize sz, long lChNum)
+{
+ IplImage* pImage;
+ if( ppImage == NULL )
+ return;
+ pImage = *ppImage;
+ if( pImage != NULL )
+ {
+ if (pImage->width != sz.width || pImage->height != sz.height || pImage->nChannels != lChNum)
+ cvReleaseImage( &pImage );
+ }
+ if( pImage == NULL )
+ pImage = cvCreateImage( sz, IPL_DEPTH_8U, lChNum);
+ *ppImage = pImage;
+}
+
+#endif //__VECTRACK_H__
diff --git a/cvaux/src/_cvvm.h b/cvaux/src/_cvvm.h
new file mode 100644
index 0000000..940da5c
--- /dev/null
+++ b/cvaux/src/_cvvm.h
@@ -0,0 +1,298 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _CV_VM_H_
+#define _CV_VM_H_
+
+/*----------------------- Internal ViewMorphing Functions ------------------------------*/
+
+/*======================================================================================*/
+
+typedef struct CvMatrix4
+{
+ float m[4][4];
+}
+CvMatrix4;
+
+
+/* Scanline section. Find coordinates by fundamental matrix */
+
+/* Epsilon and real zero */
+#define EPSILON 1.e-4
+//#define REAL_ZERO(x) ( (x) < EPSILON && (x) > -EPSILON)
+#define REAL_ZERO(x) ( (x) < 1e-8 && (x) > -1e-8)
+
+#define SIGN(x) ( (x)<0 ? -1:((x)>0?1:0 ) )
+
+CvStatus icvMakeScanlinesLengths( int* scanlines,
+ int numlines,
+ int* lens);
+
+/*=============================== PreWarp section ======================================*/
+
+CV_INLINE int icvGetColor(uchar* valueRGB);
+
+CvStatus icvFindRunsInOneImage(
+ int numLines, /* number of scanlines */
+ uchar* prewarp, /* prewarp image */
+ int* line_lens, /* line lengths in pixels */
+ int* runs, /* result runs */
+ int* num_runs);
+
+/*================================ Morphing section ====================================*/
+
+CvStatus icvMorphEpilines8uC3( uchar* first_pix, /* raster epiline from the first image */
+ uchar* second_pix, /* raster epiline from the second image */
+ uchar* dst_pix, /* raster epiline from the destination image */
+ /* (it's an output parameter) */
+ float alpha, /* relative position of camera */
+ int* first, /* first sequence of runs */
+ int first_runs, /* it's length */
+ int* second, /* second sequence of runs */
+ int second_runs,
+ int* first_corr, /* correspond information for the 1st seq */
+ int* second_corr,
+ int dst_len); /* correspond information for the 2nd seq */
+
+/*========================== Dynamic correspond section ================================*/
+
+CvStatus icvDynamicCorrespond( int* first, /* first sequence of runs */
+ /* s0|w0|s1|w1|...|s(n-1)|w(n-1)|sn */
+ int first_runs, /* number of runs */
+ int* second, /* second sequence of runs */
+ int second_runs,
+ int* first_corr, /* s0'|e0'|s1'|e1'|... */
+ int* second_corr );
+
+/*============================= PostWarp Functions =====================================*/
+
+CvStatus icvFetchLine8uC3R(
+ uchar* src, int src_step,
+ uchar* dst, int* dst_num,
+ CvSize src_size,
+ CvPoint start,
+ CvPoint end );
+
+CvStatus icvDrawLine8uC3R(
+ uchar* src, int src_num,
+ uchar* dst, int dst_step,
+ CvSize dst_size,
+ CvPoint start,
+ CvPoint end );
+
+
+/*============================== Fundamental Matrix Functions ==========================*/
+CvStatus icvPoint7( int* points1,
+ int* points2,
+ double* F,
+ int* amount
+ );
+
+CvStatus icvCubic( double a2, double a1,
+ double a0, double* squares );
+
+double icvDet( double* M );
+double icvMinor( double* M, int x, int y );
+
+int
+icvGaussMxN( double *A, double *B, int M, int N, double **solutions );
+
+CvStatus
+icvGetCoef( double *f1, double *f2, double *a2, double *a1, double *a0 );
+
+/*================================= Scanlines Functions ================================*/
+
+CvStatus icvGetCoefficient( CvMatrix3* matrix,
+ CvSize imgSize,
+ int* scanlines_1,
+ int* scanlines_2,
+ int* numlines);
+
+CvStatus icvGetCoefficientDefault( CvMatrix3* matrix,
+ CvSize imgSize,
+ int* scanlines_1,
+ int* scanlines_2,
+ int* numlines);
+
+CvStatus icvGetCoefficientStereo( CvMatrix3* matrix,
+ CvSize imgSize,
+ float* l_epipole,
+ float* r_epipole,
+ int* scanlines_1,
+ int* scanlines_2,
+ int* numlines
+ );
+
+CvStatus icvGetCoefficientOrto( CvMatrix3* matrix,
+ CvSize imgSize,
+ int* scanlines_1,
+ int* scanlines_2,
+ int* numlines);
+
+
+CvStatus icvGetCrossEpilineFrame( CvSize imgSize,
+ float* epiline,
+ int* x1,
+ int* y1,
+ int* x2,
+ int* y2
+ );
+
+CvStatus icvBuildScanlineLeftStereo(
+ CvSize imgSize,
+ CvMatrix3* matrix,
+ float* l_epipole,
+ float* l_angle,
+ float l_radius,
+ int* scanlines_1,
+ int* scanlines_2,
+ int* numlines);
+
+CvStatus icvBuildScanlineRightStereo(
+ CvSize imgSize,
+ CvMatrix3* matrix,
+ float* r_epipole,
+ float* r_angle,
+ float r_radius,
+ int* scanlines_1,
+ int* scanlines_2,
+ int* numlines);
+
+CvStatus icvGetStartEnd1(
+ CvMatrix3* matrix,
+ CvSize imgSize,
+ float* l_start_end,
+ float* r_start_end );
+
+CvStatus icvGetStartEnd2(
+ CvMatrix3* matrix,
+ CvSize imgSize,
+ float* l_start_end,
+ float* r_start_end );
+
+CvStatus icvGetStartEnd3(
+ CvMatrix3* matrix,
+ CvSize imgSize,
+ float* l_start_end,
+ float* r_start_end );
+
+CvStatus icvGetStartEnd4(
+ CvMatrix3* matrix,
+ CvSize imgSize,
+ float* l_start_end,
+ float* r_start_end );
+
+CvStatus icvBuildScanlineLeft(
+ CvMatrix3* matrix,
+ CvSize imgSize,
+ int* scanlines_1,
+ int* scanlines_2,
+ float* l_start_end,
+ int* numlines
+ );
+
+CvStatus icvBuildScanlineRight(
+ CvMatrix3* matrix,
+ CvSize imgSize,
+ int* scanlines_1,
+ int* scanlines_2,
+ float* r_start_end,
+ int* numlines
+ );
+
+
+/*=================================== LMedS Functions ==================================*/
+CvStatus icvLMedS7(
+ int* points1,
+ int* points2,
+ CvMatrix3* matrix);
+
+
+CvStatus icvLMedS( int* points1,
+ int* points2,
+ int numPoints,
+ CvMatrix3* fundamentalMatrix );
+
+
+/*
+CvStatus icvFindFundamentalMatrix(
+ int* points1,
+ int* points2,
+ int numpoints,
+ int method,
+ CvMatrix3* matrix);
+*/
+void icvChoose7( int* ml, int* mr,
+ int num, int* ml7,
+ int* mr7 );
+
+double icvMedian( int* ml, int* mr,
+ int num, double* F );
+
+int icvBoltingPoints( int* ml, int* mr,
+ int num, double* F,
+ double Mj, int* *new_ml,
+ int* *new_mr, int* new_num);
+
+CvStatus icvPoints8( int* ml, int* mr,
+ int num, double* F );
+
+CvStatus icvRank2Constraint( double* F );
+
+CvStatus icvSort( double* array, int length );
+
+double icvAnalyticPoints8( double* A,
+ int num, double* F );
+
+int icvSingularValueDecomposition( int M,
+ int N,
+ double* A,
+ double* W,
+ int get_U,
+ double* U,
+ int get_V,
+ double* V
+ );
+
+
+/*======================================================================================*/
+#endif/*_CV_VM_H_*/
+
diff --git a/cvaux/src/camshift.cpp b/cvaux/src/camshift.cpp
new file mode 100644
index 0000000..23cff7d
--- /dev/null
+++ b/cvaux/src/camshift.cpp
@@ -0,0 +1,285 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cvaux.h"
+
+CvCamShiftTracker::CvCamShiftTracker()
+{
+ int i;
+
+ memset( &m_box, 0, sizeof(m_box));
+ memset( &m_comp, 0, sizeof(m_comp));
+ memset( m_color_planes, 0, sizeof(m_color_planes));
+ m_threshold = 0;
+
+ for( i = 0; i < CV_MAX_DIM; i++ )
+ {
+ m_min_ch_val[i] = 0;
+ m_max_ch_val[i] = 255;
+ m_hist_ranges[i] = m_hist_ranges_data[i];
+ m_hist_ranges[i][0] = 0.f;
+ m_hist_ranges[i][1] = 256.f;
+ }
+
+ m_hist = 0;
+ m_back_project = 0;
+ m_temp = 0;
+ m_mask = 0;
+}
+
+
+CvCamShiftTracker::~CvCamShiftTracker()
+{
+ int i;
+
+ cvReleaseHist( &m_hist );
+ for( i = 0; i < CV_MAX_DIM; i++ )
+ cvReleaseImage( &m_color_planes[i] );
+ cvReleaseImage( &m_back_project );
+ cvReleaseImage( &m_temp );
+ cvReleaseImage( &m_mask );
+}
+
+
+void
+CvCamShiftTracker::color_transform( const IplImage* image )
+{
+ CvSize size = cvGetSize(image);
+ uchar* color_data = 0, *mask = 0;
+ uchar* planes[CV_MAX_DIM];
+ int x, color_step = 0, plane_step = 0, mask_step;
+ int dims[CV_MAX_DIM];
+ int i, n = get_hist_dims(dims);
+
+ assert( image->nChannels == 3 && m_hist != 0 );
+
+ if( !m_temp || !m_mask || !m_color_planes[0] || !m_color_planes[n-1] || !m_back_project ||
+ m_temp->width != size.width || m_temp->height != size.height ||
+ m_temp->nChannels != 3 )
+ {
+ cvReleaseImage( &m_temp );
+ m_temp = cvCreateImage( size, IPL_DEPTH_8U, 3 );
+ cvReleaseImage( &m_mask );
+ m_mask = cvCreateImage( size, IPL_DEPTH_8U, 1 );
+ cvReleaseImage( &m_back_project );
+ m_back_project = cvCreateImage( size, IPL_DEPTH_8U, 1 );
+ for( i = 0; i < CV_MAX_DIM; i++ )
+ {
+ cvReleaseImage( &m_color_planes[i] );
+ if( i < n )
+ m_color_planes[i] = cvCreateImage( size, IPL_DEPTH_8U, 1 );
+ }
+ }
+
+ cvCvtColor( image, m_temp, CV_BGR2HSV );
+ cvGetRawData( m_temp, &color_data, &color_step, &size );
+ cvGetRawData( m_mask, &mask, &mask_step, &size );
+
+ for( i = 0; i < n; i++ )
+ cvGetRawData( m_color_planes[i], &planes[i], &plane_step, &size );
+
+ for( ; size.height--; color_data += color_step, mask += mask_step )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ int val0 = color_data[x*3];
+ int val1 = color_data[x*3+1];
+ int val2 = color_data[x*3+2];
+ if( m_min_ch_val[0] <= val0 && val0 <= m_max_ch_val[0] &&
+ m_min_ch_val[1] <= val1 && val1 <= m_max_ch_val[1] &&
+ m_min_ch_val[2] <= val2 && val2 <= m_max_ch_val[2] )
+ {
+ // hue is written to the 0-th plane, saturation - to the 1-st one,
+ // so 1d histogram will automagically correspond to hue-based tracking,
+ // 2d histogram - to saturation-based tracking.
+ planes[0][x] = (uchar)val0;
+ if( n > 1 )
+ planes[1][x] = (uchar)val1;
+ if( n > 2 )
+ planes[2][x] = (uchar)val2;
+
+ mask[x] = (uchar)255;
+ }
+ else
+ {
+ planes[0][x] = 0;
+ if( n > 1 )
+ planes[1][x] = 0;
+ if( n > 2 )
+ planes[2][x] = 0;
+ mask[x] = 0;
+ }
+ }
+ for( i = 0; i < n; i++ )
+ planes[i] += plane_step;
+ }
+}
+
+
+bool
+CvCamShiftTracker::update_histogram( const IplImage* cur_frame )
+{
+ float max_val = 0;
+ int i, dims;
+
+ if( m_comp.rect.width == 0 || m_comp.rect.height == 0 ||
+ m_hist == 0 )
+ {
+ assert(0);
+ return false;
+ }
+
+ color_transform(cur_frame);
+
+ dims = cvGetDims( m_hist->bins );
+ for( i = 0; i < dims; i++ )
+ cvSetImageROI( m_color_planes[i], m_comp.rect );
+ cvSetImageROI( m_mask, m_comp.rect );
+
+ cvSetHistBinRanges( m_hist, m_hist_ranges, 1 );
+ cvCalcHist( m_color_planes, m_hist, 0, m_mask );
+
+ for( i = 0; i < dims; i++ )
+ cvSetImageROI( m_color_planes[i], m_comp.rect );
+
+ for( i = 0; i < dims; i++ )
+ cvResetImageROI( m_color_planes[i] );
+ cvResetImageROI( m_mask );
+
+ cvGetMinMaxHistValue( m_hist, 0, &max_val );
+ cvScale( m_hist->bins, m_hist->bins, max_val ? 255. / max_val : 0. );
+
+ return max_val != 0;
+}
+
+
+void
+CvCamShiftTracker::reset_histogram()
+{
+ if( m_hist )
+ cvClearHist( m_hist );
+}
+
+
+bool
+CvCamShiftTracker::track_object( const IplImage* cur_frame )
+{
+ CvRect rect;
+ CvSize bp_size;
+
+ union
+ {
+ void** arr;
+ IplImage** img;
+ } u;
+
+ if( m_comp.rect.width == 0 || m_comp.rect.height == 0 ||
+ m_hist == 0 )
+ {
+ return false;
+ }
+
+ color_transform( cur_frame );
+ u.img = m_color_planes;
+ cvCalcArrBackProject( u.arr, m_back_project, m_hist );
+ cvAnd( m_back_project, m_mask, m_back_project );
+
+ rect = m_comp.rect;
+ bp_size = cvGetSize( m_back_project );
+ if( rect.x < 0 )
+ rect.x = 0;
+ if( rect.x + rect.width > bp_size.width )
+ rect.width = bp_size.width - rect.x;
+ if( rect.y < 0 )
+ rect.y = 0;
+ if( rect.y + rect.height > bp_size.height )
+ rect.height = bp_size.height - rect.y;
+
+ cvCamShift( m_back_project, rect,
+ cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ),
+ &m_comp, &m_box );
+
+ if( m_comp.rect.width == 0 || m_comp.rect.height == 0 )
+ m_comp.rect = rect; // do not allow tracker to loose the object
+
+ return m_comp.rect.width != 0 && m_comp.rect.height != 0;
+}
+
+
+bool
+CvCamShiftTracker::set_hist_dims( int c_dims, int *dims )
+{
+ if( (unsigned)(c_dims-1) >= (unsigned)CV_MAX_DIM || dims == 0 )
+ return false;
+
+ if( m_hist )
+ {
+ int dims2[CV_MAX_DIM];
+ int c_dims2 = cvGetDims( m_hist->bins, dims2 );
+
+ if( c_dims2 == c_dims && memcmp( dims, dims2, c_dims*sizeof(dims[0])) == 0 )
+ return true;
+
+ cvReleaseHist( &m_hist );
+ }
+
+ m_hist = cvCreateHist( c_dims, dims, CV_HIST_ARRAY, 0, 0 );
+
+ return true;
+}
+
+
+bool
+CvCamShiftTracker::set_hist_bin_range( int channel, int min_val, int max_val )
+{
+ if( (unsigned)channel >= (unsigned)CV_MAX_DIM ||
+ min_val >= max_val || min_val < 0 || max_val > 256 )
+ {
+ assert(0);
+ return false;
+ }
+
+ m_hist_ranges[channel][0] = (float)min_val;
+ m_hist_ranges[channel][1] = (float)max_val;
+
+ return true;
+}
+
+/* End of file. */
diff --git a/cvaux/src/cv3dtracker.cpp b/cvaux/src/cv3dtracker.cpp
new file mode 100644
index 0000000..aa8a0e3
--- /dev/null
+++ b/cvaux/src/cv3dtracker.cpp
@@ -0,0 +1,588 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2002, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+#if _MSC_VER >= 1200
+#pragma warning(disable:4786) // Disable MSVC warnings in the standard library.
+#pragma warning(disable:4100)
+#pragma warning(disable:4512)
+#endif
+#include <stdio.h>
+#include <map>
+#include <algorithm>
+#if _MSC_VER >= 1200
+#pragma warning(default:4100)
+#pragma warning(default:4512)
+#endif
+
+#define ARRAY_SIZEOF(a) (sizeof(a)/sizeof((a)[0]))
+
+static void FillObjectPoints(CvPoint3D32f *obj_points, CvSize etalon_size, float square_size);
+static void DrawEtalon(IplImage *img, CvPoint2D32f *corners,
+ int corner_count, CvSize etalon_size, int draw_ordered);
+static void MultMatrix(float rm[4][4], const float m1[4][4], const float m2[4][4]);
+static void MultVectorMatrix(float rv[4], const float v[4], const float m[4][4]);
+static CvPoint3D32f ImageCStoWorldCS(const Cv3dTrackerCameraInfo &camera_info, CvPoint2D32f p);
+static bool intersection(CvPoint3D32f o1, CvPoint3D32f p1,
+ CvPoint3D32f o2, CvPoint3D32f p2,
+ CvPoint3D32f &r1, CvPoint3D32f &r2);
+
+/////////////////////////////////
+// cv3dTrackerCalibrateCameras //
+/////////////////////////////////
+CV_IMPL CvBool cv3dTrackerCalibrateCameras(int num_cameras,
+ const Cv3dTrackerCameraIntrinsics camera_intrinsics[], // size is num_cameras
+ CvSize etalon_size,
+ float square_size,
+ IplImage *samples[], // size is num_cameras
+ Cv3dTrackerCameraInfo camera_info[]) // size is num_cameras
+{
+ CV_FUNCNAME("cv3dTrackerCalibrateCameras");
+ const int num_points = etalon_size.width * etalon_size.height;
+ int cameras_done = 0; // the number of cameras whose positions have been determined
+ CvPoint3D32f *object_points = NULL; // real-world coordinates of checkerboard points
+ CvPoint2D32f *points = NULL; // 2d coordinates of checkerboard points as seen by a camera
+ IplImage *gray_img = NULL; // temporary image for color conversion
+ IplImage *tmp_img = NULL; // temporary image used by FindChessboardCornerGuesses
+ int c, i, j;
+
+ if (etalon_size.width < 3 || etalon_size.height < 3)
+ CV_ERROR(CV_StsBadArg, "Chess board size is invalid");
+
+ for (c = 0; c < num_cameras; c++)
+ {
+ // CV_CHECK_IMAGE is not available in the cvaux library
+ // so perform the checks inline.
+
+ //CV_CALL(CV_CHECK_IMAGE(samples[c]));
+
+ if( samples[c] == NULL )
+ CV_ERROR( CV_HeaderIsNull, "Null image" );
+
+ if( samples[c]->dataOrder != IPL_DATA_ORDER_PIXEL && samples[c]->nChannels > 1 )
+ CV_ERROR( CV_BadOrder, "Unsupported image format" );
+
+ if( samples[c]->maskROI != 0 || samples[c]->tileInfo != 0 )
+ CV_ERROR( CV_StsBadArg, "Unsupported image format" );
+
+ if( samples[c]->imageData == 0 )
+ CV_ERROR( CV_BadDataPtr, "Null image data" );
+
+ if( samples[c]->roi &&
+ ((samples[c]->roi->xOffset | samples[c]->roi->yOffset
+ | samples[c]->roi->width | samples[c]->roi->height) < 0 ||
+ samples[c]->roi->xOffset + samples[c]->roi->width > samples[c]->width ||
+ samples[c]->roi->yOffset + samples[c]->roi->height > samples[c]->height ||
+ (unsigned) (samples[c]->roi->coi) > (unsigned) (samples[c]->nChannels)))
+ CV_ERROR( CV_BadROISize, "Invalid ROI" );
+
+ // End of CV_CHECK_IMAGE inline expansion
+
+ if (samples[c]->depth != IPL_DEPTH_8U)
+ CV_ERROR(CV_BadDepth, "Channel depth of source image must be 8");
+
+ if (samples[c]->nChannels != 3 && samples[c]->nChannels != 1)
+ CV_ERROR(CV_BadNumChannels, "Source image must have 1 or 3 channels");
+ }
+
+ CV_CALL(object_points = (CvPoint3D32f *)cvAlloc(num_points * sizeof(CvPoint3D32f)));
+ CV_CALL(points = (CvPoint2D32f *)cvAlloc(num_points * sizeof(CvPoint2D32f)));
+
+ // fill in the real-world coordinates of the checkerboard points
+ FillObjectPoints(object_points, etalon_size, square_size);
+
+ for (c = 0; c < num_cameras; c++)
+ {
+ CvSize image_size = cvSize(samples[c]->width, samples[c]->height);
+ IplImage *img;
+
+ // The input samples are not required to all have the same size or color
+ // format. If they have different sizes, the temporary images are
+ // reallocated as necessary.
+ if (samples[c]->nChannels == 3)
+ {
+ // convert to gray
+ if (gray_img == NULL || gray_img->width != samples[c]->width ||
+ gray_img->height != samples[c]->height )
+ {
+ if (gray_img != NULL)
+ cvReleaseImage(&gray_img);
+ CV_CALL(gray_img = cvCreateImage(image_size, IPL_DEPTH_8U, 1));
+ }
+
+ CV_CALL(cvCvtColor(samples[c], gray_img, CV_BGR2GRAY));
+
+ img = gray_img;
+ }
+ else
+ {
+ // no color conversion required
+ img = samples[c];
+ }
+
+ if (tmp_img == NULL || tmp_img->width != samples[c]->width ||
+ tmp_img->height != samples[c]->height )
+ {
+ if (tmp_img != NULL)
+ cvReleaseImage(&tmp_img);
+ CV_CALL(tmp_img = cvCreateImage(image_size, IPL_DEPTH_8U, 1));
+ }
+
+ int count = num_points;
+ bool found = cvFindChessBoardCornerGuesses(img, tmp_img, 0,
+ etalon_size, points, &count) != 0;
+ if (count == 0)
+ continue;
+
+ // If found is true, it means all the points were found (count = num_points).
+ // If found is false but count is non-zero, it means that not all points were found.
+
+ cvFindCornerSubPix(img, points, count, cvSize(5,5), cvSize(-1,-1),
+ cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 10, 0.01f));
+
+ // If the image origin is BL (bottom-left), fix the y coordinates
+ // so they are relative to the true top of the image.
+ if (samples[c]->origin == IPL_ORIGIN_BL)
+ {
+ for (i = 0; i < count; i++)
+ points[i].y = samples[c]->height - 1 - points[i].y;
+ }
+
+ if (found)
+ {
+ // Make sure x coordinates are increasing and y coordinates are decreasing.
+ // (The y coordinate of point (0,0) should be the greatest, because the point
+ // on the checkerboard that is the origin is nearest the bottom of the image.)
+ // This is done after adjusting the y coordinates according to the image origin.
+ if (points[0].x > points[1].x)
+ {
+ // reverse points in each row
+ for (j = 0; j < etalon_size.height; j++)
+ {
+ CvPoint2D32f *row = &points[j*etalon_size.width];
+ for (i = 0; i < etalon_size.width/2; i++)
+ std::swap(row[i], row[etalon_size.width-i-1]);
+ }
+ }
+
+ if (points[0].y < points[etalon_size.width].y)
+ {
+ // reverse points in each column
+ for (i = 0; i < etalon_size.width; i++)
+ {
+ for (j = 0; j < etalon_size.height/2; j++)
+ std::swap(points[i+j*etalon_size.width],
+ points[i+(etalon_size.height-j-1)*etalon_size.width]);
+ }
+ }
+ }
+
+ DrawEtalon(samples[c], points, count, etalon_size, found);
+
+ if (!found)
+ continue;
+
+ float rotVect[3];
+ float rotMatr[9];
+ float transVect[3];
+
+ cvFindExtrinsicCameraParams(count,
+ image_size,
+ points,
+ object_points,
+ const_cast<float *>(camera_intrinsics[c].focal_length),
+ camera_intrinsics[c].principal_point,
+ const_cast<float *>(camera_intrinsics[c].distortion),
+ rotVect,
+ transVect);
+
+ // Check result against an arbitrary limit to eliminate impossible values.
+ // (If the chess board were truly that far away, the camera wouldn't be able to
+ // see the squares.)
+ if (transVect[0] > 1000*square_size
+ || transVect[1] > 1000*square_size
+ || transVect[2] > 1000*square_size)
+ {
+ // ignore impossible results
+ continue;
+ }
+
+ CvMat rotMatrDescr = cvMat(3, 3, CV_32FC1, rotMatr);
+ CvMat rotVectDescr = cvMat(3, 1, CV_32FC1, rotVect);
+
+ /* Calc rotation matrix by Rodrigues Transform */
+ cvRodrigues2( &rotVectDescr, &rotMatrDescr );
+
+ //combine the two transformations into one matrix
+ //order is important! rotations are not commutative
+ float tmat[4][4] = { { 1.f, 0.f, 0.f, 0.f },
+ { 0.f, 1.f, 0.f, 0.f },
+ { 0.f, 0.f, 1.f, 0.f },
+ { transVect[0], transVect[1], transVect[2], 1.f } };
+
+ float rmat[4][4] = { { rotMatr[0], rotMatr[1], rotMatr[2], 0.f },
+ { rotMatr[3], rotMatr[4], rotMatr[5], 0.f },
+ { rotMatr[6], rotMatr[7], rotMatr[8], 0.f },
+ { 0.f, 0.f, 0.f, 1.f } };
+
+
+ MultMatrix(camera_info[c].mat, tmat, rmat);
+
+ // change the transformation of the cameras to put them in the world coordinate
+ // system we want to work with.
+
+ // Start with an identity matrix; then fill in the values to accomplish
+ // the desired transformation.
+ float smat[4][4] = { { 1.f, 0.f, 0.f, 0.f },
+ { 0.f, 1.f, 0.f, 0.f },
+ { 0.f, 0.f, 1.f, 0.f },
+ { 0.f, 0.f, 0.f, 1.f } };
+
+ // First, reflect through the origin by inverting all three axes.
+ smat[0][0] = -1.f;
+ smat[1][1] = -1.f;
+ smat[2][2] = -1.f;
+ MultMatrix(tmat, camera_info[c].mat, smat);
+
+ // Scale x and y coordinates by the focal length (allowing for non-square pixels
+ // and/or non-symmetrical lenses).
+ smat[0][0] = 1.0f / camera_intrinsics[c].focal_length[0];
+ smat[1][1] = 1.0f / camera_intrinsics[c].focal_length[1];
+ smat[2][2] = 1.0f;
+ MultMatrix(camera_info[c].mat, smat, tmat);
+
+ camera_info[c].principal_point = camera_intrinsics[c].principal_point;
+ camera_info[c].valid = true;
+
+ cameras_done++;
+ }
+
+exit:
+ cvReleaseImage(&gray_img);
+ cvReleaseImage(&tmp_img);
+ cvFree(&object_points);
+ cvFree(&points);
+
+ return cameras_done == num_cameras;
+}
+
+// fill in the real-world coordinates of the checkerboard points
+static void FillObjectPoints(CvPoint3D32f *obj_points, CvSize etalon_size, float square_size)
+{
+ int x, y, i;
+
+ for (y = 0, i = 0; y < etalon_size.height; y++)
+ {
+ for (x = 0; x < etalon_size.width; x++, i++)
+ {
+ obj_points[i].x = square_size * x;
+ obj_points[i].y = square_size * y;
+ obj_points[i].z = 0;
+ }
+ }
+}
+
+
+// Mark the points found on the input image
+// The marks are drawn multi-colored if all the points were found.
+static void DrawEtalon(IplImage *img, CvPoint2D32f *corners,
+ int corner_count, CvSize etalon_size, int draw_ordered)
+{
+ const int r = 4;
+ int i;
+ int x, y;
+ CvPoint prev_pt = { 0, 0 };
+ static const CvScalar rgb_colors[] = {
+ {{0,0,255}},
+ {{0,128,255}},
+ {{0,200,200}},
+ {{0,255,0}},
+ {{200,200,0}},
+ {{255,0,0}},
+ {{255,0,255}} };
+ static const CvScalar gray_colors[] = {
+ {{80}}, {{120}}, {{160}}, {{200}}, {{100}}, {{140}}, {{180}}
+ };
+ const CvScalar* colors = img->nChannels == 3 ? rgb_colors : gray_colors;
+
+ CvScalar color = colors[0];
+ for (y = 0, i = 0; y < etalon_size.height; y++)
+ {
+ if (draw_ordered)
+ color = colors[y % ARRAY_SIZEOF(rgb_colors)];
+
+ for (x = 0; x < etalon_size.width && i < corner_count; x++, i++)
+ {
+ CvPoint pt;
+ pt.x = cvRound(corners[i].x);
+ pt.y = cvRound(corners[i].y);
+ if (img->origin == IPL_ORIGIN_BL)
+ pt.y = img->height - 1 - pt.y;
+
+ if (draw_ordered)
+ {
+ if (i != 0)
+ cvLine(img, prev_pt, pt, color, 1, CV_AA);
+ prev_pt = pt;
+ }
+
+ cvLine( img, cvPoint(pt.x - r, pt.y - r),
+ cvPoint(pt.x + r, pt.y + r), color, 1, CV_AA );
+ cvLine( img, cvPoint(pt.x - r, pt.y + r),
+ cvPoint(pt.x + r, pt.y - r), color, 1, CV_AA );
+ cvCircle( img, pt, r+1, color, 1, CV_AA );
+ }
+ }
+}
+
+// Find the midpoint of the line segment between two points.
+static CvPoint3D32f midpoint(const CvPoint3D32f &p1, const CvPoint3D32f &p2)
+{
+ return cvPoint3D32f((p1.x+p2.x)/2, (p1.y+p2.y)/2, (p1.z+p2.z)/2);
+}
+
+static void operator +=(CvPoint3D32f &p1, const CvPoint3D32f &p2)
+{
+ p1.x += p2.x;
+ p1.y += p2.y;
+ p1.z += p2.z;
+}
+
+static CvPoint3D32f operator /(const CvPoint3D32f &p, int d)
+{
+ return cvPoint3D32f(p.x/d, p.y/d, p.z/d);
+}
+
+static const Cv3dTracker2dTrackedObject *find(const Cv3dTracker2dTrackedObject v[], int num_objects, int id)
+{
+ for (int i = 0; i < num_objects; i++)
+ {
+ if (v[i].id == id)
+ return &v[i];
+ }
+ return NULL;
+}
+
+#define CAMERA_POS(c) (cvPoint3D32f((c).mat[3][0], (c).mat[3][1], (c).mat[3][2]))
+
+//////////////////////////////
+// cv3dTrackerLocateObjects //
+//////////////////////////////
+CV_IMPL int cv3dTrackerLocateObjects(int num_cameras, int num_objects,
+ const Cv3dTrackerCameraInfo camera_info[], // size is num_cameras
+ const Cv3dTracker2dTrackedObject tracking_info[], // size is num_objects*num_cameras
+ Cv3dTrackerTrackedObject tracked_objects[]) // size is num_objects
+{
+ /*CV_FUNCNAME("cv3dTrackerLocateObjects");*/
+ int found_objects = 0;
+
+ // count how many cameras could see each object
+ std::map<int, int> count;
+ for (int c = 0; c < num_cameras; c++)
+ {
+ if (!camera_info[c].valid)
+ continue;
+
+ for (int i = 0; i < num_objects; i++)
+ {
+ const Cv3dTracker2dTrackedObject *o = &tracking_info[c*num_objects+i];
+ if (o->id != -1)
+ count[o->id]++;
+ }
+ }
+
+ // process each object that was seen by at least two cameras
+ for (std::map<int, int>::iterator i = count.begin(); i != count.end(); i++)
+ {
+ if (i->second < 2)
+ continue; // ignore object seen by only one camera
+ int id = i->first;
+
+ // find an approximation of the objects location for each pair of cameras that
+ // could see this object, and average them
+ CvPoint3D32f total = cvPoint3D32f(0, 0, 0);
+ int weight = 0;
+
+ for (int c1 = 0; c1 < num_cameras-1; c1++)
+ {
+ if (!camera_info[c1].valid)
+ continue;
+
+ const Cv3dTracker2dTrackedObject *o1 = find(&tracking_info[c1*num_objects],
+ num_objects, id);
+ if (o1 == NULL)
+ continue; // this camera didn't see this object
+
+ CvPoint3D32f p1a = CAMERA_POS(camera_info[c1]);
+ CvPoint3D32f p1b = ImageCStoWorldCS(camera_info[c1], o1->p);
+
+ for (int c2 = c1 + 1; c2 < num_cameras; c2++)
+ {
+ if (!camera_info[c2].valid)
+ continue;
+
+ const Cv3dTracker2dTrackedObject *o2 = find(&tracking_info[c2*num_objects],
+ num_objects, id);
+ if (o2 == NULL)
+ continue; // this camera didn't see this object
+
+ CvPoint3D32f p2a = CAMERA_POS(camera_info[c2]);
+ CvPoint3D32f p2b = ImageCStoWorldCS(camera_info[c2], o2->p);
+
+ // these variables are initialized simply to avoid erroneous error messages
+ // from the compiler
+ CvPoint3D32f r1 = cvPoint3D32f(0, 0, 0);
+ CvPoint3D32f r2 = cvPoint3D32f(0, 0, 0);
+
+ // find the intersection of the two lines (or the points of closest
+ // approach, if they don't intersect)
+ if (!intersection(p1a, p1b, p2a, p2b, r1, r2))
+ continue;
+
+ total += midpoint(r1, r2);
+ weight++;
+ }
+ }
+
+ CvPoint3D32f center = total/weight;
+ tracked_objects[found_objects++] = cv3dTrackerTrackedObject(id, center);
+ }
+
+ return found_objects;
+}
+
+#define EPS 1e-9
+
+// Compute the determinant of the 3x3 matrix represented by 3 row vectors.
+static inline double det(CvPoint3D32f v1, CvPoint3D32f v2, CvPoint3D32f v3)
+{
+ return v1.x*v2.y*v3.z + v1.z*v2.x*v3.y + v1.y*v2.z*v3.x
+ - v1.z*v2.y*v3.x - v1.x*v2.z*v3.y - v1.y*v2.x*v3.z;
+}
+
+static CvPoint3D32f operator +(CvPoint3D32f a, CvPoint3D32f b)
+{
+ return cvPoint3D32f(a.x + b.x, a.y + b.y, a.z + b.z);
+}
+
+static CvPoint3D32f operator -(CvPoint3D32f a, CvPoint3D32f b)
+{
+ return cvPoint3D32f(a.x - b.x, a.y - b.y, a.z - b.z);
+}
+
+static CvPoint3D32f operator *(CvPoint3D32f v, double f)
+{
+ return cvPoint3D32f(f*v.x, f*v.y, f*v.z);
+}
+
+
+// Find the intersection of two lines, or if they don't intersect,
+// the points of closest approach.
+// The lines are defined by (o1,p1) and (o2, p2).
+// If they intersect, r1 and r2 will be the same.
+// Returns false on error.
+static bool intersection(CvPoint3D32f o1, CvPoint3D32f p1,
+ CvPoint3D32f o2, CvPoint3D32f p2,
+ CvPoint3D32f &r1, CvPoint3D32f &r2)
+{
+ CvPoint3D32f x = o2 - o1;
+ CvPoint3D32f d1 = p1 - o1;
+ CvPoint3D32f d2 = p2 - o2;
+
+ CvPoint3D32f cross = cvPoint3D32f(d1.y*d2.z - d1.z*d2.y,
+ d1.z*d2.x - d1.x*d2.z,
+ d1.x*d2.y - d1.y*d2.x);
+ double den = cross.x*cross.x + cross.y*cross.y + cross.z*cross.z;
+
+ if (den < EPS)
+ return false;
+
+ double t1 = det(x, d2, cross) / den;
+ double t2 = det(x, d1, cross) / den;
+
+ r1 = o1 + d1 * t1;
+ r2 = o2 + d2 * t2;
+
+ return true;
+}
+
+// Convert from image to camera space by transforming point p in
+// the image plane by the camera matrix.
+static CvPoint3D32f ImageCStoWorldCS(const Cv3dTrackerCameraInfo &camera_info, CvPoint2D32f p)
+{
+ float tp[4];
+ tp[0] = (float)p.x - camera_info.principal_point.x;
+ tp[1] = (float)p.y - camera_info.principal_point.y;
+ tp[2] = 1.f;
+ tp[3] = 1.f;
+
+ float tr[4];
+ //multiply tp by mat to get tr
+ MultVectorMatrix(tr, tp, camera_info.mat);
+
+ return cvPoint3D32f(tr[0]/tr[3], tr[1]/tr[3], tr[2]/tr[3]);
+}
+
+// Multiply affine transformation m1 by the affine transformation m2 and
+// return the result in rm.
+static void MultMatrix(float rm[4][4], const float m1[4][4], const float m2[4][4])
+{
+ for (int i=0; i<=3; i++)
+ for (int j=0; j<=3; j++)
+ {
+ rm[i][j]= 0.0;
+ for (int k=0; k <= 3; k++)
+ rm[i][j] += m1[i][k]*m2[k][j];
+ }
+}
+
+// Multiply the vector v by the affine transformation matrix m and return the
+// result in rv.
+void MultVectorMatrix(float rv[4], const float v[4], const float m[4][4])
+{
+ for (int i=0; i<=3; i++)
+ {
+ rv[i] = 0.f;
+ for (int j=0;j<=3;j++)
+ rv[i] += v[j] * m[j][i];
+ }
+}
diff --git a/cvaux/src/cvaux.cpp b/cvaux/src/cvaux.cpp
new file mode 100644
index 0000000..528dffc
--- /dev/null
+++ b/cvaux/src/cvaux.cpp
@@ -0,0 +1,44 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+/* End of file. */
diff --git a/cvaux/src/cvauxutils.cpp b/cvaux/src/cvauxutils.cpp
new file mode 100644
index 0000000..528dffc
--- /dev/null
+++ b/cvaux/src/cvauxutils.cpp
@@ -0,0 +1,44 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+/* End of file. */
diff --git a/cvaux/src/cvbgfg_acmmm2003.cpp b/cvaux/src/cvbgfg_acmmm2003.cpp
new file mode 100644
index 0000000..bcb03b3
--- /dev/null
+++ b/cvaux/src/cvbgfg_acmmm2003.cpp
@@ -0,0 +1,740 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+
+// This file implements the foreground/background pixel
+// discrimination algorithm described in
+//
+// Foreground Object Detection from Videos Containing Complex Background
+// Li, Huan, Gu, Tian 2003 9p
+// http://muq.org/~cynbe/bib/foreground-object-detection-from-videos-containing-complex-background.pdf
+
+
+#include "_cvaux.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+//#include <algorithm>
+
+static double* _cv_max_element( double* start, double* end )
+{
+ double* p = start++;
+
+ for( ; start != end; ++start) {
+
+ if (*p < *start) p = start;
+ }
+
+ return p;
+}
+
+static void CV_CDECL icvReleaseFGDStatModel( CvFGDStatModel** model );
+static int CV_CDECL icvUpdateFGDStatModel( IplImage* curr_frame,
+ CvFGDStatModel* model );
+
+// Function cvCreateFGDStatModel initializes foreground detection process
+// parameters:
+// first_frame - frame from video sequence
+// parameters - (optional) if NULL default parameters of the algorithm will be used
+// p_model - pointer to CvFGDStatModel structure
+CV_IMPL CvBGStatModel*
+cvCreateFGDStatModel( IplImage* first_frame, CvFGDStatModelParams* parameters )
+{
+ CvFGDStatModel* p_model = 0;
+
+ CV_FUNCNAME( "cvCreateFGDStatModel" );
+
+ __BEGIN__;
+
+ int i, j, k, pixel_count, buf_size;
+ CvFGDStatModelParams params;
+
+ if( !CV_IS_IMAGE(first_frame) )
+ CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" );
+
+ if (first_frame->nChannels != 3)
+ CV_ERROR( CV_StsBadArg, "first_frame must have 3 color channels" );
+
+ // Initialize parameters:
+ if( parameters == NULL )
+ {
+ params.Lc = CV_BGFG_FGD_LC;
+ params.N1c = CV_BGFG_FGD_N1C;
+ params.N2c = CV_BGFG_FGD_N2C;
+
+ params.Lcc = CV_BGFG_FGD_LCC;
+ params.N1cc = CV_BGFG_FGD_N1CC;
+ params.N2cc = CV_BGFG_FGD_N2CC;
+
+ params.delta = CV_BGFG_FGD_DELTA;
+
+ params.alpha1 = CV_BGFG_FGD_ALPHA_1;
+ params.alpha2 = CV_BGFG_FGD_ALPHA_2;
+ params.alpha3 = CV_BGFG_FGD_ALPHA_3;
+
+ params.T = CV_BGFG_FGD_T;
+ params.minArea = CV_BGFG_FGD_MINAREA;
+
+ params.is_obj_without_holes = 1;
+ params.perform_morphing = 1;
+ }
+ else
+ {
+ params = *parameters;
+ }
+
+ CV_CALL( p_model = (CvFGDStatModel*)cvAlloc( sizeof(*p_model) ));
+ memset( p_model, 0, sizeof(*p_model) );
+ p_model->type = CV_BG_MODEL_FGD;
+ p_model->release = (CvReleaseBGStatModel)icvReleaseFGDStatModel;
+ p_model->update = (CvUpdateBGStatModel)icvUpdateFGDStatModel;;
+ p_model->params = params;
+
+ // Initialize storage pools:
+ pixel_count = first_frame->width * first_frame->height;
+
+ buf_size = pixel_count*sizeof(p_model->pixel_stat[0]);
+ CV_CALL( p_model->pixel_stat = (CvBGPixelStat*)cvAlloc(buf_size) );
+ memset( p_model->pixel_stat, 0, buf_size );
+
+ buf_size = pixel_count*params.N2c*sizeof(p_model->pixel_stat[0].ctable[0]);
+ CV_CALL( p_model->pixel_stat[0].ctable = (CvBGPixelCStatTable*)cvAlloc(buf_size) );
+ memset( p_model->pixel_stat[0].ctable, 0, buf_size );
+
+ buf_size = pixel_count*params.N2cc*sizeof(p_model->pixel_stat[0].cctable[0]);
+ CV_CALL( p_model->pixel_stat[0].cctable = (CvBGPixelCCStatTable*)cvAlloc(buf_size) );
+ memset( p_model->pixel_stat[0].cctable, 0, buf_size );
+
+ for( i = 0, k = 0; i < first_frame->height; i++ ) {
+ for( j = 0; j < first_frame->width; j++, k++ )
+ {
+ p_model->pixel_stat[k].ctable = p_model->pixel_stat[0].ctable + k*params.N2c;
+ p_model->pixel_stat[k].cctable = p_model->pixel_stat[0].cctable + k*params.N2cc;
+ }
+ }
+
+ // Init temporary images:
+ CV_CALL( p_model->Ftd = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
+ CV_CALL( p_model->Fbd = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
+ CV_CALL( p_model->foreground = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
+
+ CV_CALL( p_model->background = cvCloneImage(first_frame));
+ CV_CALL( p_model->prev_frame = cvCloneImage(first_frame));
+ CV_CALL( p_model->storage = cvCreateMemStorage());
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ {
+ CvBGStatModel* base_ptr = (CvBGStatModel*)p_model;
+
+ if( p_model && p_model->release )
+ p_model->release( &base_ptr );
+ else
+ cvFree( &p_model );
+ p_model = 0;
+ }
+
+ return (CvBGStatModel*)p_model;
+}
+
+
+static void CV_CDECL
+icvReleaseFGDStatModel( CvFGDStatModel** _model )
+{
+ CV_FUNCNAME( "icvReleaseFGDStatModel" );
+
+ __BEGIN__;
+
+ if( !_model )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( *_model )
+ {
+ CvFGDStatModel* model = *_model;
+ if( model->pixel_stat )
+ {
+ cvFree( &model->pixel_stat[0].ctable );
+ cvFree( &model->pixel_stat[0].cctable );
+ cvFree( &model->pixel_stat );
+ }
+
+ cvReleaseImage( &model->Ftd );
+ cvReleaseImage( &model->Fbd );
+ cvReleaseImage( &model->foreground );
+ cvReleaseImage( &model->background );
+ cvReleaseImage( &model->prev_frame );
+ cvReleaseMemStorage(&model->storage);
+
+ cvFree( _model );
+ }
+
+ __END__;
+}
+
+// Function cvChangeDetection performs change detection for Foreground detection algorithm
+// parameters:
+// prev_frame -
+// curr_frame -
+// change_mask -
+CV_IMPL int
+cvChangeDetection( IplImage* prev_frame,
+ IplImage* curr_frame,
+ IplImage* change_mask )
+{
+ int i, j, b, x, y, thres;
+ const int PIXELRANGE=256;
+
+ if( !prev_frame
+ || !curr_frame
+ || !change_mask
+ || prev_frame->nChannels != 3
+ || curr_frame->nChannels != 3
+ || change_mask->nChannels != 1
+ || prev_frame->depth != IPL_DEPTH_8U
+ || curr_frame->depth != IPL_DEPTH_8U
+ || change_mask->depth != IPL_DEPTH_8U
+ || prev_frame->width != curr_frame->width
+ || prev_frame->height != curr_frame->height
+ || prev_frame->width != change_mask->width
+ || prev_frame->height != change_mask->height
+ ){
+ return 0;
+ }
+
+ cvZero ( change_mask );
+
+ // All operations per colour
+ for (b=0 ; b<prev_frame->nChannels ; b++) {
+
+ // Create histogram:
+
+ long HISTOGRAM[PIXELRANGE];
+ for (i=0 ; i<PIXELRANGE; i++) HISTOGRAM[i]=0;
+
+ for (y=0 ; y<curr_frame->height ; y++)
+ {
+ uchar* rowStart1 = (uchar*)curr_frame->imageData + y * curr_frame->widthStep + b;
+ uchar* rowStart2 = (uchar*)prev_frame->imageData + y * prev_frame->widthStep + b;
+ for (x=0 ; x<curr_frame->width ; x++, rowStart1+=curr_frame->nChannels, rowStart2+=prev_frame->nChannels) {
+ int diff = abs( int(*rowStart1) - int(*rowStart2) );
+ HISTOGRAM[diff]++;
+ }
+ }
+
+ double relativeVariance[PIXELRANGE];
+ for (i=0 ; i<PIXELRANGE; i++) relativeVariance[i]=0;
+
+ for (thres=PIXELRANGE-2; thres>=0 ; thres--)
+ {
+ // fprintf(stderr, "Iter %d\n", thres);
+ double sum=0;
+ double sqsum=0;
+ int count=0;
+ // fprintf(stderr, "Iter %d entering loop\n", thres);
+ for (j=thres ; j<PIXELRANGE ; j++) {
+ sum += double(j)*double(HISTOGRAM[j]);
+ sqsum += double(j*j)*double(HISTOGRAM[j]);
+ count += HISTOGRAM[j];
+ }
+ count = count == 0 ? 1 : count;
+ // fprintf(stderr, "Iter %d finishing loop\n", thres);
+ double my = sum / count;
+ double sigma = sqrt( sqsum/count - my*my);
+ // fprintf(stderr, "Iter %d sum=%g sqsum=%g count=%d sigma = %g\n", thres, sum, sqsum, count, sigma);
+ // fprintf(stderr, "Writing to %x\n", &(relativeVariance[thres]));
+ relativeVariance[thres] = sigma;
+ // fprintf(stderr, "Iter %d finished\n", thres);
+ }
+
+ // Find maximum:
+ uchar bestThres = 0;
+
+ double* pBestThres = _cv_max_element(relativeVariance, relativeVariance+PIXELRANGE);
+ bestThres = (uchar)(*pBestThres); if (bestThres <10) bestThres=10;
+
+ for (y=0 ; y<prev_frame->height ; y++)
+ {
+ uchar* rowStart1 = (uchar*)(curr_frame->imageData) + y * curr_frame->widthStep + b;
+ uchar* rowStart2 = (uchar*)(prev_frame->imageData) + y * prev_frame->widthStep + b;
+ uchar* rowStart3 = (uchar*)(change_mask->imageData) + y * change_mask->widthStep;
+ for (x = 0; x < curr_frame->width; x++, rowStart1+=curr_frame->nChannels,
+ rowStart2+=prev_frame->nChannels, rowStart3+=change_mask->nChannels) {
+ // OR between different color channels
+ int diff = abs( int(*rowStart1) - int(*rowStart2) );
+ if ( diff > bestThres)
+ *rowStart3 |=255;
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+#define MIN_PV 1E-10
+
+
+#define V_C(k,l) ctable[k].v[l]
+#define PV_C(k) ctable[k].Pv
+#define PVB_C(k) ctable[k].Pvb
+#define V_CC(k,l) cctable[k].v[l]
+#define PV_CC(k) cctable[k].Pv
+#define PVB_CC(k) cctable[k].Pvb
+
+
+// Function cvUpdateFGDStatModel updates statistical model and returns number of foreground regions
+// parameters:
+// curr_frame - current frame from video sequence
+// p_model - pointer to CvFGDStatModel structure
+static int CV_CDECL
+icvUpdateFGDStatModel( IplImage* curr_frame, CvFGDStatModel* model )
+{
+ int mask_step = model->Ftd->widthStep;
+ CvSeq *first_seq = NULL, *prev_seq = NULL, *seq = NULL;
+ IplImage* prev_frame = model->prev_frame;
+ int region_count = 0;
+ int FG_pixels_count = 0;
+ int deltaC = cvRound(model->params.delta * 256 / model->params.Lc);
+ int deltaCC = cvRound(model->params.delta * 256 / model->params.Lcc);
+ int i, j, k, l;
+
+ //clear storages
+ cvClearMemStorage(model->storage);
+ cvZero(model->foreground);
+
+ // From foreground pixel candidates using image differencing
+ // with adaptive thresholding. The algorithm is from:
+ //
+ // Thresholding for Change Detection
+ // Paul L. Rosin 1998 6p
+ // http://www.cis.temple.edu/~latecki/Courses/CIS750-03/Papers/thresh-iccv.pdf
+ //
+ cvChangeDetection( prev_frame, curr_frame, model->Ftd );
+ cvChangeDetection( model->background, curr_frame, model->Fbd );
+
+ for( i = 0; i < model->Ftd->height; i++ )
+ {
+ for( j = 0; j < model->Ftd->width; j++ )
+ {
+ if( ((uchar*)model->Fbd->imageData)[i*mask_step+j] || ((uchar*)model->Ftd->imageData)[i*mask_step+j] )
+ {
+ float Pb = 0;
+ float Pv = 0;
+ float Pvb = 0;
+
+ CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
+
+ CvBGPixelCStatTable* ctable = stat->ctable;
+ CvBGPixelCCStatTable* cctable = stat->cctable;
+
+ uchar* curr_data = (uchar*)(curr_frame->imageData) + i*curr_frame->widthStep + j*3;
+ uchar* prev_data = (uchar*)(prev_frame->imageData) + i*prev_frame->widthStep + j*3;
+
+ int val = 0;
+
+ // Is it a motion pixel?
+ if( ((uchar*)model->Ftd->imageData)[i*mask_step+j] )
+ {
+ if( !stat->is_trained_dyn_model ) {
+
+ val = 1;
+
+ } else {
+
+ // Compare with stored CCt vectors:
+ for( k = 0; PV_CC(k) > model->params.alpha2 && k < model->params.N1cc; k++ )
+ {
+ if ( abs( V_CC(k,0) - prev_data[0]) <= deltaCC &&
+ abs( V_CC(k,1) - prev_data[1]) <= deltaCC &&
+ abs( V_CC(k,2) - prev_data[2]) <= deltaCC &&
+ abs( V_CC(k,3) - curr_data[0]) <= deltaCC &&
+ abs( V_CC(k,4) - curr_data[1]) <= deltaCC &&
+ abs( V_CC(k,5) - curr_data[2]) <= deltaCC)
+ {
+ Pv += PV_CC(k);
+ Pvb += PVB_CC(k);
+ }
+ }
+ Pb = stat->Pbcc;
+ if( 2 * Pvb * Pb <= Pv ) val = 1;
+ }
+ }
+ else if( stat->is_trained_st_model )
+ {
+ // Compare with stored Ct vectors:
+ for( k = 0; PV_C(k) > model->params.alpha2 && k < model->params.N1c; k++ )
+ {
+ if ( abs( V_C(k,0) - curr_data[0]) <= deltaC &&
+ abs( V_C(k,1) - curr_data[1]) <= deltaC &&
+ abs( V_C(k,2) - curr_data[2]) <= deltaC )
+ {
+ Pv += PV_C(k);
+ Pvb += PVB_C(k);
+ }
+ }
+ Pb = stat->Pbc;
+ if( 2 * Pvb * Pb <= Pv ) val = 1;
+ }
+
+ // Update foreground:
+ ((uchar*)model->foreground->imageData)[i*mask_step+j] = (uchar)(val*255);
+ FG_pixels_count += val;
+
+ } // end if( change detection...
+ } // for j...
+ } // for i...
+ //end BG/FG classification
+
+ // Foreground segmentation.
+ // Smooth foreground map:
+ if( model->params.perform_morphing ){
+ cvMorphologyEx( model->foreground, model->foreground, 0, 0, CV_MOP_OPEN, model->params.perform_morphing );
+ cvMorphologyEx( model->foreground, model->foreground, 0, 0, CV_MOP_CLOSE, model->params.perform_morphing );
+ }
+
+
+ if( model->params.minArea > 0 || model->params.is_obj_without_holes ){
+
+ // Discard under-size foreground regions:
+ //
+ cvFindContours( model->foreground, model->storage, &first_seq, sizeof(CvContour), CV_RETR_LIST );
+ for( seq = first_seq; seq; seq = seq->h_next )
+ {
+ CvContour* cnt = (CvContour*)seq;
+ if( cnt->rect.width * cnt->rect.height < model->params.minArea ||
+ (model->params.is_obj_without_holes && CV_IS_SEQ_HOLE(seq)) )
+ {
+ // Delete under-size contour:
+ prev_seq = seq->h_prev;
+ if( prev_seq )
+ {
+ prev_seq->h_next = seq->h_next;
+ if( seq->h_next ) seq->h_next->h_prev = prev_seq;
+ }
+ else
+ {
+ first_seq = seq->h_next;
+ if( seq->h_next ) seq->h_next->h_prev = NULL;
+ }
+ }
+ else
+ {
+ region_count++;
+ }
+ }
+ model->foreground_regions = first_seq;
+ cvZero(model->foreground);
+ cvDrawContours(model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);
+
+ } else {
+
+ model->foreground_regions = NULL;
+ }
+
+ // Check ALL BG update condition:
+ if( ((float)FG_pixels_count/(model->Ftd->width*model->Ftd->height)) > CV_BGFG_FGD_BG_UPDATE_TRESH )
+ {
+ for( i = 0; i < model->Ftd->height; i++ )
+ for( j = 0; j < model->Ftd->width; j++ )
+ {
+ CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
+ stat->is_trained_st_model = stat->is_trained_dyn_model = 1;
+ }
+ }
+
+
+ // Update background model:
+ for( i = 0; i < model->Ftd->height; i++ )
+ {
+ for( j = 0; j < model->Ftd->width; j++ )
+ {
+ CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
+ CvBGPixelCStatTable* ctable = stat->ctable;
+ CvBGPixelCCStatTable* cctable = stat->cctable;
+
+ uchar *curr_data = (uchar*)(curr_frame->imageData)+i*curr_frame->widthStep+j*3;
+ uchar *prev_data = (uchar*)(prev_frame->imageData)+i*prev_frame->widthStep+j*3;
+
+ if( ((uchar*)model->Ftd->imageData)[i*mask_step+j] || !stat->is_trained_dyn_model )
+ {
+ float alpha = stat->is_trained_dyn_model ? model->params.alpha2 : model->params.alpha3;
+ float diff = 0;
+ int dist, min_dist = 2147483647, indx = -1;
+
+ //update Pb
+ stat->Pbcc *= (1.f-alpha);
+ if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
+ {
+ stat->Pbcc += alpha;
+ }
+
+ // Find best Vi match:
+ for(k = 0; PV_CC(k) && k < model->params.N2cc; k++ )
+ {
+ // Exponential decay of memory
+ PV_CC(k) *= (1-alpha);
+ PVB_CC(k) *= (1-alpha);
+ if( PV_CC(k) < MIN_PV )
+ {
+ PV_CC(k) = 0;
+ PVB_CC(k) = 0;
+ continue;
+ }
+
+ dist = 0;
+ for( l = 0; l < 3; l++ )
+ {
+ int val = abs( V_CC(k,l) - prev_data[l] );
+ if( val > deltaCC ) break;
+ dist += val;
+ val = abs( V_CC(k,l+3) - curr_data[l] );
+ if( val > deltaCC) break;
+ dist += val;
+ }
+ if( l == 3 && dist < min_dist )
+ {
+ min_dist = dist;
+ indx = k;
+ }
+ }
+
+
+ if( indx < 0 )
+ { // Replace N2th elem in the table by new feature:
+ indx = model->params.N2cc - 1;
+ PV_CC(indx) = alpha;
+ PVB_CC(indx) = alpha;
+ //udate Vt
+ for( l = 0; l < 3; l++ )
+ {
+ V_CC(indx,l) = prev_data[l];
+ V_CC(indx,l+3) = curr_data[l];
+ }
+ }
+ else
+ { // Update:
+ PV_CC(indx) += alpha;
+ if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
+ {
+ PVB_CC(indx) += alpha;
+ }
+ }
+
+ //re-sort CCt table by Pv
+ for( k = 0; k < indx; k++ )
+ {
+ if( PV_CC(k) <= PV_CC(indx) )
+ {
+ //shift elements
+ CvBGPixelCCStatTable tmp1, tmp2 = cctable[indx];
+ for( l = k; l <= indx; l++ )
+ {
+ tmp1 = cctable[l];
+ cctable[l] = tmp2;
+ tmp2 = tmp1;
+ }
+ break;
+ }
+ }
+
+
+ float sum1=0, sum2=0;
+ //check "once-off" changes
+ for(k = 0; PV_CC(k) && k < model->params.N1cc; k++ )
+ {
+ sum1 += PV_CC(k);
+ sum2 += PVB_CC(k);
+ }
+ if( sum1 > model->params.T ) stat->is_trained_dyn_model = 1;
+
+ diff = sum1 - stat->Pbcc * sum2;
+ // Update stat table:
+ if( diff > model->params.T )
+ {
+ //printf("once off change at motion mode\n");
+ //new BG features are discovered
+ for( k = 0; PV_CC(k) && k < model->params.N1cc; k++ )
+ {
+ PVB_CC(k) =
+ (PV_CC(k)-stat->Pbcc*PVB_CC(k))/(1-stat->Pbcc);
+ }
+ assert(stat->Pbcc<=1 && stat->Pbcc>=0);
+ }
+ }
+
+ // Handle "stationary" pixel:
+ if( !((uchar*)model->Ftd->imageData)[i*mask_step+j] )
+ {
+ float alpha = stat->is_trained_st_model ? model->params.alpha2 : model->params.alpha3;
+ float diff = 0;
+ int dist, min_dist = 2147483647, indx = -1;
+
+ //update Pb
+ stat->Pbc *= (1.f-alpha);
+ if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
+ {
+ stat->Pbc += alpha;
+ }
+
+ //find best Vi match
+ for( k = 0; k < model->params.N2c; k++ )
+ {
+ // Exponential decay of memory
+ PV_C(k) *= (1-alpha);
+ PVB_C(k) *= (1-alpha);
+ if( PV_C(k) < MIN_PV )
+ {
+ PV_C(k) = 0;
+ PVB_C(k) = 0;
+ continue;
+ }
+
+ dist = 0;
+ for( l = 0; l < 3; l++ )
+ {
+ int val = abs( V_C(k,l) - curr_data[l] );
+ if( val > deltaC ) break;
+ dist += val;
+ }
+ if( l == 3 && dist < min_dist )
+ {
+ min_dist = dist;
+ indx = k;
+ }
+ }
+
+ if( indx < 0 )
+ {//N2th elem in the table is replaced by a new features
+ indx = model->params.N2c - 1;
+ PV_C(indx) = alpha;
+ PVB_C(indx) = alpha;
+ //udate Vt
+ for( l = 0; l < 3; l++ )
+ {
+ V_C(indx,l) = curr_data[l];
+ }
+ } else
+ {//update
+ PV_C(indx) += alpha;
+ if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
+ {
+ PVB_C(indx) += alpha;
+ }
+ }
+
+ //re-sort Ct table by Pv
+ for( k = 0; k < indx; k++ )
+ {
+ if( PV_C(k) <= PV_C(indx) )
+ {
+ //shift elements
+ CvBGPixelCStatTable tmp1, tmp2 = ctable[indx];
+ for( l = k; l <= indx; l++ )
+ {
+ tmp1 = ctable[l];
+ ctable[l] = tmp2;
+ tmp2 = tmp1;
+ }
+ break;
+ }
+ }
+
+ // Check "once-off" changes:
+ float sum1=0, sum2=0;
+ for( k = 0; PV_C(k) && k < model->params.N1c; k++ )
+ {
+ sum1 += PV_C(k);
+ sum2 += PVB_C(k);
+ }
+ diff = sum1 - stat->Pbc * sum2;
+ if( sum1 > model->params.T ) stat->is_trained_st_model = 1;
+
+ // Update stat table:
+ if( diff > model->params.T )
+ {
+ //printf("once off change at stat mode\n");
+ //new BG features are discovered
+ for( k = 0; PV_C(k) && k < model->params.N1c; k++ )
+ {
+ PVB_C(k) = (PV_C(k)-stat->Pbc*PVB_C(k))/(1-stat->Pbc);
+ }
+ stat->Pbc = 1 - stat->Pbc;
+ }
+ } // if !(change detection) at pixel (i,j)
+
+ // Update the reference BG image:
+ if( !((uchar*)model->foreground->imageData)[i*mask_step+j])
+ {
+ uchar* ptr = ((uchar*)model->background->imageData) + i*model->background->widthStep+j*3;
+
+ if( !((uchar*)model->Ftd->imageData)[i*mask_step+j] &&
+ !((uchar*)model->Fbd->imageData)[i*mask_step+j] )
+ {
+ // Apply IIR filter:
+ for( l = 0; l < 3; l++ )
+ {
+ int a = cvRound(ptr[l]*(1 - model->params.alpha1) + model->params.alpha1*curr_data[l]);
+ ptr[l] = (uchar)a;
+ //((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l]*=(1 - model->params.alpha1);
+ //((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l] += model->params.alpha1*curr_data[l];
+ }
+ }
+ else
+ {
+ // Background change detected:
+ for( l = 0; l < 3; l++ )
+ {
+ //((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l] = curr_data[l];
+ ptr[l] = curr_data[l];
+ }
+ }
+ }
+ } // j
+ } // i
+
+ // Keep previous frame:
+ cvCopy( curr_frame, model->prev_frame );
+
+ return region_count;
+}
+
+/* End of file. */
diff --git a/cvaux/src/cvbgfg_codebook.cpp b/cvaux/src/cvbgfg_codebook.cpp
new file mode 100644
index 0000000..3abadff
--- /dev/null
+++ b/cvaux/src/cvbgfg_codebook.cpp
@@ -0,0 +1,362 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+CvBGCodeBookModel* cvCreateBGCodeBookModel()
+{
+ CvBGCodeBookModel* model = (CvBGCodeBookModel*)cvAlloc( sizeof(*model) );
+ memset( model, 0, sizeof(*model) );
+ model->cbBounds[0] = model->cbBounds[1] = model->cbBounds[2] = 10;
+ model->modMin[0] = 3;
+ model->modMax[0] = 10;
+ model->modMin[1] = model->modMin[2] = 1;
+ model->modMax[1] = model->modMax[2] = 1;
+ model->storage = cvCreateMemStorage();
+
+ return model;
+}
+
+void cvReleaseBGCodeBookModel( CvBGCodeBookModel** model )
+{
+ if( model && *model )
+ {
+ cvReleaseMemStorage( &(*model)->storage );
+ memset( *model, 0, sizeof(**model) );
+ cvFree( model );
+ }
+}
+
+static uchar satTab8u[768];
+#undef SAT_8U
+#define SAT_8U(x) satTab8u[(x) + 255]
+
+static void icvInitSatTab()
+{
+ static int initialized = 0;
+ if( !initialized )
+ {
+ for( int i = 0; i < 768; i++ )
+ {
+ int v = i - 255;
+ satTab8u[i] = (uchar)(v < 0 ? 0 : v > 255 ? 255 : v);
+ }
+ initialized = 1;
+ }
+}
+
+
+void cvBGCodeBookUpdate( CvBGCodeBookModel* model, const CvArr* _image,
+ CvRect roi, const CvArr* _mask )
+{
+ CV_FUNCNAME( "cvBGCodeBookUpdate" );
+
+ __BEGIN__;
+
+ CvMat stub, *image = cvGetMat( _image, &stub );
+ CvMat mstub, *mask = _mask ? cvGetMat( _mask, &mstub ) : 0;
+ int i, x, y, T;
+ int nblocks;
+ uchar cb0, cb1, cb2;
+ CvBGCodeBookElem* freeList;
+
+ CV_ASSERT( model && CV_MAT_TYPE(image->type) == CV_8UC3 &&
+ (!mask || CV_IS_MASK_ARR(mask) && CV_ARE_SIZES_EQ(image, mask)) );
+
+ if( roi.x == 0 && roi.y == 0 && roi.width == 0 && roi.height == 0 )
+ {
+ roi.width = image->cols;
+ roi.height = image->rows;
+ }
+ else
+ CV_ASSERT( (unsigned)roi.x < (unsigned)image->cols &&
+ (unsigned)roi.y < (unsigned)image->rows &&
+ roi.width >= 0 && roi.height >= 0 &&
+ roi.x + roi.width <= image->cols &&
+ roi.y + roi.height <= image->rows );
+
+ if( image->cols != model->size.width || image->rows != model->size.height )
+ {
+ cvClearMemStorage( model->storage );
+ model->freeList = 0;
+ cvFree( &model->cbmap );
+ int bufSz = image->cols*image->rows*sizeof(model->cbmap[0]);
+ model->cbmap = (CvBGCodeBookElem**)cvAlloc(bufSz);
+ memset( model->cbmap, 0, bufSz );
+ model->size = cvSize(image->cols, image->rows);
+ }
+
+ icvInitSatTab();
+
+ cb0 = model->cbBounds[0];
+ cb1 = model->cbBounds[1];
+ cb2 = model->cbBounds[2];
+
+ T = ++model->t;
+ freeList = model->freeList;
+ nblocks = (int)((model->storage->block_size - sizeof(CvMemBlock))/sizeof(*freeList));
+ nblocks = MIN( nblocks, 1024 );
+ CV_ASSERT( nblocks > 0 );
+
+ for( y = 0; y < roi.height; y++ )
+ {
+ const uchar* p = image->data.ptr + image->step*(y + roi.y) + roi.x*3;
+ const uchar* m = mask ? mask->data.ptr + mask->step*(y + roi.y) + roi.x : 0;
+ CvBGCodeBookElem** cb = model->cbmap + image->cols*(y + roi.y) + roi.x;
+
+ for( x = 0; x < roi.width; x++, p += 3, cb++ )
+ {
+ CvBGCodeBookElem *e, *found = 0;
+ uchar p0, p1, p2, l0, l1, l2, h0, h1, h2;
+ int negRun;
+
+ if( m && m[x] == 0 )
+ continue;
+
+ p0 = p[0]; p1 = p[1]; p2 = p[2];
+ l0 = SAT_8U(p0 - cb0); l1 = SAT_8U(p1 - cb1); l2 = SAT_8U(p2 - cb2);
+ h0 = SAT_8U(p0 + cb0); h1 = SAT_8U(p1 + cb1); h2 = SAT_8U(p2 + cb2);
+
+ for( e = *cb; e != 0; e = e->next )
+ {
+ if( e->learnMin[0] <= p0 && p0 <= e->learnMax[0] &&
+ e->learnMin[1] <= p1 && p1 <= e->learnMax[1] &&
+ e->learnMin[2] <= p2 && p2 <= e->learnMax[2] )
+ {
+ e->tLastUpdate = T;
+ e->boxMin[0] = MIN(e->boxMin[0], p0);
+ e->boxMax[0] = MAX(e->boxMax[0], p0);
+ e->boxMin[1] = MIN(e->boxMin[1], p1);
+ e->boxMax[1] = MAX(e->boxMax[1], p1);
+ e->boxMin[2] = MIN(e->boxMin[2], p2);
+ e->boxMax[2] = MAX(e->boxMax[2], p2);
+
+ // no need to use SAT_8U for updated learnMin[i] & learnMax[i] here,
+ // as the bounding li & hi are already within 0..255.
+ if( e->learnMin[0] > l0 ) e->learnMin[0]--;
+ if( e->learnMax[0] < h0 ) e->learnMax[0]++;
+ if( e->learnMin[1] > l1 ) e->learnMin[1]--;
+ if( e->learnMax[1] < h1 ) e->learnMax[1]++;
+ if( e->learnMin[2] > l2 ) e->learnMin[2]--;
+ if( e->learnMax[2] < h2 ) e->learnMax[2]++;
+
+ found = e;
+ break;
+ }
+ negRun = T - e->tLastUpdate;
+ e->stale = MAX( e->stale, negRun );
+ }
+
+ for( ; e != 0; e = e->next )
+ {
+ negRun = T - e->tLastUpdate;
+ e->stale = MAX( e->stale, negRun );
+ }
+
+ if( !found )
+ {
+ if( !freeList )
+ {
+ freeList = (CvBGCodeBookElem*)cvMemStorageAlloc(model->storage,
+ nblocks*sizeof(*freeList));
+ for( i = 0; i < nblocks-1; i++ )
+ freeList[i].next = &freeList[i+1];
+ freeList[nblocks-1].next = 0;
+ }
+ e = freeList;
+ freeList = freeList->next;
+
+ e->learnMin[0] = l0; e->learnMax[0] = h0;
+ e->learnMin[1] = l1; e->learnMax[1] = h1;
+ e->learnMin[2] = l2; e->learnMax[2] = h2;
+ e->boxMin[0] = e->boxMax[0] = p0;
+ e->boxMin[1] = e->boxMax[1] = p1;
+ e->boxMin[2] = e->boxMax[2] = p2;
+ e->tLastUpdate = T;
+ e->stale = 0;
+ e->next = *cb;
+ *cb = e;
+ }
+ }
+ }
+
+ model->freeList = freeList;
+
+ __END__;
+}
+
+
+int cvBGCodeBookDiff( const CvBGCodeBookModel* model, const CvArr* _image,
+ CvArr* _fgmask, CvRect roi )
+{
+ int maskCount = -1;
+
+ CV_FUNCNAME( "cvBGCodeBookDiff" );
+
+ __BEGIN__;
+
+ CvMat stub, *image = cvGetMat( _image, &stub );
+ CvMat mstub, *mask = cvGetMat( _fgmask, &mstub );
+ int x, y;
+ uchar m0, m1, m2, M0, M1, M2;
+
+ CV_ASSERT( model && CV_MAT_TYPE(image->type) == CV_8UC3 &&
+ image->cols == model->size.width && image->rows == model->size.height &&
+ CV_IS_MASK_ARR(mask) && CV_ARE_SIZES_EQ(image, mask) );
+
+ if( roi.x == 0 && roi.y == 0 && roi.width == 0 && roi.height == 0 )
+ {
+ roi.width = image->cols;
+ roi.height = image->rows;
+ }
+ else
+ CV_ASSERT( (unsigned)roi.x < (unsigned)image->cols &&
+ (unsigned)roi.y < (unsigned)image->rows &&
+ roi.width >= 0 && roi.height >= 0 &&
+ roi.x + roi.width <= image->cols &&
+ roi.y + roi.height <= image->rows );
+
+ m0 = model->modMin[0]; M0 = model->modMax[0];
+ m1 = model->modMin[1]; M1 = model->modMax[1];
+ m2 = model->modMin[2]; M2 = model->modMax[2];
+
+ maskCount = roi.height*roi.width;
+ for( y = 0; y < roi.height; y++ )
+ {
+ const uchar* p = image->data.ptr + image->step*(y + roi.y) + roi.x*3;
+ uchar* m = mask->data.ptr + mask->step*(y + roi.y) + roi.x;
+ CvBGCodeBookElem** cb = model->cbmap + image->cols*(y + roi.y) + roi.x;
+
+ for( x = 0; x < roi.width; x++, p += 3, cb++ )
+ {
+ CvBGCodeBookElem *e;
+ uchar p0 = p[0], p1 = p[1], p2 = p[2];
+ int l0 = p0 + m0, l1 = p1 + m1, l2 = p2 + m2;
+ int h0 = p0 - M0, h1 = p1 - M1, h2 = p2 - M2;
+ m[x] = (uchar)255;
+
+ for( e = *cb; e != 0; e = e->next )
+ {
+ if( e->boxMin[0] <= l0 && h0 <= e->boxMax[0] &&
+ e->boxMin[1] <= l1 && h1 <= e->boxMax[1] &&
+ e->boxMin[2] <= l2 && h2 <= e->boxMax[2] )
+ {
+ m[x] = 0;
+ maskCount--;
+ break;
+ }
+ }
+ }
+ }
+
+ __END__;
+
+ return maskCount;
+}
+
+void cvBGCodeBookClearStale( CvBGCodeBookModel* model, int staleThresh,
+ CvRect roi, const CvArr* _mask )
+{
+ CV_FUNCNAME( "cvBGCodeBookClearStale" );
+
+ __BEGIN__;
+
+ CvMat mstub, *mask = _mask ? cvGetMat( _mask, &mstub ) : 0;
+ int x, y, T;
+ CvBGCodeBookElem* freeList;
+
+ CV_ASSERT( model && (!mask || CV_IS_MASK_ARR(mask) &&
+ mask->cols == model->size.width && mask->rows == model->size.height) );
+
+ if( roi.x == 0 && roi.y == 0 && roi.width == 0 && roi.height == 0 )
+ {
+ roi.width = model->size.width;
+ roi.height = model->size.height;
+ }
+ else
+ CV_ASSERT( (unsigned)roi.x < (unsigned)mask->cols &&
+ (unsigned)roi.y < (unsigned)mask->rows &&
+ roi.width >= 0 && roi.height >= 0 &&
+ roi.x + roi.width <= mask->cols &&
+ roi.y + roi.height <= mask->rows );
+
+ icvInitSatTab();
+ freeList = model->freeList;
+ T = model->t;
+
+ for( y = 0; y < roi.height; y++ )
+ {
+ const uchar* m = mask ? mask->data.ptr + mask->step*(y + roi.y) + roi.x : 0;
+ CvBGCodeBookElem** cb = model->cbmap + model->size.width*(y + roi.y) + roi.x;
+
+ for( x = 0; x < roi.width; x++, cb++ )
+ {
+ CvBGCodeBookElem *e, first, *prev = &first;
+
+ if( m && m[x] == 0 )
+ continue;
+
+ for( first.next = e = *cb; e != 0; e = prev->next )
+ {
+ if( e->stale > staleThresh )
+ {
+ prev->next = e->next;
+ e->next = freeList;
+ freeList = e;
+ }
+ else
+ {
+ e->stale = 0;
+ e->tLastUpdate = T;
+ prev = e;
+ }
+ }
+
+ *cb = first.next;
+ }
+ }
+
+ model->freeList = freeList;
+
+ __END__;
+}
+
+/* End of file. */
+
diff --git a/cvaux/src/cvbgfg_common.cpp b/cvaux/src/cvbgfg_common.cpp
new file mode 100644
index 0000000..4185812
--- /dev/null
+++ b/cvaux/src/cvbgfg_common.cpp
@@ -0,0 +1,124 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+// Function cvRefineForegroundMaskBySegm preforms FG post-processing based on segmentation
+// (all pixels of the segment will be classified as FG if majority of pixels of the region are FG).
+// parameters:
+// segments - pointer to result of segmentation (for example MeanShiftSegmentation)
+// bg_model - pointer to CvBGStatModel structure
+CV_IMPL void cvRefineForegroundMaskBySegm( CvSeq* segments, CvBGStatModel* bg_model )
+{
+ IplImage* tmp_image = cvCreateImage(cvSize(bg_model->foreground->width,bg_model->foreground->height),
+ IPL_DEPTH_8U, 1);
+ for( ; segments; segments = ((CvSeq*)segments)->h_next )
+ {
+ CvSeq seq = *segments;
+ seq.v_next = seq.h_next = NULL;
+ cvZero(tmp_image);
+ cvDrawContours( tmp_image, &seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);
+ int num1 = cvCountNonZero(tmp_image);
+ cvAnd(tmp_image, bg_model->foreground, tmp_image);
+ int num2 = cvCountNonZero(tmp_image);
+ if( num2 > num1*0.5 )
+ cvDrawContours( bg_model->foreground, &seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);
+ else
+ cvDrawContours( bg_model->foreground, &seq, CV_RGB(0, 0, 0), CV_RGB(0, 0, 0), 10, -1);
+ }
+ cvReleaseImage(&tmp_image);
+}
+
+
+
+CV_IMPL CvSeq*
+cvSegmentFGMask( CvArr* _mask, int poly1Hull0, float perimScale,
+ CvMemStorage* storage, CvPoint offset )
+{
+ CvMat mstub, *mask = cvGetMat( _mask, &mstub );
+ CvMemStorage* tempStorage = storage ? storage : cvCreateMemStorage();
+ CvSeq *contours, *c;
+ int nContours = 0;
+ CvContourScanner scanner;
+
+ // clean up raw mask
+ cvMorphologyEx( mask, mask, 0, 0, CV_MOP_OPEN, 1 );
+ cvMorphologyEx( mask, mask, 0, 0, CV_MOP_CLOSE, 1 );
+
+ // find contours around only bigger regions
+ scanner = cvStartFindContours( mask, tempStorage,
+ sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, offset );
+
+ while( (c = cvFindNextContour( scanner )) != 0 )
+ {
+ double len = cvContourPerimeter( c );
+ double q = (mask->rows + mask->cols)/perimScale; // calculate perimeter len threshold
+ if( len < q ) //Get rid of blob if it's perimeter is too small
+ cvSubstituteContour( scanner, 0 );
+ else //Smooth it's edges if it's large enough
+ {
+ CvSeq* newC;
+ if( poly1Hull0 ) //Polygonal approximation of the segmentation
+ newC = cvApproxPoly( c, sizeof(CvContour), tempStorage, CV_POLY_APPROX_DP, 2, 0 );
+ else //Convex Hull of the segmentation
+ newC = cvConvexHull2( c, tempStorage, CV_CLOCKWISE, 1 );
+ cvSubstituteContour( scanner, newC );
+ nContours++;
+ }
+ }
+ contours = cvEndFindContours( &scanner );
+
+ // paint the found regions back into the image
+ cvZero( mask );
+ for( c=contours; c != 0; c = c->h_next )
+ cvDrawContours( mask, c, cvScalarAll(255), cvScalarAll(0), -1, CV_FILLED, 8,
+ cvPoint(-offset.x,-offset.y));
+
+ if( tempStorage != storage )
+ {
+ cvReleaseMemStorage( &tempStorage );
+ contours = 0;
+ }
+
+ return contours;
+}
+
+/* End of file. */
+
diff --git a/cvaux/src/cvbgfg_gaussmix.cpp b/cvaux/src/cvbgfg_gaussmix.cpp
new file mode 100644
index 0000000..f4655cd
--- /dev/null
+++ b/cvaux/src/cvbgfg_gaussmix.cpp
@@ -0,0 +1,597 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+
+// This is based on the "An Improved Adaptive Background Mixture Model for
+// Real-time Tracking with Shadow Detection" by P. KaewTraKulPong and R. Bowden
+// http://personal.ee.surrey.ac.uk/Personal/R.Bowden/publications/avbs01/avbs01.pdf
+//
+// The windowing method is used, but not the shadow detection. I make some of my
+// own modifications which make more sense. There are some errors in some of their
+// equations.
+//
+//IplImage values of image that are useful
+//int nSize; /* sizeof(IplImage) */
+//int depth; /* pixel depth in bits: IPL_DEPTH_8U ...*/
+//int nChannels; /* OpenCV functions support 1,2,3 or 4 channels */
+//int width; /* image width in pixels */
+//int height; /* image height in pixels */
+//int imageSize; /* image data size in bytes in case of interleaved data)*/
+//char *imageData; /* pointer to aligned image data */
+//char *imageDataOrigin; /* pointer to very origin of image -deallocation */
+//Values useful for gaussian integral
+//0.5 - 0.19146 - 0.38292
+//1.0 - 0.34134 - 0.68268
+//1.5 - 0.43319 - 0.86638
+//2.0 - 0.47725 - 0.95450
+//2.5 - 0.49379 - 0.98758
+//3.0 - 0.49865 - 0.99730
+//3.5 - 0.4997674 - 0.9995348
+//4.0 - 0.4999683 - 0.9999366
+
+#include "_cvaux.h"
+
+
+//internal functions for gaussian background detection
+static void icvInsertionSortGaussians( CvGaussBGPoint* g_point, double* sort_key, CvGaussBGStatModelParams *bg_model_params );
+
+/*
+ Test whether pixel can be explained by background model;
+ Return -1 if no match was found; otherwise the index in match[] is returned
+
+ icvMatchTest(...) assumes what all color channels component exhibit the same variance
+ icvMatchTest2(...) accounts for different variances per color channel
+ */
+static int icvMatchTest( double* src_pixel, int nChannels, int* match,
+ const CvGaussBGPoint* g_point, const CvGaussBGStatModelParams *bg_model_params );
+/*static int icvMatchTest2( double* src_pixel, int nChannels, int* match,
+ const CvGaussBGPoint* g_point, const CvGaussBGStatModelParams *bg_model_params );*/
+
+
+/*
+ The update procedure differs between
+ * the initialization phase (named *Partial* ) and
+ * the normal phase (named *Full* )
+ The initalization phase is defined as not having processed <win_size> frames yet
+ */
+static void icvUpdateFullWindow( double* src_pixel, int nChannels,
+ int* match,
+ CvGaussBGPoint* g_point,
+ const CvGaussBGStatModelParams *bg_model_params );
+static void icvUpdateFullNoMatch( IplImage* gm_image, int p,
+ int* match,
+ CvGaussBGPoint* g_point,
+ const CvGaussBGStatModelParams *bg_model_params);
+static void icvUpdatePartialWindow( double* src_pixel, int nChannels, int* match,
+ CvGaussBGPoint* g_point, const CvGaussBGStatModelParams *bg_model_params );
+static void icvUpdatePartialNoMatch( double* src_pixel, int nChannels,
+ int* match,
+ CvGaussBGPoint* g_point,
+ const CvGaussBGStatModelParams *bg_model_params);
+
+
+static void icvGetSortKey( const int nChannels, double* sort_key, const CvGaussBGPoint* g_point,
+ const CvGaussBGStatModelParams *bg_model_params );
+static void icvBackgroundTest( const int nChannels, int n, int i, int j, int *match, CvGaussBGModel* bg_model );
+
+static void CV_CDECL icvReleaseGaussianBGModel( CvGaussBGModel** bg_model );
+static int CV_CDECL icvUpdateGaussianBGModel( IplImage* curr_frame, CvGaussBGModel* bg_model );
+
+//#define for if(0);else for
+
+//g = 1 for first gaussian in list that matches else g = 0
+//Rw is the learning rate for weight and Rg is leaning rate for mean and variance
+//Ms is the match_sum which is the sum of matches for a particular gaussian
+//Ms values are incremented until the sum of Ms values in the list equals window size L
+//SMs is the sum of match_sums for gaussians in the list
+//Rw = 1/SMs note the smallest Rw gets is 1/L
+//Rg = g/Ms for SMs < L and Rg = g/(w*L) for SMs = L
+//The list is maintained in sorted order using w/sqrt(variance) as a key
+//If there is no match the last gaussian in the list is replaced by the new gaussian
+//This will result in changes to SMs which results in changes in Rw and Rg.
+//If a gaussian is replaced and SMs previously equaled L values of Ms are computed from w
+//w[n+1] = w[n] + Rw*(g - w[n]) weight
+//u[n+1] = u[n] + Rg*(x[n+1] - u[n]) mean value Sg is sum n values of g
+//v[n+1] = v[n] + Rg*((x[n+1] - u[n])*(x[n+1] - u[n])) - v[n]) variance
+//
+
+CV_IMPL CvBGStatModel*
+cvCreateGaussianBGModel( IplImage* first_frame, CvGaussBGStatModelParams* parameters )
+{
+ CvGaussBGModel* bg_model = 0;
+
+ CV_FUNCNAME( "cvCreateGaussianBGModel" );
+
+ __BEGIN__;
+
+ double var_init;
+ CvGaussBGStatModelParams params;
+ int i, j, k, m, n;
+
+ //init parameters
+ if( parameters == NULL )
+ { /* These constants are defined in cvaux/include/cvaux.h: */
+ params.win_size = CV_BGFG_MOG_WINDOW_SIZE;
+ params.bg_threshold = CV_BGFG_MOG_BACKGROUND_THRESHOLD;
+
+ params.std_threshold = CV_BGFG_MOG_STD_THRESHOLD;
+ params.weight_init = CV_BGFG_MOG_WEIGHT_INIT;
+
+ params.variance_init = CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT;
+ params.minArea = CV_BGFG_MOG_MINAREA;
+ params.n_gauss = CV_BGFG_MOG_NGAUSSIANS;
+ }
+ else
+ {
+ params = *parameters;
+ }
+
+ if( !CV_IS_IMAGE(first_frame) )
+ CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" );
+
+ CV_CALL( bg_model = (CvGaussBGModel*)cvAlloc( sizeof(*bg_model) ));
+ memset( bg_model, 0, sizeof(*bg_model) );
+ bg_model->type = CV_BG_MODEL_MOG;
+ bg_model->release = (CvReleaseBGStatModel)icvReleaseGaussianBGModel;
+ bg_model->update = (CvUpdateBGStatModel)icvUpdateGaussianBGModel;
+
+ bg_model->params = params;
+
+ //prepare storages
+ CV_CALL( bg_model->g_point = (CvGaussBGPoint*)cvAlloc(sizeof(CvGaussBGPoint)*
+ ((first_frame->width*first_frame->height) + 256)));
+
+ CV_CALL( bg_model->background = cvCreateImage(cvSize(first_frame->width,
+ first_frame->height), IPL_DEPTH_8U, first_frame->nChannels));
+ CV_CALL( bg_model->foreground = cvCreateImage(cvSize(first_frame->width,
+ first_frame->height), IPL_DEPTH_8U, 1));
+
+ CV_CALL( bg_model->storage = cvCreateMemStorage());
+
+ //initializing
+ var_init = 2 * params.std_threshold * params.std_threshold;
+ CV_CALL( bg_model->g_point[0].g_values =
+ (CvGaussBGValues*)cvAlloc( sizeof(CvGaussBGValues)*params.n_gauss*
+ (first_frame->width*first_frame->height + 128)));
+
+ for( i = 0, n = 0; i < first_frame->height; i++ )
+ {
+ for( j = 0; j < first_frame->width; j++, n++ )
+ {
+ const int p = i*first_frame->widthStep+j*first_frame->nChannels;
+
+ bg_model->g_point[n].g_values =
+ bg_model->g_point[0].g_values + n*params.n_gauss;
+ bg_model->g_point[n].g_values[0].weight = 1; //the first value seen has weight one
+ bg_model->g_point[n].g_values[0].match_sum = 1;
+ for( m = 0; m < first_frame->nChannels; m++)
+ {
+ bg_model->g_point[n].g_values[0].variance[m] = var_init;
+ bg_model->g_point[n].g_values[0].mean[m] = (unsigned char)first_frame->imageData[p + m];
+ }
+ for( k = 1; k < params.n_gauss; k++)
+ {
+ bg_model->g_point[n].g_values[k].weight = 0;
+ bg_model->g_point[n].g_values[k].match_sum = 0;
+ for( m = 0; m < first_frame->nChannels; m++){
+ bg_model->g_point[n].g_values[k].variance[m] = var_init;
+ bg_model->g_point[n].g_values[k].mean[m] = 0;
+ }
+ }
+ }
+ }
+
+ bg_model->countFrames = 0;
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ {
+ CvBGStatModel* base_ptr = (CvBGStatModel*)bg_model;
+
+ if( bg_model && bg_model->release )
+ bg_model->release( &base_ptr );
+ else
+ cvFree( &bg_model );
+ bg_model = 0;
+ }
+
+ return (CvBGStatModel*)bg_model;
+}
+
+
+static void CV_CDECL
+icvReleaseGaussianBGModel( CvGaussBGModel** _bg_model )
+{
+ CV_FUNCNAME( "icvReleaseGaussianBGModel" );
+
+ __BEGIN__;
+
+ if( !_bg_model )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( *_bg_model )
+ {
+ CvGaussBGModel* bg_model = *_bg_model;
+ if( bg_model->g_point )
+ {
+ cvFree( &bg_model->g_point[0].g_values );
+ cvFree( &bg_model->g_point );
+ }
+
+ cvReleaseImage( &bg_model->background );
+ cvReleaseImage( &bg_model->foreground );
+ cvReleaseMemStorage(&bg_model->storage);
+ memset( bg_model, 0, sizeof(*bg_model) );
+ cvFree( _bg_model );
+ }
+
+ __END__;
+}
+
+
+static int CV_CDECL
+icvUpdateGaussianBGModel( IplImage* curr_frame, CvGaussBGModel* bg_model )
+{
+ int i, j, k, n;
+ int region_count = 0;
+ CvSeq *first_seq = NULL, *prev_seq = NULL, *seq = NULL;
+
+ bg_model->countFrames++;
+
+ for( i = 0, n = 0; i < curr_frame->height; i++ )
+ {
+ for( j = 0; j < curr_frame->width; j++, n++ )
+ {
+ int match[CV_BGFG_MOG_MAX_NGAUSSIANS];
+ double sort_key[CV_BGFG_MOG_MAX_NGAUSSIANS];
+ const int nChannels = curr_frame->nChannels;
+ const int p = curr_frame->widthStep*i+j*nChannels;
+
+ // A few short cuts
+ CvGaussBGPoint* g_point = &bg_model->g_point[n];
+ const CvGaussBGStatModelParams bg_model_params = bg_model->params;
+ double pixel[4];
+ int no_match;
+
+ for( k = 0; k < nChannels; k++ )
+ pixel[k] = (uchar)curr_frame->imageData[p+k];
+
+ no_match = icvMatchTest( pixel, nChannels, match, g_point, &bg_model_params );
+ if( bg_model->countFrames >= bg_model->params.win_size )
+ {
+ icvUpdateFullWindow( pixel, nChannels, match, g_point, &bg_model->params );
+ if( no_match == -1)
+ icvUpdateFullNoMatch( curr_frame, p, match, g_point, &bg_model_params );
+ }
+ else
+ {
+ icvUpdatePartialWindow( pixel, nChannels, match, g_point, &bg_model_params );
+ if( no_match == -1)
+ icvUpdatePartialNoMatch( pixel, nChannels, match, g_point, &bg_model_params );
+ }
+ icvGetSortKey( nChannels, sort_key, g_point, &bg_model_params );
+ icvInsertionSortGaussians( g_point, sort_key, (CvGaussBGStatModelParams *)&bg_model_params );
+ icvBackgroundTest( nChannels, n, i, j, match, bg_model );
+ }
+ }
+
+ //foreground filtering
+
+ //filter small regions
+ cvClearMemStorage(bg_model->storage);
+
+ //cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_OPEN, 1 );
+ //cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_CLOSE, 1 );
+
+ cvFindContours( bg_model->foreground, bg_model->storage, &first_seq, sizeof(CvContour), CV_RETR_LIST );
+ for( seq = first_seq; seq; seq = seq->h_next )
+ {
+ CvContour* cnt = (CvContour*)seq;
+ if( cnt->rect.width * cnt->rect.height < bg_model->params.minArea )
+ {
+ //delete small contour
+ prev_seq = seq->h_prev;
+ if( prev_seq )
+ {
+ prev_seq->h_next = seq->h_next;
+ if( seq->h_next ) seq->h_next->h_prev = prev_seq;
+ }
+ else
+ {
+ first_seq = seq->h_next;
+ if( seq->h_next ) seq->h_next->h_prev = NULL;
+ }
+ }
+ else
+ {
+ region_count++;
+ }
+ }
+ bg_model->foreground_regions = first_seq;
+ cvZero(bg_model->foreground);
+ cvDrawContours(bg_model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);
+
+ return region_count;
+}
+
+static void icvInsertionSortGaussians( CvGaussBGPoint* g_point, double* sort_key, CvGaussBGStatModelParams *bg_model_params )
+{
+ int i, j;
+ for( i = 1; i < bg_model_params->n_gauss; i++ )
+ {
+ double index = sort_key[i];
+ for( j = i; j > 0 && sort_key[j-1] < index; j-- ) //sort decending order
+ {
+ double temp_sort_key = sort_key[j];
+ sort_key[j] = sort_key[j-1];
+ sort_key[j-1] = temp_sort_key;
+
+ CvGaussBGValues temp_gauss_values = g_point->g_values[j];
+ g_point->g_values[j] = g_point->g_values[j-1];
+ g_point->g_values[j-1] = temp_gauss_values;
+ }
+// sort_key[j] = index;
+ }
+}
+
+
+static int icvMatchTest( double* src_pixel, int nChannels, int* match,
+ const CvGaussBGPoint* g_point,
+ const CvGaussBGStatModelParams *bg_model_params )
+{
+ int k;
+ int matchPosition=-1;
+ for ( k = 0; k < bg_model_params->n_gauss; k++) match[k]=0;
+
+ for ( k = 0; k < bg_model_params->n_gauss; k++) {
+ double sum_d2 = 0.0;
+ double var_threshold = 0.0;
+ for(int m = 0; m < nChannels; m++){
+ double d = g_point->g_values[k].mean[m]- src_pixel[m];
+ sum_d2 += (d*d);
+ var_threshold += g_point->g_values[k].variance[m];
+ } //difference < STD_LIMIT*STD_LIMIT or difference**2 < STD_LIMIT*STD_LIMIT*VAR
+ var_threshold = bg_model_params->std_threshold*bg_model_params->std_threshold*var_threshold;
+ if(sum_d2 < var_threshold){
+ match[k] = 1;
+ matchPosition = k;
+ break;
+ }
+ }
+
+ return matchPosition;
+}
+
+/*
+static int icvMatchTest2( double* src_pixel, int nChannels, int* match,
+ const CvGaussBGPoint* g_point,
+ const CvGaussBGStatModelParams *bg_model_params )
+{
+ int k, m;
+ int matchPosition=-1;
+
+ for( k = 0; k < bg_model_params->n_gauss; k++ )
+ match[k] = 0;
+
+ for( k = 0; k < bg_model_params->n_gauss; k++ )
+ {
+ double sum_d2 = 0.0, var_threshold;
+ for( m = 0; m < nChannels; m++ )
+ {
+ double d = g_point->g_values[k].mean[m]- src_pixel[m];
+ sum_d2 += (d*d) / (g_point->g_values[k].variance[m] * g_point->g_values[k].variance[m]);
+ } //difference < STD_LIMIT*STD_LIMIT or difference**2 < STD_LIMIT*STD_LIMIT*VAR
+
+ var_threshold = bg_model_params->std_threshold*bg_model_params->std_threshold;
+ if( sum_d2 < var_threshold )
+ {
+ match[k] = 1;
+ matchPosition = k;
+ break;
+ }
+ }
+
+ return matchPosition;
+}
+*/
+
+static void icvUpdateFullWindow( double* src_pixel, int nChannels, int* match,
+ CvGaussBGPoint* g_point,
+ const CvGaussBGStatModelParams *bg_model_params )
+{
+ const double learning_rate_weight = (1.0/(double)bg_model_params->win_size);
+ for(int k = 0; k < bg_model_params->n_gauss; k++){
+ g_point->g_values[k].weight = g_point->g_values[k].weight +
+ (learning_rate_weight*((double)match[k] -
+ g_point->g_values[k].weight));
+ if(match[k]){
+ double learning_rate_gaussian = (double)match[k]/(g_point->g_values[k].weight*
+ (double)bg_model_params->win_size);
+ for(int m = 0; m < nChannels; m++){
+ const double tmpDiff = src_pixel[m] - g_point->g_values[k].mean[m];
+ g_point->g_values[k].mean[m] = g_point->g_values[k].mean[m] +
+ (learning_rate_gaussian * tmpDiff);
+ g_point->g_values[k].variance[m] = g_point->g_values[k].variance[m]+
+ (learning_rate_gaussian*((tmpDiff*tmpDiff) - g_point->g_values[k].variance[m]));
+ }
+ }
+ }
+}
+
+
+static void icvUpdatePartialWindow( double* src_pixel, int nChannels, int* match, CvGaussBGPoint* g_point, const CvGaussBGStatModelParams *bg_model_params )
+{
+ int k, m;
+ int window_current = 0;
+
+ for( k = 0; k < bg_model_params->n_gauss; k++ )
+ window_current += g_point->g_values[k].match_sum;
+
+ for( k = 0; k < bg_model_params->n_gauss; k++ )
+ {
+ g_point->g_values[k].match_sum += match[k];
+ double learning_rate_weight = (1.0/((double)window_current + 1.0)); //increased by one since sum
+ g_point->g_values[k].weight = g_point->g_values[k].weight +
+ (learning_rate_weight*((double)match[k] - g_point->g_values[k].weight));
+
+ if( g_point->g_values[k].match_sum > 0 && match[k] )
+ {
+ double learning_rate_gaussian = (double)match[k]/((double)g_point->g_values[k].match_sum);
+ for( m = 0; m < nChannels; m++ )
+ {
+ const double tmpDiff = src_pixel[m] - g_point->g_values[k].mean[m];
+ g_point->g_values[k].mean[m] = g_point->g_values[k].mean[m] +
+ (learning_rate_gaussian*tmpDiff);
+ g_point->g_values[k].variance[m] = g_point->g_values[k].variance[m]+
+ (learning_rate_gaussian*((tmpDiff*tmpDiff) - g_point->g_values[k].variance[m]));
+ }
+ }
+ }
+}
+
+static void icvUpdateFullNoMatch( IplImage* gm_image, int p, int* match,
+ CvGaussBGPoint* g_point,
+ const CvGaussBGStatModelParams *bg_model_params)
+{
+ int k, m;
+ double alpha;
+ int match_sum_total = 0;
+
+ //new value of last one
+ g_point->g_values[bg_model_params->n_gauss - 1].match_sum = 1;
+
+ //get sum of all but last value of match_sum
+
+ for( k = 0; k < bg_model_params->n_gauss ; k++ )
+ match_sum_total += g_point->g_values[k].match_sum;
+
+ g_point->g_values[bg_model_params->n_gauss - 1].weight = 1./(double)match_sum_total;
+ for( m = 0; m < gm_image->nChannels ; m++ )
+ {
+ // first pass mean is image value
+ g_point->g_values[bg_model_params->n_gauss - 1].variance[m] = bg_model_params->variance_init;
+ g_point->g_values[bg_model_params->n_gauss - 1].mean[m] = (unsigned char)gm_image->imageData[p + m];
+ }
+
+ alpha = 1.0 - (1.0/bg_model_params->win_size);
+ for( k = 0; k < bg_model_params->n_gauss - 1; k++ )
+ {
+ g_point->g_values[k].weight *= alpha;
+ if( match[k] )
+ g_point->g_values[k].weight += alpha;
+ }
+}
+
+
+static void
+icvUpdatePartialNoMatch(double *pixel,
+ int nChannels,
+ int* /*match*/,
+ CvGaussBGPoint* g_point,
+ const CvGaussBGStatModelParams *bg_model_params)
+{
+ int k, m;
+ //new value of last one
+ g_point->g_values[bg_model_params->n_gauss - 1].match_sum = 1;
+
+ //get sum of all but last value of match_sum
+ int match_sum_total = 0;
+ for(k = 0; k < bg_model_params->n_gauss ; k++)
+ match_sum_total += g_point->g_values[k].match_sum;
+
+ for(m = 0; m < nChannels; m++)
+ {
+ //first pass mean is image value
+ g_point->g_values[bg_model_params->n_gauss - 1].variance[m] = bg_model_params->variance_init;
+ g_point->g_values[bg_model_params->n_gauss - 1].mean[m] = pixel[m];
+ }
+ for(k = 0; k < bg_model_params->n_gauss; k++)
+ {
+ g_point->g_values[k].weight = (double)g_point->g_values[k].match_sum /
+ (double)match_sum_total;
+ }
+}
+
+static void icvGetSortKey( const int nChannels, double* sort_key, const CvGaussBGPoint* g_point,
+ const CvGaussBGStatModelParams *bg_model_params )
+{
+ int k, m;
+ for( k = 0; k < bg_model_params->n_gauss; k++ )
+ {
+ // Avoid division by zero
+ if( g_point->g_values[k].match_sum > 0 )
+ {
+ // Independence assumption between components
+ double variance_sum = 0.0;
+ for( m = 0; m < nChannels; m++ )
+ variance_sum += g_point->g_values[k].variance[m];
+
+ sort_key[k] = g_point->g_values[k].weight/sqrt(variance_sum);
+ }
+ else
+ sort_key[k]= 0.0;
+ }
+}
+
+
+static void icvBackgroundTest( const int nChannels, int n, int i, int j, int *match, CvGaussBGModel* bg_model )
+{
+ int m, b;
+ uchar pixelValue = (uchar)255; // will switch to 0 if match found
+ double weight_sum = 0.0;
+ CvGaussBGPoint* g_point = bg_model->g_point;
+
+ for( m = 0; m < nChannels; m++)
+ bg_model->background->imageData[ bg_model->background->widthStep*i + j*nChannels + m] = (unsigned char)(g_point[n].g_values[0].mean[m]+0.5);
+
+ for( b = 0; b < bg_model->params.n_gauss; b++)
+ {
+ weight_sum += g_point[n].g_values[b].weight;
+ if( match[b] )
+ pixelValue = 0;
+ if( weight_sum > bg_model->params.bg_threshold )
+ break;
+ }
+
+ bg_model->foreground->imageData[ bg_model->foreground->widthStep*i + j] = pixelValue;
+}
+
+/* End of file. */
diff --git a/cvaux/src/cvcalibfilter.cpp b/cvaux/src/cvcalibfilter.cpp
new file mode 100644
index 0000000..e6c4fc8
--- /dev/null
+++ b/cvaux/src/cvcalibfilter.cpp
@@ -0,0 +1,906 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+#include <stdio.h>
+
+#undef quad
+
+#if _MSC_VER >= 1200
+#pragma warning( disable: 4701 )
+#endif
+
+CvCalibFilter::CvCalibFilter()
+{
+ /* etalon data */
+ etalonType = CV_CALIB_ETALON_USER;
+ etalonParamCount = 0;
+ etalonParams = 0;
+ etalonPointCount = 0;
+ etalonPoints = 0;
+
+ /* camera data */
+ cameraCount = 1;
+
+ memset( points, 0, sizeof(points));
+ memset( undistMap, 0, sizeof(undistMap));
+ undistImg = 0;
+ memset( latestCounts, 0, sizeof(latestCounts));
+ memset( latestPoints, 0, sizeof(latestPoints));
+ memset( &stereo, 0, sizeof(stereo) );
+ maxPoints = 0;
+ framesTotal = 15;
+ framesAccepted = 0;
+ isCalibrated = false;
+
+ imgSize = cvSize(0,0);
+ grayImg = 0;
+ tempImg = 0;
+ storage = 0;
+
+ memset( rectMap, 0, sizeof(rectMap));
+}
+
+
+CvCalibFilter::~CvCalibFilter()
+{
+ SetCameraCount(0);
+ cvFree( &etalonParams );
+ cvFree( &etalonPoints );
+ cvReleaseMat( &grayImg );
+ cvReleaseMat( &tempImg );
+ cvReleaseMat( &undistImg );
+ cvReleaseMemStorage( &storage );
+}
+
+
+bool CvCalibFilter::SetEtalon( CvCalibEtalonType type, double* params,
+ int pointCount, CvPoint2D32f* points )
+{
+ int i, arrSize;
+
+ Stop();
+
+ for( i = 0; i < MAX_CAMERAS; i++ )
+ cvFree( latestPoints + i );
+
+ if( type == CV_CALIB_ETALON_USER || type != etalonType )
+ {
+ cvFree( &etalonParams );
+ }
+
+ etalonType = type;
+
+ switch( etalonType )
+ {
+ case CV_CALIB_ETALON_CHESSBOARD:
+ etalonParamCount = 3;
+ if( !params || cvRound(params[0]) != params[0] || params[0] < 3 ||
+ cvRound(params[1]) != params[1] || params[1] < 3 || params[2] <= 0 )
+ {
+ assert(0);
+ return false;
+ }
+
+ pointCount = cvRound((params[0] - 1)*(params[1] - 1));
+ break;
+
+ case CV_CALIB_ETALON_USER:
+ etalonParamCount = 0;
+
+ if( !points || pointCount < 4 )
+ {
+ assert(0);
+ return false;
+ }
+ break;
+
+ default:
+ assert(0);
+ return false;
+ }
+
+ if( etalonParamCount > 0 )
+ {
+ arrSize = etalonParamCount * sizeof(etalonParams[0]);
+ etalonParams = (double*)cvAlloc( arrSize );
+ }
+
+ arrSize = pointCount * sizeof(etalonPoints[0]);
+
+ if( etalonPointCount != pointCount )
+ {
+ cvFree( &etalonPoints );
+ etalonPointCount = pointCount;
+ etalonPoints = (CvPoint2D32f*)cvAlloc( arrSize );
+ }
+
+ switch( etalonType )
+ {
+ case CV_CALIB_ETALON_CHESSBOARD:
+ {
+ int etalonWidth = cvRound( params[0] ) - 1;
+ int etalonHeight = cvRound( params[1] ) - 1;
+ int x, y, k = 0;
+
+ etalonParams[0] = etalonWidth;
+ etalonParams[1] = etalonHeight;
+ etalonParams[2] = params[2];
+
+ for( y = 0; y < etalonHeight; y++ )
+ for( x = 0; x < etalonWidth; x++ )
+ {
+ etalonPoints[k++] = cvPoint2D32f( (etalonWidth - 1 - x)*params[2],
+ y*params[2] );
+ }
+ }
+ break;
+
+ case CV_CALIB_ETALON_USER:
+ memcpy( etalonParams, params, arrSize );
+ memcpy( etalonPoints, points, arrSize );
+ break;
+
+ default:
+ assert(0);
+ return false;
+ }
+
+ return true;
+}
+
+
+CvCalibEtalonType
+CvCalibFilter::GetEtalon( int* paramCount, const double** params,
+ int* pointCount, const CvPoint2D32f** points ) const
+{
+ if( paramCount )
+ *paramCount = etalonParamCount;
+
+ if( params )
+ *params = etalonParams;
+
+ if( pointCount )
+ *pointCount = etalonPointCount;
+
+ if( points )
+ *points = etalonPoints;
+
+ return etalonType;
+}
+
+
+void CvCalibFilter::SetCameraCount( int count )
+{
+ Stop();
+
+ if( count != cameraCount )
+ {
+ for( int i = 0; i < cameraCount; i++ )
+ {
+ cvFree( points + i );
+ cvFree( latestPoints + i );
+ cvReleaseMat( &undistMap[i][0] );
+ cvReleaseMat( &undistMap[i][1] );
+ cvReleaseMat( &rectMap[i][0] );
+ cvReleaseMat( &rectMap[i][1] );
+ }
+
+ memset( latestCounts, 0, sizeof(latestPoints) );
+ maxPoints = 0;
+ cameraCount = count;
+ }
+}
+
+
+bool CvCalibFilter::SetFrames( int frames )
+{
+ if( frames < 5 )
+ {
+ assert(0);
+ return false;
+ }
+
+ framesTotal = frames;
+ return true;
+}
+
+
+void CvCalibFilter::Stop( bool calibrate )
+{
+ int i, j;
+ isCalibrated = false;
+
+ // deallocate undistortion maps
+ for( i = 0; i < cameraCount; i++ )
+ {
+ cvReleaseMat( &undistMap[i][0] );
+ cvReleaseMat( &undistMap[i][1] );
+ cvReleaseMat( &rectMap[i][0] );
+ cvReleaseMat( &rectMap[i][1] );
+ }
+
+ if( calibrate && framesAccepted > 0 )
+ {
+ int n = framesAccepted;
+ CvPoint3D32f* buffer =
+ (CvPoint3D32f*)cvAlloc( n * etalonPointCount * sizeof(buffer[0]));
+ CvMat mat;
+ float* rotMatr = (float*)cvAlloc( n * 9 * sizeof(rotMatr[0]));
+ float* transVect = (float*)cvAlloc( n * 3 * sizeof(transVect[0]));
+ int* counts = (int*)cvAlloc( n * sizeof(counts[0]));
+
+ cvInitMatHeader( &mat, 1, sizeof(CvCamera)/sizeof(float), CV_32FC1, 0 );
+ memset( cameraParams, 0, cameraCount * sizeof(cameraParams[0]));
+
+ for( i = 0; i < framesAccepted; i++ )
+ {
+ counts[i] = etalonPointCount;
+ for( j = 0; j < etalonPointCount; j++ )
+ buffer[i * etalonPointCount + j] = cvPoint3D32f( etalonPoints[j].x,
+ etalonPoints[j].y, 0 );
+ }
+
+ for( i = 0; i < cameraCount; i++ )
+ {
+ cvCalibrateCamera( framesAccepted, counts,
+ imgSize, points[i], buffer,
+ cameraParams[i].distortion,
+ cameraParams[i].matrix,
+ transVect, rotMatr, 0 );
+
+ cameraParams[i].imgSize[0] = (float)imgSize.width;
+ cameraParams[i].imgSize[1] = (float)imgSize.height;
+
+// cameraParams[i].focalLength[0] = cameraParams[i].matrix[0];
+// cameraParams[i].focalLength[1] = cameraParams[i].matrix[4];
+
+// cameraParams[i].principalPoint[0] = cameraParams[i].matrix[2];
+// cameraParams[i].principalPoint[1] = cameraParams[i].matrix[5];
+
+ memcpy( cameraParams[i].rotMatr, rotMatr, 9 * sizeof(rotMatr[0]));
+ memcpy( cameraParams[i].transVect, transVect, 3 * sizeof(transVect[0]));
+
+ mat.data.ptr = (uchar*)(cameraParams + i);
+
+ /* check resultant camera parameters: if there are some INF's or NAN's,
+ stop and reset results */
+ if( !cvCheckArr( &mat, CV_CHECK_RANGE | CV_CHECK_QUIET, -10000, 10000 ))
+ break;
+ }
+
+
+
+ isCalibrated = i == cameraCount;
+
+ {/* calibrate stereo cameras */
+ if( cameraCount == 2 )
+ {
+ stereo.camera[0] = &cameraParams[0];
+ stereo.camera[1] = &cameraParams[1];
+
+ icvStereoCalibration( framesAccepted, counts,
+ imgSize,
+ points[0],points[1],
+ buffer,
+ &stereo);
+
+ for( i = 0; i < 9; i++ )
+ {
+ stereo.fundMatr[i] = stereo.fundMatr[i];
+ }
+
+ }
+
+ }
+
+ cvFree( &buffer );
+ cvFree( &counts );
+ cvFree( &rotMatr );
+ cvFree( &transVect );
+ }
+
+ framesAccepted = 0;
+}
+
+
+bool CvCalibFilter::FindEtalon( IplImage** imgs )
+{
+ return FindEtalon( (CvMat**)imgs );
+}
+
+
+bool CvCalibFilter::FindEtalon( CvMat** mats )
+{
+ bool result = true;
+
+ if( !mats || etalonPointCount == 0 )
+ {
+ assert(0);
+ result = false;
+ }
+
+ if( result )
+ {
+ int i, tempPointCount0 = etalonPointCount*2;
+
+ for( i = 0; i < cameraCount; i++ )
+ {
+ if( !latestPoints[i] )
+ latestPoints[i] = (CvPoint2D32f*)
+ cvAlloc( tempPointCount0*2*sizeof(latestPoints[0]));
+ }
+
+ for( i = 0; i < cameraCount; i++ )
+ {
+ CvSize size;
+ int tempPointCount = tempPointCount0;
+ bool found = false;
+
+ if( !CV_IS_MAT(mats[i]) && !CV_IS_IMAGE(mats[i]))
+ {
+ assert(0);
+ break;
+ }
+
+ size = cvGetSize(mats[i]);
+
+ if( size.width != imgSize.width || size.height != imgSize.height )
+ {
+ imgSize = size;
+ }
+
+ if( !grayImg || grayImg->width != imgSize.width ||
+ grayImg->height != imgSize.height )
+ {
+ cvReleaseMat( &grayImg );
+ cvReleaseMat( &tempImg );
+ grayImg = cvCreateMat( imgSize.height, imgSize.width, CV_8UC1 );
+ tempImg = cvCreateMat( imgSize.height, imgSize.width, CV_8UC1 );
+ }
+
+ if( !storage )
+ storage = cvCreateMemStorage();
+
+ switch( etalonType )
+ {
+ case CV_CALIB_ETALON_CHESSBOARD:
+ if( CV_MAT_CN(cvGetElemType(mats[i])) == 1 )
+ cvCopy( mats[i], grayImg );
+ else
+ cvCvtColor( mats[i], grayImg, CV_BGR2GRAY );
+ found = cvFindChessBoardCornerGuesses( grayImg, tempImg, storage,
+ cvSize( cvRound(etalonParams[0]),
+ cvRound(etalonParams[1])),
+ latestPoints[i], &tempPointCount ) != 0;
+ if( found )
+ cvFindCornerSubPix( grayImg, latestPoints[i], tempPointCount,
+ cvSize(5,5), cvSize(-1,-1),
+ cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,10,0.1));
+ break;
+ default:
+ assert(0);
+ result = false;
+ break;
+ }
+
+ latestCounts[i] = found ? tempPointCount : -tempPointCount;
+ result = result && found;
+ }
+ }
+
+ if( storage )
+ cvClearMemStorage( storage );
+
+ return result;
+}
+
+
+bool CvCalibFilter::Push( const CvPoint2D32f** pts )
+{
+ bool result = true;
+ int i, newMaxPoints = etalonPointCount*(MAX(framesAccepted,framesTotal) + 1);
+
+ isCalibrated = false;
+
+ if( !pts )
+ {
+ for( i = 0; i < cameraCount; i++ )
+ if( latestCounts[i] <= 0 )
+ return false;
+ pts = (const CvPoint2D32f**)latestPoints;
+ }
+
+ for( i = 0; i < cameraCount; i++ )
+ {
+ if( !pts[i] )
+ {
+ assert(0);
+ break;
+ }
+
+ if( maxPoints < newMaxPoints )
+ {
+ CvPoint2D32f* prev = points[i];
+ cvFree( points + i );
+ points[i] = (CvPoint2D32f*)cvAlloc( newMaxPoints * sizeof(prev[0]));
+ memcpy( points[i], prev, maxPoints * sizeof(prev[0]));
+ }
+
+ memcpy( points[i] + framesAccepted*etalonPointCount, pts[i],
+ etalonPointCount*sizeof(points[0][0]));
+ }
+
+ if( maxPoints < newMaxPoints )
+ maxPoints = newMaxPoints;
+
+ result = i == cameraCount;
+
+ if( ++framesAccepted >= framesTotal )
+ Stop( true );
+ return result;
+}
+
+
+bool CvCalibFilter::GetLatestPoints( int idx, CvPoint2D32f** pts,
+ int* count, bool* found )
+{
+ int n;
+
+ if( (unsigned)idx >= (unsigned)cameraCount ||
+ !pts || !count || !found )
+ {
+ assert(0);
+ return false;
+ }
+
+ n = latestCounts[idx];
+
+ *found = n > 0;
+ *count = abs(n);
+ *pts = latestPoints[idx];
+
+ return true;
+}
+
+
+void CvCalibFilter::DrawPoints( IplImage** dst )
+{
+ DrawPoints( (CvMat**)dst );
+}
+
+
+void CvCalibFilter::DrawPoints( CvMat** dstarr )
+{
+ int i, j;
+
+ if( !dstarr )
+ {
+ assert(0);
+ return;
+ }
+
+ if( latestCounts )
+ {
+ for( i = 0; i < cameraCount; i++ )
+ {
+ if( dstarr[i] && latestCounts[i] )
+ {
+ CvMat dst_stub, *dst;
+ int count = 0;
+ bool found = false;
+ CvPoint2D32f* pts = 0;
+
+ GetLatestPoints( i, &pts, &count, &found );
+
+ dst = cvGetMat( dstarr[i], &dst_stub );
+
+ static const CvScalar line_colors[] =
+ {
+ {{0,0,255}},
+ {{0,128,255}},
+ {{0,200,200}},
+ {{0,255,0}},
+ {{200,200,0}},
+ {{255,0,0}},
+ {{255,0,255}}
+ };
+
+ const int colorCount = sizeof(line_colors)/sizeof(line_colors[0]);
+ const int r = 4;
+ CvScalar color = line_colors[0];
+ CvPoint prev_pt = { 0, 0};
+
+ for( j = 0; j < count; j++ )
+ {
+ CvPoint pt;
+ pt.x = cvRound(pts[j].x);
+ pt.y = cvRound(pts[j].y);
+
+ if( found )
+ {
+ if( etalonType == CV_CALIB_ETALON_CHESSBOARD )
+ color = line_colors[(j/cvRound(etalonParams[0]))%colorCount];
+ else
+ color = CV_RGB(0,255,0);
+
+ if( j != 0 )
+ cvLine( dst, prev_pt, pt, color, 1, CV_AA );
+ }
+
+ cvLine( dst, cvPoint( pt.x - r, pt.y - r ),
+ cvPoint( pt.x + r, pt.y + r ), color, 1, CV_AA );
+
+ cvLine( dst, cvPoint( pt.x - r, pt.y + r),
+ cvPoint( pt.x + r, pt.y - r), color, 1, CV_AA );
+
+ cvCircle( dst, pt, r+1, color, 1, CV_AA );
+
+ prev_pt = pt;
+ }
+ }
+ }
+ }
+}
+
+
+/* Get total number of frames and already accepted pair of frames */
+int CvCalibFilter::GetFrameCount( int* total ) const
+{
+ if( total )
+ *total = framesTotal;
+
+ return framesAccepted;
+}
+
+
+/* Get camera parameters for specified camera. If camera is not calibrated
+ the function returns 0 */
+const CvCamera* CvCalibFilter::GetCameraParams( int idx ) const
+{
+ if( (unsigned)idx >= (unsigned)cameraCount )
+ {
+ assert(0);
+ return 0;
+ }
+
+ return isCalibrated ? cameraParams + idx : 0;
+}
+
+
+/* Get camera parameters for specified camera. If camera is not calibrated
+ the function returns 0 */
+const CvStereoCamera* CvCalibFilter::GetStereoParams() const
+{
+ if( !(isCalibrated && cameraCount == 2) )
+ {
+ assert(0);
+ return 0;
+ }
+
+ return &stereo;
+}
+
+
+/* Sets camera parameters for all cameras */
+bool CvCalibFilter::SetCameraParams( CvCamera* params )
+{
+ CvMat mat;
+ int arrSize;
+
+ Stop();
+
+ if( !params )
+ {
+ assert(0);
+ return false;
+ }
+
+ arrSize = cameraCount * sizeof(params[0]);
+
+ cvInitMatHeader( &mat, 1, cameraCount * (arrSize/sizeof(float)),
+ CV_32FC1, params );
+ cvCheckArr( &mat, CV_CHECK_RANGE, -10000, 10000 );
+
+ memcpy( cameraParams, params, arrSize );
+ isCalibrated = true;
+
+ return true;
+}
+
+
+bool CvCalibFilter::SaveCameraParams( const char* filename )
+{
+ if( isCalibrated )
+ {
+ int i, j;
+
+ FILE* f = fopen( filename, "w" );
+
+ if( !f ) return false;
+
+ fprintf( f, "%d\n\n", cameraCount );
+
+ for( i = 0; i < cameraCount; i++ )
+ {
+ for( j = 0; j < (int)(sizeof(cameraParams[i])/sizeof(float)); j++ )
+ {
+ fprintf( f, "%15.10f ", ((float*)(cameraParams + i))[j] );
+ }
+ fprintf( f, "\n\n" );
+ }
+
+ /* Save stereo params */
+
+ /* Save quad */
+ for( i = 0; i < 2; i++ )
+ {
+ for( j = 0; j < 4; j++ )
+ {
+ fprintf(f, "%15.10f ", stereo.quad[i][j].x );
+ fprintf(f, "%15.10f ", stereo.quad[i][j].y );
+ }
+ fprintf(f, "\n");
+ }
+
+ /* Save coeffs */
+ for( i = 0; i < 2; i++ )
+ {
+ for( j = 0; j < 9; j++ )
+ {
+ fprintf(f, "%15.10lf ", stereo.coeffs[i][j/3][j%3] );
+ }
+ fprintf(f, "\n");
+ }
+
+
+ fclose(f);
+ return true;
+ }
+
+ return true;
+}
+
+
+bool CvCalibFilter::LoadCameraParams( const char* filename )
+{
+ int i, j;
+ int d = 0;
+ FILE* f = fopen( filename, "r" );
+
+ isCalibrated = false;
+
+ if( !f ) return false;
+
+ if( fscanf( f, "%d", &d ) != 1 || d <= 0 || d > 10 )
+ return false;
+
+ SetCameraCount( d );
+
+ for( i = 0; i < cameraCount; i++ )
+ {
+ for( j = 0; j < (int)(sizeof(cameraParams[i])/sizeof(float)); j++ )
+ {
+ fscanf( f, "%f", &((float*)(cameraParams + i))[j] );
+ }
+ }
+
+
+ /* Load stereo params */
+
+ /* load quad */
+ for( i = 0; i < 2; i++ )
+ {
+ for( j = 0; j < 4; j++ )
+ {
+ fscanf(f, "%f ", &(stereo.quad[i][j].x) );
+ fscanf(f, "%f ", &(stereo.quad[i][j].y) );
+ }
+ }
+
+ /* Load coeffs */
+ for( i = 0; i < 2; i++ )
+ {
+ for( j = 0; j < 9; j++ )
+ {
+ fscanf(f, "%lf ", &(stereo.coeffs[i][j/3][j%3]) );
+ }
+ }
+
+
+
+
+ fclose(f);
+
+ stereo.warpSize = cvSize( cvRound(cameraParams[0].imgSize[0]), cvRound(cameraParams[0].imgSize[1]));
+
+ isCalibrated = true;
+
+ return true;
+}
+
+
+bool CvCalibFilter::Rectify( IplImage** srcarr, IplImage** dstarr )
+{
+ return Rectify( (CvMat**)srcarr, (CvMat**)dstarr );
+}
+
+bool CvCalibFilter::Rectify( CvMat** srcarr, CvMat** dstarr )
+{
+ int i;
+
+ if( !srcarr || !dstarr )
+ {
+ assert(0);
+ return false;
+ }
+
+ if( isCalibrated && cameraCount == 2 )
+ {
+ for( i = 0; i < cameraCount; i++ )
+ {
+ if( srcarr[i] && dstarr[i] )
+ {
+ IplImage src_stub, *src;
+ IplImage dst_stub, *dst;
+
+ src = cvGetImage( srcarr[i], &src_stub );
+ dst = cvGetImage( dstarr[i], &dst_stub );
+
+ if( src->imageData == dst->imageData )
+ {
+ if( !undistImg ||
+ undistImg->width != src->width ||
+ undistImg->height != src->height ||
+ CV_MAT_CN(undistImg->type) != src->nChannels )
+ {
+ cvReleaseMat( &undistImg );
+ undistImg = cvCreateMat( src->height, src->width,
+ CV_8U + (src->nChannels-1)*8 );
+ }
+ cvCopy( src, undistImg );
+ src = cvGetImage( undistImg, &src_stub );
+ }
+
+ cvZero( dst );
+
+ if( !rectMap[i][0] || rectMap[i][0]->width != src->width ||
+ rectMap[i][0]->height != src->height )
+ {
+ cvReleaseMat( &rectMap[i][0] );
+ cvReleaseMat( &rectMap[i][1] );
+ rectMap[i][0] = cvCreateMat(stereo.warpSize.height,stereo.warpSize.width,CV_32FC1);
+ rectMap[i][1] = cvCreateMat(stereo.warpSize.height,stereo.warpSize.width,CV_32FC1);
+ cvComputePerspectiveMap(stereo.coeffs[i], rectMap[i][0], rectMap[i][1]);
+ }
+ cvRemap( src, dst, rectMap[i][0], rectMap[i][1] );
+ }
+ }
+ }
+ else
+ {
+ for( i = 0; i < cameraCount; i++ )
+ {
+ if( srcarr[i] != dstarr[i] )
+ cvCopy( srcarr[i], dstarr[i] );
+ }
+ }
+
+ return true;
+}
+
+bool CvCalibFilter::Undistort( IplImage** srcarr, IplImage** dstarr )
+{
+ return Undistort( (CvMat**)srcarr, (CvMat**)dstarr );
+}
+
+
+bool CvCalibFilter::Undistort( CvMat** srcarr, CvMat** dstarr )
+{
+ int i;
+
+ if( !srcarr || !dstarr )
+ {
+ assert(0);
+ return false;
+ }
+
+ if( isCalibrated )
+ {
+ for( i = 0; i < cameraCount; i++ )
+ {
+ if( srcarr[i] && dstarr[i] )
+ {
+ CvMat src_stub, *src;
+ CvMat dst_stub, *dst;
+
+ src = cvGetMat( srcarr[i], &src_stub );
+ dst = cvGetMat( dstarr[i], &dst_stub );
+
+ if( src->data.ptr == dst->data.ptr )
+ {
+ if( !undistImg || undistImg->width != src->width ||
+ undistImg->height != src->height ||
+ CV_ARE_TYPES_EQ( undistImg, src ))
+ {
+ cvReleaseMat( &undistImg );
+ undistImg = cvCreateMat( src->height, src->width, src->type );
+ }
+
+ cvCopy( src, undistImg );
+ src = undistImg;
+ }
+
+ #if 1
+ {
+ CvMat A = cvMat( 3, 3, CV_32FC1, cameraParams[i].matrix );
+ CvMat k = cvMat( 1, 4, CV_32FC1, cameraParams[i].distortion );
+
+ if( !undistMap[i][0] || undistMap[i][0]->width != src->width ||
+ undistMap[i][0]->height != src->height )
+ {
+ cvReleaseMat( &undistMap[i][0] );
+ cvReleaseMat( &undistMap[i][1] );
+ undistMap[i][0] = cvCreateMat( src->height, src->width, CV_32FC1 );
+ undistMap[i][1] = cvCreateMat( src->height, src->width, CV_32FC1 );
+ cvInitUndistortMap( &A, &k, undistMap[i][0], undistMap[i][1] );
+ }
+
+ cvRemap( src, dst, undistMap[i][0], undistMap[i][1] );
+ #else
+ cvUndistort2( src, dst, &A, &k );
+ #endif
+ }
+ }
+ }
+ }
+ else
+ {
+ for( i = 0; i < cameraCount; i++ )
+ {
+ if( srcarr[i] != dstarr[i] )
+ cvCopy( srcarr[i], dstarr[i] );
+ }
+ }
+
+
+ return true;
+}
diff --git a/cvaux/src/cvclique.cpp b/cvaux/src/cvclique.cpp
new file mode 100644
index 0000000..df7f8a9
--- /dev/null
+++ b/cvaux/src/cvclique.cpp
@@ -0,0 +1,709 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+#if 0
+
+#include <float.h>
+#include <limits.h>
+#include <stdio.h>
+
+
+#include "_cvutils.h"
+#include "_cvwrap.h"
+
+/*typedef struct CvCliqueFinder
+{
+ CvGraph* graph;
+ int** adj_matr;
+ int N; //graph size
+
+ // stacks, counters etc/
+ int k; //stack size
+ int* current_comp;
+ int** All;
+
+ int* ne;
+ int* ce;
+ int* fixp; //node with minimal disconnections
+ int* nod;
+ int* s; //for selected candidate
+ int status;
+ int best_score;
+
+} CvCliqueFinder;
+*/
+
+#define GO 1
+#define BACK 2
+#define PEREBOR 3
+#define NEXT PEREBOR
+#define END 4
+
+
+#define CV_GET_ADJ_VTX( vertex, edge ) \
+( \
+ assert(edge->vtx[0]==vertex||edge->vtx[1] == vertex ), \
+ (edge->vtx[0] == vertex)?edge->vtx[1]:edge->vtx[0] \
+)
+
+
+#define NUMBER( v ) ((v)->flags >> 1 )
+
+void _MarkNodes( CvGraph* graph )
+{
+ //set number of vertices to their flags
+ for( int i = 0; i < graph->total; i++ )
+ {
+ CvGraphVtx* ver = cvGetGraphVtx( graph, i );
+ if( ver )
+ {
+ ver->flags = i<<1;
+ }
+ }
+}
+
+void _FillAdjMatrix( CvGraph* graph, int** connected, int reverse )
+{
+ //assume all vertices are marked
+ for( int i = 0; i < graph->total; i++ )
+ {
+ for( int j = 0; j < graph->total; j++ )
+ {
+ connected[i][j] = 0|reverse;
+ }
+ //memset( connected[i], 0, sizeof(int)*graph->total );
+ CvGraphVtx* ver = cvGetGraphVtx( graph, i );
+ if( ver )
+ {
+ connected[i][i] = 1;
+ for( CvGraphEdge* e = ver->first; e ; e = CV_NEXT_GRAPH_EDGE( e, ver ) )
+ {
+ CvGraphVtx* v = CV_GET_ADJ_VTX( ver, e );
+ connected[i][NUMBER(v)] = 1^reverse;
+ }
+ }
+ }
+}
+
+
+void cvStartFindCliques( CvGraph* graph, CvCliqueFinder* finder, int reverse, int weighted, int weighted_edges )
+{
+ int i;
+
+ if (weighted)
+ {
+ finder->weighted = 1;
+ finder->best_weight = 0;
+ finder->vertex_weights = (float*)malloc( sizeof(float)*(graph->total+1));
+ finder->cur_weight = (float*)malloc( sizeof(float)*(graph->total+1));
+ finder->cand_weight = (float*)malloc( sizeof(float)*(graph->total+1));
+
+ finder->cur_weight[0] = 0;
+ finder->cand_weight[0] = 0;
+ for( i = 0 ; i < graph->total; i++ )
+ {
+ CvGraphWeightedVtx* ver = (CvGraphWeightedVtx*)cvGetGraphVtx( graph, i );
+ assert(ver);
+ assert(ver->weight>=0);
+ finder->vertex_weights[i] = ver->weight;
+ finder->cand_weight[0] += ver->weight;
+ }
+ }
+ else finder->weighted = 0;
+
+ if (weighted_edges)
+ {
+ finder->weighted_edges = 1;
+ //finder->best_weight = 0;
+ finder->edge_weights = (float*)malloc( sizeof(float)*(graph->total)*(graph->total));
+ //finder->cur_weight = (float*)malloc( sizeof(float)*(graph->total+1));
+ //finder->cand_weight = (float*)malloc( sizeof(float)*(graph->total+1));
+
+ //finder->cur_weight[0] = 0;
+ //finder->cand_weight[0] = 0;
+ memset( finder->edge_weights, 0, sizeof(float)*(graph->total)*(graph->total) );
+ for( i = 0 ; i < graph->total; i++ )
+ {
+ CvGraphVtx* ver1 = cvGetGraphVtx( graph, i );
+ if(!ver1) continue;
+ for( int j = i ; j < graph->total; j++ )
+ {
+ CvGraphVtx* ver2 = cvGetGraphVtx( graph, j );
+ if(!ver2) continue;
+ CvGraphEdge* edge = cvFindGraphEdgeByPtr( graph, ver1, ver2 );
+ if( edge )
+ {
+ assert( ((CvGraphWeightedEdge*)edge)->weight >= 0 );
+ finder->edge_weights[ i * graph->total + j ] =
+ finder->edge_weights[ j * graph->total + i ] = ((CvGraphWeightedEdge*)edge)->weight;
+ }
+ }
+ }
+ }
+ else finder->weighted_edges = 0;
+
+
+ //int* Compsub; //current component (vertex stack)
+ finder->k = 0; //counter of steps
+ int N = finder->N = graph->total;
+ finder->current_comp = new int[N];
+ finder->All = new int*[N];
+ for( i = 0 ; i < finder->N; i++ )
+ {
+ finder->All[i] = new int[N];
+ }
+
+ finder->ne = new int[N+1];
+ finder->ce = new int[N+1];
+ finder->fixp = new int[N+1]; //node with minimal disconnections
+ finder->nod = new int[N+1];
+ finder->s = new int[N+1]; //for selected candidate
+
+ //form adj matrix
+ finder->adj_matr = new int*[N]; //assume filled with 0
+ for( i = 0 ; i < N; i++ )
+ {
+ finder->adj_matr[i] = new int[N];
+ }
+
+ //set number to vertices
+ _MarkNodes( graph );
+ _FillAdjMatrix( graph, finder->adj_matr, reverse );
+
+ //init all arrays
+ int k = finder->k = 0; //stack size
+ memset( finder->All[k], 0, sizeof(int) * N );
+ for( i = 0; i < N; i++ ) finder->All[k][i] = i;
+ finder->ne[0] = 0;
+ finder->ce[0] = N;
+
+ finder->status = GO;
+ finder->best_score = 0;
+
+}
+
+void cvEndFindCliques( CvCliqueFinder* finder )
+{
+ int i;
+
+ //int* Compsub; //current component (vertex stack)
+ delete finder->current_comp;
+ for( i = 0 ; i < finder->N; i++ )
+ {
+ delete finder->All[i];
+ }
+ delete finder->All;
+
+ delete finder->ne;
+ delete finder->ce;
+ delete finder->fixp; //node with minimal disconnections
+ delete finder->nod;
+ delete finder->s; //for selected candidate
+
+ //delete adj matrix
+ for( i = 0 ; i < finder->N; i++ )
+ {
+ delete finder->adj_matr[i];
+ }
+ delete finder->adj_matr;
+
+ if(finder->weighted)
+ {
+ free(finder->vertex_weights);
+ free(finder->cur_weight);
+ free(finder->cand_weight);
+ }
+ if(finder->weighted_edges)
+ {
+ free(finder->edge_weights);
+ }
+}
+
+int cvFindNextMaximalClique( CvCliqueFinder* finder )
+{
+ int** connected = finder->adj_matr;
+// int N = finder->N; //graph size
+
+ // stacks, counters etc/
+ int k = finder->k; //stack size
+ int* Compsub = finder->current_comp;
+ int** All = finder->All;
+
+ int* ne = finder->ne;
+ int* ce = finder->ce;
+ int* fixp = finder->fixp; //node with minimal disconnections
+ int* nod = finder->nod;
+ int* s = finder->s; //for selected candidate
+
+ //START
+ while( k >= 0)
+ {
+ int* old = All[k];
+ switch(finder->status)
+ {
+ case GO://Forward step
+ /* we have all sets and will choose fixed point */
+ {
+ //check potential size of clique
+ if( (!finder->weighted) && (k + ce[k] - ne[k] < finder->best_score) )
+ {
+ finder->status = BACK;
+ break;
+ }
+ //check potential weight
+ if( finder->weighted && !finder->weighted_edges &&
+ finder->cur_weight[k] + finder->cand_weight[k] < finder->best_weight )
+ {
+ finder->status = BACK;
+ break;
+ }
+
+ int minnod = ce[k];
+ nod[k] = 0;
+
+ //for every vertex of All determine counter value and choose minimum
+ for( int i = 0; i < ce[k] && minnod != 0; i++)
+ {
+ int p = old[i]; //current point
+ int count = 0; //counter
+ int pos = 0;
+
+ /* Count disconnections with candidates */
+ for (int j = ne[k]; j < ce[k] && (count < minnod); j++)
+ {
+ if ( !connected[p][old[j]] )
+ {
+ count++;
+ /* Save position of potential candidate */
+ pos = j;
+ }
+ }
+
+ /* Test new minimum */
+ if (count < minnod)
+ {
+ fixp[k] = p; //set current point as fixed
+ minnod = count; //new value for minnod
+ if (i < ne[k]) //if current fixed point belongs to 'not'
+ {
+ s[k] = pos; //s - selected candidate
+ }
+ else
+ {
+ s[k] = i; //selected candidate is fixed point itself
+ /* preincr */
+ nod[k] = 1; //nod is aux variable, 1 means fixp == s
+ }
+ }
+ }//for
+
+ nod[k] = minnod + nod[k];
+ finder->status = NEXT;//go to backtrackcycle
+ }
+ break;
+ case NEXT:
+ //here we will look for candidate to translate into not
+ //s[k] now contains index of choosen candidate
+ {
+ int* new_ = All[k+1];
+ if( nod[k] != 0 )
+ {
+ //swap selected and first candidate
+ int i, p = old[s[k]];
+ old[s[k]] = old[ne[k]];
+ int sel = old[ne[k]] = p;
+
+ int newne = 0;
+ //fill new set 'not'
+ for ( i = 0; i < ne[k]; i++)
+ {
+ if (connected[sel][old[i]])
+ {
+ new_[newne] = old[i];
+ newne++;
+
+ }
+ }
+ //fill new set 'candidate'
+ int newce = newne;
+ i++;//skip selected candidate
+
+ float candweight = 0;
+
+ for (; i < ce[k]; i++)
+ {
+ if (connected[sel][old[i]])
+ {
+ new_[newce] = old[i];
+
+ if( finder->weighted )
+ candweight += finder->vertex_weights[old[i]];
+
+ newce++;
+ }
+ }
+
+ nod[k]--;
+
+ //add selected to stack
+ Compsub[k] = sel;
+
+ k++;
+ assert( k <= finder->N );
+ if( finder->weighted )
+ {
+ //update weights of current clique and candidates
+ finder->cur_weight[k] = finder->cur_weight[k-1] + finder->vertex_weights[sel];
+ finder->cand_weight[k] = candweight;
+ }
+ if( finder->weighted_edges )
+ {
+ //update total weight by edge weights
+ float added = 0;
+ for( int ind = 0; ind < k-1; ind++ )
+ {
+ added += finder->edge_weights[ Compsub[ind] * finder->N + sel ];
+ }
+ finder->cur_weight[k] += added;
+ }
+
+ //check if 'not' and 'cand' are both empty
+ if( newce == 0 )
+ {
+ finder->best_score = MAX(finder->best_score, k );
+
+ if( finder->weighted )
+ finder->best_weight = MAX( finder->best_weight, finder->cur_weight[k] );
+ /*FILE* file = fopen("cliques.txt", "a" );
+
+ for (int t=0; t<k; t++)
+ {
+ fprintf(file, "%d ", Compsub[t]);
+ }
+ fprintf(file, "\n");
+
+ fclose(file);
+ */
+
+ //output new clique//************************
+ finder->status = BACK;
+ finder->k = k;
+
+ return CLIQUE_FOUND;
+
+ }
+ else //check nonempty set of candidates
+ if( newne < newce )
+ {
+ //go further
+ ne[k] = newne;
+ ce[k] = newce;
+ finder->status = GO;
+ break;
+ }
+
+ }
+ else
+ finder->status = BACK;
+
+ }
+ break;
+
+ case BACK:
+ {
+ //decrease stack
+ k--;
+ old = All[k];
+ if( k < 0 ) break;
+
+ //add to not
+ ne[k]++;
+
+ if( nod[k] > 0 )
+ {
+ //select next candidate
+ for( s[k] = ne[k]; s[k] < ce[k]; s[k]++ )
+ {
+ if( !connected[fixp[k]][old[s[k]]])
+ break;
+ }
+ assert( s[k] < ce[k] );
+ finder->status = NEXT;
+ }
+ else
+ finder->status = BACK;
+
+ }
+ break;
+ case END: assert(0);
+
+ }
+ }//end while
+
+ finder->status = END;
+ return CLIQUE_END;
+}
+
+
+
+
+void cvBronKerbosch( CvGraph* graph )
+{
+ int* Compsub; //current component (vertex stack)
+ int k = 0; //counter of steps
+ int N = graph->total;
+ int i;
+ Compsub = new int[N];
+ int** All = new int*[N];
+ for( i = 0 ; i < N; i++ )
+ {
+ All[i] = new int[N];
+ }
+
+ int* ne = new int[N];
+ int* ce = new int[N];
+ int* fixp = new int[N]; //node with minimal disconnections
+ int* nod = new int[N];
+ int* s = new int[N]; //for selected candidate
+
+ //form adj matrix
+ int** connected = new int*[N]; //assume filled with 0
+ for( i = 0 ; i < N; i++ )
+ {
+ connected[i] = new int[N];
+ }
+
+
+
+ //set number to vertices
+ _MarkNodes( graph );
+ _FillAdjMatrix( graph, connected, 0 );
+
+ //init all arrays
+ k = 0; //stack size
+ memset( All[k], 0, sizeof(int) * N );
+ for( i = 0; i < N; i++ ) All[k][i] = i;
+ ne[0] = 0;
+ ce[0] = N;
+
+ int status = GO;
+ int best_score = 0;
+
+ //START
+ while( k >= 0)
+ {
+ int* old = All[k];
+ switch(status)
+ {
+ case GO://Forward step
+ /* we have all sets and will choose fixed point */
+ {
+
+ if( k + ce[k] - ne[k] < best_score )
+ {
+ status = BACK;
+ break;
+ }
+
+ int minnod = ce[k];
+ nod[k] = 0;
+
+ //for every vertex of All determine counter value and choose minimum
+ for( int i = 0; i < ce[k] && minnod != 0; i++)
+ {
+ int p = old[i]; //current point
+ int count = 0; //counter
+ int pos = 0;
+
+ /* Count disconnections with candidates */
+ for (int j = ne[k]; j < ce[k] && (count < minnod); j++)
+ {
+ if ( !connected[p][old[j]] )
+ {
+ count++;
+ /* Save position of potential candidate */
+ pos = j;
+ }
+ }
+
+ /* Test new minimum */
+ if (count < minnod)
+ {
+ fixp[k] = p; //set current point as fixed
+ minnod = count; //new value for minnod
+ if (i < ne[k]) //if current fixed point belongs to 'not'
+ {
+ s[k] = pos; //s - selected candidate
+ }
+ else
+ {
+ s[k] = i; //selected candidate is fixed point itself
+ /* preincr */
+ nod[k] = 1; //nod is aux variable, 1 means fixp == s
+ }
+ }
+ }//for
+
+ nod[k] = minnod + nod[k];
+ status = NEXT;//go to backtrackcycle
+ }
+ break;
+ case NEXT:
+ //here we will look for candidate to translate into not
+ //s[k] now contains index of choosen candidate
+ {
+ int* new_ = All[k+1];
+ if( nod[k] != 0 )
+ {
+ //swap selected and first candidate
+ int p = old[s[k]];
+ old[s[k]] = old[ne[k]];
+ int sel = old[ne[k]] = p;
+
+ int newne = 0;
+ //fill new set 'not'
+ for ( i = 0; i < ne[k]; i++)
+ {
+ if (connected[sel][old[i]])
+ {
+ new_[newne] = old[i];
+ newne++;
+
+ }
+ }
+ //fill new set 'candidate'
+ int newce = newne;
+ i++;//skip selected candidate
+ for (; i < ce[k]; i++)
+ {
+ if (connected[sel][old[i]])
+ {
+ new_[newce] = old[i];
+ newce++;
+ }
+ }
+
+ nod[k]--;
+
+ //add selected to stack
+ Compsub[k] = sel;
+ k++;
+
+ //check if 'not' and 'cand' are both empty
+ if( newce == 0 )
+ {
+ best_score = MAX(best_score, k );
+
+ FILE* file = fopen("cliques.txt", "a" );
+
+ for (int t=0; t<k; t++)
+ {
+ fprintf(file, "%d ", Compsub[t]);
+ }
+ fprintf(file, "\n");
+
+ fclose(file);
+
+ /*for( int t = 0; t < k; t++ )
+ {
+ printf("%d ", Compsub[t] );
+ }
+ printf("\n"); */
+
+ //printf("found %d\n", k);
+
+ //output new clique//************************
+ status = BACK;
+ }
+ else //check nonempty set of candidates
+ if( newne < newce )
+ {
+ //go further
+ ne[k] = newne;
+ ce[k] = newce;
+ status = GO;
+ break;
+ }
+
+ }
+ else
+ status = BACK;
+
+ }
+ break;
+
+ case BACK:
+ {
+ //decrease stack
+ k--;
+ old = All[k];
+ if( k < 0 ) break;
+
+ //add to not
+ ne[k]++;
+
+ if( nod[k] > 0 )
+ {
+ //select next candidate
+ for( s[k] = ne[k]; s[k] < ce[k]; s[k]++ )
+ {
+ if( !connected[fixp[k]][old[s[k]]])
+ break;
+ }
+ assert( s[k] < ce[k] );
+ status = NEXT;
+ }
+ else
+ status = BACK;
+
+ }
+ break;
+
+
+ }
+ }//end while
+
+}//end cvBronKerbosch
+
+#endif
+
diff --git a/cvaux/src/cvcorrespond.cpp b/cvaux/src/cvcorrespond.cpp
new file mode 100644
index 0000000..c0c55e1
--- /dev/null
+++ b/cvaux/src/cvcorrespond.cpp
@@ -0,0 +1,403 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cvaux.h"
+#include "_cvvm.h"
+#include <stdlib.h>
+#include <assert.h>
+
+
+/*======================================================================================*/
+
+CvStatus
+icvDynamicCorrespond( int *first, /* first sequence of runs */
+ /* s0|w0|s1|w1|...|s(n-1)|w(n-1)|sn */
+ int first_runs, /* number of runs */
+ int *second, /* second sequence of runs */
+ int second_runs, int *first_corr, /* s0'|e0'|s1'|e1'|... */
+ int *second_corr )
+{
+
+ float Pd, Fi, S;
+ float Occlusion;
+ float *costTable;
+ uchar *matchEdges;
+ int prev;
+ int curr;
+ int baseIndex;
+ int i, j;
+ int i_1, j_1;
+ int n;
+ int l_beg, r_beg, l_end, r_end, l_len, r_len;
+ int first_curr;
+ int second_curr;
+ int l_color, r_color;
+ int len_color;
+ float cost, cost1;
+ float min1, min2, min3;
+ float cmin;
+ uchar cpath;
+ int row_size;
+
+ /* Test arguments for errors */
+
+ if( (first == 0) ||
+ (first_runs < 1) ||
+ (second == 0) || (second_runs < 1) || (first_corr == 0) || (second_corr == 0) )
+
+ return CV_BADFACTOR_ERR;
+
+
+ Pd = 0.95f;
+ Fi = (float) CV_PI;
+ S = 1;
+
+ Occlusion = (float) log( Pd * Fi / ((1 - Pd) * sqrt( fabs( (CV_PI * 2) * (1. / S) ))));
+
+ costTable = (float *)cvAlloc( (first_runs + 1) * (second_runs + 1) * sizeof( float ));
+
+ if( costTable == 0 )
+ return CV_OUTOFMEM_ERR;
+
+ matchEdges = (uchar *)cvAlloc( (first_runs + 1) * (second_runs + 1) * sizeof( uchar ));
+
+ if( matchEdges == 0 )
+ {
+ cvFree( &costTable );
+ return CV_OUTOFMEM_ERR;
+ }
+
+ row_size = first_runs + 1;
+
+ /* ============= Fill costTable ============= */
+
+ costTable[0] = 0.0f;
+
+ /* Fill upper line in the cost Table */
+
+ prev = first[0];
+ curr = 2;
+
+ for( n = 0; n < first_runs; n++ )
+ {
+
+ l_end = first[curr];
+ curr += 2;
+ costTable[n + 1] = costTable[n] + Occlusion * (l_end - prev);
+ prev = l_end;
+
+ } /* for */
+
+ /* Fill lefter line in the cost Table */
+
+ prev = second[0];
+ curr = 2;
+ baseIndex = 0;
+
+ for( n = 0; n < second_runs; n++ )
+ {
+
+ l_end = second[curr];
+ curr += 2;
+ costTable[baseIndex + row_size] = costTable[baseIndex] + Occlusion * (l_end - prev);
+ baseIndex += row_size;
+ prev = l_end;
+
+ } /* for */
+
+ /* Count costs in the all rest cells */
+
+ first_curr = 0;
+ second_curr = 0;
+
+ for( i = 1; i <= first_runs; i++ )
+ {
+ for( j = 1; j <= second_runs; j++ )
+ {
+
+ first_curr = (i - 1) * 2;
+ second_curr = (j - 1) * 2;
+
+ l_beg = first[first_curr];
+ first_curr++;
+ l_color = first[first_curr];
+ first_curr++;
+ l_end = first[first_curr];
+ l_len = l_end - l_beg + 1;
+
+ r_beg = second[second_curr];
+ second_curr++;
+ r_color = second[second_curr];
+ second_curr++;
+ r_end = second[second_curr];
+ r_len = r_end - r_beg + 1;
+
+ i_1 = i - 1;
+ j_1 = j - 1;
+
+ if( r_len == l_len )
+ {
+ cost = 0;
+ }
+ else
+ {
+
+ if( r_len > l_len )
+ {
+ cost = (float) (r_len * r_len - l_len * l_len) * (1 / (r_len * l_len));
+ }
+ else
+ {
+ cost = (float) (l_len * l_len - r_len * r_len) * (1 / (r_len * l_len));
+ }
+ } /* if */
+
+ len_color = r_color - l_color;
+
+ cost1 = (float) ((len_color * len_color) >> 2);
+
+ min2 = costTable[i_1 + j * row_size] + Occlusion * l_len;
+
+ min3 = costTable[i + j_1 * row_size] + Occlusion * r_len;
+
+ min1 = costTable[i_1 + j_1 * row_size] + cost + (float) cost1;
+
+ if( min1 < min2 )
+ {
+
+ if( min1 < min3 )
+ {
+ cmin = min1;
+ cpath = 1;
+ }
+ else
+ {
+ cmin = min3;
+ cpath = 3;
+ } /* if */
+
+ }
+ else
+ {
+
+ if( min2 < min3 )
+ {
+ cmin = min2;
+ cpath = 2;
+ }
+ else
+ {
+ cmin = min3;
+ cpath = 3;
+ } /* if */
+
+ } /* if */
+
+ costTable[i + j * row_size] = cmin;
+ matchEdges[i + j * row_size] = cpath;
+ } /* for */
+ } /* for */
+
+ /* =========== Reconstruct the Path =========== */
+
+ i = first_runs;
+ j = second_runs;
+
+ first_curr = i * 2 - 2;
+ second_curr = j * 2 - 2;
+
+
+ while( i > 0 && j > 0 )
+ {
+
+ /* Connect begins */
+ switch (matchEdges[i + j * row_size])
+ {
+
+ case 1: /* to diagonal */
+
+ first_corr[first_curr] = second[second_curr];
+ first_corr[first_curr + 1] = second[second_curr + 2];
+ second_corr[second_curr] = first[first_curr];
+ second_corr[second_curr + 1] = first[first_curr + 2];
+
+ first_curr -= 2;
+ second_curr -= 2;
+ i--;
+ j--;
+
+ break;
+
+ case 2: /* to left */
+
+ first_corr[first_curr] = second[second_curr + 2];
+ first_corr[first_curr + 1] = second[second_curr + 2];
+
+ first_curr -= 2;
+ i--;
+
+ break;
+
+ case 3: /* to up */
+
+ second_corr[second_curr] = first[first_curr + 2];
+ second_corr[second_curr + 1] = first[first_curr + 2];
+
+ second_curr -= 2;
+ j--;
+
+ break;
+ } /* switch */
+ } /* while */
+
+ /* construct rest of horisontal path if its need */
+ while( i > 0 )
+ {
+
+ first_corr[first_curr] = second[second_curr + 2]; /* connect to begin */
+ first_corr[first_curr + 1] = second[second_curr + 2]; /* connect to begin */
+
+ first_curr -= 2;
+ i--;
+
+ } /* while */
+
+ /* construct rest of vertical path if its need */
+ while( j > 0 )
+ {
+
+ second_corr[second_curr] = first[first_curr + 2];
+ second_corr[second_curr + 1] = first[first_curr + 2];
+
+ second_curr -= 2;
+ j--;
+
+ } /* while */
+
+ cvFree( &costTable );
+ cvFree( &matchEdges );
+
+ return CV_NO_ERR;
+} /* icvDynamicCorrespond */
+
+
+/*======================================================================================*/
+
+static CvStatus
+icvDynamicCorrespondMulti( int lines, /* number of scanlines */
+ int *first, /* s0|w0|s1|w1|...s(n-1)|w(n-1)|sn */
+ int *first_runs, /* numbers of runs */
+ int *second, int *second_runs, int *first_corr, /* s0'|e0'|s1'|e1'|... */
+ int *second_corr )
+{
+ CvStatus error;
+
+ int currFirst;
+ int currSecond;
+ int currFirstCorr;
+ int currSecondCorr;
+ int n;
+
+ /* Test errors */
+
+ if( (lines < 1) ||
+ (first == 0) ||
+ (first_runs == 0) ||
+ (second == 0) || (second_runs == 0) || (first_corr == 0) || (second_corr == 0) )
+ return CV_BADFACTOR_ERR;
+
+ currFirst = 0;
+ currSecond = 0;
+ currFirstCorr = 0;
+ currSecondCorr = 0;
+
+ for( n = 0; n < lines; n++ )
+ {
+
+ error = icvDynamicCorrespond( &(first[currFirst]),
+ first_runs[n],
+ &(second[currSecond]),
+ second_runs[n],
+ &(first_corr[currFirstCorr]),
+ &(second_corr[currSecondCorr]) );
+
+ if( error != CV_NO_ERR )
+ return error;
+
+ currFirst += first_runs[n] * 2 + 1;
+ currSecond += second_runs[n] * 2 + 1;
+ currFirstCorr += first_runs[n] * 2;
+ currSecondCorr += second_runs[n] * 2;
+
+ }
+
+ return CV_NO_ERR;
+
+} /* icvDynamicCorrespondMulti */
+
+
+/*======================================================================================*/
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvDynamicCorrespondMulti
+// Purpose: The functions
+// Context:
+// Parameters:
+//
+// Notes:
+//F*/
+CV_IMPL void
+cvDynamicCorrespondMulti( int lines, /* number of scanlines */
+ int *first, /* s0|w0|s1|w1|...s(n-1)|w(n-1)|sn */
+ int *first_runs, /* numbers of runs */
+ int *second, int *second_runs, int *first_corr, /* s0'|e0'|s1'|e1'|... */
+ int *second_corr )
+{
+ CV_FUNCNAME( "cvDynamicCorrespondMulti" );
+ __BEGIN__;
+
+ IPPI_CALL( icvDynamicCorrespondMulti( lines, /* number of scanlines */
+ first, /* s0|w0|s1|w1|...s(n-1)|w(n-1)|sn */
+ first_runs, /* numbers of runs */
+ second, second_runs, first_corr, /* s0'|e0'|s1'|e1'|... */
+ second_corr ));
+ __CLEANUP__;
+ __END__;
+}
diff --git a/cvaux/src/cvcorrimages.cpp b/cvaux/src/cvcorrimages.cpp
new file mode 100644
index 0000000..12261e9
--- /dev/null
+++ b/cvaux/src/cvcorrimages.cpp
@@ -0,0 +1,1152 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+//#include "cvtypes.h"
+//#include <float.h>
+//#include <limits.h>
+//#include "cv.h"
+//#include "highgui.h"
+
+#include <stdio.h>
+
+/* Valery Mosyagin */
+
+/* ===== Function for find corresponding between images ===== */
+
+/* Create feature points on image and return number of them. Array points fills by found points */
+int icvCreateFeaturePoints(IplImage *image, CvMat *points, CvMat *status)
+{
+ int foundFeaturePoints = 0;
+ IplImage *grayImage = 0;
+ IplImage *eigImage = 0;
+ IplImage *tmpImage = 0;
+ CvPoint2D32f *cornerPoints = 0;
+
+ CV_FUNCNAME( "icvFeatureCreatePoints" );
+ __BEGIN__;
+
+ /* Test for errors */
+ if( image == 0 || points == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ /* Test image size */
+ int w,h;
+ w = image->width;
+ h = image->height;
+
+ if( w <= 0 || h <= 0)
+ {
+ CV_ERROR( CV_StsOutOfRange, "Size of image must be > 0" );
+ }
+
+ /* Test for matrices */
+ if( !CV_IS_MAT(points) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameter points must be a matrix" );
+ }
+
+ int needNumPoints;
+ needNumPoints = points->cols;
+ if( needNumPoints <= 0 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of need points must be > 0" );
+ }
+
+ if( points->rows != 2 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of point coordinates must be == 2" );
+ }
+
+ if( status != 0 )
+ {
+ /* If status matrix exist test it for correct */
+ if( !CV_IS_MASK_ARR(status) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Statuses must be a mask arrays" );
+ }
+
+ if( status->cols != needNumPoints )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of points and statuses must be the same" );
+ }
+
+ if( status->rows !=1 )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Number of rows of status must be 1" );
+ }
+ }
+
+ /* Create temporary images */
+ CV_CALL( grayImage = cvCreateImage(cvSize(w,h), 8,1) );
+ CV_CALL( eigImage = cvCreateImage(cvSize(w,h),32,1) );
+ CV_CALL( tmpImage = cvCreateImage(cvSize(w,h),32,1) );
+
+ /* Create points */
+ CV_CALL( cornerPoints = (CvPoint2D32f*)cvAlloc( sizeof(CvPoint2D32f) * needNumPoints) );
+
+ int foundNum;
+ double quality;
+ double minDist;
+
+ cvCvtColor(image,grayImage, CV_BGR2GRAY);
+
+ foundNum = needNumPoints;
+ quality = 0.01;
+ minDist = 5;
+ cvGoodFeaturesToTrack(grayImage, eigImage, tmpImage, cornerPoints, &foundNum, quality, minDist);
+
+ /* Copy found points to result */
+ int i;
+ for( i = 0; i < foundNum; i++ )
+ {
+ cvmSet(points,0,i,cornerPoints[i].x);
+ cvmSet(points,1,i,cornerPoints[i].y);
+ }
+
+ /* Set status if need */
+ if( status )
+ {
+ for( i = 0; i < foundNum; i++ )
+ {
+ status->data.ptr[i] = 1;
+ }
+
+ for( i = foundNum; i < needNumPoints; i++ )
+ {
+ status->data.ptr[i] = 0;
+ }
+ }
+
+ foundFeaturePoints = foundNum;
+
+ __END__;
+
+ /* Free allocated memory */
+ cvReleaseImage(&grayImage);
+ cvReleaseImage(&eigImage);
+ cvReleaseImage(&tmpImage);
+ cvFree(&cornerPoints);
+
+ return foundFeaturePoints;
+}
+
+/*-------------------------------------------------------------------------------------*/
+
+/* For given points1 (with pntStatus) on image1 finds corresponding points2 on image2 and set pntStatus2 for them */
+/* Returns number of corresponding points */
+int icvFindCorrForGivenPoints( IplImage *image1,/* Image 1 */
+ IplImage *image2,/* Image 2 */
+ CvMat *points1,
+ CvMat *pntStatus1,
+ CvMat *points2,
+ CvMat *pntStatus2,
+ int useFilter,/*Use fundamental matrix to filter points */
+ double threshold)/* Threshold for good points in filter */
+{
+ int resNumCorrPoints = 0;
+ CvPoint2D32f* cornerPoints1 = 0;
+ CvPoint2D32f* cornerPoints2 = 0;
+ char* status = 0;
+ float* errors = 0;
+ CvMat* tmpPoints1 = 0;
+ CvMat* tmpPoints2 = 0;
+ CvMat* pStatus = 0;
+ IplImage *grayImage1 = 0;
+ IplImage *grayImage2 = 0;
+ IplImage *pyrImage1 = 0;
+ IplImage *pyrImage2 = 0;
+
+ CV_FUNCNAME( "icvFindCorrForGivenPoints" );
+ __BEGIN__;
+
+ /* Test input data for errors */
+
+ /* Test for null pointers */
+ if( image1 == 0 || image2 == 0 ||
+ points1 == 0 || points2 == 0 ||
+ pntStatus1 == 0 || pntStatus2 == 0)
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ /* Test image size */
+ int w,h;
+ w = image1->width;
+ h = image1->height;
+
+ if( w <= 0 || h <= 0)
+ {
+ CV_ERROR( CV_StsOutOfRange, "Size of image1 must be > 0" );
+ }
+
+ if( image2->width != w || image2->height != h )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of images must be the same" );
+ }
+
+ /* Test for matrices */
+ if( !CV_IS_MAT(points1) || !CV_IS_MAT(points2) ||
+ !CV_IS_MAT(pntStatus1) || !CV_IS_MAT(pntStatus2) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters (points and status) must be a matrices" );
+ }
+
+ /* Test type of status matrices */
+ if( !CV_IS_MASK_ARR(pntStatus1) || !CV_IS_MASK_ARR(pntStatus2) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Statuses must be a mask arrays" );
+ }
+
+ /* Test number of points */
+ int numPoints;
+ numPoints = points1->cols;
+
+ if( numPoints <= 0 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of points1 must be > 0" );
+ }
+
+ if( points2->cols != numPoints || pntStatus1->cols != numPoints || pntStatus2->cols != numPoints )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of points and statuses must be the same" );
+ }
+
+ if( points1->rows != 2 || points2->rows != 2 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of points coordinates must be 2" );
+ }
+
+ if( pntStatus1->rows != 1 || pntStatus2->rows != 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Status must be a matrix 1xN" );
+ }
+ /* ----- End test ----- */
+
+
+ /* Compute number of visible points on image1 */
+ int numVisPoints;
+ numVisPoints = cvCountNonZero(pntStatus1);
+
+ if( numVisPoints > 0 )
+ {
+ /* Create temporary images */
+ /* We must use iplImage againts hughgui images */
+
+/*
+ CvvImage grayImage1;
+ CvvImage grayImage2;
+ CvvImage pyrImage1;
+ CvvImage pyrImage2;
+*/
+
+ /* Create Ipl images */
+ CV_CALL( grayImage1 = cvCreateImage(cvSize(w,h),8,1) );
+ CV_CALL( grayImage2 = cvCreateImage(cvSize(w,h),8,1) );
+ CV_CALL( pyrImage1 = cvCreateImage(cvSize(w,h),8,1) );
+ CV_CALL( pyrImage2 = cvCreateImage(cvSize(w,h),8,1) );
+
+ CV_CALL( cornerPoints1 = (CvPoint2D32f*)cvAlloc( sizeof(CvPoint2D32f)*numVisPoints) );
+ CV_CALL( cornerPoints2 = (CvPoint2D32f*)cvAlloc( sizeof(CvPoint2D32f)*numVisPoints) );
+ CV_CALL( status = (char*)cvAlloc( sizeof(char)*numVisPoints) );
+ CV_CALL( errors = (float*)cvAlloc( 2 * sizeof(float)*numVisPoints) );
+
+ int i;
+ for( i = 0; i < numVisPoints; i++ )
+ {
+ status[i] = 1;
+ }
+
+ /* !!! Need test creation errors */
+ /*
+ if( !grayImage1.Create(w,h,8)) EXIT;
+ if( !grayImage2.Create(w,h,8)) EXIT;
+ if( !pyrImage1. Create(w,h,8)) EXIT;
+ if( !pyrImage2. Create(w,h,8)) EXIT;
+ */
+
+ cvCvtColor(image1,grayImage1,CV_BGR2GRAY);
+ cvCvtColor(image2,grayImage2,CV_BGR2GRAY);
+
+ /*
+ grayImage1.CopyOf(image1,0);
+ grayImage2.CopyOf(image2,0);
+ */
+
+ /* Copy points good points from input data */
+ uchar *stat1 = pntStatus1->data.ptr;
+ uchar *stat2 = pntStatus2->data.ptr;
+
+ int curr = 0;
+ for( i = 0; i < numPoints; i++ )
+ {
+ if( stat1[i] )
+ {
+ cornerPoints1[curr].x = (float)cvmGet(points1,0,i);
+ cornerPoints1[curr].y = (float)cvmGet(points1,1,i);
+ curr++;
+ }
+ }
+
+ /* Define number of levels of pyramid */
+ cvCalcOpticalFlowPyrLK( grayImage1, grayImage2,
+ pyrImage1, pyrImage2,
+ cornerPoints1, cornerPoints2,
+ numVisPoints, cvSize(10,10), 3,
+ status, errors,
+ cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03),
+ 0/*CV_LKFLOW_PYR_A_READY*/ );
+
+
+ memset(stat2,0,sizeof(uchar)*numPoints);
+
+ int currVis = 0;
+ int totalCorns = 0;
+
+ /* Copy new points and set status */
+ /* stat1 may not be the same as stat2 */
+ for( i = 0; i < numPoints; i++ )
+ {
+ if( stat1[i] )
+ {
+ if( status[currVis] && errors[currVis] < 1000 )
+ {
+ stat2[i] = 1;
+ cvmSet(points2,0,i,cornerPoints2[currVis].x);
+ cvmSet(points2,1,i,cornerPoints2[currVis].y);
+ totalCorns++;
+ }
+ currVis++;
+ }
+ }
+
+ resNumCorrPoints = totalCorns;
+
+ /* Filter points using RANSAC */
+ if( useFilter )
+ {
+ resNumCorrPoints = 0;
+ /* Use RANSAC filter for found points */
+ if( totalCorns > 7 )
+ {
+ /* Create array with good points only */
+ CV_CALL( tmpPoints1 = cvCreateMat(2,totalCorns,CV_64F) );
+ CV_CALL( tmpPoints2 = cvCreateMat(2,totalCorns,CV_64F) );
+
+ /* Copy just good points */
+ int currPoint = 0;
+ for( i = 0; i < numPoints; i++ )
+ {
+ if( stat2[i] )
+ {
+ cvmSet(tmpPoints1,0,currPoint,cvmGet(points1,0,i));
+ cvmSet(tmpPoints1,1,currPoint,cvmGet(points1,1,i));
+
+ cvmSet(tmpPoints2,0,currPoint,cvmGet(points2,0,i));
+ cvmSet(tmpPoints2,1,currPoint,cvmGet(points2,1,i));
+
+ currPoint++;
+ }
+ }
+
+ /* Compute fundamental matrix */
+ CvMat fundMatr;
+ double fundMatr_dat[9];
+ fundMatr = cvMat(3,3,CV_64F,fundMatr_dat);
+
+ CV_CALL( pStatus = cvCreateMat(1,totalCorns,CV_32F) );
+
+ int num = cvFindFundamentalMat(tmpPoints1,tmpPoints2,&fundMatr,CV_FM_RANSAC,threshold,0.99,pStatus);
+ if( num > 0 )
+ {
+ int curr = 0;
+ /* Set final status for points2 */
+ for( i = 0; i < numPoints; i++ )
+ {
+ if( stat2[i] )
+ {
+ if( cvmGet(pStatus,0,curr) == 0 )
+ {
+ stat2[i] = 0;
+ }
+ curr++;
+ }
+ }
+ resNumCorrPoints = curr;
+ }
+ }
+ }
+ }
+
+ __END__;
+
+ /* Free allocated memory */
+ cvFree(&cornerPoints1);
+ cvFree(&cornerPoints2);
+ cvFree(&status);
+ cvFree(&errors);
+ cvFree(&tmpPoints1);
+ cvFree(&tmpPoints2);
+ cvReleaseMat( &pStatus );
+ cvReleaseImage( &grayImage1 );
+ cvReleaseImage( &grayImage2 );
+ cvReleaseImage( &pyrImage1 );
+ cvReleaseImage( &pyrImage2 );
+
+ return resNumCorrPoints;
+}
+/*-------------------------------------------------------------------------------------*/
+int icvGrowPointsAndStatus(CvMat **oldPoints,CvMat **oldStatus,CvMat *addPoints,CvMat *addStatus,int addCreateNum)
+{
+ /* Add to existing points and status arrays new points or just grow */
+ CvMat *newOldPoint = 0;
+ CvMat *newOldStatus = 0;
+ int newTotalNumber = 0;
+
+ CV_FUNCNAME( "icvGrowPointsAndStatus" );
+ __BEGIN__;
+
+ /* Test for errors */
+ if( oldPoints == 0 || oldStatus == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( *oldPoints == 0 || *oldStatus == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(*oldPoints))
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "oldPoints must be a pointer to a matrix" );
+ }
+
+ if( !CV_IS_MASK_ARR(*oldStatus))
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "oldStatus must be a pointer to a mask array" );
+ }
+
+ int oldNum;
+ oldNum = (*oldPoints)->cols;
+ if( oldNum < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of old points must be > 0" );
+ }
+
+ /* Define if need number of add points */
+ int addNum;
+ addNum = 0;
+ if( addPoints != 0 && addStatus != 0 )
+ {/* We have aditional points */
+ if( CV_IS_MAT(addPoints) && CV_IS_MASK_ARR(addStatus) )
+ {
+ addNum = addPoints->cols;
+ if( addStatus->cols != addNum )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of add points and statuses must be the same" );
+ }
+ }
+ }
+
+ /* */
+
+ int numCoord;
+ numCoord = (*oldPoints)->rows;
+ newTotalNumber = oldNum + addNum + addCreateNum;
+
+ if( newTotalNumber )
+ {
+ /* Free allocated memory */
+ newOldPoint = cvCreateMat(numCoord,newTotalNumber,CV_64F);
+ newOldStatus = cvCreateMat(1,newTotalNumber,CV_8S);
+
+ /* Copy old values to */
+ int i;
+
+ /* Clear all values */
+ cvZero(newOldPoint);
+ cvZero(newOldStatus);
+
+ for( i = 0; i < oldNum; i++ )
+ {
+ int currCoord;
+ for( currCoord = 0; currCoord < numCoord; currCoord++ )
+ {
+ cvmSet(newOldPoint,currCoord,i,cvmGet(*oldPoints,currCoord,i));
+ }
+ newOldStatus->data.ptr[i] = (*oldStatus)->data.ptr[i];
+ }
+
+ /* Copy additional points and statuses */
+ if( addNum )
+ {
+ for( i = 0; i < addNum; i++ )
+ {
+ int currCoord;
+ for( currCoord = 0; currCoord < numCoord; currCoord++ )
+ {
+ cvmSet(newOldPoint,currCoord,i+oldNum,cvmGet(addPoints,currCoord,i));
+ }
+ newOldStatus->data.ptr[i+oldNum] = addStatus->data.ptr[i];
+ //cvmSet(newOldStatus,0,i,cvmGet(addStatus,0,i));
+ }
+ }
+
+ /* Delete previous data */
+ cvReleaseMat(oldPoints);
+ cvReleaseMat(oldStatus);
+
+ /* copy pointers */
+ *oldPoints = newOldPoint;
+ *oldStatus = newOldStatus;
+
+ }
+ __END__;
+
+ return newTotalNumber;
+}
+/*-------------------------------------------------------------------------------------*/
+int icvRemoveDoublePoins( CvMat *oldPoints,/* Points on prev image */
+ CvMat *newPoints,/* New points */
+ CvMat *oldStatus,/* Status for old points */
+ CvMat *newStatus,
+ CvMat *origStatus,
+ float threshold)/* Status for new points */
+{
+
+ CvMemStorage* storage = 0;
+ CvSubdiv2D* subdiv = 0;
+ CvSeq* seq = 0;
+
+ int originalPoints = 0;
+
+ CV_FUNCNAME( "icvRemoveDoublePoins" );
+ __BEGIN__;
+
+ /* Test input data */
+ if( oldPoints == 0 || newPoints == 0 ||
+ oldStatus == 0 || newStatus == 0 || origStatus == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(oldPoints) || !CV_IS_MAT(newPoints) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters points must be a matrices" );
+ }
+
+ if( !CV_IS_MASK_ARR(oldStatus) || !CV_IS_MASK_ARR(newStatus) || !CV_IS_MASK_ARR(origStatus) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters statuses must be a mask array" );
+ }
+
+ int oldNumPoints;
+ oldNumPoints = oldPoints->cols;
+ if( oldNumPoints < 0 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of oldPoints must be >= 0" );
+ }
+
+ if( oldStatus->cols != oldNumPoints )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of old Points and old Statuses must be the same" );
+ }
+
+ int newNumPoints;
+ newNumPoints = newPoints->cols;
+ if( newNumPoints < 0 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of newPoints must be >= 0" );
+ }
+
+ if( newStatus->cols != newNumPoints )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of new Points and new Statuses must be the same" );
+ }
+
+ if( origStatus->cols != newNumPoints )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of new Points and new original Status must be the same" );
+ }
+
+ if( oldPoints->rows != 2)
+ {
+ CV_ERROR( CV_StsOutOfRange, "OldPoints must have 2 coordinates >= 0" );
+ }
+
+ if( newPoints->rows != 2)
+ {
+ CV_ERROR( CV_StsOutOfRange, "NewPoints must have 2 coordinates >= 0" );
+ }
+
+ if( oldStatus->rows != 1 || newStatus->rows != 1 || origStatus->rows != 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Statuses must have 1 row" );
+ }
+
+ /* we have points on image and wants add new points */
+ /* use subdivision for find nearest points */
+
+ /* Define maximum and minimum X and Y */
+ float minX,minY;
+ float maxX,maxY;
+
+ minX = minY = FLT_MAX;
+ maxX = maxY = FLT_MIN;
+
+ int i;
+
+ for( i = 0; i < oldNumPoints; i++ )
+ {
+ if( oldStatus->data.ptr[i] )
+ {
+ float x = (float)cvmGet(oldPoints,0,i);
+ float y = (float)cvmGet(oldPoints,1,i);
+
+ if( x < minX )
+ minX = x;
+
+ if( x > maxX )
+ maxX = x;
+
+ if( y < minY )
+ minY = y;
+
+ if( y > maxY )
+ maxY = y;
+ }
+ }
+
+ for( i = 0; i < newNumPoints; i++ )
+ {
+ if( newStatus->data.ptr[i] )
+ {
+ float x = (float)cvmGet(newPoints,0,i);
+ float y = (float)cvmGet(newPoints,1,i);
+
+ if( x < minX )
+ minX = x;
+
+ if( x > maxX )
+ maxX = x;
+
+ if( y < minY )
+ minY = y;
+
+ if( y > maxY )
+ maxY = y;
+ }
+ }
+
+
+ /* Creare subdivision for old image */
+ storage = cvCreateMemStorage(0);
+// subdiv = cvCreateSubdivDelaunay2D( cvRect( 0, 0, size.width, size.height ), storage );
+ subdiv = cvCreateSubdivDelaunay2D( cvRect( cvRound(minX)-5, cvRound(minY)-5, cvRound(maxX-minX)+10, cvRound(maxY-minY)+10 ), storage );
+ seq = cvCreateSeq( 0, sizeof(*seq), sizeof(CvPoint2D32f), storage );
+
+ /* Insert each point from first image */
+ for( i = 0; i < oldNumPoints; i++ )
+ {
+ /* Add just exist points */
+ if( oldStatus->data.ptr[i] )
+ {
+ CvPoint2D32f pt;
+ pt.x = (float)cvmGet(oldPoints,0,i);
+ pt.y = (float)cvmGet(oldPoints,1,i);
+
+ CvSubdiv2DPoint* point;
+ point = cvSubdivDelaunay2DInsert( subdiv, pt );
+ }
+ }
+
+
+ /* Find nearest points */
+ /* for each new point */
+ int flag;
+ for( i = 0; i < newNumPoints; i++ )
+ {
+ flag = 0;
+ /* Test just exist points */
+ if( newStatus->data.ptr[i] )
+ {
+ flag = 1;
+ /* Let this is a good point */
+ //originalPoints++;
+
+ CvPoint2D32f pt;
+
+ pt.x = (float)cvmGet(newPoints,0,i);
+ pt.y = (float)cvmGet(newPoints,1,i);
+
+ CvSubdiv2DPoint* point = cvFindNearestPoint2D( subdiv, pt );
+
+ if( point )
+ {
+ /* Test distance of found nearest point */
+ double minDistance = icvSqDist2D32f( pt, point->pt );
+
+ if( minDistance < threshold*threshold )
+ {
+ /* Point is double. Turn it off */
+ /* Set status */
+ //newStatus->data.ptr[i] = 0;
+
+ /* No this is a double point */
+ //originalPoints--;
+ flag = 0;
+ }
+ }
+ }
+ originalPoints += flag;
+ origStatus->data .ptr[i] = (uchar)flag;
+ }
+
+ __END__;
+
+ cvReleaseMemStorage( &storage );
+
+
+ return originalPoints;
+
+
+}
+
+void icvComputeProjectMatrix(CvMat* objPoints,CvMat* projPoints,CvMat* projMatr);
+
+/*-------------------------------------------------------------------------------------*/
+void icvComputeProjectMatrixStatus(CvMat *objPoints4D,CvMat *points2,CvMat *status, CvMat *projMatr)
+{
+ /* Compute number of good points */
+ int num = cvCountNonZero(status);
+
+ /* Create arrays */
+ CvMat *objPoints = 0;
+ objPoints = cvCreateMat(4,num,CV_64F);
+
+ CvMat *points2D = 0;
+ points2D = cvCreateMat(2,num,CV_64F);
+
+ int currVis = 0;
+ int i;
+#if 1
+ FILE *file;
+ file = fopen("d:\\test\\projStatus.txt","w");
+#endif
+ int totalNum = objPoints4D->cols;
+ for( i = 0; i < totalNum; i++ )
+ {
+ fprintf(file,"%d (%d) ",i,status->data.ptr[i]);
+ if( status->data.ptr[i] )
+ {
+
+#if 1
+ double X,Y,Z,W;
+ double x,y;
+ X = cvmGet(objPoints4D,0,i);
+ Y = cvmGet(objPoints4D,1,i);
+ Z = cvmGet(objPoints4D,2,i);
+ W = cvmGet(objPoints4D,3,i);
+
+ x = cvmGet(points2,0,i);
+ y = cvmGet(points2,1,i);
+ fprintf(file,"%d (%lf %lf %lf %lf) - (%lf %lf)",i,X,Y,Z,W,x,y );
+#endif
+ cvmSet(objPoints,0,currVis,cvmGet(objPoints4D,0,i));
+ cvmSet(objPoints,1,currVis,cvmGet(objPoints4D,1,i));
+ cvmSet(objPoints,2,currVis,cvmGet(objPoints4D,2,i));
+ cvmSet(objPoints,3,currVis,cvmGet(objPoints4D,3,i));
+
+ cvmSet(points2D,0,currVis,cvmGet(points2,0,i));
+ cvmSet(points2D,1,currVis,cvmGet(points2,1,i));
+
+ currVis++;
+ }
+
+ fprintf(file,"\n");
+ }
+
+#if 1
+ fclose(file);
+#endif
+
+ icvComputeProjectMatrix(objPoints,points2D,projMatr);
+
+ /* Free allocated memory */
+ cvReleaseMat(&objPoints);
+ cvReleaseMat(&points2D);
+}
+
+
+
+/*-------------------------------------------------------------------------------------*/
+/* For given N images
+ we have corresponding points on N images
+ computed projection matrices
+ reconstructed 4D points
+
+ we must to compute
+
+
+*/
+
+void icvAddNewImageToPrevious____(
+ IplImage *newImage,//Image to add
+ IplImage *oldImage,//Previous image
+ CvMat *oldPoints,// previous 2D points on prev image (some points may be not visible)
+ CvMat *oldPntStatus,//Status for each point on prev image
+ CvMat *objPoints4D,//prev 4D points
+ CvMat *newPoints, //Points on new image corr for prev
+ CvMat *newPntStatus,// New point status for new image
+ CvMat *newFPoints2D1,//new feature points on prev image
+ CvMat *newFPoints2D2,//new feature points on new image
+ CvMat *newFPointsStatus,
+ CvMat *newProjMatr,
+ int useFilter,
+ double threshold)//New projection matrix
+{
+ CvMat *points2 = 0;
+ CvMat *status = 0;
+ CvMat *newFPointsStatusTmp = 0;
+
+ //CV_FUNCNAME( "icvAddNewImageToPrevious____" );
+ __BEGIN__;
+
+ /* First found correspondence points for images */
+
+ /* Test input params */
+
+ int numPoints;
+ numPoints = oldPoints->cols;
+
+ /* Allocate memory */
+
+ points2 = cvCreateMat(2,numPoints,CV_64F);
+ status = cvCreateMat(1,numPoints,CV_8S);
+ newFPointsStatusTmp = cvCreateMat(1, newFPoints2D1->cols,CV_8S);
+
+ int corrNum;
+ corrNum = icvFindCorrForGivenPoints( oldImage,/* Image 1 */
+ newImage,/* Image 2 */
+ oldPoints,
+ oldPntStatus,
+ points2,
+ status,
+ useFilter,/*Use fundamental matrix to filter points */
+ threshold);/* Threshold for good points in filter */
+
+ cvCopy(status,newPntStatus);
+ cvCopy(points2,newPoints);
+
+ CvMat projMatr;
+ double projMatr_dat[12];
+ projMatr = cvMat(3,4,CV_64F,projMatr_dat);
+
+ if( corrNum >= 6 )
+ {/* We can compute projection matrix */
+// icvComputeProjectMatrix(objPoints4D,points2,&projMatr);
+ icvComputeProjectMatrixStatus(objPoints4D,points2,status,&projMatr);
+ cvCopy(&projMatr,newProjMatr);
+
+ /* Create new points and find correspondence */
+ icvCreateFeaturePoints(newImage, newFPoints2D2,newFPointsStatus);
+
+ /* Good if we test new points before find corr points */
+
+ /* Find correspondence for new found points */
+ icvFindCorrForGivenPoints( newImage,/* Image 1 */
+ oldImage,/* Image 2 */
+ newFPoints2D2,
+ newFPointsStatus,//prev status
+ newFPoints2D1,
+ newFPointsStatusTmp,//new status
+ useFilter,/*Use fundamental matrix to filter points */
+ threshold);/* Threshold for good points in filter */
+
+ /* We generated new points on image test for exist points */
+
+ /* Remove all new double points */
+
+ int origNum;
+ /* Find point of old image */
+ origNum = icvRemoveDoublePoins( oldPoints,/* Points on prev image */
+ newFPoints2D1,/* New points */
+ oldPntStatus,/* Status for old points */
+ newFPointsStatusTmp,
+ newFPointsStatusTmp,//orig status
+ 20);/* Status for new points */
+
+ /* Find double points on new image */
+ origNum = icvRemoveDoublePoins( newPoints,/* Points on prev image */
+ newFPoints2D2,/* New points */
+ newPntStatus,/* Status for old points */
+ newFPointsStatusTmp,
+ newFPointsStatusTmp,//orig status
+ 20);/* Status for new points */
+
+
+
+ /* Add all new good points to result */
+
+
+ /* Copy new status to old */
+ cvCopy(newFPointsStatusTmp,newFPointsStatus);
+
+
+ }
+
+
+
+ __END__;
+
+ /* Free allocated memory */
+
+ return;
+}
+/*-------------------------------------------------------------------------------------*/
+//int icvDelete//
+//CreateGood
+
+/*-------------------------------------------------------------------------------------*/
+int icvDeleteSparsInPoints( int numImages,
+ CvMat **points,
+ CvMat **status,
+ CvMat *wasStatus)/* status of previous configuration */
+{
+ /* Delete points which no exist on any of images */
+ /* numImages - number of images */
+ /* points - arrays of points for each image. Changing */
+ /* status - arrays of status for each image. Changing */
+ /* Function returns number of common points */
+
+ int comNumber = 0;
+ CV_FUNCNAME( "icvDeleteSparsInPoints" );
+ __BEGIN__;
+
+ /* Test for errors */
+ if( numImages < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of images must be more than 0" );
+ }
+
+ if( points == 0 || status == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+ int numPoints;
+
+ numPoints = points[0]->cols;
+ ////////// TESTS //////////
+
+ int numCoord;
+ numCoord = points[0]->rows;// !!! may be number of coordinates is not correct !!!
+
+ int i;
+ int currExistPoint;
+ currExistPoint = 0;
+
+ if( wasStatus )
+ {
+ cvZero(wasStatus);
+ }
+
+ int currImage;
+ for( i = 0; i < numPoints; i++ )
+ {
+ int flag = 0;
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ flag |= status[currImage]->data.ptr[i];
+ }
+
+ if( flag )
+ {
+ /* Current point exists */
+ /* Copy points and status */
+ if( currExistPoint != i )/* Copy just if different */
+ {
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ /* Copy points */
+ for( int currCoord = 0; currCoord < numCoord; currCoord++ )
+ {
+ cvmSet(points[currImage],currCoord,currExistPoint, cvmGet(points[currImage],currCoord,i) );
+ }
+
+ /* Copy status */
+ status[currImage]->data.ptr[currExistPoint] = status[currImage]->data.ptr[i];
+ }
+ }
+ if( wasStatus )
+ {
+ wasStatus->data.ptr[i] = 1;
+ }
+
+ currExistPoint++;
+
+ }
+ }
+
+ /* Rest of final status of points must be set to 0 */
+ for( i = currExistPoint; i < numPoints; i++ )
+ {
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ status[currImage]->data.ptr[i] = 0;
+ }
+ }
+
+ comNumber = currExistPoint;
+
+ __END__;
+ return comNumber;
+}
+
+#if 0
+/*-------------------------------------------------------------------------------------*/
+void icvGrowPointsArray(CvMat **points)
+{
+
+
+}
+
+/*-------------------------------------------------------------------------------------*/
+void icvAddNewArrayPoints()
+{
+
+}
+
+/*-------------------------------------------------------------------------------------*/
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
+
+/* Add image to existing images and corr points */
+#if 0
+/* Returns: 1 if new image was added good */
+/* 0 image was not added. Not enought corr points */
+int AddImageToStruct( IplImage *newImage,//Image to add
+ IplImage *oldImage,//Previous image
+ CvMat *oldPoints,// previous 2D points on prev image (some points may be not visible)
+ CvMat *oldPntStatus,//Status for each point on prev image
+ CvMat *objPoints4D,//prev 4D points
+ CvMat *newPntStatus,// New point status for new image
+ CvMat *newPoints,//New corresponding points on new image
+ CvMat *newPoints2D1,//new points on prev image
+ CvMat *newPoints2D2,//new points on new image
+ CvMat *newProjMatr);//New projection matrix
+{
+
+ /* Add new image. Create new corr points */
+ /* Track exist points from oldImage to newImage */
+ /* Create new vector status */
+ CvMat *status;
+ int numPoints = oldPoints->cols;
+ status = cvCreateMat(1,numPoints,CV_64F);
+ /* Copy status */
+ cvConvert(pntStatus,status);
+
+ int corrNum = FindCorrForGivenPoints(oldImage,newImage,oldPoints,newPoints,status);
+
+ /* Status has new status of points */
+
+ CvMat projMatr;
+ double projMatr_dat[12];
+ projMatr = cvMat(3,4,CV_64F,projMatr_dat);
+
+ /* If number of corr points is 6 or more can compute projection matrix */
+ if( corrNum >= 6)
+ {
+ /* Compute projection matrix for new image using corresponding points */
+ icvComputeProjectMatrix(objPoints4D,newPoints,&projMatr);
+
+ CvMat *tmpPoints;
+ /* Create new points and find correspondence */
+ int num = FindFeaturePoints(newImage, &tmpPoints);
+ if( num > 0 )
+ {
+ CvMat *newPoints;
+ newPoints = cvCreateMat(2,num,CV_64F);
+ CvMat *status;
+ status = cvCreateMat(1,num,CV_64F);
+ /* Set status for all points */
+ int i;
+ for( i = 0; i < num; i++ )
+ {
+ cvmSet(status,0,i,1.0);
+ }
+
+ int corrNum2 = FindCorrForGivenPoints(oldImage,newImage,tmpPoints,newPoints,status);
+
+ /* !!! Filter points using projection matrices or not ??? */
+
+ /* !!! Need to filter nearest points */
+
+ /* Add new found points to exist points and optimize again */
+ CvMat *new2DPoints;
+ CvMat *newStatus;
+
+ /* add new status to old status */
+
+
+
+
+
+ }
+ else
+ {
+ /* No new points were found */
+ }
+ }
+ else
+ {
+ /* We can't compute projection matrix for new image */
+ return 0;
+ }
+
+}
+#endif
diff --git a/cvaux/src/cvcreatehandmask.cpp b/cvaux/src/cvcreatehandmask.cpp
new file mode 100644
index 0000000..45b953c
--- /dev/null
+++ b/cvaux/src/cvcreatehandmask.cpp
@@ -0,0 +1,138 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cvaux.h"
+
+#define CV_MAX2( a, b ) ((a)>(b) ? (a) : (b))
+#define CV_MIN2( a, b ) ((a)<(b) ? (a) : (b))
+
+/****************************************************************************************\
+
+ create hand mask
+
+\****************************************************************************************/
+
+static CvStatus icvCreateHandMask8uC1R(CvSeq * numbers,
+ uchar * image_mask, int step,
+ CvSize size, CvRect * roi )
+{
+
+ CvSeqReader reader;
+ CvPoint pt;
+ int k_point;
+ int i_min, i_max, j_min, j_max;
+
+ if( numbers == NULL )
+ return CV_NULLPTR_ERR;
+
+ if( !CV_IS_SEQ_POINT_SET( numbers ))
+ return CV_BADFLAG_ERR;
+
+ i_max = j_max = 0;
+ i_min = size.height;
+ j_min = size.width;
+
+ cvStartReadSeq( numbers, &reader, 0 );
+
+ k_point = numbers->total;
+ assert( k_point > 0 );
+ if( k_point <= 0 )
+ return CV_BADSIZE_ERR;
+
+ memset( image_mask, 0, step * size.height );
+
+ while( k_point-- > 0 )
+ {
+ CV_READ_SEQ_ELEM( pt, reader );
+
+ i_min = CV_MIN2( i_min, pt.y );
+ i_max = CV_MAX2( i_max, pt.y );
+ j_min = CV_MIN2( j_min, pt.x );
+ j_max = CV_MAX2( j_max, pt.x );
+
+ *(image_mask + pt.y * step + pt.x) = 255;
+ }
+
+ roi->x = j_min;
+ roi->y = i_min;
+ roi->width = j_max - j_min + 1;
+ roi->height = i_max - i_min + 1;
+
+ return CV_OK;
+
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvCreateHandMask
+// Purpose: creates hand mask image
+// Context:
+// Parameters:
+// numbers - pointer to the input sequence of the point's indexes inside
+// hand region
+// img_mask - pointer to the result mask image
+// roi - result hand mask ROI
+//
+// Notes:
+//F*/
+CV_IMPL void
+cvCreateHandMask( CvSeq * numbers, IplImage * img_mask, CvRect * roi )
+{
+ uchar *img_mask_data = 0;
+ int img_mask_step = 0;
+ CvSize img_mask_size;
+
+ CV_FUNCNAME( "cvCreateHandMask" );
+
+ __BEGIN__;
+
+ if( img_mask->depth != IPL_DEPTH_8U )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+
+ if( img_mask->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, "output image have wrong number of channels" );
+
+ cvGetImageRawData( img_mask, &img_mask_data, &img_mask_step, &img_mask_size );
+
+ IPPI_CALL( icvCreateHandMask8uC1R( numbers, img_mask_data,
+ img_mask_step, img_mask_size, roi ));
+
+ __END__;
+}
diff --git a/cvaux/src/cvdpstereo.cpp b/cvaux/src/cvdpstereo.cpp
new file mode 100644
index 0000000..3527809
--- /dev/null
+++ b/cvaux/src/cvdpstereo.cpp
@@ -0,0 +1,554 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+/****************************************************************************************\
+ The code below is some modification of Stan Birchfield's algorithm described in:
+
+ Depth Discontinuities by Pixel-to-Pixel Stereo
+ Stan Birchfield and Carlo Tomasi
+ International Journal of Computer Vision,
+ 35(3): 269-293, December 1999.
+
+ This implementation uses different cost function that results in
+ O(pixPerRow*maxDisparity) complexity of dynamic programming stage versus
+ O(pixPerRow*log(pixPerRow)*maxDisparity) in the above paper.
+\****************************************************************************************/
+
+/****************************************************************************************\
+* Find stereo correspondence by dynamic programming algorithm *
+\****************************************************************************************/
+#define ICV_DP_STEP_LEFT 0
+#define ICV_DP_STEP_UP 1
+#define ICV_DP_STEP_DIAG 2
+
+#define ICV_BIRCH_DIFF_LUM 5
+
+#define ICV_MAX_DP_SUM_VAL (INT_MAX/4)
+
+typedef struct _CvDPCell
+{
+ uchar step; //local-optimal step
+ int sum; //current sum
+}_CvDPCell;
+
+typedef struct _CvRightImData
+{
+ uchar min_val, max_val;
+} _CvRightImData;
+
+#define CV_IMAX3(a,b,c) ((temp3 = (a) >= (b) ? (a) : (b)),(temp3 >= (c) ? temp3 : (c)))
+#define CV_IMIN3(a,b,c) ((temp3 = (a) <= (b) ? (a) : (b)),(temp3 <= (c) ? temp3 : (c)))
+
+void icvFindStereoCorrespondenceByBirchfieldDP( uchar* src1, uchar* src2,
+ uchar* disparities,
+ CvSize size, int widthStep,
+ int maxDisparity,
+ float _param1, float _param2,
+ float _param3, float _param4,
+ float _param5 )
+{
+ int x, y, i, j, temp3;
+ int d, s;
+ int dispH = maxDisparity + 3;
+ uchar *dispdata;
+ int imgW = size.width;
+ int imgH = size.height;
+ uchar val, prevval, prev, curr;
+ int min_val;
+ uchar* dest = disparities;
+ int param1 = cvRound(_param1);
+ int param2 = cvRound(_param2);
+ int param3 = cvRound(_param3);
+ int param4 = cvRound(_param4);
+ int param5 = cvRound(_param5);
+
+ #define CELL(d,x) cells[(d)+(x)*dispH]
+
+ uchar* dsi = (uchar*)cvAlloc(sizeof(uchar)*imgW*dispH);
+ uchar* edges = (uchar*)cvAlloc(sizeof(uchar)*imgW*imgH);
+ _CvDPCell* cells = (_CvDPCell*)cvAlloc(sizeof(_CvDPCell)*imgW*MAX(dispH,(imgH+1)/2));
+ _CvRightImData* rData = (_CvRightImData*)cvAlloc(sizeof(_CvRightImData)*imgW);
+ int* reliabilities = (int*)cells;
+
+ for( y = 0; y < imgH; y++ )
+ {
+ uchar* srcdata1 = src1 + widthStep * y;
+ uchar* srcdata2 = src2 + widthStep * y;
+
+ //init rData
+ prevval = prev = srcdata2[0];
+ for( j = 1; j < imgW; j++ )
+ {
+ curr = srcdata2[j];
+ val = (uchar)((curr + prev)>>1);
+ rData[j-1].max_val = (uchar)CV_IMAX3( val, prevval, prev );
+ rData[j-1].min_val = (uchar)CV_IMIN3( val, prevval, prev );
+ prevval = val;
+ prev = curr;
+ }
+ rData[j-1] = rData[j-2];//last elem
+
+ // fill dissimularity space image
+ for( i = 1; i <= maxDisparity + 1; i++ )
+ {
+ dsi += imgW;
+ rData--;
+ for( j = i - 1; j < imgW - 1; j++ )
+ {
+ int t;
+ if( (t = srcdata1[j] - rData[j+1].max_val) >= 0 )
+ {
+ dsi[j] = (uchar)t;
+ }
+ else if( (t = rData[j+1].min_val - srcdata1[j]) >= 0 )
+ {
+ dsi[j] = (uchar)t;
+ }
+ else
+ {
+ dsi[j] = 0;
+ }
+ }
+ }
+ dsi -= (maxDisparity+1)*imgW;
+ rData += maxDisparity+1;
+
+ //intensity gradients image construction
+ //left row
+ edges[y*imgW] = edges[y*imgW+1] = edges[y*imgW+2] = 2;
+ edges[y*imgW+imgW-1] = edges[y*imgW+imgW-2] = edges[y*imgW+imgW-3] = 1;
+ for( j = 3; j < imgW-4; j++ )
+ {
+ edges[y*imgW+j] = 0;
+
+ if( ( CV_IMAX3( srcdata1[j-3], srcdata1[j-2], srcdata1[j-1] ) -
+ CV_IMIN3( srcdata1[j-3], srcdata1[j-2], srcdata1[j-1] ) ) >= ICV_BIRCH_DIFF_LUM )
+ {
+ edges[y*imgW+j] |= 1;
+ }
+ if( ( CV_IMAX3( srcdata2[j+3], srcdata2[j+2], srcdata2[j+1] ) -
+ CV_IMIN3( srcdata2[j+3], srcdata2[j+2], srcdata2[j+1] ) ) >= ICV_BIRCH_DIFF_LUM )
+ {
+ edges[y*imgW+j] |= 2;
+ }
+ }
+
+ //find correspondence using dynamical programming
+ //init DP table
+ for( x = 0; x < imgW; x++ )
+ {
+ CELL(0,x).sum = CELL(dispH-1,x).sum = ICV_MAX_DP_SUM_VAL;
+ CELL(0,x).step = CELL(dispH-1,x).step = ICV_DP_STEP_LEFT;
+ }
+ for( d = 2; d < dispH; d++ )
+ {
+ CELL(d,d-2).sum = ICV_MAX_DP_SUM_VAL;
+ CELL(d,d-2).step = ICV_DP_STEP_UP;
+ }
+ CELL(1,0).sum = 0;
+ CELL(1,0).step = ICV_DP_STEP_LEFT;
+
+ for( x = 1; x < imgW; x++ )
+ {
+ int d = MIN( x + 1, maxDisparity + 1);
+ uchar* _edges = edges + y*imgW + x;
+ int e0 = _edges[0] & 1;
+ _CvDPCell* _cell = cells + x*dispH;
+
+ do
+ {
+ int s = dsi[d*imgW+x];
+ int sum[3];
+
+ //check left step
+ sum[0] = _cell[d-dispH].sum - param2;
+
+ //check up step
+ if( _cell[d+1].step != ICV_DP_STEP_DIAG && e0 )
+ {
+ sum[1] = _cell[d+1].sum + param1;
+
+ if( _cell[d-1-dispH].step != ICV_DP_STEP_UP && (_edges[1-d] & 2) )
+ {
+ int t;
+
+ sum[2] = _cell[d-1-dispH].sum + param1;
+
+ t = sum[1] < sum[0];
+
+ //choose local-optimal pass
+ if( sum[t] <= sum[2] )
+ {
+ _cell[d].step = (uchar)t;
+ _cell[d].sum = sum[t] + s;
+ }
+ else
+ {
+ _cell[d].step = ICV_DP_STEP_DIAG;
+ _cell[d].sum = sum[2] + s;
+ }
+ }
+ else
+ {
+ if( sum[0] <= sum[1] )
+ {
+ _cell[d].step = ICV_DP_STEP_LEFT;
+ _cell[d].sum = sum[0] + s;
+ }
+ else
+ {
+ _cell[d].step = ICV_DP_STEP_UP;
+ _cell[d].sum = sum[1] + s;
+ }
+ }
+ }
+ else if( _cell[d-1-dispH].step != ICV_DP_STEP_UP && (_edges[1-d] & 2) )
+ {
+ sum[2] = _cell[d-1-dispH].sum + param1;
+ if( sum[0] <= sum[2] )
+ {
+ _cell[d].step = ICV_DP_STEP_LEFT;
+ _cell[d].sum = sum[0] + s;
+ }
+ else
+ {
+ _cell[d].step = ICV_DP_STEP_DIAG;
+ _cell[d].sum = sum[2] + s;
+ }
+ }
+ else
+ {
+ _cell[d].step = ICV_DP_STEP_LEFT;
+ _cell[d].sum = sum[0] + s;
+ }
+ }
+ while( --d );
+ }// for x
+
+ //extract optimal way and fill disparity image
+ dispdata = dest + widthStep * y;
+
+ //find min_val
+ min_val = ICV_MAX_DP_SUM_VAL;
+ for( i = 1; i <= maxDisparity + 1; i++ )
+ {
+ if( min_val > CELL(i,imgW-1).sum )
+ {
+ d = i;
+ min_val = CELL(i,imgW-1).sum;
+ }
+ }
+
+ //track optimal pass
+ for( x = imgW - 1; x > 0; x-- )
+ {
+ dispdata[x] = (uchar)(d - 1);
+ while( CELL(d,x).step == ICV_DP_STEP_UP ) d++;
+ if ( CELL(d,x).step == ICV_DP_STEP_DIAG )
+ {
+ s = x;
+ while( CELL(d,x).step == ICV_DP_STEP_DIAG )
+ {
+ d--;
+ x--;
+ }
+ for( i = x; i < s; i++ )
+ {
+ dispdata[i] = (uchar)(d-1);
+ }
+ }
+ }//for x
+ }// for y
+
+ //Postprocessing the Disparity Map
+
+ //remove obvious errors in the disparity map
+ for( x = 0; x < imgW; x++ )
+ {
+ for( y = 1; y < imgH - 1; y++ )
+ {
+ if( dest[(y-1)*widthStep+x] == dest[(y+1)*widthStep+x] )
+ {
+ dest[y*widthStep+x] = dest[(y-1)*widthStep+x];
+ }
+ }
+ }
+
+ //compute intensity Y-gradients
+ for( x = 0; x < imgW; x++ )
+ {
+ for( y = 1; y < imgH - 1; y++ )
+ {
+ if( ( CV_IMAX3( src1[(y-1)*widthStep+x], src1[y*widthStep+x],
+ src1[(y+1)*widthStep+x] ) -
+ CV_IMIN3( src1[(y-1)*widthStep+x], src1[y*widthStep+x],
+ src1[(y+1)*widthStep+x] ) ) >= ICV_BIRCH_DIFF_LUM )
+ {
+ edges[y*imgW+x] |= 4;
+ edges[(y+1)*imgW+x] |= 4;
+ edges[(y-1)*imgW+x] |= 4;
+ y++;
+ }
+ }
+ }
+
+ //remove along any particular row, every gradient
+ //for which two adjacent columns do not agree.
+ for( y = 0; y < imgH; y++ )
+ {
+ prev = edges[y*imgW];
+ for( x = 1; x < imgW - 1; x++ )
+ {
+ curr = edges[y*imgW+x];
+ if( (curr & 4) &&
+ ( !( prev & 4 ) ||
+ !( edges[y*imgW+x+1] & 4 ) ) )
+ {
+ edges[y*imgW+x] -= 4;
+ }
+ prev = curr;
+ }
+ }
+
+ // define reliability
+ for( x = 0; x < imgW; x++ )
+ {
+ for( y = 1; y < imgH; y++ )
+ {
+ i = y - 1;
+ for( ; y < imgH && dest[y*widthStep+x] == dest[(y-1)*widthStep+x]; y++ )
+ ;
+ s = y - i;
+ for( ; i < y; i++ )
+ {
+ reliabilities[i*imgW+x] = s;
+ }
+ }
+ }
+
+ //Y - propagate reliable regions
+ for( x = 0; x < imgW; x++ )
+ {
+ for( y = 0; y < imgH; y++ )
+ {
+ d = dest[y*widthStep+x];
+ if( reliabilities[y*imgW+x] >= param4 && !(edges[y*imgW+x] & 4) &&
+ d > 0 )//highly || moderately
+ {
+ disparities[y*widthStep+x] = (uchar)d;
+ //up propagation
+ for( i = y - 1; i >= 0; i-- )
+ {
+ if( ( edges[i*imgW+x] & 4 ) ||
+ ( dest[i*widthStep+x] < d &&
+ reliabilities[i*imgW+x] >= param3 ) ||
+ ( reliabilities[y*imgW+x] < param5 &&
+ dest[i*widthStep+x] - 1 == d ) ) break;
+
+ disparities[i*widthStep+x] = (uchar)d;
+ }
+
+ //down propagation
+ for( i = y + 1; i < imgH; i++ )
+ {
+ if( ( edges[i*imgW+x] & 4 ) ||
+ ( dest[i*widthStep+x] < d &&
+ reliabilities[i*imgW+x] >= param3 ) ||
+ ( reliabilities[y*imgW+x] < param5 &&
+ dest[i*widthStep+x] - 1 == d ) ) break;
+
+ disparities[i*widthStep+x] = (uchar)d;
+ }
+ y = i - 1;
+ }
+ else
+ {
+ disparities[y*widthStep+x] = (uchar)d;
+ }
+ }
+ }
+
+ // define reliability along X
+ for( y = 0; y < imgH; y++ )
+ {
+ for( x = 1; x < imgW; x++ )
+ {
+ i = x - 1;
+ for( ; x < imgW && dest[y*widthStep+x] == dest[y*widthStep+x-1]; x++ );
+ s = x - i;
+ for( ; i < x; i++ )
+ {
+ reliabilities[y*imgW+i] = s;
+ }
+ }
+ }
+
+ //X - propagate reliable regions
+ for( y = 0; y < imgH; y++ )
+ {
+ for( x = 0; x < imgW; x++ )
+ {
+ d = dest[y*widthStep+x];
+ if( reliabilities[y*imgW+x] >= param4 && !(edges[y*imgW+x] & 1) &&
+ d > 0 )//highly || moderately
+ {
+ disparities[y*widthStep+x] = (uchar)d;
+ //up propagation
+ for( i = x - 1; i >= 0; i-- )
+ {
+ if( (edges[y*imgW+i] & 1) ||
+ ( dest[y*widthStep+i] < d &&
+ reliabilities[y*imgW+i] >= param3 ) ||
+ ( reliabilities[y*imgW+x] < param5 &&
+ dest[y*widthStep+i] - 1 == d ) ) break;
+
+ disparities[y*widthStep+i] = (uchar)d;
+ }
+
+ //down propagation
+ for( i = x + 1; i < imgW; i++ )
+ {
+ if( (edges[y*imgW+i] & 1) ||
+ ( dest[y*widthStep+i] < d &&
+ reliabilities[y*imgW+i] >= param3 ) ||
+ ( reliabilities[y*imgW+x] < param5 &&
+ dest[y*widthStep+i] - 1 == d ) ) break;
+
+ disparities[y*widthStep+i] = (uchar)d;
+ }
+ x = i - 1;
+ }
+ else
+ {
+ disparities[y*widthStep+x] = (uchar)d;
+ }
+ }
+ }
+
+ //release resources
+ cvFree( &dsi );
+ cvFree( &edges );
+ cvFree( &cells );
+ cvFree( &rData );
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////
+//
+// Name: cvFindStereoCorrespondence
+// Purpose: find stereo correspondence on stereo-pair
+// Context:
+// Parameters:
+// leftImage - left image of stereo-pair (format 8uC1).
+// rightImage - right image of stereo-pair (format 8uC1).
+// mode -mode of correspondance retrieval (now CV_RETR_DP_BIRCHFIELD only)
+// dispImage - destination disparity image
+// maxDisparity - maximal disparity
+// param1, param2, param3, param4, param5 - parameters of algorithm
+// Returns:
+// Notes:
+// Images must be rectified.
+// All images must have format 8uC1.
+//F*/
+CV_IMPL void
+cvFindStereoCorrespondence(
+ const CvArr* leftImage, const CvArr* rightImage,
+ int mode,
+ CvArr* depthImage,
+ int maxDisparity,
+ double param1, double param2, double param3,
+ double param4, double param5 )
+{
+ CV_FUNCNAME( "cvFindStereoCorrespondence" );
+
+ __BEGIN__;
+
+ CvMat *src1, *src2;
+ CvMat *dst;
+ CvMat src1_stub, src2_stub, dst_stub;
+ int coi;
+
+ CV_CALL( src1 = cvGetMat( leftImage, &src1_stub, &coi ));
+ if( coi ) CV_ERROR( CV_BadCOI, "COI is not supported by the function" );
+ CV_CALL( src2 = cvGetMat( rightImage, &src2_stub, &coi ));
+ if( coi ) CV_ERROR( CV_BadCOI, "COI is not supported by the function" );
+ CV_CALL( dst = cvGetMat( depthImage, &dst_stub, &coi ));
+ if( coi ) CV_ERROR( CV_BadCOI, "COI is not supported by the function" );
+
+ // check args
+ if( CV_MAT_TYPE( src1->type ) != CV_8UC1 ||
+ CV_MAT_TYPE( src2->type ) != CV_8UC1 ||
+ CV_MAT_TYPE( dst->type ) != CV_8UC1) CV_ERROR(CV_StsUnsupportedFormat,
+ "All images must be single-channel and have 8u" );
+
+ if( !CV_ARE_SIZES_EQ( src1, src2 ) || !CV_ARE_SIZES_EQ( src1, dst ) )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( maxDisparity <= 0 || maxDisparity >= src1->width || maxDisparity > 255 )
+ CV_ERROR(CV_StsOutOfRange,
+ "parameter /maxDisparity/ is out of range");
+
+ if( mode == CV_DISPARITY_BIRCHFIELD )
+ {
+ if( param1 == CV_UNDEF_SC_PARAM ) param1 = CV_IDP_BIRCHFIELD_PARAM1;
+ if( param2 == CV_UNDEF_SC_PARAM ) param2 = CV_IDP_BIRCHFIELD_PARAM2;
+ if( param3 == CV_UNDEF_SC_PARAM ) param3 = CV_IDP_BIRCHFIELD_PARAM3;
+ if( param4 == CV_UNDEF_SC_PARAM ) param4 = CV_IDP_BIRCHFIELD_PARAM4;
+ if( param5 == CV_UNDEF_SC_PARAM ) param5 = CV_IDP_BIRCHFIELD_PARAM5;
+
+ CV_CALL( icvFindStereoCorrespondenceByBirchfieldDP( src1->data.ptr,
+ src2->data.ptr, dst->data.ptr,
+ cvGetMatSize( src1 ), src1->step,
+ maxDisparity, (float)param1, (float)param2, (float)param3,
+ (float)param4, (float)param5 ) );
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg, "Unsupported mode of function" );
+ }
+
+ __END__;
+}
+
+/* End of file. */
+
diff --git a/cvaux/src/cveigenobjects.cpp b/cvaux/src/cveigenobjects.cpp
new file mode 100644
index 0000000..041aa98
--- /dev/null
+++ b/cvaux/src/cveigenobjects.cpp
@@ -0,0 +1,1811 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+CvStatus CV_STDCALL
+icvJacobiEigens_32f(float *A, float *V, float *E, int n, float eps)
+{
+ int i, j, k, ind;
+ float *AA = A, *VV = V;
+ double Amax, anorm = 0, ax;
+
+ if( A == NULL || V == NULL || E == NULL )
+ return CV_NULLPTR_ERR;
+ if( n <= 0 )
+ return CV_BADSIZE_ERR;
+ if( eps < 1.0e-7f )
+ eps = 1.0e-7f;
+
+ /*-------- Prepare --------*/
+ for( i = 0; i < n; i++, VV += n, AA += n )
+ {
+ for( j = 0; j < i; j++ )
+ {
+ double Am = AA[j];
+
+ anorm += Am * Am;
+ }
+ for( j = 0; j < n; j++ )
+ VV[j] = 0.f;
+ VV[i] = 1.f;
+ }
+
+ anorm = sqrt( anorm + anorm );
+ ax = anorm * eps / n;
+ Amax = anorm;
+
+ while( Amax > ax )
+ {
+ Amax /= n;
+ do /* while (ind) */
+ {
+ int p, q;
+ float *V1 = V, *A1 = A;
+
+ ind = 0;
+ for( p = 0; p < n - 1; p++, A1 += n, V1 += n )
+ {
+ float *A2 = A + n * (p + 1), *V2 = V + n * (p + 1);
+
+ for( q = p + 1; q < n; q++, A2 += n, V2 += n )
+ {
+ double x, y, c, s, c2, s2, a;
+ float *A3, Apq = A1[q], App, Aqq, Aip, Aiq, Vpi, Vqi;
+
+ if( fabs( Apq ) < Amax )
+ continue;
+
+ ind = 1;
+
+ /*---- Calculation of rotation angle's sine & cosine ----*/
+ App = A1[p];
+ Aqq = A2[q];
+ y = 5.0e-1 * (App - Aqq);
+ x = -Apq / sqrt( (double)Apq * Apq + (double)y * y );
+ if( y < 0.0 )
+ x = -x;
+ s = x / sqrt( 2.0 * (1.0 + sqrt( 1.0 - (double)x * x )));
+ s2 = s * s;
+ c = sqrt( 1.0 - s2 );
+ c2 = c * c;
+ a = 2.0 * Apq * c * s;
+
+ /*---- Apq annulation ----*/
+ A3 = A;
+ for( i = 0; i < p; i++, A3 += n )
+ {
+ Aip = A3[p];
+ Aiq = A3[q];
+ Vpi = V1[i];
+ Vqi = V2[i];
+ A3[p] = (float) (Aip * c - Aiq * s);
+ A3[q] = (float) (Aiq * c + Aip * s);
+ V1[i] = (float) (Vpi * c - Vqi * s);
+ V2[i] = (float) (Vqi * c + Vpi * s);
+ }
+ for( ; i < q; i++, A3 += n )
+ {
+ Aip = A1[i];
+ Aiq = A3[q];
+ Vpi = V1[i];
+ Vqi = V2[i];
+ A1[i] = (float) (Aip * c - Aiq * s);
+ A3[q] = (float) (Aiq * c + Aip * s);
+ V1[i] = (float) (Vpi * c - Vqi * s);
+ V2[i] = (float) (Vqi * c + Vpi * s);
+ }
+ for( ; i < n; i++ )
+ {
+ Aip = A1[i];
+ Aiq = A2[i];
+ Vpi = V1[i];
+ Vqi = V2[i];
+ A1[i] = (float) (Aip * c - Aiq * s);
+ A2[i] = (float) (Aiq * c + Aip * s);
+ V1[i] = (float) (Vpi * c - Vqi * s);
+ V2[i] = (float) (Vqi * c + Vpi * s);
+ }
+ A1[p] = (float) (App * c2 + Aqq * s2 - a);
+ A2[q] = (float) (App * s2 + Aqq * c2 + a);
+ A1[q] = A2[p] = 0.0f;
+ } /*q */
+ } /*p */
+ }
+ while( ind );
+ Amax /= n;
+ } /* while ( Amax > ax ) */
+
+ for( i = 0, k = 0; i < n; i++, k += n + 1 )
+ E[i] = A[k];
+ /*printf(" M = %d\n", M); */
+
+ /* -------- ordering -------- */
+ for( i = 0; i < n; i++ )
+ {
+ int m = i;
+ float Em = (float) fabs( E[i] );
+
+ for( j = i + 1; j < n; j++ )
+ {
+ float Ej = (float) fabs( E[j] );
+
+ m = (Em < Ej) ? j : m;
+ Em = (Em < Ej) ? Ej : Em;
+ }
+ if( m != i )
+ {
+ int l;
+ float b = E[i];
+
+ E[i] = E[m];
+ E[m] = b;
+ for( j = 0, k = i * n, l = m * n; j < n; j++, k++, l++ )
+ {
+ b = V[k];
+ V[k] = V[l];
+ V[l] = b;
+ }
+ }
+ }
+
+ return CV_NO_ERR;
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvCalcCovarMatrixEx_8u32fR
+// Purpose: The function calculates a covariance matrix for a group of input objects
+// (images, vectors, etc.). ROI supported.
+// Context:
+// Parameters: nObjects - number of source objects
+// objects - array of pointers to ROIs of the source objects
+// imgStep - full width of each source object row in bytes
+// avg - pointer to averaged object
+// avgStep - full width of averaged object row in bytes
+// size - ROI size of each source and averaged objects
+// covarMatrix - covariance matrix (output parameter; must be allocated
+// before call)
+//
+// Returns: CV_NO_ERR or error code
+//
+// Notes:
+//F*/
+static CvStatus CV_STDCALL
+icvCalcCovarMatrixEx_8u32fR( int nObjects, void *input, int objStep1,
+ int ioFlags, int ioBufSize, uchar* buffer,
+ void *userData, float *avg, int avgStep,
+ CvSize size, float *covarMatrix )
+{
+ int objStep = objStep1;
+
+ /* ---- TEST OF PARAMETERS ---- */
+
+ if( nObjects < 2 )
+ return CV_BADFACTOR_ERR;
+ if( ioFlags < 0 || ioFlags > 3 )
+ return CV_BADFACTOR_ERR;
+ if( ioFlags && ioBufSize < 1024 )
+ return CV_BADFACTOR_ERR;
+ if( ioFlags && buffer == NULL )
+ return CV_NULLPTR_ERR;
+ if( input == NULL || avg == NULL || covarMatrix == NULL )
+ return CV_NULLPTR_ERR;
+ if( size.width > objStep || 4 * size.width > avgStep || size.height < 1 )
+ return CV_BADSIZE_ERR;
+
+ avgStep /= 4;
+
+ if( ioFlags & CV_EIGOBJ_INPUT_CALLBACK ) /* ==== USE INPUT CALLBACK ==== */
+ {
+ int nio, ngr, igr, n = size.width * size.height, mm = 0;
+ CvCallback read_callback = ((CvInput *) & input)->callback;
+ uchar *buffer2;
+
+ objStep = n;
+ nio = ioBufSize / n; /* number of objects in buffer */
+ ngr = nObjects / nio; /* number of io groups */
+ if( nObjects % nio )
+ mm = 1;
+ ngr += mm;
+
+ buffer2 = (uchar *)cvAlloc( sizeof( uchar ) * n );
+ if( buffer2 == NULL )
+ return CV_OUTOFMEM_ERR;
+
+ for( igr = 0; igr < ngr; igr++ )
+ {
+ int k, l;
+ int io, jo, imin = igr * nio, imax = imin + nio;
+ uchar *bu1 = buffer, *bu2;
+
+ if( imax > nObjects )
+ imax = nObjects;
+
+ /* read igr group */
+ for( io = imin; io < imax; io++, bu1 += n )
+ {
+ CvStatus r;
+
+ r = (CvStatus)read_callback( io, (void *) bu1, userData );
+ if( r )
+ return r;
+ }
+
+ /* diagonal square calc */
+ bu1 = buffer;
+ for( io = imin; io < imax; io++, bu1 += n )
+ {
+ bu2 = bu1;
+ for( jo = io; jo < imax; jo++, bu2 += n )
+ {
+ float w = 0.f;
+ float *fu = avg;
+ int ij = 0;
+
+ for( k = 0; k < size.height; k++, fu += avgStep )
+ for( l = 0; l < size.width; l++, ij++ )
+ {
+ float f = fu[l], u1 = bu1[ij], u2 = bu2[ij];
+
+ w += (u1 - f) * (u2 - f);
+ }
+ covarMatrix[io * nObjects + jo] = covarMatrix[jo * nObjects + io] = w;
+ }
+ }
+
+ /* non-diagonal elements calc */
+ for( jo = imax; jo < nObjects; jo++ )
+ {
+ CvStatus r;
+
+ bu1 = buffer;
+ bu2 = buffer2;
+
+ /* read jo object */
+ r = (CvStatus)read_callback( jo, (void *) bu2, userData );
+ if( r )
+ return r;
+
+ for( io = imin; io < imax; io++, bu1 += n )
+ {
+ float w = 0.f;
+ float *fu = avg;
+ int ij = 0;
+
+ for( k = 0; k < size.height; k++, fu += avgStep )
+ {
+ for( l = 0; l < size.width - 3; l += 4, ij += 4 )
+ {
+ float f = fu[l];
+ uchar u1 = bu1[ij];
+ uchar u2 = bu2[ij];
+
+ w += (u1 - f) * (u2 - f);
+ f = fu[l + 1];
+ u1 = bu1[ij + 1];
+ u2 = bu2[ij + 1];
+ w += (u1 - f) * (u2 - f);
+ f = fu[l + 2];
+ u1 = bu1[ij + 2];
+ u2 = bu2[ij + 2];
+ w += (u1 - f) * (u2 - f);
+ f = fu[l + 3];
+ u1 = bu1[ij + 3];
+ u2 = bu2[ij + 3];
+ w += (u1 - f) * (u2 - f);
+ }
+ for( ; l < size.width; l++, ij++ )
+ {
+ float f = fu[l], u1 = bu1[ij], u2 = bu2[ij];
+
+ w += (u1 - f) * (u2 - f);
+ }
+ }
+ covarMatrix[io * nObjects + jo] = covarMatrix[jo * nObjects + io] = w;
+ }
+ }
+ } /* igr */
+
+ cvFree( &buffer2 );
+ } /* if() */
+
+ else
+ /* ==== NOT USE INPUT CALLBACK ==== */
+ {
+ int i, j;
+ uchar **objects = (uchar **) (((CvInput *) & input)->data);
+
+ for( i = 0; i < nObjects; i++ )
+ {
+ uchar *bu = objects[i];
+
+ for( j = i; j < nObjects; j++ )
+ {
+ int k, l;
+ float w = 0.f;
+ float *a = avg;
+ uchar *bu1 = bu;
+ uchar *bu2 = objects[j];
+
+ for( k = 0; k < size.height;
+ k++, bu1 += objStep, bu2 += objStep, a += avgStep )
+ {
+ for( l = 0; l < size.width - 3; l += 4 )
+ {
+ float f = a[l];
+ uchar u1 = bu1[l];
+ uchar u2 = bu2[l];
+
+ w += (u1 - f) * (u2 - f);
+ f = a[l + 1];
+ u1 = bu1[l + 1];
+ u2 = bu2[l + 1];
+ w += (u1 - f) * (u2 - f);
+ f = a[l + 2];
+ u1 = bu1[l + 2];
+ u2 = bu2[l + 2];
+ w += (u1 - f) * (u2 - f);
+ f = a[l + 3];
+ u1 = bu1[l + 3];
+ u2 = bu2[l + 3];
+ w += (u1 - f) * (u2 - f);
+ }
+ for( ; l < size.width; l++ )
+ {
+ float f = a[l];
+ uchar u1 = bu1[l];
+ uchar u2 = bu2[l];
+
+ w += (u1 - f) * (u2 - f);
+ }
+ }
+
+ covarMatrix[i * nObjects + j] = covarMatrix[j * nObjects + i] = w;
+ }
+ }
+ } /* else */
+
+ return CV_NO_ERR;
+}
+
+/*======================== end of icvCalcCovarMatrixEx_8u32fR ===========================*/
+
+
+static int
+icvDefaultBufferSize( void )
+{
+ return 10 * 1024 * 1024;
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvCalcEigenObjects_8u32fR
+// Purpose: The function calculates an orthonormal eigen basis and a mean (averaged)
+// object for a group of input objects (images, vectors, etc.). ROI supported.
+// Context:
+// Parameters: nObjects - number of source objects
+// input - pointer either to array of pointers to input objects
+// or to read callback function (depending on ioFlags)
+// imgStep - full width of each source object row in bytes
+// output - pointer either to array of pointers to output eigen objects
+// or to write callback function (depending on ioFlags)
+// eigStep - full width of each eigenobject row in bytes
+// size - ROI size of each source object
+// ioFlags - input/output flags (see Notes)
+// ioBufSize - input/output buffer size
+// userData - pointer to the structure which contains all necessary
+// data for the callback functions
+// calcLimit - determines the calculation finish conditions
+// avg - pointer to averaged object (has the same size as ROI)
+// avgStep - full width of averaged object row in bytes
+// eigVals - pointer to corresponding eigenvalues (array of <nObjects>
+// elements in descending order)
+//
+// Returns: CV_NO_ERR or error code
+//
+// Notes: 1. input/output data (that is, input objects and eigen ones) may either
+// be allocated in the RAM or be read from/written to the HDD (or any
+// other device) by read/write callback functions. It depends on the
+// value of ioFlags paramater, which may be the following:
+// CV_EIGOBJ_NO_CALLBACK, or 0;
+// CV_EIGOBJ_INPUT_CALLBACK;
+// CV_EIGOBJ_OUTPUT_CALLBACK;
+// CV_EIGOBJ_BOTH_CALLBACK, or
+// CV_EIGOBJ_INPUT_CALLBACK | CV_EIGOBJ_OUTPUT_CALLBACK.
+// The callback functions as well as the user data structure must be
+// developed by the user.
+//
+// 2. If ioBufSize = 0, or it's too large, the function dermines buffer size
+// itself.
+//
+// 3. Depending on calcLimit parameter, calculations are finished either if
+// eigenfaces number comes up to certain value or the relation of the
+// current eigenvalue and the largest one comes down to certain value
+// (or any of the above conditions takes place). The calcLimit->type value
+// must be CV_TERMCRIT_NUMB, CV_TERMCRIT_EPS or
+// CV_TERMCRIT_NUMB | CV_TERMCRIT_EPS. The function returns the real
+// values calcLimit->max_iter and calcLimit->epsilon.
+//
+// 4. eigVals may be equal to NULL (if you don't need eigen values in further).
+//
+//F*/
+static CvStatus CV_STDCALL
+icvCalcEigenObjects_8u32fR( int nObjects, void* input, int objStep,
+ void* output, int eigStep, CvSize size,
+ int ioFlags, int ioBufSize, void* userData,
+ CvTermCriteria* calcLimit, float* avg,
+ int avgStep, float *eigVals )
+{
+ int i, j, n, iev = 0, m1 = nObjects - 1, objStep1 = objStep, eigStep1 = eigStep / 4;
+ CvSize objSize, eigSize, avgSize;
+ float *c = 0;
+ float *ev = 0;
+ float *bf = 0;
+ uchar *buf = 0;
+ void *buffer = 0;
+ float m = 1.0f / (float) nObjects;
+ CvStatus r;
+
+ if( m1 > calcLimit->max_iter && calcLimit->type != CV_TERMCRIT_EPS )
+ m1 = calcLimit->max_iter;
+
+ /* ---- TEST OF PARAMETERS ---- */
+
+ if( nObjects < 2 )
+ return CV_BADFACTOR_ERR;
+ if( ioFlags < 0 || ioFlags > 3 )
+ return CV_BADFACTOR_ERR;
+ if( input == NULL || output == NULL || avg == NULL )
+ return CV_NULLPTR_ERR;
+ if( size.width > objStep || 4 * size.width > eigStep ||
+ 4 * size.width > avgStep || size.height < 1 )
+ return CV_BADSIZE_ERR;
+ if( !(ioFlags & CV_EIGOBJ_INPUT_CALLBACK) )
+ for( i = 0; i < nObjects; i++ )
+ if( ((uchar **) input)[i] == NULL )
+ return CV_NULLPTR_ERR;
+ if( !(ioFlags & CV_EIGOBJ_OUTPUT_CALLBACK) )
+ for( i = 0; i < m1; i++ )
+ if( ((float **) output)[i] == NULL )
+ return CV_NULLPTR_ERR;
+
+ avgStep /= 4;
+ eigStep /= 4;
+
+ if( objStep == size.width && eigStep == size.width && avgStep == size.width )
+ {
+ size.width *= size.height;
+ size.height = 1;
+ objStep = objStep1 = eigStep = eigStep1 = avgStep = size.width;
+ }
+ objSize = eigSize = avgSize = size;
+
+ if( ioFlags & CV_EIGOBJ_INPUT_CALLBACK )
+ {
+ objSize.width *= objSize.height;
+ objSize.height = 1;
+ objStep = objSize.width;
+ objStep1 = size.width;
+ }
+
+ if( ioFlags & CV_EIGOBJ_OUTPUT_CALLBACK )
+ {
+ eigSize.width *= eigSize.height;
+ eigSize.height = 1;
+ eigStep = eigSize.width;
+ eigStep1 = size.width;
+ }
+
+ n = objSize.height * objSize.width * (ioFlags & CV_EIGOBJ_INPUT_CALLBACK) +
+ 2 * eigSize.height * eigSize.width * (ioFlags & CV_EIGOBJ_OUTPUT_CALLBACK);
+
+ /* Buffer size determination */
+ if( ioFlags )
+ {
+ int size = icvDefaultBufferSize();
+ ioBufSize = MIN( size, n );
+ }
+
+ /* memory allocation (if necesseay) */
+
+ if( ioFlags & CV_EIGOBJ_INPUT_CALLBACK )
+ {
+ buf = (uchar *) cvAlloc( sizeof( uchar ) * objSize.width );
+ if( buf == NULL )
+ return CV_OUTOFMEM_ERR;
+ }
+
+ if( ioFlags )
+ {
+ buffer = (void *) cvAlloc( ioBufSize );
+ if( buffer == NULL )
+ {
+ if( buf )
+ cvFree( &buf );
+ return CV_OUTOFMEM_ERR;
+ }
+ }
+
+ /* Calculation of averaged object */
+ bf = avg;
+ for( i = 0; i < avgSize.height; i++, bf += avgStep )
+ for( j = 0; j < avgSize.width; j++ )
+ bf[j] = 0.f;
+
+ for( i = 0; i < nObjects; i++ )
+ {
+ int k, l;
+ uchar *bu = (ioFlags & CV_EIGOBJ_INPUT_CALLBACK) ? buf : ((uchar **) input)[i];
+
+ if( ioFlags & CV_EIGOBJ_INPUT_CALLBACK )
+ {
+ CvCallback read_callback = ((CvInput *) & input)->callback;
+
+ r = (CvStatus)read_callback( i, (void *) buf, userData );
+ if( r )
+ {
+ if( buffer )
+ cvFree( &buffer );
+ if( buf )
+ cvFree( &buf );
+ return r;
+ }
+ }
+
+ bf = avg;
+ for( k = 0; k < avgSize.height; k++, bf += avgStep, bu += objStep1 )
+ for( l = 0; l < avgSize.width; l++ )
+ bf[l] += bu[l];
+ }
+
+ bf = avg;
+ for( i = 0; i < avgSize.height; i++, bf += avgStep )
+ for( j = 0; j < avgSize.width; j++ )
+ bf[j] *= m;
+
+ /* Calculation of covariance matrix */
+ c = (float *) cvAlloc( sizeof( float ) * nObjects * nObjects );
+
+ if( c == NULL )
+ {
+ if( buffer )
+ cvFree( &buffer );
+ if( buf )
+ cvFree( &buf );
+ return CV_OUTOFMEM_ERR;
+ }
+
+ r = icvCalcCovarMatrixEx_8u32fR( nObjects, input, objStep1, ioFlags, ioBufSize,
+ (uchar *) buffer, userData, avg, 4 * avgStep, size, c );
+ if( r )
+ {
+ cvFree( &c );
+ if( buffer )
+ cvFree( &buffer );
+ if( buf )
+ cvFree( &buf );
+ return r;
+ }
+
+ /* Calculation of eigenvalues & eigenvectors */
+ ev = (float *) cvAlloc( sizeof( float ) * nObjects * nObjects );
+
+ if( ev == NULL )
+ {
+ cvFree( &c );
+ if( buffer )
+ cvFree( &buffer );
+ if( buf )
+ cvFree( &buf );
+ return CV_OUTOFMEM_ERR;
+ }
+
+ if( eigVals == NULL )
+ {
+ eigVals = (float *) cvAlloc( sizeof( float ) * nObjects );
+
+ if( eigVals == NULL )
+ {
+ cvFree( &c );
+ cvFree( &ev );
+ if( buffer )
+ cvFree( &buffer );
+ if( buf )
+ cvFree( &buf );
+ return CV_OUTOFMEM_ERR;
+ }
+ iev = 1;
+ }
+
+ r = icvJacobiEigens_32f( c, ev, eigVals, nObjects, 0.0f );
+ cvFree( &c );
+ if( r )
+ {
+ cvFree( &ev );
+ if( buffer )
+ cvFree( &buffer );
+ if( buf )
+ cvFree( &buf );
+ if( iev )
+ cvFree( &eigVals );
+ return r;
+ }
+
+ /* Eigen objects number determination */
+ if( calcLimit->type != CV_TERMCRIT_NUMBER )
+ {
+ for( i = 0; i < m1; i++ )
+ if( fabs( eigVals[i] / eigVals[0] ) < calcLimit->epsilon )
+ break;
+ m1 = calcLimit->max_iter = i;
+ }
+ else
+ m1 = calcLimit->max_iter;
+ calcLimit->epsilon = (float) fabs( eigVals[m1 - 1] / eigVals[0] );
+
+ for( i = 0; i < m1; i++ )
+ eigVals[i] = (float) (1.0 / sqrt( (double)eigVals[i] ));
+
+ /* ----------------- Calculation of eigenobjects ----------------------- */
+ if( ioFlags & CV_EIGOBJ_OUTPUT_CALLBACK )
+ {
+ int nio, ngr, igr;
+
+ nio = ioBufSize / (4 * eigSize.width); /* number of eigen objects in buffer */
+ ngr = m1 / nio; /* number of io groups */
+ if( nObjects % nio )
+ ngr += 1;
+
+ for( igr = 0; igr < ngr; igr++ )
+ {
+ int i, io, ie, imin = igr * nio, imax = imin + nio;
+
+ if( imax > m1 )
+ imax = m1;
+
+ for( i = 0; i < eigSize.width * (imax - imin); i++ )
+ ((float *) buffer)[i] = 0.f;
+
+ for( io = 0; io < nObjects; io++ )
+ {
+ uchar *bu = ioFlags & CV_EIGOBJ_INPUT_CALLBACK ? buf : ((uchar **) input)[io];
+
+ if( ioFlags & CV_EIGOBJ_INPUT_CALLBACK )
+ {
+ CvCallback read_callback = ((CvInput *) & input)->callback;
+
+ r = (CvStatus)read_callback( io, (void *) buf, userData );
+ if( r )
+ {
+ cvFree( &ev );
+ if( iev )
+ cvFree( &eigVals );
+ if( buffer )
+ cvFree( &buffer );
+ if( buf )
+ cvFree( &buf );
+ return r;
+ }
+ }
+
+ for( ie = imin; ie < imax; ie++ )
+ {
+ int k, l;
+ uchar *bv = bu;
+ float e = ev[ie * nObjects + io] * eigVals[ie];
+ float *be = ((float *) buffer) + ((ie - imin) * eigStep);
+
+ bf = avg;
+ for( k = 0; k < size.height; k++, bv += objStep1,
+ bf += avgStep, be += eigStep1 )
+ {
+ for( l = 0; l < size.width - 3; l += 4 )
+ {
+ float f = bf[l];
+ uchar v = bv[l];
+
+ be[l] += e * (v - f);
+ f = bf[l + 1];
+ v = bv[l + 1];
+ be[l + 1] += e * (v - f);
+ f = bf[l + 2];
+ v = bv[l + 2];
+ be[l + 2] += e * (v - f);
+ f = bf[l + 3];
+ v = bv[l + 3];
+ be[l + 3] += e * (v - f);
+ }
+ for( ; l < size.width; l++ )
+ be[l] += e * (bv[l] - bf[l]);
+ }
+ }
+ } /* io */
+
+ for( ie = imin; ie < imax; ie++ ) /* calculated eigen objects writting */
+ {
+ CvCallback write_callback = ((CvInput *) & output)->callback;
+ float *be = ((float *) buffer) + ((ie - imin) * eigStep);
+
+ r = (CvStatus)write_callback( ie, (void *) be, userData );
+ if( r )
+ {
+ cvFree( &ev );
+ if( iev )
+ cvFree( &eigVals );
+ if( buffer )
+ cvFree( &buffer );
+ if( buf )
+ cvFree( &buf );
+ return r;
+ }
+ }
+ } /* igr */
+ }
+
+ else
+ {
+ int k, p, l;
+
+ for( i = 0; i < m1; i++ ) /* e.o. annulation */
+ {
+ float *be = ((float **) output)[i];
+
+ for( p = 0; p < eigSize.height; p++, be += eigStep )
+ for( l = 0; l < eigSize.width; l++ )
+ be[l] = 0.0f;
+ }
+
+ for( k = 0; k < nObjects; k++ )
+ {
+ uchar *bv = (ioFlags & CV_EIGOBJ_INPUT_CALLBACK) ? buf : ((uchar **) input)[k];
+
+ if( ioFlags & CV_EIGOBJ_INPUT_CALLBACK )
+ {
+ CvCallback read_callback = ((CvInput *) & input)->callback;
+
+ r = (CvStatus)read_callback( k, (void *) buf, userData );
+ if( r )
+ {
+ cvFree( &ev );
+ if( iev )
+ cvFree( &eigVals );
+ if( buffer )
+ cvFree( &buffer );
+ if( buf )
+ cvFree( &buf );
+ return r;
+ }
+ }
+
+ for( i = 0; i < m1; i++ )
+ {
+ float v = eigVals[i] * ev[i * nObjects + k];
+ float *be = ((float **) output)[i];
+ uchar *bu = bv;
+
+ bf = avg;
+
+ for( p = 0; p < size.height; p++, bu += objStep1,
+ bf += avgStep, be += eigStep1 )
+ {
+ for( l = 0; l < size.width - 3; l += 4 )
+ {
+ float f = bf[l];
+ uchar u = bu[l];
+
+ be[l] += v * (u - f);
+ f = bf[l + 1];
+ u = bu[l + 1];
+ be[l + 1] += v * (u - f);
+ f = bf[l + 2];
+ u = bu[l + 2];
+ be[l + 2] += v * (u - f);
+ f = bf[l + 3];
+ u = bu[l + 3];
+ be[l + 3] += v * (u - f);
+ }
+ for( ; l < size.width; l++ )
+ be[l] += v * (bu[l] - bf[l]);
+ }
+ } /* i */
+ } /* k */
+ } /* else */
+
+ cvFree( &ev );
+ if( iev )
+ cvFree( &eigVals );
+ else
+ for( i = 0; i < m1; i++ )
+ eigVals[i] = 1.f / (eigVals[i] * eigVals[i]);
+ if( buffer )
+ cvFree( &buffer );
+ if( buf )
+ cvFree( &buf );
+ return CV_NO_ERR;
+}
+
+/* --- End of icvCalcEigenObjects_8u32fR --- */
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvCalcDecompCoeff_8u32fR
+// Purpose: The function calculates one decomposition coefficient of input object
+// using previously calculated eigen object and the mean (averaged) object
+// Context:
+// Parameters: obj - input object
+// objStep - its step (in bytes)
+// eigObj - pointer to eigen object
+// eigStep - its step (in bytes)
+// avg - pointer to averaged object
+// avgStep - its step (in bytes)
+// size - ROI size of each source object
+//
+// Returns: decomposition coefficient value or large negative value (if error)
+//
+// Notes:
+//F*/
+static float CV_STDCALL
+icvCalcDecompCoeff_8u32fR( uchar* obj, int objStep,
+ float *eigObj, int eigStep,
+ float *avg, int avgStep, CvSize size )
+{
+ int i, k;
+ float w = 0.0f;
+
+ if( size.width > objStep || 4 * size.width > eigStep
+ || 4 * size.width > avgStep || size.height < 1 )
+ return -1.0e30f;
+ if( obj == NULL || eigObj == NULL || avg == NULL )
+ return -1.0e30f;
+
+ eigStep /= 4;
+ avgStep /= 4;
+
+ if( size.width == objStep && size.width == eigStep && size.width == avgStep )
+ {
+ size.width *= size.height;
+ size.height = 1;
+ objStep = eigStep = avgStep = size.width;
+ }
+
+ for( i = 0; i < size.height; i++, obj += objStep, eigObj += eigStep, avg += avgStep )
+ {
+ for( k = 0; k < size.width - 4; k += 4 )
+ {
+ float o = (float) obj[k];
+ float e = eigObj[k];
+ float a = avg[k];
+
+ w += e * (o - a);
+ o = (float) obj[k + 1];
+ e = eigObj[k + 1];
+ a = avg[k + 1];
+ w += e * (o - a);
+ o = (float) obj[k + 2];
+ e = eigObj[k + 2];
+ a = avg[k + 2];
+ w += e * (o - a);
+ o = (float) obj[k + 3];
+ e = eigObj[k + 3];
+ a = avg[k + 3];
+ w += e * (o - a);
+ }
+ for( ; k < size.width; k++ )
+ w += eigObj[k] * ((float) obj[k] - avg[k]);
+ }
+
+ return w;
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Names: icvEigenDecomposite_8u32fR
+// Purpose: The function calculates all decomposition coefficients for input object
+// using previously calculated eigen objects basis and the mean (averaged)
+// object
+// Context:
+// Parameters: obj - input object
+// objStep - its step (in bytes)
+// nEigObjs - number of eigen objects
+// eigInput - pointer either to array of pointers to eigen objects
+// or to read callback function (depending on ioFlags)
+// eigStep - eigen objects step (in bytes)
+// ioFlags - input/output flags
+// iserData - pointer to the structure which contains all necessary
+// data for the callback function
+// avg - pointer to averaged object
+// avgStep - its step (in bytes)
+// size - ROI size of each source object
+// coeffs - calculated coefficients (output data)
+//
+// Returns: icv status
+//
+// Notes: see notes for icvCalcEigenObjects_8u32fR function
+//F*/
+static CvStatus CV_STDCALL
+icvEigenDecomposite_8u32fR( uchar * obj, int objStep, int nEigObjs,
+ void *eigInput, int eigStep, int ioFlags,
+ void *userData, float *avg, int avgStep,
+ CvSize size, float *coeffs )
+{
+ int i;
+
+ if( nEigObjs < 2 )
+ return CV_BADFACTOR_ERR;
+ if( ioFlags < 0 || ioFlags > 1 )
+ return CV_BADFACTOR_ERR;
+ if( size.width > objStep || 4 * size.width > eigStep ||
+ 4 * size.width > avgStep || size.height < 1 )
+ return CV_BADSIZE_ERR;
+ if( obj == NULL || eigInput == NULL || coeffs == NULL || avg == NULL )
+ return CV_NULLPTR_ERR;
+ if( !ioFlags )
+ for( i = 0; i < nEigObjs; i++ )
+ if( ((uchar **) eigInput)[i] == NULL )
+ return CV_NULLPTR_ERR;
+
+ if( ioFlags ) /* callback */
+
+ {
+ float *buffer;
+ CvCallback read_callback = ((CvInput *) & eigInput)->callback;
+
+ eigStep = 4 * size.width;
+
+ /* memory allocation */
+ buffer = (float *) cvAlloc( sizeof( float ) * size.width * size.height );
+
+ if( buffer == NULL )
+ return CV_OUTOFMEM_ERR;
+
+ for( i = 0; i < nEigObjs; i++ )
+ {
+ float w;
+ CvStatus r = (CvStatus)read_callback( i, (void *) buffer, userData );
+
+ if( r )
+ {
+ cvFree( &buffer );
+ return r;
+ }
+ w = icvCalcDecompCoeff_8u32fR( obj, objStep, buffer,
+ eigStep, avg, avgStep, size );
+ if( w < -1.0e29f )
+ {
+ cvFree( &buffer );
+ return CV_NOTDEFINED_ERR;
+ }
+ coeffs[i] = w;
+ }
+ cvFree( &buffer );
+ }
+
+ else
+ /* no callback */
+ for( i = 0; i < nEigObjs; i++ )
+ {
+ float w = icvCalcDecompCoeff_8u32fR( obj, objStep, ((float **) eigInput)[i],
+ eigStep, avg, avgStep, size );
+
+ if( w < -1.0e29f )
+ return CV_NOTDEFINED_ERR;
+ coeffs[i] = w;
+ }
+
+ return CV_NO_ERR;
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Names: icvEigenProjection_8u32fR
+// Purpose: The function calculates object projection to the eigen sub-space (restores
+// an object) using previously calculated eigen objects basis, mean (averaged)
+// object and decomposition coefficients of the restored object
+// Context:
+// Parameters: nEigObjs - Number of eigen objects
+// eigens - Array of pointers to eigen objects
+// eigStep - Eigen objects step (in bytes)
+// coeffs - Previously calculated decomposition coefficients
+// avg - Pointer to averaged object
+// avgStep - Its step (in bytes)
+// rest - Pointer to restored object
+// restStep - Its step (in bytes)
+// size - ROI size of each object
+//
+// Returns: CV status
+//
+// Notes:
+//F*/
+static CvStatus CV_STDCALL
+icvEigenProjection_8u32fR( int nEigObjs, void *eigInput, int eigStep,
+ int ioFlags, void *userData, float *coeffs,
+ float *avg, int avgStep, uchar * rest,
+ int restStep, CvSize size )
+{
+ int i, j, k;
+ float *buf;
+ float *buffer = NULL;
+ float *b;
+ CvCallback read_callback = ((CvInput *) & eigInput)->callback;
+
+ if( size.width > avgStep || 4 * size.width > eigStep || size.height < 1 )
+ return CV_BADSIZE_ERR;
+ if( rest == NULL || eigInput == NULL || avg == NULL || coeffs == NULL )
+ return CV_NULLPTR_ERR;
+ if( ioFlags < 0 || ioFlags > 1 )
+ return CV_BADFACTOR_ERR;
+ if( !ioFlags )
+ for( i = 0; i < nEigObjs; i++ )
+ if( ((uchar **) eigInput)[i] == NULL )
+ return CV_NULLPTR_ERR;
+ eigStep /= 4;
+ avgStep /= 4;
+
+ if( size.width == restStep && size.width == eigStep && size.width == avgStep )
+ {
+ size.width *= size.height;
+ size.height = 1;
+ restStep = eigStep = avgStep = size.width;
+ }
+
+ buf = (float *) cvAlloc( sizeof( float ) * size.width * size.height );
+
+ if( buf == NULL )
+ return CV_OUTOFMEM_ERR;
+ b = buf;
+ for( i = 0; i < size.height; i++, avg += avgStep, b += size.width )
+ for( j = 0; j < size.width; j++ )
+ b[j] = avg[j];
+
+ if( ioFlags )
+ {
+ buffer = (float *) cvAlloc( sizeof( float ) * size.width * size.height );
+
+ if( buffer == NULL )
+ {
+ cvFree( &buf );
+ return CV_OUTOFMEM_ERR;
+ }
+ eigStep = size.width;
+ }
+
+ for( k = 0; k < nEigObjs; k++ )
+ {
+ float *e = ioFlags ? buffer : ((float **) eigInput)[k];
+ float c = coeffs[k];
+
+ if( ioFlags ) /* read eigen object */
+ {
+ CvStatus r = (CvStatus)read_callback( k, (void *) buffer, userData );
+
+ if( r )
+ {
+ cvFree( &buf );
+ cvFree( &buffer );
+ return r;
+ }
+ }
+
+ b = buf;
+ for( i = 0; i < size.height; i++, e += eigStep, b += size.width )
+ {
+ for( j = 0; j < size.width - 3; j += 4 )
+ {
+ float b0 = c * e[j];
+ float b1 = c * e[j + 1];
+ float b2 = c * e[j + 2];
+ float b3 = c * e[j + 3];
+
+ b[j] += b0;
+ b[j + 1] += b1;
+ b[j + 2] += b2;
+ b[j + 3] += b3;
+ }
+ for( ; j < size.width; j++ )
+ b[j] += c * e[j];
+ }
+ }
+
+ b = buf;
+ for( i = 0; i < size.height; i++, avg += avgStep, b += size.width, rest += restStep )
+ for( j = 0; j < size.width; j++ )
+ {
+ int w = cvRound( b[j] );
+
+ w = !(w & ~255) ? w : w < 0 ? 0 : 255;
+ rest[j] = (uchar) w;
+ }
+
+ cvFree( &buf );
+ if( ioFlags )
+ cvFree( &buffer );
+ return CV_NO_ERR;
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvCalcCovarMatrixEx
+// Purpose: The function calculates a covariance matrix for a group of input objects
+// (images, vectors, etc.).
+// Context:
+// Parameters: nObjects - number of source objects
+// input - pointer either to array of input objects
+// or to read callback function (depending on ioFlags)
+// ioFlags - input/output flags (see Notes to
+// cvCalcEigenObjects function)
+// ioBufSize - input/output buffer size
+// userData - pointer to the structure which contains all necessary
+// data for the callback functions
+// avg - averaged object
+// covarMatrix - covariance matrix (output parameter; must be allocated
+// before call)
+//
+// Notes: See Notes to cvCalcEigenObjects function
+//F*/
+
+CV_IMPL void
+cvCalcCovarMatrixEx( int nObjects, void* input, int ioFlags,
+ int ioBufSize, uchar* buffer, void* userData,
+ IplImage* avg, float* covarMatrix )
+{
+ float *avg_data;
+ int avg_step = 0;
+ CvSize avg_size;
+ int i;
+
+ CV_FUNCNAME( "cvCalcCovarMatrixEx" );
+
+ __BEGIN__;
+
+ cvGetImageRawData( avg, (uchar **) & avg_data, &avg_step, &avg_size );
+ if( avg->depth != IPL_DEPTH_32F )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ if( avg->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+
+ if( ioFlags == CV_EIGOBJ_NO_CALLBACK )
+ {
+ IplImage **images = (IplImage **) (((CvInput *) & input)->data);
+ uchar **objects = (uchar **) cvAlloc( sizeof( uchar * ) * nObjects );
+ int img_step = 0, old_step = 0;
+ CvSize img_size = avg_size, old_size = avg_size;
+
+ if( objects == NULL )
+ CV_ERROR( CV_StsBadArg, "Insufficient memory" );
+
+ for( i = 0; i < nObjects; i++ )
+ {
+ IplImage *img = images[i];
+ uchar *img_data;
+
+ cvGetImageRawData( img, &img_data, &img_step, &img_size );
+ if( img->depth != IPL_DEPTH_8U )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ if( img_size != avg_size || img_size != old_size )
+ CV_ERROR( CV_StsBadArg, "Different sizes of objects" );
+ if( img->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+ if( i > 0 && img_step != old_step )
+ CV_ERROR( CV_StsBadArg, "Different steps of objects" );
+
+ old_step = img_step;
+ old_size = img_size;
+ objects[i] = img_data;
+ }
+
+ CV_CALL( icvCalcCovarMatrixEx_8u32fR( nObjects,
+ (void*) objects,
+ img_step,
+ CV_EIGOBJ_NO_CALLBACK,
+ 0,
+ NULL,
+ NULL,
+ avg_data,
+ avg_step,
+ avg_size,
+ covarMatrix ));
+ cvFree( &objects );
+ }
+
+ else
+
+ {
+ CV_CALL( icvCalcCovarMatrixEx_8u32fR( nObjects,
+ input,
+ avg_step / 4,
+ ioFlags,
+ ioBufSize,
+ buffer,
+ userData,
+ avg_data,
+ avg_step,
+ avg_size,
+ covarMatrix ));
+ }
+
+ __END__;
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvCalcEigenObjects
+// Purpose: The function calculates an orthonormal eigen basis and a mean (averaged)
+// object for a group of input objects (images, vectors, etc.).
+// Context:
+// Parameters: nObjects - number of source objects
+// input - pointer either to array of input objects
+// or to read callback function (depending on ioFlags)
+// output - pointer either to output eigen objects
+// or to write callback function (depending on ioFlags)
+// ioFlags - input/output flags (see Notes)
+// ioBufSize - input/output buffer size
+// userData - pointer to the structure which contains all necessary
+// data for the callback functions
+// calcLimit - determines the calculation finish conditions
+// avg - averaged object (has the same size as ROI)
+// eigVals - pointer to corresponding eigen values (array of <nObjects>
+// elements in descending order)
+//
+// Notes: 1. input/output data (that is, input objects and eigen ones) may either
+// be allocated in the RAM or be read from/written to the HDD (or any
+// other device) by read/write callback functions. It depends on the
+// value of ioFlags paramater, which may be the following:
+// CV_EIGOBJ_NO_CALLBACK, or 0;
+// CV_EIGOBJ_INPUT_CALLBACK;
+// CV_EIGOBJ_OUTPUT_CALLBACK;
+// CV_EIGOBJ_BOTH_CALLBACK, or
+// CV_EIGOBJ_INPUT_CALLBACK | CV_EIGOBJ_OUTPUT_CALLBACK.
+// The callback functions as well as the user data structure must be
+// developed by the user.
+//
+// 2. If ioBufSize = 0, or it's too large, the function dermines buffer size
+// itself.
+//
+// 3. Depending on calcLimit parameter, calculations are finished either if
+// eigenfaces number comes up to certain value or the relation of the
+// current eigenvalue and the largest one comes down to certain value
+// (or any of the above conditions takes place). The calcLimit->type value
+// must be CV_TERMCRIT_NUMB, CV_TERMCRIT_EPS or
+// CV_TERMCRIT_NUMB | CV_TERMCRIT_EPS. The function returns the real
+// values calcLimit->max_iter and calcLimit->epsilon.
+//
+// 4. eigVals may be equal to NULL (if you don't need eigen values in further).
+//
+//F*/
+CV_IMPL void
+cvCalcEigenObjects( int nObjects,
+ void* input,
+ void* output,
+ int ioFlags,
+ int ioBufSize,
+ void* userData,
+ CvTermCriteria* calcLimit,
+ IplImage* avg,
+ float* eigVals )
+{
+ float *avg_data;
+ int avg_step = 0;
+ CvSize avg_size;
+ int i;
+ int nEigens = nObjects - 1;
+
+ CV_FUNCNAME( "cvCalcEigenObjects" );
+
+ __BEGIN__;
+
+ cvGetImageRawData( avg, (uchar **) & avg_data, &avg_step, &avg_size );
+ if( avg->depth != IPL_DEPTH_32F )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ if( avg->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+
+ if( nEigens > calcLimit->max_iter && calcLimit->type != CV_TERMCRIT_EPS )
+ nEigens = calcLimit->max_iter;
+
+ switch (ioFlags)
+ {
+ case CV_EIGOBJ_NO_CALLBACK:
+ {
+ IplImage **objects = (IplImage **) (((CvInput *) & input)->data);
+ IplImage **eigens = (IplImage **) (((CvInput *) & output)->data);
+ uchar **objs = (uchar **) cvAlloc( sizeof( uchar * ) * nObjects );
+ float **eigs = (float **) cvAlloc( sizeof( float * ) * nEigens );
+ int obj_step = 0, old_step = 0;
+ int eig_step = 0, oldeig_step = 0;
+ CvSize obj_size = avg_size, old_size = avg_size,
+
+ eig_size = avg_size, oldeig_size = avg_size;
+
+ if( objects == NULL || eigens == NULL )
+ CV_ERROR( CV_StsBadArg, "Insufficient memory" );
+
+ for( i = 0; i < nObjects; i++ )
+ {
+ IplImage *img = objects[i];
+ uchar *obj_data;
+
+ cvGetImageRawData( img, &obj_data, &obj_step, &obj_size );
+ if( img->depth != IPL_DEPTH_8U )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ if( obj_size != avg_size || obj_size != old_size )
+ CV_ERROR( CV_StsBadArg, "Different sizes of objects" );
+ if( img->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+ if( i > 0 && obj_step != old_step )
+ CV_ERROR( CV_StsBadArg, "Different steps of objects" );
+
+ old_step = obj_step;
+ old_size = obj_size;
+ objs[i] = obj_data;
+ }
+ for( i = 0; i < nEigens; i++ )
+ {
+ IplImage *eig = eigens[i];
+ float *eig_data;
+
+ cvGetImageRawData( eig, (uchar **) & eig_data, &eig_step, &eig_size );
+ if( eig->depth != IPL_DEPTH_32F )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ if( eig_size != avg_size || eig_size != oldeig_size )
+ CV_ERROR( CV_StsBadArg, "Different sizes of objects" );
+ if( eig->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+ if( i > 0 && eig_step != oldeig_step )
+ CV_ERROR( CV_StsBadArg, "Different steps of objects" );
+
+ oldeig_step = eig_step;
+ oldeig_size = eig_size;
+ eigs[i] = eig_data;
+ }
+ CV_CALL( icvCalcEigenObjects_8u32fR( nObjects, (void*) objs, obj_step,
+ (void*) eigs, eig_step, obj_size,
+ ioFlags, ioBufSize, userData,
+ calcLimit, avg_data, avg_step, eigVals ));
+ cvFree( &objs );
+ cvFree( &eigs );
+ break;
+ }
+
+ case CV_EIGOBJ_OUTPUT_CALLBACK:
+ {
+ IplImage **objects = (IplImage **) (((CvInput *) & input)->data);
+ uchar **objs = (uchar **) cvAlloc( sizeof( uchar * ) * nObjects );
+ int obj_step = 0, old_step = 0;
+ CvSize obj_size = avg_size, old_size = avg_size;
+
+ if( objects == NULL )
+ CV_ERROR( CV_StsBadArg, "Insufficient memory" );
+
+ for( i = 0; i < nObjects; i++ )
+ {
+ IplImage *img = objects[i];
+ uchar *obj_data;
+
+ cvGetImageRawData( img, &obj_data, &obj_step, &obj_size );
+ if( img->depth != IPL_DEPTH_8U )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ if( obj_size != avg_size || obj_size != old_size )
+ CV_ERROR( CV_StsBadArg, "Different sizes of objects" );
+ if( img->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+ if( i > 0 && obj_step != old_step )
+ CV_ERROR( CV_StsBadArg, "Different steps of objects" );
+
+ old_step = obj_step;
+ old_size = obj_size;
+ objs[i] = obj_data;
+ }
+ CV_CALL( icvCalcEigenObjects_8u32fR( nObjects,
+ (void*) objs,
+ obj_step,
+ output,
+ avg_step,
+ obj_size,
+ ioFlags,
+ ioBufSize,
+ userData,
+ calcLimit,
+ avg_data,
+ avg_step,
+ eigVals ));
+ cvFree( &objs );
+ break;
+ }
+
+ case CV_EIGOBJ_INPUT_CALLBACK:
+ {
+ IplImage **eigens = (IplImage **) (((CvInput *) & output)->data);
+ float **eigs = (float**) cvAlloc( sizeof( float* ) * nEigens );
+ int eig_step = 0, oldeig_step = 0;
+ CvSize eig_size = avg_size, oldeig_size = avg_size;
+
+ if( eigens == NULL )
+ CV_ERROR( CV_StsBadArg, "Insufficient memory" );
+
+ for( i = 0; i < nEigens; i++ )
+ {
+ IplImage *eig = eigens[i];
+ float *eig_data;
+
+ cvGetImageRawData( eig, (uchar **) & eig_data, &eig_step, &eig_size );
+ if( eig->depth != IPL_DEPTH_32F )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ if( eig_size != avg_size || eig_size != oldeig_size )
+ CV_ERROR( CV_StsBadArg, "Different sizes of objects" );
+ if( eig->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+ if( i > 0 && eig_step != oldeig_step )
+ CV_ERROR( CV_StsBadArg, "Different steps of objects" );
+
+ oldeig_step = eig_step;
+ oldeig_size = eig_size;
+ eigs[i] = eig_data;
+ }
+ CV_CALL( icvCalcEigenObjects_8u32fR( nObjects,
+ input,
+ avg_step / 4,
+ (void*) eigs,
+ eig_step,
+ eig_size,
+ ioFlags,
+ ioBufSize,
+ userData,
+ calcLimit,
+ avg_data,
+ avg_step,
+ eigVals ));
+ cvFree( &eigs );
+ break;
+ }
+ case CV_EIGOBJ_INPUT_CALLBACK | CV_EIGOBJ_OUTPUT_CALLBACK:
+
+ CV_CALL( icvCalcEigenObjects_8u32fR( nObjects,
+ input,
+ avg_step / 4,
+ output,
+ avg_step,
+ avg_size,
+ ioFlags,
+ ioBufSize,
+ userData,
+ calcLimit,
+ avg_data,
+ avg_step,
+ eigVals ));
+ break;
+
+ default:
+ CV_ERROR( CV_StsBadArg, "Unsupported i/o flag" );
+ }
+
+ __END__;
+}
+
+/*--------------------------------------------------------------------------------------*/
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvCalcDecompCoeff
+// Purpose: The function calculates one decomposition coefficient of input object
+// using previously calculated eigen object and the mean (averaged) object
+// Context:
+// Parameters: obj - input object
+// eigObj - eigen object
+// avg - averaged object
+//
+// Returns: decomposition coefficient value or large negative value (if error)
+//
+// Notes:
+//F*/
+
+CV_IMPL double
+cvCalcDecompCoeff( IplImage * obj, IplImage * eigObj, IplImage * avg )
+{
+ double coeff = DBL_MAX;
+
+ uchar *obj_data;
+ float *eig_data;
+ float *avg_data;
+ int obj_step = 0, eig_step = 0, avg_step = 0;
+ CvSize obj_size, eig_size, avg_size;
+
+ CV_FUNCNAME( "cvCalcDecompCoeff" );
+
+ __BEGIN__;
+
+ cvGetImageRawData( obj, &obj_data, &obj_step, &obj_size );
+ if( obj->depth != IPL_DEPTH_8U )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ if( obj->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+
+ cvGetImageRawData( eigObj, (uchar **) & eig_data, &eig_step, &eig_size );
+ if( eigObj->depth != IPL_DEPTH_32F )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ if( eigObj->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+
+ cvGetImageRawData( avg, (uchar **) & avg_data, &avg_step, &avg_size );
+ if( avg->depth != IPL_DEPTH_32F )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ if( avg->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+
+ if( obj_size != eig_size || obj_size != avg_size )
+ CV_ERROR( CV_StsBadArg, "different sizes of images" );
+
+ coeff = icvCalcDecompCoeff_8u32fR( obj_data, obj_step,
+ eig_data, eig_step,
+ avg_data, avg_step, obj_size );
+
+ __END__;
+
+ return coeff;
+}
+
+/*--------------------------------------------------------------------------------------*/
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Names: cvEigenDecomposite
+// Purpose: The function calculates all decomposition coefficients for input object
+// using previously calculated eigen objects basis and the mean (averaged)
+// object
+//
+// Parameters: obj - input object
+// nEigObjs - number of eigen objects
+// eigInput - pointer either to array of pointers to eigen objects
+// or to read callback function (depending on ioFlags)
+// ioFlags - input/output flags
+// userData - pointer to the structure which contains all necessary
+// data for the callback function
+// avg - averaged object
+// coeffs - calculated coefficients (output data)
+//
+// Notes: see notes for cvCalcEigenObjects function
+//F*/
+
+CV_IMPL void
+cvEigenDecomposite( IplImage* obj,
+ int nEigObjs,
+ void* eigInput,
+ int ioFlags,
+ void* userData,
+ IplImage* avg,
+ float* coeffs )
+{
+ float *avg_data;
+ uchar *obj_data;
+ int avg_step = 0, obj_step = 0;
+ CvSize avg_size, obj_size;
+ int i;
+
+ CV_FUNCNAME( "cvEigenDecomposite" );
+
+ __BEGIN__;
+
+ cvGetImageRawData( avg, (uchar **) & avg_data, &avg_step, &avg_size );
+ if( avg->depth != IPL_DEPTH_32F )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ if( avg->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+
+ cvGetImageRawData( obj, &obj_data, &obj_step, &obj_size );
+ if( obj->depth != IPL_DEPTH_8U )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ if( obj->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+
+ if( obj_size != avg_size )
+ CV_ERROR( CV_StsBadArg, "Different sizes of objects" );
+
+ if( ioFlags == CV_EIGOBJ_NO_CALLBACK )
+ {
+ IplImage **eigens = (IplImage **) (((CvInput *) & eigInput)->data);
+ float **eigs = (float **) cvAlloc( sizeof( float * ) * nEigObjs );
+ int eig_step = 0, old_step = 0;
+ CvSize eig_size = avg_size, old_size = avg_size;
+
+ if( eigs == NULL )
+ CV_ERROR( CV_StsBadArg, "Insufficient memory" );
+
+ for( i = 0; i < nEigObjs; i++ )
+ {
+ IplImage *eig = eigens[i];
+ float *eig_data;
+
+ cvGetImageRawData( eig, (uchar **) & eig_data, &eig_step, &eig_size );
+ if( eig->depth != IPL_DEPTH_32F )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ if( eig_size != avg_size || eig_size != old_size )
+ CV_ERROR( CV_StsBadArg, "Different sizes of objects" );
+ if( eig->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+ if( i > 0 && eig_step != old_step )
+ CV_ERROR( CV_StsBadArg, "Different steps of objects" );
+
+ old_step = eig_step;
+ old_size = eig_size;
+ eigs[i] = eig_data;
+ }
+
+ CV_CALL( icvEigenDecomposite_8u32fR( obj_data,
+ obj_step,
+ nEigObjs,
+ (void*) eigs,
+ eig_step,
+ ioFlags,
+ userData,
+ avg_data,
+ avg_step,
+ obj_size,
+ coeffs ));
+ cvFree( &eigs );
+ }
+
+ else
+
+ {
+ CV_CALL( icvEigenDecomposite_8u32fR( obj_data,
+ obj_step,
+ nEigObjs,
+ eigInput,
+ avg_step,
+ ioFlags,
+ userData,
+ avg_data,
+ avg_step,
+ obj_size,
+ coeffs ));
+ }
+
+ __END__;
+}
+
+/*--------------------------------------------------------------------------------------*/
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvEigenProjection
+// Purpose: The function calculates object projection to the eigen sub-space (restores
+// an object) using previously calculated eigen objects basis, mean (averaged)
+// object and decomposition coefficients of the restored object
+// Context:
+// Parameters: nEigObjs - number of eigen objects
+// eigInput - pointer either to array of pointers to eigen objects
+// or to read callback function (depending on ioFlags)
+// ioFlags - input/output flags
+// userData - pointer to the structure which contains all necessary
+// data for the callback function
+// coeffs - array of decomposition coefficients
+// avg - averaged object
+// proj - object projection (output data)
+//
+// Notes: see notes for cvCalcEigenObjects function
+//F*/
+
+CV_IMPL void
+cvEigenProjection( void* eigInput,
+ int nEigObjs,
+ int ioFlags,
+ void* userData,
+ float* coeffs,
+ IplImage* avg,
+ IplImage* proj )
+{
+ float *avg_data;
+ uchar *proj_data;
+ int avg_step = 0, proj_step = 0;
+ CvSize avg_size, proj_size;
+ int i;
+
+ CV_FUNCNAME( "cvEigenProjection" );
+
+ __BEGIN__;
+
+ cvGetImageRawData( avg, (uchar **) & avg_data, &avg_step, &avg_size );
+ if( avg->depth != IPL_DEPTH_32F )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ if( avg->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+
+ cvGetImageRawData( proj, &proj_data, &proj_step, &proj_size );
+ if( proj->depth != IPL_DEPTH_8U )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ if( proj->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+
+ if( proj_size != avg_size )
+ CV_ERROR( CV_StsBadArg, "Different sizes of projects" );
+
+ if( ioFlags == CV_EIGOBJ_NO_CALLBACK )
+ {
+ IplImage **eigens = (IplImage**) (((CvInput *) & eigInput)->data);
+ float **eigs = (float**) cvAlloc( sizeof( float * ) * nEigObjs );
+ int eig_step = 0, old_step = 0;
+ CvSize eig_size = avg_size, old_size = avg_size;
+
+ if( eigs == NULL )
+ CV_ERROR( CV_StsBadArg, "Insufficient memory" );
+
+ for( i = 0; i < nEigObjs; i++ )
+ {
+ IplImage *eig = eigens[i];
+ float *eig_data;
+
+ cvGetImageRawData( eig, (uchar **) & eig_data, &eig_step, &eig_size );
+ if( eig->depth != IPL_DEPTH_32F )
+ CV_ERROR( CV_BadDepth, cvUnsupportedFormat );
+ if( eig_size != avg_size || eig_size != old_size )
+ CV_ERROR( CV_StsBadArg, "Different sizes of objects" );
+ if( eig->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+ if( i > 0 && eig_step != old_step )
+ CV_ERROR( CV_StsBadArg, "Different steps of objects" );
+
+ old_step = eig_step;
+ old_size = eig_size;
+ eigs[i] = eig_data;
+ }
+
+ CV_CALL( icvEigenProjection_8u32fR( nEigObjs,
+ (void*) eigs,
+ eig_step,
+ ioFlags,
+ userData,
+ coeffs,
+ avg_data,
+ avg_step,
+ proj_data,
+ proj_step,
+ avg_size ));
+ cvFree( &eigs );
+ }
+
+ else
+
+ {
+ CV_CALL( icvEigenProjection_8u32fR( nEigObjs,
+ eigInput,
+ avg_step,
+ ioFlags,
+ userData,
+ coeffs,
+ avg_data,
+ avg_step,
+ proj_data,
+ proj_step,
+ avg_size ));
+ }
+
+ __END__;
+}
+
+/* End of file. */
diff --git a/cvaux/src/cvepilines.cpp b/cvaux/src/cvepilines.cpp
new file mode 100644
index 0000000..cf96c72
--- /dev/null
+++ b/cvaux/src/cvepilines.cpp
@@ -0,0 +1,3722 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+
+#include "_cvaux.h"
+#include "cvtypes.h"
+#include <float.h>
+#include <limits.h>
+#include "cv.h"
+
+/* Valery Mosyagin */
+
+#undef quad
+
+#define EPS64D 1e-9
+
+int cvComputeEssentialMatrix( CvMatr32f rotMatr,
+ CvMatr32f transVect,
+ CvMatr32f essMatr);
+
+int cvConvertEssential2Fundamental( CvMatr32f essMatr,
+ CvMatr32f fundMatr,
+ CvMatr32f cameraMatr1,
+ CvMatr32f cameraMatr2);
+
+int cvComputeEpipolesFromFundMatrix(CvMatr32f fundMatr,
+ CvPoint3D32f* epipole1,
+ CvPoint3D32f* epipole2);
+
+void icvTestPoint( CvPoint2D64d testPoint,
+ CvVect64d line1,CvVect64d line2,
+ CvPoint2D64d basePoint,
+ int* result);
+
+
+
+int icvGetSymPoint3D( CvPoint3D64d pointCorner,
+ CvPoint3D64d point1,
+ CvPoint3D64d point2,
+ CvPoint3D64d *pointSym2)
+{
+ double len1,len2;
+ double alpha;
+ icvGetPieceLength3D(pointCorner,point1,&len1);
+ if( len1 < EPS64D )
+ {
+ return CV_BADARG_ERR;
+ }
+ icvGetPieceLength3D(pointCorner,point2,&len2);
+ alpha = len2 / len1;
+
+ pointSym2->x = pointCorner.x + alpha*(point1.x - pointCorner.x);
+ pointSym2->y = pointCorner.y + alpha*(point1.y - pointCorner.y);
+ pointSym2->z = pointCorner.z + alpha*(point1.z - pointCorner.z);
+ return CV_NO_ERR;
+}
+
+/* author Valery Mosyagin */
+
+/* Compute 3D point for scanline and alpha betta */
+int icvCompute3DPoint( double alpha,double betta,
+ CvStereoLineCoeff* coeffs,
+ CvPoint3D64d* point)
+{
+
+ double partX;
+ double partY;
+ double partZ;
+ double partAll;
+ double invPartAll;
+
+ double alphabetta = alpha*betta;
+
+ partAll = alpha - betta;
+ if( fabs(partAll) > 0.00001 ) /* alpha must be > betta */
+ {
+
+ partX = coeffs->Xcoef + coeffs->XcoefA *alpha +
+ coeffs->XcoefB*betta + coeffs->XcoefAB*alphabetta;
+
+ partY = coeffs->Ycoef + coeffs->YcoefA *alpha +
+ coeffs->YcoefB*betta + coeffs->YcoefAB*alphabetta;
+
+ partZ = coeffs->Zcoef + coeffs->ZcoefA *alpha +
+ coeffs->ZcoefB*betta + coeffs->ZcoefAB*alphabetta;
+
+ invPartAll = 1.0 / partAll;
+
+ point->x = partX * invPartAll;
+ point->y = partY * invPartAll;
+ point->z = partZ * invPartAll;
+ return CV_NO_ERR;
+ }
+ else
+ {
+ return CV_BADFACTOR_ERR;
+ }
+}
+
+/*--------------------------------------------------------------------------------------*/
+
+/* Compute rotate matrix and trans vector for change system */
+int icvCreateConvertMatrVect( CvMatr64d rotMatr1,
+ CvMatr64d transVect1,
+ CvMatr64d rotMatr2,
+ CvMatr64d transVect2,
+ CvMatr64d convRotMatr,
+ CvMatr64d convTransVect)
+{
+ double invRotMatr2[9];
+ double tmpVect[3];
+
+
+ icvInvertMatrix_64d(rotMatr2,3,invRotMatr2);
+ /* Test for error */
+
+ icvMulMatrix_64d( rotMatr1,
+ 3,3,
+ invRotMatr2,
+ 3,3,
+ convRotMatr);
+
+ icvMulMatrix_64d( convRotMatr,
+ 3,3,
+ transVect2,
+ 1,3,
+ tmpVect);
+
+ icvSubVector_64d(transVect1,tmpVect,convTransVect,3);
+
+
+ return CV_NO_ERR;
+}
+
+/*--------------------------------------------------------------------------------------*/
+
+/* Compute point coordinates in other system */
+int icvConvertPointSystem(CvPoint3D64d M2,
+ CvPoint3D64d* M1,
+ CvMatr64d rotMatr,
+ CvMatr64d transVect
+ )
+{
+ double tmpVect[3];
+
+ icvMulMatrix_64d( rotMatr,
+ 3,3,
+ (double*)&M2,
+ 1,3,
+ tmpVect);
+
+ icvAddVector_64d(tmpVect,transVect,(double*)M1,3);
+
+ return CV_NO_ERR;
+}
+/*--------------------------------------------------------------------------------------*/
+int icvComputeCoeffForStereoV3( double quad1[4][2],
+ double quad2[4][2],
+ int numScanlines,
+ CvMatr64d camMatr1,
+ CvMatr64d rotMatr1,
+ CvMatr64d transVect1,
+ CvMatr64d camMatr2,
+ CvMatr64d rotMatr2,
+ CvMatr64d transVect2,
+ CvStereoLineCoeff* startCoeffs,
+ int* needSwapCamera)
+{
+ /* For each pair */
+ /* In this function we must define position of cameras */
+
+ CvPoint2D64d point1;
+ CvPoint2D64d point2;
+ CvPoint2D64d point3;
+ CvPoint2D64d point4;
+
+ int currLine;
+ *needSwapCamera = 0;
+ for( currLine = 0; currLine < numScanlines; currLine++ )
+ {
+ /* Compute points */
+ double alpha = ((double)currLine)/((double)(numScanlines)); /* maybe - 1 */
+
+ point1.x = (1.0 - alpha) * quad1[0][0] + alpha * quad1[3][0];
+ point1.y = (1.0 - alpha) * quad1[0][1] + alpha * quad1[3][1];
+
+ point2.x = (1.0 - alpha) * quad1[1][0] + alpha * quad1[2][0];
+ point2.y = (1.0 - alpha) * quad1[1][1] + alpha * quad1[2][1];
+
+ point3.x = (1.0 - alpha) * quad2[0][0] + alpha * quad2[3][0];
+ point3.y = (1.0 - alpha) * quad2[0][1] + alpha * quad2[3][1];
+
+ point4.x = (1.0 - alpha) * quad2[1][0] + alpha * quad2[2][0];
+ point4.y = (1.0 - alpha) * quad2[1][1] + alpha * quad2[2][1];
+
+ /* We can compute coeffs for this line */
+ icvComCoeffForLine( point1,
+ point2,
+ point3,
+ point4,
+ camMatr1,
+ rotMatr1,
+ transVect1,
+ camMatr2,
+ rotMatr2,
+ transVect2,
+ &startCoeffs[currLine],
+ needSwapCamera);
+ }
+ return CV_NO_ERR;
+}
+/*--------------------------------------------------------------------------------------*/
+int icvComputeCoeffForStereoNew( double quad1[4][2],
+ double quad2[4][2],
+ int numScanlines,
+ CvMatr32f camMatr1,
+ CvMatr32f rotMatr1,
+ CvMatr32f transVect1,
+ CvMatr32f camMatr2,
+ CvStereoLineCoeff* startCoeffs,
+ int* needSwapCamera)
+{
+ /* Convert data */
+
+ double camMatr1_64d[9];
+ double camMatr2_64d[9];
+
+ double rotMatr1_64d[9];
+ double transVect1_64d[3];
+
+ double rotMatr2_64d[9];
+ double transVect2_64d[3];
+
+ icvCvt_32f_64d(camMatr1,camMatr1_64d,9);
+ icvCvt_32f_64d(camMatr2,camMatr2_64d,9);
+
+ icvCvt_32f_64d(rotMatr1,rotMatr1_64d,9);
+ icvCvt_32f_64d(transVect1,transVect1_64d,3);
+
+ rotMatr2_64d[0] = 1;
+ rotMatr2_64d[1] = 0;
+ rotMatr2_64d[2] = 0;
+ rotMatr2_64d[3] = 0;
+ rotMatr2_64d[4] = 1;
+ rotMatr2_64d[5] = 0;
+ rotMatr2_64d[6] = 0;
+ rotMatr2_64d[7] = 0;
+ rotMatr2_64d[8] = 1;
+
+ transVect2_64d[0] = 0;
+ transVect2_64d[1] = 0;
+ transVect2_64d[2] = 0;
+
+ int status = icvComputeCoeffForStereoV3( quad1,
+ quad2,
+ numScanlines,
+ camMatr1_64d,
+ rotMatr1_64d,
+ transVect1_64d,
+ camMatr2_64d,
+ rotMatr2_64d,
+ transVect2_64d,
+ startCoeffs,
+ needSwapCamera);
+
+
+ return status;
+
+}
+/*--------------------------------------------------------------------------------------*/
+int icvComputeCoeffForStereo( CvStereoCamera* stereoCamera)
+{
+ double quad1[4][2];
+ double quad2[4][2];
+
+ int i;
+ for( i = 0; i < 4; i++ )
+ {
+ quad1[i][0] = stereoCamera->quad[0][i].x;
+ quad1[i][1] = stereoCamera->quad[0][i].y;
+
+ quad2[i][0] = stereoCamera->quad[1][i].x;
+ quad2[i][1] = stereoCamera->quad[1][i].y;
+ }
+
+ icvComputeCoeffForStereoNew( quad1,
+ quad2,
+ stereoCamera->warpSize.height,
+ stereoCamera->camera[0]->matrix,
+ stereoCamera->rotMatrix,
+ stereoCamera->transVector,
+ stereoCamera->camera[1]->matrix,
+ stereoCamera->lineCoeffs,
+ &(stereoCamera->needSwapCameras));
+ return CV_OK;
+}
+
+
+
+/*--------------------------------------------------------------------------------------*/
+int icvComCoeffForLine( CvPoint2D64d point1,
+ CvPoint2D64d point2,
+ CvPoint2D64d point3,
+ CvPoint2D64d point4,
+ CvMatr64d camMatr1,
+ CvMatr64d rotMatr1,
+ CvMatr64d transVect1,
+ CvMatr64d camMatr2,
+ CvMatr64d rotMatr2,
+ CvMatr64d transVect2,
+ CvStereoLineCoeff* coeffs,
+ int* needSwapCamera)
+{
+ /* Get direction for all points */
+ /* Direction for camera 1 */
+
+ double direct1[3];
+ double direct2[3];
+ double camPoint1[3];
+
+ double directS3[3];
+ double directS4[3];
+ double direct3[3];
+ double direct4[3];
+ double camPoint2[3];
+
+ icvGetDirectionForPoint( point1,
+ camMatr1,
+ (CvPoint3D64d*)direct1);
+
+ icvGetDirectionForPoint( point2,
+ camMatr1,
+ (CvPoint3D64d*)direct2);
+
+ /* Direction for camera 2 */
+
+ icvGetDirectionForPoint( point3,
+ camMatr2,
+ (CvPoint3D64d*)directS3);
+
+ icvGetDirectionForPoint( point4,
+ camMatr2,
+ (CvPoint3D64d*)directS4);
+
+ /* Create convertion for camera 2: two direction and camera point */
+
+ double convRotMatr[9];
+ double convTransVect[3];
+
+ icvCreateConvertMatrVect( rotMatr1,
+ transVect1,
+ rotMatr2,
+ transVect2,
+ convRotMatr,
+ convTransVect);
+
+ double zeroVect[3];
+ zeroVect[0] = zeroVect[1] = zeroVect[2] = 0.0;
+ camPoint1[0] = camPoint1[1] = camPoint1[2] = 0.0;
+
+ icvConvertPointSystem(*((CvPoint3D64d*)directS3),(CvPoint3D64d*)direct3,convRotMatr,convTransVect);
+ icvConvertPointSystem(*((CvPoint3D64d*)directS4),(CvPoint3D64d*)direct4,convRotMatr,convTransVect);
+ icvConvertPointSystem(*((CvPoint3D64d*)zeroVect),(CvPoint3D64d*)camPoint2,convRotMatr,convTransVect);
+
+ double pointB[3];
+
+ int postype = 0;
+
+ /* Changed order */
+ /* Compute point B: xB,yB,zB */
+ icvGetCrossLines(*((CvPoint3D64d*)camPoint1),*((CvPoint3D64d*)direct2),
+ *((CvPoint3D64d*)camPoint2),*((CvPoint3D64d*)direct3),
+ (CvPoint3D64d*)pointB);
+
+ if( pointB[2] < 0 )/* If negative use other lines for cross */
+ {
+ postype = 1;
+ icvGetCrossLines(*((CvPoint3D64d*)camPoint1),*((CvPoint3D64d*)direct1),
+ *((CvPoint3D64d*)camPoint2),*((CvPoint3D64d*)direct4),
+ (CvPoint3D64d*)pointB);
+ }
+
+ CvPoint3D64d pointNewA;
+ CvPoint3D64d pointNewC;
+
+ pointNewA.x = pointNewA.y = pointNewA.z = 0;
+ pointNewC.x = pointNewC.y = pointNewC.z = 0;
+
+ if( postype == 0 )
+ {
+ icvGetSymPoint3D( *((CvPoint3D64d*)camPoint1),
+ *((CvPoint3D64d*)direct1),
+ *((CvPoint3D64d*)pointB),
+ &pointNewA);
+
+ icvGetSymPoint3D( *((CvPoint3D64d*)camPoint2),
+ *((CvPoint3D64d*)direct4),
+ *((CvPoint3D64d*)pointB),
+ &pointNewC);
+ }
+ else
+ {/* In this case we must change cameras */
+ *needSwapCamera = 1;
+ icvGetSymPoint3D( *((CvPoint3D64d*)camPoint2),
+ *((CvPoint3D64d*)direct3),
+ *((CvPoint3D64d*)pointB),
+ &pointNewA);
+
+ icvGetSymPoint3D( *((CvPoint3D64d*)camPoint1),
+ *((CvPoint3D64d*)direct2),
+ *((CvPoint3D64d*)pointB),
+ &pointNewC);
+ }
+
+
+ double gamma;
+
+ double x1,y1,z1;
+
+ x1 = camPoint1[0];
+ y1 = camPoint1[1];
+ z1 = camPoint1[2];
+
+ double xA,yA,zA;
+ double xB,yB,zB;
+ double xC,yC,zC;
+
+ xA = pointNewA.x;
+ yA = pointNewA.y;
+ zA = pointNewA.z;
+
+ xB = pointB[0];
+ yB = pointB[1];
+ zB = pointB[2];
+
+ xC = pointNewC.x;
+ yC = pointNewC.y;
+ zC = pointNewC.z;
+
+ double len1,len2;
+ len1 = sqrt( (xA-xB)*(xA-xB) + (yA-yB)*(yA-yB) + (zA-zB)*(zA-zB) );
+ len2 = sqrt( (xB-xC)*(xB-xC) + (yB-yC)*(yB-yC) + (zB-zC)*(zB-zC) );
+ gamma = len2 / len1;
+
+ icvComputeStereoLineCoeffs( pointNewA,
+ *((CvPoint3D64d*)pointB),
+ *((CvPoint3D64d*)camPoint1),
+ gamma,
+ coeffs);
+
+ return CV_NO_ERR;
+}
+
+
+/*--------------------------------------------------------------------------------------*/
+
+int icvGetDirectionForPoint( CvPoint2D64d point,
+ CvMatr64d camMatr,
+ CvPoint3D64d* direct)
+{
+ /* */
+ double invMatr[9];
+
+ /* Invert matrix */
+
+ icvInvertMatrix_64d(camMatr,3,invMatr);
+ /* TEST FOR ERRORS */
+
+ double vect[3];
+ vect[0] = point.x;
+ vect[1] = point.y;
+ vect[2] = 1;
+
+ /* Mul matr */
+ icvMulMatrix_64d( invMatr,
+ 3,3,
+ vect,
+ 1,3,
+ (double*)direct);
+
+ return CV_NO_ERR;
+}
+
+/*--------------------------------------------------------------------------------------*/
+
+int icvGetCrossLines(CvPoint3D64d point11,CvPoint3D64d point12,
+ CvPoint3D64d point21,CvPoint3D64d point22,
+ CvPoint3D64d* midPoint)
+{
+ double xM,yM,zM;
+ double xN,yN,zN;
+
+ double xA,yA,zA;
+ double xB,yB,zB;
+
+ double xC,yC,zC;
+ double xD,yD,zD;
+
+ xA = point11.x;
+ yA = point11.y;
+ zA = point11.z;
+
+ xB = point12.x;
+ yB = point12.y;
+ zB = point12.z;
+
+ xC = point21.x;
+ yC = point21.y;
+ zC = point21.z;
+
+ xD = point22.x;
+ yD = point22.y;
+ zD = point22.z;
+
+ double a11,a12,a21,a22;
+ double b1,b2;
+
+ a11 = (xB-xA)*(xB-xA)+(yB-yA)*(yB-yA)+(zB-zA)*(zB-zA);
+ a12 = -(xD-xC)*(xB-xA)-(yD-yC)*(yB-yA)-(zD-zC)*(zB-zA);
+ a21 = (xB-xA)*(xD-xC)+(yB-yA)*(yD-yC)+(zB-zA)*(zD-zC);
+ a22 = -(xD-xC)*(xD-xC)-(yD-yC)*(yD-yC)-(zD-zC)*(zD-zC);
+ b1 = -( (xA-xC)*(xB-xA)+(yA-yC)*(yB-yA)+(zA-zC)*(zB-zA) );
+ b2 = -( (xA-xC)*(xD-xC)+(yA-yC)*(yD-yC)+(zA-zC)*(zD-zC) );
+
+ double delta;
+ double deltaA,deltaB;
+ double alpha,betta;
+
+ delta = a11*a22-a12*a21;
+
+ if( fabs(delta) < EPS64D )
+ {
+ /*return ERROR;*/
+ }
+
+ deltaA = b1*a22-b2*a12;
+ deltaB = a11*b2-b1*a21;
+
+ alpha = deltaA / delta;
+ betta = deltaB / delta;
+
+ xM = xA+alpha*(xB-xA);
+ yM = yA+alpha*(yB-yA);
+ zM = zA+alpha*(zB-zA);
+
+ xN = xC+betta*(xD-xC);
+ yN = yC+betta*(yD-yC);
+ zN = zC+betta*(zD-zC);
+
+ /* Compute middle point */
+ midPoint->x = (xM + xN) * 0.5;
+ midPoint->y = (yM + yN) * 0.5;
+ midPoint->z = (zM + zN) * 0.5;
+
+ return CV_NO_ERR;
+}
+
+/*--------------------------------------------------------------------------------------*/
+
+int icvComputeStereoLineCoeffs( CvPoint3D64d pointA,
+ CvPoint3D64d pointB,
+ CvPoint3D64d pointCam1,
+ double gamma,
+ CvStereoLineCoeff* coeffs)
+{
+ double x1,y1,z1;
+
+ x1 = pointCam1.x;
+ y1 = pointCam1.y;
+ z1 = pointCam1.z;
+
+ double xA,yA,zA;
+ double xB,yB,zB;
+
+ xA = pointA.x;
+ yA = pointA.y;
+ zA = pointA.z;
+
+ xB = pointB.x;
+ yB = pointB.y;
+ zB = pointB.z;
+
+ if( gamma > 0 )
+ {
+ coeffs->Xcoef = -x1 + xA;
+ coeffs->XcoefA = xB + x1 - xA;
+ coeffs->XcoefB = -xA - gamma * x1 + gamma * xA;
+ coeffs->XcoefAB = -xB + xA + gamma * xB - gamma * xA;
+
+ coeffs->Ycoef = -y1 + yA;
+ coeffs->YcoefA = yB + y1 - yA;
+ coeffs->YcoefB = -yA - gamma * y1 + gamma * yA;
+ coeffs->YcoefAB = -yB + yA + gamma * yB - gamma * yA;
+
+ coeffs->Zcoef = -z1 + zA;
+ coeffs->ZcoefA = zB + z1 - zA;
+ coeffs->ZcoefB = -zA - gamma * z1 + gamma * zA;
+ coeffs->ZcoefAB = -zB + zA + gamma * zB - gamma * zA;
+ }
+ else
+ {
+ gamma = - gamma;
+ coeffs->Xcoef = -( -x1 + xA);
+ coeffs->XcoefB = -( xB + x1 - xA);
+ coeffs->XcoefA = -( -xA - gamma * x1 + gamma * xA);
+ coeffs->XcoefAB = -( -xB + xA + gamma * xB - gamma * xA);
+
+ coeffs->Ycoef = -( -y1 + yA);
+ coeffs->YcoefB = -( yB + y1 - yA);
+ coeffs->YcoefA = -( -yA - gamma * y1 + gamma * yA);
+ coeffs->YcoefAB = -( -yB + yA + gamma * yB - gamma * yA);
+
+ coeffs->Zcoef = -( -z1 + zA);
+ coeffs->ZcoefB = -( zB + z1 - zA);
+ coeffs->ZcoefA = -( -zA - gamma * z1 + gamma * zA);
+ coeffs->ZcoefAB = -( -zB + zA + gamma * zB - gamma * zA);
+ }
+
+
+
+ return CV_NO_ERR;
+}
+/*--------------------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------------------*/
+
+/* This function get minimum angle started at point which contains rect */
+int icvGetAngleLine( CvPoint2D64d startPoint, CvSize imageSize,CvPoint2D64d *point1,CvPoint2D64d *point2)
+{
+ /* Get crosslines with image corners */
+
+ /* Find four lines */
+
+ CvPoint2D64d pa,pb,pc,pd;
+
+ pa.x = 0;
+ pa.y = 0;
+
+ pb.x = imageSize.width-1;
+ pb.y = 0;
+
+ pd.x = imageSize.width-1;
+ pd.y = imageSize.height-1;
+
+ pc.x = 0;
+ pc.y = imageSize.height-1;
+
+ /* We can compute points for angle */
+ /* Test for place section */
+
+ if( startPoint.x < 0 )
+ {/* 1,4,7 */
+ if( startPoint.y < 0)
+ {/* 1 */
+ *point1 = pb;
+ *point2 = pc;
+ }
+ else if( startPoint.y > imageSize.height-1 )
+ {/* 7 */
+ *point1 = pa;
+ *point2 = pd;
+ }
+ else
+ {/* 4 */
+ *point1 = pa;
+ *point2 = pc;
+ }
+ }
+ else if ( startPoint.x > imageSize.width-1 )
+ {/* 3,6,9 */
+ if( startPoint.y < 0 )
+ {/* 3 */
+ *point1 = pa;
+ *point2 = pd;
+ }
+ else if ( startPoint.y > imageSize.height-1 )
+ {/* 9 */
+ *point1 = pb;
+ *point2 = pc;
+ }
+ else
+ {/* 6 */
+ *point1 = pb;
+ *point2 = pd;
+ }
+ }
+ else
+ {/* 2,5,8 */
+ if( startPoint.y < 0 )
+ {/* 2 */
+ if( startPoint.x < imageSize.width/2 )
+ {
+ *point1 = pb;
+ *point2 = pa;
+ }
+ else
+ {
+ *point1 = pa;
+ *point2 = pb;
+ }
+ }
+ else if( startPoint.y > imageSize.height-1 )
+ {/* 8 */
+ if( startPoint.x < imageSize.width/2 )
+ {
+ *point1 = pc;
+ *point2 = pd;
+ }
+ else
+ {
+ *point1 = pd;
+ *point2 = pc;
+ }
+ }
+ else
+ {/* 5 - point in the image */
+ return 2;
+ }
+ }
+ return 0;
+}/* GetAngleLine */
+
+/*---------------------------------------------------------------------------------------*/
+
+void icvGetCoefForPiece( CvPoint2D64d p_start,CvPoint2D64d p_end,
+ double *a,double *b,double *c,
+ int* result)
+{
+ double det;
+ double detA,detB,detC;
+
+ det = p_start.x*p_end.y+p_end.x+p_start.y-p_end.y-p_start.y*p_end.x-p_start.x;
+ if( fabs(det) < EPS64D)/* Error */
+ {
+ *result = 0;
+ return;
+ }
+
+ detA = p_start.y - p_end.y;
+ detB = p_end.x - p_start.x;
+ detC = p_start.x*p_end.y - p_end.x*p_start.y;
+
+ double invDet = 1.0 / det;
+ *a = detA * invDet;
+ *b = detB * invDet;
+ *c = detC * invDet;
+
+ *result = 1;
+ return;
+}
+
+/*---------------------------------------------------------------------------------------*/
+
+/* Get common area of rectifying */
+void icvGetCommonArea( CvSize imageSize,
+ CvPoint3D64d epipole1,CvPoint3D64d epipole2,
+ CvMatr64d fundMatr,
+ CvVect64d coeff11,CvVect64d coeff12,
+ CvVect64d coeff21,CvVect64d coeff22,
+ int* result)
+{
+ int res = 0;
+ CvPoint2D64d point11;
+ CvPoint2D64d point12;
+ CvPoint2D64d point21;
+ CvPoint2D64d point22;
+
+ double corr11[3];
+ double corr12[3];
+ double corr21[3];
+ double corr22[3];
+
+ double pointW11[3];
+ double pointW12[3];
+ double pointW21[3];
+ double pointW22[3];
+
+ double transFundMatr[3*3];
+ /* Compute transpose of fundamental matrix */
+ icvTransposeMatrix_64d( fundMatr, 3, 3, transFundMatr );
+
+ CvPoint2D64d epipole1_2d;
+ CvPoint2D64d epipole2_2d;
+
+ if( fabs(epipole1.z) < 1e-8 )
+ {/* epipole1 in infinity */
+ *result = 0;
+ return;
+ }
+ epipole1_2d.x = epipole1.x / epipole1.z;
+ epipole1_2d.y = epipole1.y / epipole1.z;
+
+ if( fabs(epipole2.z) < 1e-8 )
+ {/* epipole2 in infinity */
+ *result = 0;
+ return;
+ }
+ epipole2_2d.x = epipole2.x / epipole2.z;
+ epipole2_2d.y = epipole2.y / epipole2.z;
+
+ int stat = icvGetAngleLine( epipole1_2d, imageSize,&point11,&point12);
+ if( stat == 2 )
+ {
+ /* No angle */
+ *result = 0;
+ return;
+ }
+
+ stat = icvGetAngleLine( epipole2_2d, imageSize,&point21,&point22);
+ if( stat == 2 )
+ {
+ /* No angle */
+ *result = 0;
+ return;
+ }
+
+ /* ============= Computation for line 1 ================ */
+ /* Find correspondence line for angle points11 */
+ /* corr21 = Fund'*p1 */
+
+ pointW11[0] = point11.x;
+ pointW11[1] = point11.y;
+ pointW11[2] = 1.0;
+
+ icvTransformVector_64d( transFundMatr, /* !!! Modified from not transposed */
+ pointW11,
+ corr21,
+ 3,3);
+
+ /* Find crossing of line with image 2 */
+ CvPoint2D64d start;
+ CvPoint2D64d end;
+ icvGetCrossRectDirect( imageSize,
+ corr21[0],corr21[1],corr21[2],
+ &start,&end,
+ &res);
+
+ if( res == 0 )
+ {/* We have not cross */
+ /* We must define new angle */
+
+ pointW21[0] = point21.x;
+ pointW21[1] = point21.y;
+ pointW21[2] = 1.0;
+
+ /* Find correspondence line for this angle points */
+ /* We know point and try to get corr line */
+ /* For point21 */
+ /* corr11 = Fund * p21 */
+
+ icvTransformVector_64d( fundMatr, /* !!! Modified */
+ pointW21,
+ corr11,
+ 3,3);
+
+ /* We have cross. And it's result cross for up line. Set result coefs */
+
+ /* Set coefs for line 1 image 1 */
+ coeff11[0] = corr11[0];
+ coeff11[1] = corr11[1];
+ coeff11[2] = corr11[2];
+
+ /* Set coefs for line 1 image 2 */
+ icvGetCoefForPiece( epipole2_2d,point21,
+ &coeff21[0],&coeff21[1],&coeff21[2],
+ &res);
+ if( res == 0 )
+ {
+ *result = 0;
+ return;/* Error */
+ }
+ }
+ else
+ {/* Line 1 cross image 2 */
+ /* Set coefs for line 1 image 1 */
+ icvGetCoefForPiece( epipole1_2d,point11,
+ &coeff11[0],&coeff11[1],&coeff11[2],
+ &res);
+ if( res == 0 )
+ {
+ *result = 0;
+ return;/* Error */
+ }
+
+ /* Set coefs for line 1 image 2 */
+ coeff21[0] = corr21[0];
+ coeff21[1] = corr21[1];
+ coeff21[2] = corr21[2];
+
+ }
+
+ /* ============= Computation for line 2 ================ */
+ /* Find correspondence line for angle points11 */
+ /* corr22 = Fund*p2 */
+
+ pointW12[0] = point12.x;
+ pointW12[1] = point12.y;
+ pointW12[2] = 1.0;
+
+ icvTransformVector_64d( transFundMatr,
+ pointW12,
+ corr22,
+ 3,3);
+
+ /* Find crossing of line with image 2 */
+ icvGetCrossRectDirect( imageSize,
+ corr22[0],corr22[1],corr22[2],
+ &start,&end,
+ &res);
+
+ if( res == 0 )
+ {/* We have not cross */
+ /* We must define new angle */
+
+ pointW22[0] = point22.x;
+ pointW22[1] = point22.y;
+ pointW22[2] = 1.0;
+
+ /* Find correspondence line for this angle points */
+ /* We know point and try to get corr line */
+ /* For point21 */
+ /* corr2 = Fund' * p1 */
+
+ icvTransformVector_64d( fundMatr,
+ pointW22,
+ corr12,
+ 3,3);
+
+
+ /* We have cross. And it's result cross for down line. Set result coefs */
+
+ /* Set coefs for line 2 image 1 */
+ coeff12[0] = corr12[0];
+ coeff12[1] = corr12[1];
+ coeff12[2] = corr12[2];
+
+ /* Set coefs for line 1 image 2 */
+ icvGetCoefForPiece( epipole2_2d,point22,
+ &coeff22[0],&coeff22[1],&coeff22[2],
+ &res);
+ if( res == 0 )
+ {
+ *result = 0;
+ return;/* Error */
+ }
+ }
+ else
+ {/* Line 2 cross image 2 */
+ /* Set coefs for line 2 image 1 */
+ icvGetCoefForPiece( epipole1_2d,point12,
+ &coeff12[0],&coeff12[1],&coeff12[2],
+ &res);
+ if( res == 0 )
+ {
+ *result = 0;
+ return;/* Error */
+ }
+
+ /* Set coefs for line 1 image 2 */
+ coeff22[0] = corr22[0];
+ coeff22[1] = corr22[1];
+ coeff22[2] = corr22[2];
+
+ }
+
+ /* Now we know common area */
+
+ return;
+
+}/* GetCommonArea */
+
+/*---------------------------------------------------------------------------------------*/
+
+/* Get cross for direction1 and direction2 */
+/* Result = 1 - cross */
+/* Result = 2 - parallel and not equal */
+/* Result = 3 - parallel and equal */
+
+void icvGetCrossDirectDirect( CvVect64d direct1,CvVect64d direct2,
+ CvPoint2D64d *cross,int* result)
+{
+ double det = direct1[0]*direct2[1] - direct2[0]*direct1[1];
+ double detx = -direct1[2]*direct2[1] + direct1[1]*direct2[2];
+
+ if( fabs(det) > EPS64D )
+ {/* Have cross */
+ cross->x = detx/det;
+ cross->y = (-direct1[0]*direct2[2] + direct2[0]*direct1[2])/det;
+ *result = 1;
+ }
+ else
+ {/* may be parallel */
+ if( fabs(detx) > EPS64D )
+ {/* parallel and not equal */
+ *result = 2;
+ }
+ else
+ {/* equals */
+ *result = 3;
+ }
+ }
+
+ return;
+}
+
+/*---------------------------------------------------------------------------------------*/
+
+/* Get cross for piece p1,p2 and direction a,b,c */
+/* Result = 0 - no cross */
+/* Result = 1 - cross */
+/* Result = 2 - parallel and not equal */
+/* Result = 3 - parallel and equal */
+
+void icvGetCrossPieceDirect( CvPoint2D64d p_start,CvPoint2D64d p_end,
+ double a,double b,double c,
+ CvPoint2D64d *cross,int* result)
+{
+
+ if( (a*p_start.x + b*p_start.y + c) * (a*p_end.x + b*p_end.y + c) <= 0 )
+ {/* Have cross */
+ double det;
+ double detxc,detyc;
+
+ det = a * (p_end.x - p_start.x) + b * (p_end.y - p_start.y);
+
+ if( fabs(det) < EPS64D )
+ {/* lines are parallel and may be equal or line is point */
+ if( fabs(a*p_start.x + b*p_start.y + c) < EPS64D )
+ {/* line is point or not diff */
+ *result = 3;
+ return;
+ }
+ else
+ {
+ *result = 2;
+ }
+ return;
+ }
+
+ detxc = b*(p_end.y*p_start.x - p_start.y*p_end.x) + c*(p_start.x - p_end.x);
+ detyc = a*(p_end.x*p_start.y - p_start.x*p_end.y) + c*(p_start.y - p_end.y);
+
+ cross->x = detxc / det;
+ cross->y = detyc / det;
+ *result = 1;
+
+ }
+ else
+ {
+ *result = 0;
+ }
+ return;
+}
+/*--------------------------------------------------------------------------------------*/
+
+void icvGetCrossPiecePiece( CvPoint2D64d p1_start,CvPoint2D64d p1_end,
+ CvPoint2D64d p2_start,CvPoint2D64d p2_end,
+ CvPoint2D64d* cross,
+ int* result)
+{
+ double ex1,ey1,ex2,ey2;
+ double px1,py1,px2,py2;
+ double del;
+ double delA,delB,delX,delY;
+ double alpha,betta;
+
+ ex1 = p1_start.x;
+ ey1 = p1_start.y;
+ ex2 = p1_end.x;
+ ey2 = p1_end.y;
+
+ px1 = p2_start.x;
+ py1 = p2_start.y;
+ px2 = p2_end.x;
+ py2 = p2_end.y;
+
+ del = (py1-py2)*(ex1-ex2)-(px1-px2)*(ey1-ey2);
+ if( fabs(del) <= EPS64D )
+ {/* May be they are parallel !!! */
+ *result = 0;
+ return;
+ }
+
+ delA = (ey1-ey2)*(ex1-px1) + (ex1-ex2)*(py1-ey1);
+ delB = (py1-py2)*(ex1-px1) + (px1-px2)*(py1-ey1);
+
+ alpha = delA / del;
+ betta = delB / del;
+
+ if( alpha < 0 || alpha > 1.0 || betta < 0 || betta > 1.0)
+ {
+ *result = 0;
+ return;
+ }
+
+ delX = (px1-px2)*(ey1*(ex1-ex2)-ex1*(ey1-ey2))+
+ (ex1-ex2)*(px1*(py1-py2)-py1*(px1-px2));
+
+ delY = (py1-py2)*(ey1*(ex1-ex2)-ex1*(ey1-ey2))+
+ (ey1-ey2)*(px1*(py1-py2)-py1*(px1-px2));
+
+ cross->x = delX / del;
+ cross->y = delY / del;
+
+ *result = 1;
+ return;
+}
+
+
+/*---------------------------------------------------------------------------------------*/
+
+void icvGetPieceLength(CvPoint2D64d point1,CvPoint2D64d point2,double* dist)
+{
+ double dx = point2.x - point1.x;
+ double dy = point2.y - point1.y;
+ *dist = sqrt( dx*dx + dy*dy );
+ return;
+}
+
+/*---------------------------------------------------------------------------------------*/
+
+void icvGetPieceLength3D(CvPoint3D64d point1,CvPoint3D64d point2,double* dist)
+{
+ double dx = point2.x - point1.x;
+ double dy = point2.y - point1.y;
+ double dz = point2.z - point1.z;
+ *dist = sqrt( dx*dx + dy*dy + dz*dz );
+ return;
+}
+
+/*---------------------------------------------------------------------------------------*/
+
+/* Find line from epipole which cross image rect */
+/* Find points of cross 0 or 1 or 2. Return number of points in cross */
+void icvGetCrossRectDirect( CvSize imageSize,
+ double a,double b,double c,
+ CvPoint2D64d *start,CvPoint2D64d *end,
+ int* result)
+{
+ CvPoint2D64d frameBeg;
+ CvPoint2D64d frameEnd;
+ CvPoint2D64d cross[4];
+ int haveCross[4];
+
+ haveCross[0] = 0;
+ haveCross[1] = 0;
+ haveCross[2] = 0;
+ haveCross[3] = 0;
+
+ frameBeg.x = 0;
+ frameBeg.y = 0;
+ frameEnd.x = imageSize.width;
+ frameEnd.y = 0;
+
+ icvGetCrossPieceDirect(frameBeg,frameEnd,a,b,c,&cross[0],&haveCross[0]);
+
+ frameBeg.x = imageSize.width;
+ frameBeg.y = 0;
+ frameEnd.x = imageSize.width;
+ frameEnd.y = imageSize.height;
+ icvGetCrossPieceDirect(frameBeg,frameEnd,a,b,c,&cross[1],&haveCross[1]);
+
+ frameBeg.x = imageSize.width;
+ frameBeg.y = imageSize.height;
+ frameEnd.x = 0;
+ frameEnd.y = imageSize.height;
+ icvGetCrossPieceDirect(frameBeg,frameEnd,a,b,c,&cross[2],&haveCross[2]);
+
+ frameBeg.x = 0;
+ frameBeg.y = imageSize.height;
+ frameEnd.x = 0;
+ frameEnd.y = 0;
+ icvGetCrossPieceDirect(frameBeg,frameEnd,a,b,c,&cross[3],&haveCross[3]);
+
+ double maxDist;
+
+ int maxI=0,maxJ=0;
+
+
+ int i,j;
+
+ maxDist = -1.0;
+
+ double distance;
+
+ for( i = 0; i < 3; i++ )
+ {
+ if( haveCross[i] == 1 )
+ {
+ for( j = i + 1; j < 4; j++ )
+ {
+ if( haveCross[j] == 1)
+ {/* Compute dist */
+ icvGetPieceLength(cross[i],cross[j],&distance);
+ if( distance > maxDist )
+ {
+ maxI = i;
+ maxJ = j;
+ maxDist = distance;
+ }
+ }
+ }
+ }
+ }
+
+ if( maxDist >= 0 )
+ {/* We have cross */
+ *start = cross[maxI];
+ *result = 1;
+ if( maxDist > 0 )
+ {
+ *end = cross[maxJ];
+ *result = 2;
+ }
+ }
+ else
+ {
+ *result = 0;
+ }
+
+ return;
+}/* GetCrossRectDirect */
+
+/*---------------------------------------------------------------------------------------*/
+void icvProjectPointToImage( CvPoint3D64d point,
+ CvMatr64d camMatr,CvMatr64d rotMatr,CvVect64d transVect,
+ CvPoint2D64d* projPoint)
+{
+
+ double tmpVect1[3];
+ double tmpVect2[3];
+
+ icvMulMatrix_64d ( rotMatr,
+ 3,3,
+ (double*)&point,
+ 1,3,
+ tmpVect1);
+
+ icvAddVector_64d ( tmpVect1, transVect,tmpVect2, 3);
+
+ icvMulMatrix_64d ( camMatr,
+ 3,3,
+ tmpVect2,
+ 1,3,
+ tmpVect1);
+
+ projPoint->x = tmpVect1[0] / tmpVect1[2];
+ projPoint->y = tmpVect1[1] / tmpVect1[2];
+
+ return;
+}
+
+/*---------------------------------------------------------------------------------------*/
+/* Get quads for transform images */
+void icvGetQuadsTransform(
+ CvSize imageSize,
+ CvMatr64d camMatr1,
+ CvMatr64d rotMatr1,
+ CvVect64d transVect1,
+ CvMatr64d camMatr2,
+ CvMatr64d rotMatr2,
+ CvVect64d transVect2,
+ CvSize* warpSize,
+ double quad1[4][2],
+ double quad2[4][2],
+ CvMatr64d fundMatr,
+ CvPoint3D64d* epipole1,
+ CvPoint3D64d* epipole2
+ )
+{
+ /* First compute fundamental matrix and epipoles */
+ int res;
+
+
+ /* Compute epipoles and fundamental matrix using new functions */
+ {
+ double convRotMatr[9];
+ double convTransVect[3];
+
+ icvCreateConvertMatrVect( rotMatr1,
+ transVect1,
+ rotMatr2,
+ transVect2,
+ convRotMatr,
+ convTransVect);
+ float convRotMatr_32f[9];
+ float convTransVect_32f[3];
+
+ icvCvt_64d_32f(convRotMatr,convRotMatr_32f,9);
+ icvCvt_64d_32f(convTransVect,convTransVect_32f,3);
+
+ /* We know R and t */
+ /* Compute essential matrix */
+ float essMatr[9];
+ float fundMatr_32f[9];
+
+ float camMatr1_32f[9];
+ float camMatr2_32f[9];
+
+ icvCvt_64d_32f(camMatr1,camMatr1_32f,9);
+ icvCvt_64d_32f(camMatr2,camMatr2_32f,9);
+
+ cvComputeEssentialMatrix( convRotMatr_32f,
+ convTransVect_32f,
+ essMatr);
+
+ cvConvertEssential2Fundamental( essMatr,
+ fundMatr_32f,
+ camMatr1_32f,
+ camMatr2_32f);
+
+ CvPoint3D32f epipole1_32f;
+ CvPoint3D32f epipole2_32f;
+
+ cvComputeEpipolesFromFundMatrix( fundMatr_32f,
+ &epipole1_32f,
+ &epipole2_32f);
+ /* copy to 64d epipoles */
+ epipole1->x = epipole1_32f.x;
+ epipole1->y = epipole1_32f.y;
+ epipole1->z = epipole1_32f.z;
+
+ epipole2->x = epipole2_32f.x;
+ epipole2->y = epipole2_32f.y;
+ epipole2->z = epipole2_32f.z;
+
+ /* Convert fundamental matrix */
+ icvCvt_32f_64d(fundMatr_32f,fundMatr,9);
+ }
+
+ double coeff11[3];
+ double coeff12[3];
+ double coeff21[3];
+ double coeff22[3];
+
+ icvGetCommonArea( imageSize,
+ *epipole1,*epipole2,
+ fundMatr,
+ coeff11,coeff12,
+ coeff21,coeff22,
+ &res);
+
+ CvPoint2D64d point11, point12,point21, point22;
+ double width1,width2;
+ double height1,height2;
+ double tmpHeight1,tmpHeight2;
+
+ CvPoint2D64d epipole1_2d;
+ CvPoint2D64d epipole2_2d;
+
+ /* ----- Image 1 ----- */
+ if( fabs(epipole1->z) < 1e-8 )
+ {
+ return;
+ }
+ epipole1_2d.x = epipole1->x / epipole1->z;
+ epipole1_2d.y = epipole1->y / epipole1->z;
+
+ icvGetCutPiece( coeff11,coeff12,
+ epipole1_2d,
+ imageSize,
+ &point11,&point12,
+ &point21,&point22,
+ &res);
+
+ /* Compute distance */
+ icvGetPieceLength(point11,point21,&width1);
+ icvGetPieceLength(point11,point12,&tmpHeight1);
+ icvGetPieceLength(point21,point22,&tmpHeight2);
+ height1 = MAX(tmpHeight1,tmpHeight2);
+
+ quad1[0][0] = point11.x;
+ quad1[0][1] = point11.y;
+
+ quad1[1][0] = point21.x;
+ quad1[1][1] = point21.y;
+
+ quad1[2][0] = point22.x;
+ quad1[2][1] = point22.y;
+
+ quad1[3][0] = point12.x;
+ quad1[3][1] = point12.y;
+
+ /* ----- Image 2 ----- */
+ if( fabs(epipole2->z) < 1e-8 )
+ {
+ return;
+ }
+ epipole2_2d.x = epipole2->x / epipole2->z;
+ epipole2_2d.y = epipole2->y / epipole2->z;
+
+ icvGetCutPiece( coeff21,coeff22,
+ epipole2_2d,
+ imageSize,
+ &point11,&point12,
+ &point21,&point22,
+ &res);
+
+ /* Compute distance */
+ icvGetPieceLength(point11,point21,&width2);
+ icvGetPieceLength(point11,point12,&tmpHeight1);
+ icvGetPieceLength(point21,point22,&tmpHeight2);
+ height2 = MAX(tmpHeight1,tmpHeight2);
+
+ quad2[0][0] = point11.x;
+ quad2[0][1] = point11.y;
+
+ quad2[1][0] = point21.x;
+ quad2[1][1] = point21.y;
+
+ quad2[2][0] = point22.x;
+ quad2[2][1] = point22.y;
+
+ quad2[3][0] = point12.x;
+ quad2[3][1] = point12.y;
+
+
+ /*=======================================================*/
+ /* This is a new additional way to compute quads. */
+ /* We must correct quads */
+ {
+ double convRotMatr[9];
+ double convTransVect[3];
+
+ double newQuad1[4][2];
+ double newQuad2[4][2];
+
+
+ icvCreateConvertMatrVect( rotMatr1,
+ transVect1,
+ rotMatr2,
+ transVect2,
+ convRotMatr,
+ convTransVect);
+
+ /* -------------Compute for first image-------------- */
+ CvPoint2D32f pointb1;
+ CvPoint2D32f pointe1;
+
+ CvPoint2D32f pointb2;
+ CvPoint2D32f pointe2;
+
+ pointb1.x = (float)quad1[0][0];
+ pointb1.y = (float)quad1[0][1];
+
+ pointe1.x = (float)quad1[3][0];
+ pointe1.y = (float)quad1[3][1];
+
+ icvComputeeInfiniteProject1(convRotMatr,
+ camMatr1,
+ camMatr2,
+ pointb1,
+ &pointb2);
+
+ icvComputeeInfiniteProject1(convRotMatr,
+ camMatr1,
+ camMatr2,
+ pointe1,
+ &pointe2);
+
+ /* JUST TEST FOR POINT */
+
+ /* Compute distances */
+ double dxOld,dyOld;
+ double dxNew,dyNew;
+ double distOld,distNew;
+
+ dxOld = quad2[1][0] - quad2[0][0];
+ dyOld = quad2[1][1] - quad2[0][1];
+ distOld = dxOld*dxOld + dyOld*dyOld;
+
+ dxNew = quad2[1][0] - pointb2.x;
+ dyNew = quad2[1][1] - pointb2.y;
+ distNew = dxNew*dxNew + dyNew*dyNew;
+
+ if( distNew > distOld )
+ {/* Get new points for second quad */
+ newQuad2[0][0] = pointb2.x;
+ newQuad2[0][1] = pointb2.y;
+ newQuad2[3][0] = pointe2.x;
+ newQuad2[3][1] = pointe2.y;
+ newQuad1[0][0] = quad1[0][0];
+ newQuad1[0][1] = quad1[0][1];
+ newQuad1[3][0] = quad1[3][0];
+ newQuad1[3][1] = quad1[3][1];
+ }
+ else
+ {/* Get new points for first quad */
+
+ pointb2.x = (float)quad2[0][0];
+ pointb2.y = (float)quad2[0][1];
+
+ pointe2.x = (float)quad2[3][0];
+ pointe2.y = (float)quad2[3][1];
+
+ icvComputeeInfiniteProject2(convRotMatr,
+ camMatr1,
+ camMatr2,
+ &pointb1,
+ pointb2);
+
+ icvComputeeInfiniteProject2(convRotMatr,
+ camMatr1,
+ camMatr2,
+ &pointe1,
+ pointe2);
+
+
+ /* JUST TEST FOR POINT */
+
+ newQuad2[0][0] = quad2[0][0];
+ newQuad2[0][1] = quad2[0][1];
+ newQuad2[3][0] = quad2[3][0];
+ newQuad2[3][1] = quad2[3][1];
+
+ newQuad1[0][0] = pointb1.x;
+ newQuad1[0][1] = pointb1.y;
+ newQuad1[3][0] = pointe1.x;
+ newQuad1[3][1] = pointe1.y;
+ }
+
+ /* -------------Compute for second image-------------- */
+ pointb1.x = (float)quad1[1][0];
+ pointb1.y = (float)quad1[1][1];
+
+ pointe1.x = (float)quad1[2][0];
+ pointe1.y = (float)quad1[2][1];
+
+ icvComputeeInfiniteProject1(convRotMatr,
+ camMatr1,
+ camMatr2,
+ pointb1,
+ &pointb2);
+
+ icvComputeeInfiniteProject1(convRotMatr,
+ camMatr1,
+ camMatr2,
+ pointe1,
+ &pointe2);
+
+ /* Compute distances */
+
+ dxOld = quad2[0][0] - quad2[1][0];
+ dyOld = quad2[0][1] - quad2[1][1];
+ distOld = dxOld*dxOld + dyOld*dyOld;
+
+ dxNew = quad2[0][0] - pointb2.x;
+ dyNew = quad2[0][1] - pointb2.y;
+ distNew = dxNew*dxNew + dyNew*dyNew;
+
+ if( distNew > distOld )
+ {/* Get new points for second quad */
+ newQuad2[1][0] = pointb2.x;
+ newQuad2[1][1] = pointb2.y;
+ newQuad2[2][0] = pointe2.x;
+ newQuad2[2][1] = pointe2.y;
+ newQuad1[1][0] = quad1[1][0];
+ newQuad1[1][1] = quad1[1][1];
+ newQuad1[2][0] = quad1[2][0];
+ newQuad1[2][1] = quad1[2][1];
+ }
+ else
+ {/* Get new points for first quad */
+
+ pointb2.x = (float)quad2[1][0];
+ pointb2.y = (float)quad2[1][1];
+
+ pointe2.x = (float)quad2[2][0];
+ pointe2.y = (float)quad2[2][1];
+
+ icvComputeeInfiniteProject2(convRotMatr,
+ camMatr1,
+ camMatr2,
+ &pointb1,
+ pointb2);
+
+ icvComputeeInfiniteProject2(convRotMatr,
+ camMatr1,
+ camMatr2,
+ &pointe1,
+ pointe2);
+
+ newQuad2[1][0] = quad2[1][0];
+ newQuad2[1][1] = quad2[1][1];
+ newQuad2[2][0] = quad2[2][0];
+ newQuad2[2][1] = quad2[2][1];
+
+ newQuad1[1][0] = pointb1.x;
+ newQuad1[1][1] = pointb1.y;
+ newQuad1[2][0] = pointe1.x;
+ newQuad1[2][1] = pointe1.y;
+ }
+
+
+
+/*-------------------------------------------------------------------------------*/
+
+ /* Copy new quads to old quad */
+ int i;
+ for( i = 0; i < 4; i++ )
+ {
+ {
+ quad1[i][0] = newQuad1[i][0];
+ quad1[i][1] = newQuad1[i][1];
+ quad2[i][0] = newQuad2[i][0];
+ quad2[i][1] = newQuad2[i][1];
+ }
+ }
+ }
+ /*=======================================================*/
+
+ double warpWidth,warpHeight;
+
+ warpWidth = MAX(width1,width2);
+ warpHeight = MAX(height1,height2);
+
+ warpSize->width = (int)warpWidth;
+ warpSize->height = (int)warpHeight;
+
+ warpSize->width = cvRound(warpWidth-1);
+ warpSize->height = cvRound(warpHeight-1);
+
+/* !!! by Valery Mosyagin. this lines added just for test no warp */
+ warpSize->width = imageSize.width;
+ warpSize->height = imageSize.height;
+
+ return;
+}
+
+
+/*---------------------------------------------------------------------------------------*/
+
+void icvGetQuadsTransformNew( CvSize imageSize,
+ CvMatr32f camMatr1,
+ CvMatr32f camMatr2,
+ CvMatr32f rotMatr1,
+ CvVect32f transVect1,
+ CvSize* warpSize,
+ double quad1[4][2],
+ double quad2[4][2],
+ CvMatr32f fundMatr,
+ CvPoint3D32f* epipole1,
+ CvPoint3D32f* epipole2
+ )
+{
+ /* Convert data */
+ /* Convert camera matrix */
+ double camMatr1_64d[9];
+ double camMatr2_64d[9];
+ double rotMatr1_64d[9];
+ double transVect1_64d[3];
+ double rotMatr2_64d[9];
+ double transVect2_64d[3];
+ double fundMatr_64d[9];
+ CvPoint3D64d epipole1_64d;
+ CvPoint3D64d epipole2_64d;
+
+ icvCvt_32f_64d(camMatr1,camMatr1_64d,9);
+ icvCvt_32f_64d(camMatr2,camMatr2_64d,9);
+ icvCvt_32f_64d(rotMatr1,rotMatr1_64d,9);
+ icvCvt_32f_64d(transVect1,transVect1_64d,3);
+
+ /* Create vector and matrix */
+
+ rotMatr2_64d[0] = 1;
+ rotMatr2_64d[1] = 0;
+ rotMatr2_64d[2] = 0;
+ rotMatr2_64d[3] = 0;
+ rotMatr2_64d[4] = 1;
+ rotMatr2_64d[5] = 0;
+ rotMatr2_64d[6] = 0;
+ rotMatr2_64d[7] = 0;
+ rotMatr2_64d[8] = 1;
+
+ transVect2_64d[0] = 0;
+ transVect2_64d[1] = 0;
+ transVect2_64d[2] = 0;
+
+ icvGetQuadsTransform( imageSize,
+ camMatr1_64d,
+ rotMatr1_64d,
+ transVect1_64d,
+ camMatr2_64d,
+ rotMatr2_64d,
+ transVect2_64d,
+ warpSize,
+ quad1,
+ quad2,
+ fundMatr_64d,
+ &epipole1_64d,
+ &epipole2_64d
+ );
+
+ /* Convert epipoles */
+ epipole1->x = (float)(epipole1_64d.x);
+ epipole1->y = (float)(epipole1_64d.y);
+ epipole1->z = (float)(epipole1_64d.z);
+
+ epipole2->x = (float)(epipole2_64d.x);
+ epipole2->y = (float)(epipole2_64d.y);
+ epipole2->z = (float)(epipole2_64d.z);
+
+ /* Convert fundamental matrix */
+ icvCvt_64d_32f(fundMatr_64d,fundMatr,9);
+
+ return;
+}
+
+/*---------------------------------------------------------------------------------------*/
+void icvGetQuadsTransformStruct( CvStereoCamera* stereoCamera)
+{
+ /* Wrapper for icvGetQuadsTransformNew */
+
+
+ double quad1[4][2];
+ double quad2[4][2];
+
+ icvGetQuadsTransformNew( cvSize(cvRound(stereoCamera->camera[0]->imgSize[0]),cvRound(stereoCamera->camera[0]->imgSize[1])),
+ stereoCamera->camera[0]->matrix,
+ stereoCamera->camera[1]->matrix,
+ stereoCamera->rotMatrix,
+ stereoCamera->transVector,
+ &(stereoCamera->warpSize),
+ quad1,
+ quad2,
+ stereoCamera->fundMatr,
+ &(stereoCamera->epipole[0]),
+ &(stereoCamera->epipole[1])
+ );
+
+ int i;
+ for( i = 0; i < 4; i++ )
+ {
+ stereoCamera->quad[0][i] = cvPoint2D32f(quad1[i][0],quad1[i][1]);
+ stereoCamera->quad[1][i] = cvPoint2D32f(quad2[i][0],quad2[i][1]);
+ }
+
+ return;
+}
+
+/*---------------------------------------------------------------------------------------*/
+void icvComputeStereoParamsForCameras(CvStereoCamera* stereoCamera)
+{
+ /* For given intrinsic and extrinsic parameters computes rest parameters
+ ** such as fundamental matrix. warping coeffs, epipoles, ...
+ */
+
+
+ /* compute rotate matrix and translate vector */
+ double rotMatr1[9];
+ double rotMatr2[9];
+
+ double transVect1[3];
+ double transVect2[3];
+
+ double convRotMatr[9];
+ double convTransVect[3];
+
+ /* fill matrices */
+ icvCvt_32f_64d(stereoCamera->camera[0]->rotMatr,rotMatr1,9);
+ icvCvt_32f_64d(stereoCamera->camera[1]->rotMatr,rotMatr2,9);
+
+ icvCvt_32f_64d(stereoCamera->camera[0]->transVect,transVect1,3);
+ icvCvt_32f_64d(stereoCamera->camera[1]->transVect,transVect2,3);
+
+ icvCreateConvertMatrVect( rotMatr1,
+ transVect1,
+ rotMatr2,
+ transVect2,
+ convRotMatr,
+ convTransVect);
+
+ /* copy to stereo camera params */
+ icvCvt_64d_32f(convRotMatr,stereoCamera->rotMatrix,9);
+ icvCvt_64d_32f(convTransVect,stereoCamera->transVector,3);
+
+
+ icvGetQuadsTransformStruct(stereoCamera);
+ icvComputeRestStereoParams(stereoCamera);
+}
+
+
+
+/*---------------------------------------------------------------------------------------*/
+
+/* Get cut line for one image */
+void icvGetCutPiece( CvVect64d areaLineCoef1,CvVect64d areaLineCoef2,
+ CvPoint2D64d epipole,
+ CvSize imageSize,
+ CvPoint2D64d* point11,CvPoint2D64d* point12,
+ CvPoint2D64d* point21,CvPoint2D64d* point22,
+ int* result)
+{
+ /* Compute nearest cut line to epipole */
+ /* Get corners inside sector */
+ /* Collect all candidate point */
+
+ CvPoint2D64d candPoints[8];
+ CvPoint2D64d midPoint;
+ int numPoints = 0;
+ int res;
+ int i;
+
+ double cutLine1[3];
+ double cutLine2[3];
+
+ /* Find middle line of sector */
+ double midLine[3];
+
+
+ /* Different way */
+ CvPoint2D64d pointOnLine1; pointOnLine1.x = pointOnLine1.y = 0;
+ CvPoint2D64d pointOnLine2; pointOnLine2.x = pointOnLine2.y = 0;
+
+ CvPoint2D64d start1,end1;
+
+ icvGetCrossRectDirect( imageSize,
+ areaLineCoef1[0],areaLineCoef1[1],areaLineCoef1[2],
+ &start1,&end1,&res);
+ if( res > 0 )
+ {
+ pointOnLine1 = start1;
+ }
+
+ icvGetCrossRectDirect( imageSize,
+ areaLineCoef2[0],areaLineCoef2[1],areaLineCoef2[2],
+ &start1,&end1,&res);
+ if( res > 0 )
+ {
+ pointOnLine2 = start1;
+ }
+
+ icvGetMiddleAnglePoint(epipole,pointOnLine1,pointOnLine2,&midPoint);
+
+ icvGetCoefForPiece(epipole,midPoint,&midLine[0],&midLine[1],&midLine[2],&res);
+
+ /* Test corner points */
+ CvPoint2D64d cornerPoint;
+ CvPoint2D64d tmpPoints[2];
+
+ cornerPoint.x = 0;
+ cornerPoint.y = 0;
+ icvTestPoint( cornerPoint, areaLineCoef1, areaLineCoef2, epipole, &res);
+ if( res == 1 )
+ {/* Add point */
+ candPoints[numPoints] = cornerPoint;
+ numPoints++;
+ }
+
+ cornerPoint.x = imageSize.width;
+ cornerPoint.y = 0;
+ icvTestPoint( cornerPoint, areaLineCoef1, areaLineCoef2, epipole, &res);
+ if( res == 1 )
+ {/* Add point */
+ candPoints[numPoints] = cornerPoint;
+ numPoints++;
+ }
+
+ cornerPoint.x = imageSize.width;
+ cornerPoint.y = imageSize.height;
+ icvTestPoint( cornerPoint, areaLineCoef1, areaLineCoef2, epipole, &res);
+ if( res == 1 )
+ {/* Add point */
+ candPoints[numPoints] = cornerPoint;
+ numPoints++;
+ }
+
+ cornerPoint.x = 0;
+ cornerPoint.y = imageSize.height;
+ icvTestPoint( cornerPoint, areaLineCoef1, areaLineCoef2, epipole, &res);
+ if( res == 1 )
+ {/* Add point */
+ candPoints[numPoints] = cornerPoint;
+ numPoints++;
+ }
+
+ /* Find cross line 1 with image border */
+ icvGetCrossRectDirect( imageSize,
+ areaLineCoef1[0],areaLineCoef1[1],areaLineCoef1[2],
+ &tmpPoints[0], &tmpPoints[1],
+ &res);
+ for( i = 0; i < res; i++ )
+ {
+ candPoints[numPoints++] = tmpPoints[i];
+ }
+
+ /* Find cross line 2 with image border */
+ icvGetCrossRectDirect( imageSize,
+ areaLineCoef2[0],areaLineCoef2[1],areaLineCoef2[2],
+ &tmpPoints[0], &tmpPoints[1],
+ &res);
+
+ for( i = 0; i < res; i++ )
+ {
+ candPoints[numPoints++] = tmpPoints[i];
+ }
+
+ if( numPoints < 2 )
+ {
+ *result = 0;
+ return;/* Error. Not enought points */
+ }
+ /* Project all points to middle line and get max and min */
+
+ CvPoint2D64d projPoint;
+ CvPoint2D64d minPoint; minPoint.x = minPoint.y = FLT_MAX;
+ CvPoint2D64d maxPoint; maxPoint.x = maxPoint.y = -FLT_MAX;
+
+
+ double dist;
+ double maxDist = 0;
+ double minDist = 10000000;
+
+
+ for( i = 0; i < numPoints; i++ )
+ {
+ icvProjectPointToDirect(candPoints[i], midLine, &projPoint);
+ icvGetPieceLength(epipole,projPoint,&dist);
+ if( dist < minDist)
+ {
+ minDist = dist;
+ minPoint = projPoint;
+ }
+
+ if( dist > maxDist)
+ {
+ maxDist = dist;
+ maxPoint = projPoint;
+ }
+ }
+
+ /* We know maximum and minimum points. Now we can compute cut lines */
+
+ icvGetNormalDirect(midLine,minPoint,cutLine1);
+ icvGetNormalDirect(midLine,maxPoint,cutLine2);
+
+ /* Test for begin of line. */
+ CvPoint2D64d tmpPoint2;
+
+ /* Get cross with */
+ icvGetCrossDirectDirect(areaLineCoef1,cutLine1,point11,&res);
+ icvGetCrossDirectDirect(areaLineCoef2,cutLine1,point12,&res);
+
+ icvGetCrossDirectDirect(areaLineCoef1,cutLine2,point21,&res);
+ icvGetCrossDirectDirect(areaLineCoef2,cutLine2,point22,&res);
+
+ if( epipole.x > imageSize.width * 0.5 )
+ {/* Need to change points */
+ tmpPoint2 = *point11;
+ *point11 = *point21;
+ *point21 = tmpPoint2;
+
+ tmpPoint2 = *point12;
+ *point12 = *point22;
+ *point22 = tmpPoint2;
+ }
+
+ return;
+}
+/*---------------------------------------------------------------------------------------*/
+/* Get middle angle */
+void icvGetMiddleAnglePoint( CvPoint2D64d basePoint,
+ CvPoint2D64d point1,CvPoint2D64d point2,
+ CvPoint2D64d* midPoint)
+{/* !!! May be need to return error */
+
+ double dist1;
+ double dist2;
+ icvGetPieceLength(basePoint,point1,&dist1);
+ icvGetPieceLength(basePoint,point2,&dist2);
+ CvPoint2D64d pointNew1;
+ CvPoint2D64d pointNew2;
+ double alpha = dist2/dist1;
+
+ pointNew1.x = basePoint.x + (1.0/alpha) * ( point2.x - basePoint.x );
+ pointNew1.y = basePoint.y + (1.0/alpha) * ( point2.y - basePoint.y );
+
+ pointNew2.x = basePoint.x + alpha * ( point1.x - basePoint.x );
+ pointNew2.y = basePoint.y + alpha * ( point1.y - basePoint.y );
+
+ int res;
+ icvGetCrossPiecePiece(point1,point2,pointNew1,pointNew2,midPoint,&res);
+
+ return;
+}
+
+/*---------------------------------------------------------------------------------------*/
+/* Get normal direct to direct in line */
+void icvGetNormalDirect(CvVect64d direct,CvPoint2D64d point,CvVect64d normDirect)
+{
+ normDirect[0] = direct[1];
+ normDirect[1] = - direct[0];
+ normDirect[2] = -(normDirect[0]*point.x + normDirect[1]*point.y);
+ return;
+}
+
+/*---------------------------------------------------------------------------------------*/
+CV_IMPL double icvGetVect(CvPoint2D64d basePoint,CvPoint2D64d point1,CvPoint2D64d point2)
+{
+ return (point1.x - basePoint.x)*(point2.y - basePoint.y) -
+ (point2.x - basePoint.x)*(point1.y - basePoint.y);
+}
+/*---------------------------------------------------------------------------------------*/
+/* Test for point in sector */
+/* Return 0 - point not inside sector */
+/* Return 1 - point inside sector */
+void icvTestPoint( CvPoint2D64d testPoint,
+ CvVect64d line1,CvVect64d line2,
+ CvPoint2D64d basePoint,
+ int* result)
+{
+ CvPoint2D64d point1,point2;
+
+ icvProjectPointToDirect(testPoint,line1,&point1);
+ icvProjectPointToDirect(testPoint,line2,&point2);
+
+ double sign1 = icvGetVect(basePoint,point1,point2);
+ double sign2 = icvGetVect(basePoint,point1,testPoint);
+ if( sign1 * sign2 > 0 )
+ {/* Correct for first line */
+ sign1 = - sign1;
+ sign2 = icvGetVect(basePoint,point2,testPoint);
+ if( sign1 * sign2 > 0 )
+ {/* Correct for both lines */
+ *result = 1;
+ }
+ else
+ {
+ *result = 0;
+ }
+ }
+ else
+ {
+ *result = 0;
+ }
+
+ return;
+}
+
+/*---------------------------------------------------------------------------------------*/
+/* Project point to line */
+void icvProjectPointToDirect( CvPoint2D64d point,CvVect64d lineCoeff,
+ CvPoint2D64d* projectPoint)
+{
+ double a = lineCoeff[0];
+ double b = lineCoeff[1];
+
+ double det = 1.0 / ( a*a + b*b );
+ double delta = a*point.y - b*point.x;
+
+ projectPoint->x = ( -a*lineCoeff[2] - b * delta ) * det;
+ projectPoint->y = ( -b*lineCoeff[2] + a * delta ) * det ;
+
+ return;
+}
+
+/*---------------------------------------------------------------------------------------*/
+/* Get distance from point to direction */
+void icvGetDistanceFromPointToDirect( CvPoint2D64d point,CvVect64d lineCoef,double*dist)
+{
+ CvPoint2D64d tmpPoint;
+ icvProjectPointToDirect(point,lineCoef,&tmpPoint);
+ double dx = point.x - tmpPoint.x;
+ double dy = point.y - tmpPoint.y;
+ *dist = sqrt(dx*dx+dy*dy);
+ return;
+}
+/*---------------------------------------------------------------------------------------*/
+
+CV_IMPL IplImage* icvCreateIsometricImage( IplImage* src, IplImage* dst,
+ int desired_depth, int desired_num_channels )
+{
+ CvSize src_size ;
+ src_size.width = src->width;
+ src_size.height = src->height;
+
+ CvSize dst_size = src_size;
+
+ if( dst )
+ {
+ dst_size.width = dst->width;
+ dst_size.height = dst->height;
+ }
+
+ if( !dst || dst->depth != desired_depth ||
+ dst->nChannels != desired_num_channels ||
+ dst_size.width != src_size.width ||
+ dst_size.height != dst_size.height )
+ {
+ cvReleaseImage( &dst );
+ dst = cvCreateImage( src_size, desired_depth, desired_num_channels );
+ CvRect rect = cvRect(0,0,src_size.width,src_size.height);
+ cvSetImageROI( dst, rect );
+
+ }
+
+ return dst;
+}
+
+int
+icvCvt_32f_64d( float *src, double *dst, int size )
+{
+ int t;
+
+ if( !src || !dst )
+ return CV_NULLPTR_ERR;
+ if( size <= 0 )
+ return CV_BADRANGE_ERR;
+
+ for( t = 0; t < size; t++ )
+ {
+ dst[t] = (double) (src[t]);
+ }
+
+ return CV_OK;
+}
+
+/*======================================================================================*/
+/* Type conversion double -> float */
+int
+icvCvt_64d_32f( double *src, float *dst, int size )
+{
+ int t;
+
+ if( !src || !dst )
+ return CV_NULLPTR_ERR;
+ if( size <= 0 )
+ return CV_BADRANGE_ERR;
+
+ for( t = 0; t < size; t++ )
+ {
+ dst[t] = (float) (src[t]);
+ }
+
+ return CV_OK;
+}
+
+/*----------------------------------------------------------------------------------*/
+
+
+/* Find line which cross frame by line(a,b,c) */
+void FindLineForEpiline( CvSize imageSize,
+ float a,float b,float c,
+ CvPoint2D32f *start,CvPoint2D32f *end,
+ int* result)
+{
+ result = result;
+ CvPoint2D32f frameBeg;
+
+ CvPoint2D32f frameEnd;
+ CvPoint2D32f cross[4];
+ int haveCross[4];
+ float dist;
+
+ haveCross[0] = 0;
+ haveCross[1] = 0;
+ haveCross[2] = 0;
+ haveCross[3] = 0;
+
+ frameBeg.x = 0;
+ frameBeg.y = 0;
+ frameEnd.x = (float)(imageSize.width);
+ frameEnd.y = 0;
+ haveCross[0] = icvGetCrossLineDirect(frameBeg,frameEnd,a,b,c,&cross[0]);
+
+ frameBeg.x = (float)(imageSize.width);
+ frameBeg.y = 0;
+ frameEnd.x = (float)(imageSize.width);
+ frameEnd.y = (float)(imageSize.height);
+ haveCross[1] = icvGetCrossLineDirect(frameBeg,frameEnd,a,b,c,&cross[1]);
+
+ frameBeg.x = (float)(imageSize.width);
+ frameBeg.y = (float)(imageSize.height);
+ frameEnd.x = 0;
+ frameEnd.y = (float)(imageSize.height);
+ haveCross[2] = icvGetCrossLineDirect(frameBeg,frameEnd,a,b,c,&cross[2]);
+
+ frameBeg.x = 0;
+ frameBeg.y = (float)(imageSize.height);
+ frameEnd.x = 0;
+ frameEnd.y = 0;
+ haveCross[3] = icvGetCrossLineDirect(frameBeg,frameEnd,a,b,c,&cross[3]);
+
+ int n;
+ float minDist = (float)(INT_MAX);
+ float maxDist = (float)(INT_MIN);
+
+ int maxN = -1;
+ int minN = -1;
+
+ double midPointX = imageSize.width / 2.0;
+ double midPointY = imageSize.height / 2.0;
+
+ for( n = 0; n < 4; n++ )
+ {
+ if( haveCross[n] > 0 )
+ {
+ dist = (float)((midPointX - cross[n].x)*(midPointX - cross[n].x) +
+ (midPointY - cross[n].y)*(midPointY - cross[n].y));
+
+ if( dist < minDist )
+ {
+ minDist = dist;
+ minN = n;
+ }
+
+ if( dist > maxDist )
+ {
+ maxDist = dist;
+ maxN = n;
+ }
+ }
+ }
+
+ if( minN >= 0 && maxN >= 0 && (minN != maxN) )
+ {
+ *start = cross[minN];
+ *end = cross[maxN];
+ }
+ else
+ {
+ start->x = 0;
+ start->y = 0;
+ end->x = 0;
+ end->y = 0;
+ }
+
+ return;
+
+}
+
+
+/*----------------------------------------------------------------------------------*/
+
+int GetAngleLinee( CvPoint2D32f epipole, CvSize imageSize,CvPoint2D32f point1,CvPoint2D32f point2)
+{
+ float width = (float)(imageSize.width);
+ float height = (float)(imageSize.height);
+
+ /* Get crosslines with image corners */
+
+ /* Find four lines */
+
+ CvPoint2D32f pa,pb,pc,pd;
+
+ pa.x = 0;
+ pa.y = 0;
+
+ pb.x = width;
+ pb.y = 0;
+
+ pd.x = width;
+ pd.y = height;
+
+ pc.x = 0;
+ pc.y = height;
+
+ /* We can compute points for angle */
+ /* Test for place section */
+
+ float x,y;
+ x = epipole.x;
+ y = epipole.y;
+
+ if( x < 0 )
+ {/* 1,4,7 */
+ if( y < 0)
+ {/* 1 */
+ point1 = pb;
+ point2 = pc;
+ }
+ else if( y > height )
+ {/* 7 */
+ point1 = pa;
+ point2 = pd;
+ }
+ else
+ {/* 4 */
+ point1 = pa;
+ point2 = pc;
+ }
+ }
+ else if ( x > width )
+ {/* 3,6,9 */
+ if( y < 0 )
+ {/* 3 */
+ point1 = pa;
+ point2 = pd;
+ }
+ else if ( y > height )
+ {/* 9 */
+ point1 = pc;
+ point2 = pb;
+ }
+ else
+ {/* 6 */
+ point1 = pb;
+ point2 = pd;
+ }
+ }
+ else
+ {/* 2,5,8 */
+ if( y < 0 )
+ {/* 2 */
+ point1 = pa;
+ point2 = pb;
+ }
+ else if( y > height )
+ {/* 8 */
+ point1 = pc;
+ point2 = pd;
+ }
+ else
+ {/* 5 - point in the image */
+ return 2;
+ }
+
+
+ }
+
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------------------*/
+void icvComputePerspectiveCoeffs(const CvPoint2D32f srcQuad[4],const CvPoint2D32f dstQuad[4],double coeffs[3][3])
+{/* Computes perspective coeffs for transformation from src to dst quad */
+
+
+ CV_FUNCNAME( "icvComputePerspectiveCoeffs" );
+
+ __BEGIN__;
+
+ double A[64];
+ double b[8];
+ double c[8];
+ CvPoint2D32f pt[4];
+ int i;
+
+ pt[0] = srcQuad[0];
+ pt[1] = srcQuad[1];
+ pt[2] = srcQuad[2];
+ pt[3] = srcQuad[3];
+
+ for( i = 0; i < 4; i++ )
+ {
+#if 0
+ double x = dstQuad[i].x;
+ double y = dstQuad[i].y;
+ double X = pt[i].x;
+ double Y = pt[i].y;
+#else
+ double x = pt[i].x;
+ double y = pt[i].y;
+ double X = dstQuad[i].x;
+ double Y = dstQuad[i].y;
+#endif
+ double* a = A + i*16;
+
+ a[0] = x;
+ a[1] = y;
+ a[2] = 1;
+ a[3] = 0;
+ a[4] = 0;
+ a[5] = 0;
+ a[6] = -X*x;
+ a[7] = -X*y;
+
+ a += 8;
+
+ a[0] = 0;
+ a[1] = 0;
+ a[2] = 0;
+ a[3] = x;
+ a[4] = y;
+ a[5] = 1;
+ a[6] = -Y*x;
+ a[7] = -Y*y;
+
+ b[i*2] = X;
+ b[i*2 + 1] = Y;
+ }
+
+ {
+ double invA[64];
+ CvMat matA = cvMat( 8, 8, CV_64F, A );
+ CvMat matInvA = cvMat( 8, 8, CV_64F, invA );
+ CvMat matB = cvMat( 8, 1, CV_64F, b );
+ CvMat matX = cvMat( 8, 1, CV_64F, c );
+
+ CV_CALL( cvPseudoInverse( &matA, &matInvA ));
+ CV_CALL( cvMatMulAdd( &matInvA, &matB, 0, &matX ));
+ }
+
+ coeffs[0][0] = c[0];
+ coeffs[0][1] = c[1];
+ coeffs[0][2] = c[2];
+ coeffs[1][0] = c[3];
+ coeffs[1][1] = c[4];
+ coeffs[1][2] = c[5];
+ coeffs[2][0] = c[6];
+ coeffs[2][1] = c[7];
+ coeffs[2][2] = 1.0;
+
+ __END__;
+
+ return;
+}
+
+/*--------------------------------------------------------------------------------------*/
+
+CV_IMPL void cvComputePerspectiveMap(const double c[3][3], CvArr* rectMapX, CvArr* rectMapY )
+{
+ CV_FUNCNAME( "cvComputePerspectiveMap" );
+
+ __BEGIN__;
+
+ CvSize size;
+ CvMat stubx, *mapx = (CvMat*)rectMapX;
+ CvMat stuby, *mapy = (CvMat*)rectMapY;
+ int i, j;
+
+ CV_CALL( mapx = cvGetMat( mapx, &stubx ));
+ CV_CALL( mapy = cvGetMat( mapy, &stuby ));
+
+ if( CV_MAT_TYPE( mapx->type ) != CV_32FC1 || CV_MAT_TYPE( mapy->type ) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ size = cvGetMatSize(mapx);
+ assert( fabs(c[2][2] - 1.) < FLT_EPSILON );
+
+ for( i = 0; i < size.height; i++ )
+ {
+ float* mx = (float*)(mapx->data.ptr + mapx->step*i);
+ float* my = (float*)(mapy->data.ptr + mapy->step*i);
+
+ for( j = 0; j < size.width; j++ )
+ {
+ double w = 1./(c[2][0]*j + c[2][1]*i + 1.);
+ double x = (c[0][0]*j + c[0][1]*i + c[0][2])*w;
+ double y = (c[1][0]*j + c[1][1]*i + c[1][2])*w;
+
+ mx[j] = (float)x;
+ my[j] = (float)y;
+ }
+ }
+
+ __END__;
+}
+
+/*--------------------------------------------------------------------------------------*/
+
+CV_IMPL void cvInitPerspectiveTransform( CvSize size, const CvPoint2D32f quad[4], double matrix[3][3],
+ CvArr* rectMap )
+{
+ /* Computes Perspective Transform coeffs and map if need
+ for given image size and given result quad */
+ CV_FUNCNAME( "cvInitPerspectiveTransform" );
+
+ __BEGIN__;
+
+ double A[64];
+ double b[8];
+ double c[8];
+ CvPoint2D32f pt[4];
+ CvMat mapstub, *map = (CvMat*)rectMap;
+ int i, j;
+
+ if( map )
+ {
+ CV_CALL( map = cvGetMat( map, &mapstub ));
+
+ if( CV_MAT_TYPE( map->type ) != CV_32FC2 )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( map->width != size.width || map->height != size.height )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+ }
+
+ pt[0] = cvPoint2D32f( 0, 0 );
+ pt[1] = cvPoint2D32f( size.width, 0 );
+ pt[2] = cvPoint2D32f( size.width, size.height );
+ pt[3] = cvPoint2D32f( 0, size.height );
+
+ for( i = 0; i < 4; i++ )
+ {
+#if 0
+ double x = quad[i].x;
+ double y = quad[i].y;
+ double X = pt[i].x;
+ double Y = pt[i].y;
+#else
+ double x = pt[i].x;
+ double y = pt[i].y;
+ double X = quad[i].x;
+ double Y = quad[i].y;
+#endif
+ double* a = A + i*16;
+
+ a[0] = x;
+ a[1] = y;
+ a[2] = 1;
+ a[3] = 0;
+ a[4] = 0;
+ a[5] = 0;
+ a[6] = -X*x;
+ a[7] = -X*y;
+
+ a += 8;
+
+ a[0] = 0;
+ a[1] = 0;
+ a[2] = 0;
+ a[3] = x;
+ a[4] = y;
+ a[5] = 1;
+ a[6] = -Y*x;
+ a[7] = -Y*y;
+
+ b[i*2] = X;
+ b[i*2 + 1] = Y;
+ }
+
+ {
+ double invA[64];
+ CvMat matA = cvMat( 8, 8, CV_64F, A );
+ CvMat matInvA = cvMat( 8, 8, CV_64F, invA );
+ CvMat matB = cvMat( 8, 1, CV_64F, b );
+ CvMat matX = cvMat( 8, 1, CV_64F, c );
+
+ CV_CALL( cvPseudoInverse( &matA, &matInvA ));
+ CV_CALL( cvMatMulAdd( &matInvA, &matB, 0, &matX ));
+ }
+
+ matrix[0][0] = c[0];
+ matrix[0][1] = c[1];
+ matrix[0][2] = c[2];
+ matrix[1][0] = c[3];
+ matrix[1][1] = c[4];
+ matrix[1][2] = c[5];
+ matrix[2][0] = c[6];
+ matrix[2][1] = c[7];
+ matrix[2][2] = 1.0;
+
+ if( map )
+ {
+ for( i = 0; i < size.height; i++ )
+ {
+ CvPoint2D32f* maprow = (CvPoint2D32f*)(map->data.ptr + map->step*i);
+ for( j = 0; j < size.width; j++ )
+ {
+ double w = 1./(c[6]*j + c[7]*i + 1.);
+ double x = (c[0]*j + c[1]*i + c[2])*w;
+ double y = (c[3]*j + c[4]*i + c[5])*w;
+
+ maprow[j].x = (float)x;
+ maprow[j].y = (float)y;
+ }
+ }
+ }
+
+ __END__;
+
+ return;
+}
+
+
+/*-----------------------------------------------------------------------*/
+/* Compute projected infinite point for second image if first image point is known */
+void icvComputeeInfiniteProject1( CvMatr64d rotMatr,
+ CvMatr64d camMatr1,
+ CvMatr64d camMatr2,
+ CvPoint2D32f point1,
+ CvPoint2D32f* point2)
+{
+ double invMatr1[9];
+ icvInvertMatrix_64d(camMatr1,3,invMatr1);
+ double P1[3];
+ double p1[3];
+ p1[0] = (double)(point1.x);
+ p1[1] = (double)(point1.y);
+ p1[2] = 1;
+
+ icvMulMatrix_64d( invMatr1,
+ 3,3,
+ p1,
+ 1,3,
+ P1);
+
+ double invR[9];
+ icvTransposeMatrix_64d( rotMatr, 3, 3, invR );
+
+ /* Change system 1 to system 2 */
+ double P2[3];
+ icvMulMatrix_64d( invR,
+ 3,3,
+ P1,
+ 1,3,
+ P2);
+
+ /* Now we can project this point to image 2 */
+ double projP[3];
+
+ icvMulMatrix_64d( camMatr2,
+ 3,3,
+ P2,
+ 1,3,
+ projP);
+
+ point2->x = (float)(projP[0] / projP[2]);
+ point2->y = (float)(projP[1] / projP[2]);
+
+ return;
+}
+
+/*-----------------------------------------------------------------------*/
+/* Compute projected infinite point for second image if first image point is known */
+void icvComputeeInfiniteProject2( CvMatr64d rotMatr,
+ CvMatr64d camMatr1,
+ CvMatr64d camMatr2,
+ CvPoint2D32f* point1,
+ CvPoint2D32f point2)
+{
+ double invMatr2[9];
+ icvInvertMatrix_64d(camMatr2,3,invMatr2);
+ double P2[3];
+ double p2[3];
+ p2[0] = (double)(point2.x);
+ p2[1] = (double)(point2.y);
+ p2[2] = 1;
+
+ icvMulMatrix_64d( invMatr2,
+ 3,3,
+ p2,
+ 1,3,
+ P2);
+
+ /* Change system 1 to system 2 */
+
+ double P1[3];
+ icvMulMatrix_64d( rotMatr,
+ 3,3,
+ P2,
+ 1,3,
+ P1);
+
+ /* Now we can project this point to image 2 */
+ double projP[3];
+
+ icvMulMatrix_64d( camMatr1,
+ 3,3,
+ P1,
+ 1,3,
+ projP);
+
+ point1->x = (float)(projP[0] / projP[2]);
+ point1->y = (float)(projP[1] / projP[2]);
+
+ return;
+}
+
+/* Select best R and t for given cameras, points, ... */
+/* For both cameras */
+int icvSelectBestRt( int numImages,
+ int* numPoints,
+ CvPoint2D32f* imagePoints1,
+ CvPoint2D32f* imagePoints2,
+ CvPoint3D32f* objectPoints,
+
+ CvMatr32f cameraMatrix1,
+ CvVect32f distortion1,
+ CvMatr32f rotMatrs1,
+ CvVect32f transVects1,
+
+ CvMatr32f cameraMatrix2,
+ CvVect32f distortion2,
+ CvMatr32f rotMatrs2,
+ CvVect32f transVects2,
+
+ CvMatr32f bestRotMatr,
+ CvVect32f bestTransVect
+ )
+{
+
+ /* Need to convert input data 32 -> 64 */
+ CvPoint3D64d* objectPoints_64d;
+
+ double* rotMatrs1_64d;
+ double* rotMatrs2_64d;
+
+ double* transVects1_64d;
+ double* transVects2_64d;
+
+ double cameraMatrix1_64d[9];
+ double cameraMatrix2_64d[9];
+
+ double distortion1_64d[4];
+ double distortion2_64d[4];
+
+ /* allocate memory for 64d data */
+ int totalNum = 0;
+
+ int i;
+ for( i = 0; i < numImages; i++ )
+ {
+ totalNum += numPoints[i];
+ }
+
+ objectPoints_64d = (CvPoint3D64d*)calloc(totalNum,sizeof(CvPoint3D64d));
+
+ rotMatrs1_64d = (double*)calloc(numImages,sizeof(double)*9);
+ rotMatrs2_64d = (double*)calloc(numImages,sizeof(double)*9);
+
+ transVects1_64d = (double*)calloc(numImages,sizeof(double)*3);
+ transVects2_64d = (double*)calloc(numImages,sizeof(double)*3);
+
+ /* Convert input data to 64d */
+
+ icvCvt_32f_64d((float*)objectPoints, (double*)objectPoints_64d, totalNum*3);
+
+ icvCvt_32f_64d(rotMatrs1, rotMatrs1_64d, numImages*9);
+ icvCvt_32f_64d(rotMatrs2, rotMatrs2_64d, numImages*9);
+
+ icvCvt_32f_64d(transVects1, transVects1_64d, numImages*3);
+ icvCvt_32f_64d(transVects2, transVects2_64d, numImages*3);
+
+ /* Convert to arrays */
+ icvCvt_32f_64d(cameraMatrix1, cameraMatrix1_64d, 9);
+ icvCvt_32f_64d(cameraMatrix2, cameraMatrix2_64d, 9);
+
+ icvCvt_32f_64d(distortion1, distortion1_64d, 4);
+ icvCvt_32f_64d(distortion2, distortion2_64d, 4);
+
+
+ /* for each R and t compute error for image pair */
+ float* errors;
+
+ errors = (float*)calloc(numImages*numImages,sizeof(float));
+ if( errors == 0 )
+ {
+ return CV_OUTOFMEM_ERR;
+ }
+
+ int currImagePair;
+ int currRt;
+ for( currRt = 0; currRt < numImages; currRt++ )
+ {
+ int begPoint = 0;
+ for(currImagePair = 0; currImagePair < numImages; currImagePair++ )
+ {
+ /* For current R,t R,t compute relative position of cameras */
+
+ double convRotMatr[9];
+ double convTransVect[3];
+
+ icvCreateConvertMatrVect( rotMatrs1_64d + currRt*9,
+ transVects1_64d + currRt*3,
+ rotMatrs2_64d + currRt*9,
+ transVects2_64d + currRt*3,
+ convRotMatr,
+ convTransVect);
+
+ /* Project points using relative position of cameras */
+
+ double convRotMatr2[9];
+ double convTransVect2[3];
+
+ convRotMatr2[0] = 1;
+ convRotMatr2[1] = 0;
+ convRotMatr2[2] = 0;
+
+ convRotMatr2[3] = 0;
+ convRotMatr2[4] = 1;
+ convRotMatr2[5] = 0;
+
+ convRotMatr2[6] = 0;
+ convRotMatr2[7] = 0;
+ convRotMatr2[8] = 1;
+
+ convTransVect2[0] = 0;
+ convTransVect2[1] = 0;
+ convTransVect2[2] = 0;
+
+ /* Compute error for given pair and Rt */
+ /* We must project points to image and compute error */
+
+ CvPoint2D64d* projImagePoints1;
+ CvPoint2D64d* projImagePoints2;
+
+ CvPoint3D64d* points1;
+ CvPoint3D64d* points2;
+
+ int numberPnt;
+ numberPnt = numPoints[currImagePair];
+ projImagePoints1 = (CvPoint2D64d*)calloc(numberPnt,sizeof(CvPoint2D64d));
+ projImagePoints2 = (CvPoint2D64d*)calloc(numberPnt,sizeof(CvPoint2D64d));
+
+ points1 = (CvPoint3D64d*)calloc(numberPnt,sizeof(CvPoint3D64d));
+ points2 = (CvPoint3D64d*)calloc(numberPnt,sizeof(CvPoint3D64d));
+
+ /* Transform object points to first camera position */
+ int i;
+ for( i = 0; i < numberPnt; i++ )
+ {
+ /* Create second camera point */
+ CvPoint3D64d tmpPoint;
+ tmpPoint.x = (double)(objectPoints[i].x);
+ tmpPoint.y = (double)(objectPoints[i].y);
+ tmpPoint.z = (double)(objectPoints[i].z);
+
+ icvConvertPointSystem( tmpPoint,
+ points2+i,
+ rotMatrs2_64d + currImagePair*9,
+ transVects2_64d + currImagePair*3);
+
+ /* Create first camera point using R, t */
+ icvConvertPointSystem( points2[i],
+ points1+i,
+ convRotMatr,
+ convTransVect);
+
+ CvPoint3D64d tmpPoint2 = { 0, 0, 0 };
+ icvConvertPointSystem( tmpPoint,
+ &tmpPoint2,
+ rotMatrs1_64d + currImagePair*9,
+ transVects1_64d + currImagePair*3);
+ double err;
+ double dx,dy,dz;
+ dx = tmpPoint2.x - points1[i].x;
+ dy = tmpPoint2.y - points1[i].y;
+ dz = tmpPoint2.z - points1[i].z;
+ err = sqrt(dx*dx + dy*dy + dz*dz);
+
+
+ }
+
+#if 0
+ cvProjectPointsSimple( numPoints[currImagePair],
+ objectPoints_64d + begPoint,
+ rotMatrs1_64d + currRt*9,
+ transVects1_64d + currRt*3,
+ cameraMatrix1_64d,
+ distortion1_64d,
+ projImagePoints1);
+
+ cvProjectPointsSimple( numPoints[currImagePair],
+ objectPoints_64d + begPoint,
+ rotMatrs2_64d + currRt*9,
+ transVects2_64d + currRt*3,
+ cameraMatrix2_64d,
+ distortion2_64d,
+ projImagePoints2);
+#endif
+
+ /* Project with no translate and no rotation */
+
+#if 0
+ {
+ double nodist[4] = {0,0,0,0};
+ cvProjectPointsSimple( numPoints[currImagePair],
+ points1,
+ convRotMatr2,
+ convTransVect2,
+ cameraMatrix1_64d,
+ nodist,
+ projImagePoints1);
+
+ cvProjectPointsSimple( numPoints[currImagePair],
+ points2,
+ convRotMatr2,
+ convTransVect2,
+ cameraMatrix2_64d,
+ nodist,
+ projImagePoints2);
+
+ }
+#endif
+
+ cvProjectPointsSimple( numPoints[currImagePair],
+ points1,
+ convRotMatr2,
+ convTransVect2,
+ cameraMatrix1_64d,
+ distortion1_64d,
+ projImagePoints1);
+
+ cvProjectPointsSimple( numPoints[currImagePair],
+ points2,
+ convRotMatr2,
+ convTransVect2,
+ cameraMatrix2_64d,
+ distortion2_64d,
+ projImagePoints2);
+
+ /* points are projected. Compute error */
+
+ int currPoint;
+ double err1 = 0;
+ double err2 = 0;
+ double err;
+ for( currPoint = 0; currPoint < numberPnt; currPoint++ )
+ {
+ double len1,len2;
+ double dx1,dy1;
+ dx1 = imagePoints1[begPoint+currPoint].x - projImagePoints1[currPoint].x;
+ dy1 = imagePoints1[begPoint+currPoint].y - projImagePoints1[currPoint].y;
+ len1 = sqrt(dx1*dx1 + dy1*dy1);
+ err1 += len1;
+
+ double dx2,dy2;
+ dx2 = imagePoints2[begPoint+currPoint].x - projImagePoints2[currPoint].x;
+ dy2 = imagePoints2[begPoint+currPoint].y - projImagePoints2[currPoint].y;
+ len2 = sqrt(dx2*dx2 + dy2*dy2);
+ err2 += len2;
+ }
+
+ err1 /= (float)(numberPnt);
+ err2 /= (float)(numberPnt);
+
+ err = (err1+err2) * 0.5;
+ begPoint += numberPnt;
+
+ /* Set this error to */
+ errors[numImages*currImagePair+currRt] = (float)err;
+
+ free(points1);
+ free(points2);
+ free(projImagePoints1);
+ free(projImagePoints2);
+ }
+ }
+
+ /* Just select R and t with minimal average error */
+
+ int bestnumRt = 0;
+ float minError = 0;/* Just for no warnings. Uses 'first' flag. */
+ int first = 1;
+ for( currRt = 0; currRt < numImages; currRt++ )
+ {
+ float avErr = 0;
+ for(currImagePair = 0; currImagePair < numImages; currImagePair++ )
+ {
+ avErr += errors[numImages*currImagePair+currRt];
+ }
+ avErr /= (float)(numImages);
+
+ if( first )
+ {
+ bestnumRt = 0;
+ minError = avErr;
+ first = 0;
+ }
+ else
+ {
+ if( avErr < minError )
+ {
+ bestnumRt = currRt;
+ minError = avErr;
+ }
+ }
+
+ }
+
+ double bestRotMatr_64d[9];
+ double bestTransVect_64d[3];
+
+ icvCreateConvertMatrVect( rotMatrs1_64d + bestnumRt * 9,
+ transVects1_64d + bestnumRt * 3,
+ rotMatrs2_64d + bestnumRt * 9,
+ transVects2_64d + bestnumRt * 3,
+ bestRotMatr_64d,
+ bestTransVect_64d);
+
+ icvCvt_64d_32f(bestRotMatr_64d,bestRotMatr,9);
+ icvCvt_64d_32f(bestTransVect_64d,bestTransVect,3);
+
+
+ free(errors);
+
+ return CV_OK;
+}
+
+
+/* ----------------- Stereo calibration functions --------------------- */
+
+float icvDefinePointPosition(CvPoint2D32f point1,CvPoint2D32f point2,CvPoint2D32f point)
+{
+ float ax = point2.x - point1.x;
+ float ay = point2.y - point1.y;
+
+ float bx = point.x - point1.x;
+ float by = point.y - point1.y;
+
+ return (ax*by - ay*bx);
+}
+
+/* Convert function for stereo warping */
+int icvConvertWarpCoordinates(double coeffs[3][3],
+ CvPoint2D32f* cameraPoint,
+ CvPoint2D32f* warpPoint,
+ int direction)
+{
+ double x,y;
+ double det;
+ if( direction == CV_WARP_TO_CAMERA )
+ {/* convert from camera image to warped image coordinates */
+ x = warpPoint->x;
+ y = warpPoint->y;
+
+ det = (coeffs[2][0] * x + coeffs[2][1] * y + coeffs[2][2]);
+ if( fabs(det) > 1e-8 )
+ {
+ cameraPoint->x = (float)((coeffs[0][0] * x + coeffs[0][1] * y + coeffs[0][2]) / det);
+ cameraPoint->y = (float)((coeffs[1][0] * x + coeffs[1][1] * y + coeffs[1][2]) / det);
+ return CV_OK;
+ }
+ }
+ else if( direction == CV_CAMERA_TO_WARP )
+ {/* convert from warped image to camera image coordinates */
+ x = cameraPoint->x;
+ y = cameraPoint->y;
+
+ det = (coeffs[2][0]*x-coeffs[0][0])*(coeffs[2][1]*y-coeffs[1][1])-(coeffs[2][1]*x-coeffs[0][1])*(coeffs[2][0]*y-coeffs[1][0]);
+
+ if( fabs(det) > 1e-8 )
+ {
+ warpPoint->x = (float)(((coeffs[0][2]-coeffs[2][2]*x)*(coeffs[2][1]*y-coeffs[1][1])-(coeffs[2][1]*x-coeffs[0][1])*(coeffs[1][2]-coeffs[2][2]*y))/det);
+ warpPoint->y = (float)(((coeffs[2][0]*x-coeffs[0][0])*(coeffs[1][2]-coeffs[2][2]*y)-(coeffs[0][2]-coeffs[2][2]*x)*(coeffs[2][0]*y-coeffs[1][0]))/det);
+ return CV_OK;
+ }
+ }
+
+ return CV_BADFACTOR_ERR;
+}
+
+/* Compute stereo params using some camera params */
+/* by Valery Mosyagin. int ComputeRestStereoParams(StereoParams *stereoparams) */
+int icvComputeRestStereoParams(CvStereoCamera *stereoparams)
+{
+
+
+ icvGetQuadsTransformStruct(stereoparams);
+
+ cvInitPerspectiveTransform( stereoparams->warpSize,
+ stereoparams->quad[0],
+ stereoparams->coeffs[0],
+ 0);
+
+ cvInitPerspectiveTransform( stereoparams->warpSize,
+ stereoparams->quad[1],
+ stereoparams->coeffs[1],
+ 0);
+
+ /* Create border for warped images */
+ CvPoint2D32f corns[4];
+ corns[0].x = 0;
+ corns[0].y = 0;
+
+ corns[1].x = (float)(stereoparams->camera[0]->imgSize[0]-1);
+ corns[1].y = 0;
+
+ corns[2].x = (float)(stereoparams->camera[0]->imgSize[0]-1);
+ corns[2].y = (float)(stereoparams->camera[0]->imgSize[1]-1);
+
+ corns[3].x = 0;
+ corns[3].y = (float)(stereoparams->camera[0]->imgSize[1]-1);
+
+ int i;
+ for( i = 0; i < 4; i++ )
+ {
+ /* For first camera */
+ icvConvertWarpCoordinates( stereoparams->coeffs[0],
+ corns+i,
+ stereoparams->border[0]+i,
+ CV_CAMERA_TO_WARP);
+
+ /* For second camera */
+ icvConvertWarpCoordinates( stereoparams->coeffs[1],
+ corns+i,
+ stereoparams->border[1]+i,
+ CV_CAMERA_TO_WARP);
+ }
+
+ /* Test compute */
+ {
+ CvPoint2D32f warpPoints[4];
+ warpPoints[0] = cvPoint2D32f(0,0);
+ warpPoints[1] = cvPoint2D32f(stereoparams->warpSize.width-1,0);
+ warpPoints[2] = cvPoint2D32f(stereoparams->warpSize.width-1,stereoparams->warpSize.height-1);
+ warpPoints[3] = cvPoint2D32f(0,stereoparams->warpSize.height-1);
+
+ CvPoint2D32f camPoints1[4];
+ CvPoint2D32f camPoints2[4];
+
+ for( int i = 0; i < 4; i++ )
+ {
+ icvConvertWarpCoordinates(stereoparams->coeffs[0],
+ camPoints1+i,
+ warpPoints+i,
+ CV_WARP_TO_CAMERA);
+
+ icvConvertWarpCoordinates(stereoparams->coeffs[1],
+ camPoints2+i,
+ warpPoints+i,
+ CV_WARP_TO_CAMERA);
+ }
+ }
+
+
+ /* Allocate memory for scanlines coeffs */
+
+ stereoparams->lineCoeffs = (CvStereoLineCoeff*)calloc(stereoparams->warpSize.height,sizeof(CvStereoLineCoeff));
+
+ /* Compute coeffs for epilines */
+
+ icvComputeCoeffForStereo( stereoparams);
+
+ /* all coeffs are known */
+ return CV_OK;
+}
+
+/*-------------------------------------------------------------------------------------------*/
+
+int icvStereoCalibration( int numImages,
+ int* nums,
+ CvSize imageSize,
+ CvPoint2D32f* imagePoints1,
+ CvPoint2D32f* imagePoints2,
+ CvPoint3D32f* objectPoints,
+ CvStereoCamera* stereoparams
+ )
+{
+ /* Firstly we must calibrate both cameras */
+ /* Alocate memory for data */
+ /* Allocate for translate vectors */
+ float* transVects1;
+ float* transVects2;
+ float* rotMatrs1;
+ float* rotMatrs2;
+
+ transVects1 = (float*)calloc(numImages,sizeof(float)*3);
+ transVects2 = (float*)calloc(numImages,sizeof(float)*3);
+
+ rotMatrs1 = (float*)calloc(numImages,sizeof(float)*9);
+ rotMatrs2 = (float*)calloc(numImages,sizeof(float)*9);
+
+ /* Calibrate first camera */
+ cvCalibrateCamera( numImages,
+ nums,
+ imageSize,
+ imagePoints1,
+ objectPoints,
+ stereoparams->camera[0]->distortion,
+ stereoparams->camera[0]->matrix,
+ transVects1,
+ rotMatrs1,
+ 1);
+
+ /* Calibrate second camera */
+ cvCalibrateCamera( numImages,
+ nums,
+ imageSize,
+ imagePoints2,
+ objectPoints,
+ stereoparams->camera[1]->distortion,
+ stereoparams->camera[1]->matrix,
+ transVects2,
+ rotMatrs2,
+ 1);
+
+ /* Cameras are calibrated */
+
+ stereoparams->camera[0]->imgSize[0] = (float)imageSize.width;
+ stereoparams->camera[0]->imgSize[1] = (float)imageSize.height;
+
+ stereoparams->camera[1]->imgSize[0] = (float)imageSize.width;
+ stereoparams->camera[1]->imgSize[1] = (float)imageSize.height;
+
+ icvSelectBestRt( numImages,
+ nums,
+ imagePoints1,
+ imagePoints2,
+ objectPoints,
+ stereoparams->camera[0]->matrix,
+ stereoparams->camera[0]->distortion,
+ rotMatrs1,
+ transVects1,
+ stereoparams->camera[1]->matrix,
+ stereoparams->camera[1]->distortion,
+ rotMatrs2,
+ transVects2,
+ stereoparams->rotMatrix,
+ stereoparams->transVector
+ );
+
+ /* Free memory */
+ free(transVects1);
+ free(transVects2);
+ free(rotMatrs1);
+ free(rotMatrs2);
+
+ icvComputeRestStereoParams(stereoparams);
+
+ return CV_NO_ERR;
+}
+
+/* Find line from epipole */
+void FindLine(CvPoint2D32f epipole,CvSize imageSize,CvPoint2D32f point,CvPoint2D32f *start,CvPoint2D32f *end)
+{
+ CvPoint2D32f frameBeg;
+ CvPoint2D32f frameEnd;
+ CvPoint2D32f cross[4];
+ int haveCross[4];
+ float dist;
+
+ haveCross[0] = 0;
+ haveCross[1] = 0;
+ haveCross[2] = 0;
+ haveCross[3] = 0;
+
+ frameBeg.x = 0;
+ frameBeg.y = 0;
+ frameEnd.x = (float)(imageSize.width);
+ frameEnd.y = 0;
+ haveCross[0] = icvGetCrossPieceVector(frameBeg,frameEnd,epipole,point,&cross[0]);
+
+ frameBeg.x = (float)(imageSize.width);
+ frameBeg.y = 0;
+ frameEnd.x = (float)(imageSize.width);
+ frameEnd.y = (float)(imageSize.height);
+ haveCross[1] = icvGetCrossPieceVector(frameBeg,frameEnd,epipole,point,&cross[1]);
+
+ frameBeg.x = (float)(imageSize.width);
+ frameBeg.y = (float)(imageSize.height);
+ frameEnd.x = 0;
+ frameEnd.y = (float)(imageSize.height);
+ haveCross[2] = icvGetCrossPieceVector(frameBeg,frameEnd,epipole,point,&cross[2]);
+
+ frameBeg.x = 0;
+ frameBeg.y = (float)(imageSize.height);
+ frameEnd.x = 0;
+ frameEnd.y = 0;
+ haveCross[3] = icvGetCrossPieceVector(frameBeg,frameEnd,epipole,point,&cross[3]);
+
+ int n;
+ float minDist = (float)(INT_MAX);
+ float maxDist = (float)(INT_MIN);
+
+ int maxN = -1;
+ int minN = -1;
+
+ for( n = 0; n < 4; n++ )
+ {
+ if( haveCross[n] > 0 )
+ {
+ dist = (epipole.x - cross[n].x)*(epipole.x - cross[n].x) +
+ (epipole.y - cross[n].y)*(epipole.y - cross[n].y);
+
+ if( dist < minDist )
+ {
+ minDist = dist;
+ minN = n;
+ }
+
+ if( dist > maxDist )
+ {
+ maxDist = dist;
+ maxN = n;
+ }
+ }
+ }
+
+ if( minN >= 0 && maxN >= 0 && (minN != maxN) )
+ {
+ *start = cross[minN];
+ *end = cross[maxN];
+ }
+ else
+ {
+ start->x = 0;
+ start->y = 0;
+ end->x = 0;
+ end->y = 0;
+ }
+
+ return;
+}
+
+
+/* Find line which cross frame by line(a,b,c) */
+void FindLineForEpiline(CvSize imageSize,float a,float b,float c,CvPoint2D32f *start,CvPoint2D32f *end)
+{
+ CvPoint2D32f frameBeg;
+ CvPoint2D32f frameEnd;
+ CvPoint2D32f cross[4];
+ int haveCross[4];
+ float dist;
+
+ haveCross[0] = 0;
+ haveCross[1] = 0;
+ haveCross[2] = 0;
+ haveCross[3] = 0;
+
+ frameBeg.x = 0;
+ frameBeg.y = 0;
+ frameEnd.x = (float)(imageSize.width);
+ frameEnd.y = 0;
+ haveCross[0] = icvGetCrossLineDirect(frameBeg,frameEnd,a,b,c,&cross[0]);
+
+ frameBeg.x = (float)(imageSize.width);
+ frameBeg.y = 0;
+ frameEnd.x = (float)(imageSize.width);
+ frameEnd.y = (float)(imageSize.height);
+ haveCross[1] = icvGetCrossLineDirect(frameBeg,frameEnd,a,b,c,&cross[1]);
+
+ frameBeg.x = (float)(imageSize.width);
+ frameBeg.y = (float)(imageSize.height);
+ frameEnd.x = 0;
+ frameEnd.y = (float)(imageSize.height);
+ haveCross[2] = icvGetCrossLineDirect(frameBeg,frameEnd,a,b,c,&cross[2]);
+
+ frameBeg.x = 0;
+ frameBeg.y = (float)(imageSize.height);
+ frameEnd.x = 0;
+ frameEnd.y = 0;
+ haveCross[3] = icvGetCrossLineDirect(frameBeg,frameEnd,a,b,c,&cross[3]);
+
+ int n;
+ float minDist = (float)(INT_MAX);
+ float maxDist = (float)(INT_MIN);
+
+ int maxN = -1;
+ int minN = -1;
+
+ double midPointX = imageSize.width / 2.0;
+ double midPointY = imageSize.height / 2.0;
+
+ for( n = 0; n < 4; n++ )
+ {
+ if( haveCross[n] > 0 )
+ {
+ dist = (float)((midPointX - cross[n].x)*(midPointX - cross[n].x) +
+ (midPointY - cross[n].y)*(midPointY - cross[n].y));
+
+ if( dist < minDist )
+ {
+ minDist = dist;
+ minN = n;
+ }
+
+ if( dist > maxDist )
+ {
+ maxDist = dist;
+ maxN = n;
+ }
+ }
+ }
+
+ if( minN >= 0 && maxN >= 0 && (minN != maxN) )
+ {
+ *start = cross[minN];
+ *end = cross[maxN];
+ }
+ else
+ {
+ start->x = 0;
+ start->y = 0;
+ end->x = 0;
+ end->y = 0;
+ }
+
+ return;
+
+}
+
+/* Cross lines */
+int GetCrossLines(CvPoint2D32f p1_start,CvPoint2D32f p1_end,CvPoint2D32f p2_start,CvPoint2D32f p2_end,CvPoint2D32f *cross)
+{
+ double ex1,ey1,ex2,ey2;
+ double px1,py1,px2,py2;
+ double del;
+ double delA,delB,delX,delY;
+ double alpha,betta;
+
+ ex1 = p1_start.x;
+ ey1 = p1_start.y;
+ ex2 = p1_end.x;
+ ey2 = p1_end.y;
+
+ px1 = p2_start.x;
+ py1 = p2_start.y;
+ px2 = p2_end.x;
+ py2 = p2_end.y;
+
+ del = (ex1-ex2)*(py2-py1)+(ey2-ey1)*(px2-px1);
+ if( del == 0)
+ {
+ return -1;
+ }
+
+ delA = (px1-ex1)*(py1-py2) + (ey1-py1)*(px1-px2);
+ delB = (ex1-px1)*(ey1-ey2) + (py1-ey1)*(ex1-ex2);
+
+ alpha = delA / del;
+ betta = -delB / del;
+
+ if( alpha < 0 || alpha > 1.0 || betta < 0 || betta > 1.0)
+ {
+ return -1;
+ }
+
+ delX = (ex1-ex2)*(py1*(px1-px2)-px1*(py1-py2))+
+ (px1-px2)*(ex1*(ey1-ey2)-ey1*(ex1-ex2));
+
+ delY = (ey1-ey2)*(px1*(py1-py2)-py1*(px1-px2))+
+ (py1-py2)*(ey1*(ex1-ex2)-ex1*(ey1-ey2));
+
+ cross->x = (float)( delX / del);
+ cross->y = (float)(-delY / del);
+ return 1;
+}
+
+
+int icvGetCrossPieceVector(CvPoint2D32f p1_start,CvPoint2D32f p1_end,CvPoint2D32f v2_start,CvPoint2D32f v2_end,CvPoint2D32f *cross)
+{
+ double ex1,ey1,ex2,ey2;
+ double px1,py1,px2,py2;
+ double del;
+ double delA,delB,delX,delY;
+ double alpha,betta;
+
+ ex1 = p1_start.x;
+ ey1 = p1_start.y;
+ ex2 = p1_end.x;
+ ey2 = p1_end.y;
+
+ px1 = v2_start.x;
+ py1 = v2_start.y;
+ px2 = v2_end.x;
+ py2 = v2_end.y;
+
+ del = (ex1-ex2)*(py2-py1)+(ey2-ey1)*(px2-px1);
+ if( del == 0)
+ {
+ return -1;
+ }
+
+ delA = (px1-ex1)*(py1-py2) + (ey1-py1)*(px1-px2);
+ delB = (ex1-px1)*(ey1-ey2) + (py1-ey1)*(ex1-ex2);
+
+ alpha = delA / del;
+ betta = -delB / del;
+
+ if( alpha < 0 || alpha > 1.0 )
+ {
+ return -1;
+ }
+
+ delX = (ex1-ex2)*(py1*(px1-px2)-px1*(py1-py2))+
+ (px1-px2)*(ex1*(ey1-ey2)-ey1*(ex1-ex2));
+
+ delY = (ey1-ey2)*(px1*(py1-py2)-py1*(px1-px2))+
+ (py1-py2)*(ey1*(ex1-ex2)-ex1*(ey1-ey2));
+
+ cross->x = (float)( delX / del);
+ cross->y = (float)(-delY / del);
+ return 1;
+}
+
+
+int icvGetCrossLineDirect(CvPoint2D32f p1,CvPoint2D32f p2,float a,float b,float c,CvPoint2D32f* cross)
+{
+ double del;
+ double delX,delY,delA;
+
+ double px1,px2,py1,py2;
+ double X,Y,alpha;
+
+ px1 = p1.x;
+ py1 = p1.y;
+
+ px2 = p2.x;
+ py2 = p2.y;
+
+ del = a * (px2 - px1) + b * (py2-py1);
+ if( del == 0 )
+ {
+ return -1;
+ }
+
+ delA = - c - a*px1 - b*py1;
+ alpha = delA / del;
+
+ if( alpha < 0 || alpha > 1.0 )
+ {
+ return -1;/* no cross */
+ }
+
+ delX = b * (py1*(px1-px2) - px1*(py1-py2)) + c * (px1-px2);
+ delY = a * (px1*(py1-py2) - py1*(px1-px2)) + c * (py1-py2);
+
+ X = delX / del;
+ Y = delY / del;
+
+ cross->x = (float)X;
+ cross->y = (float)Y;
+
+ return 1;
+}
+
+int cvComputeEpipoles( CvMatr32f camMatr1, CvMatr32f camMatr2,
+ CvMatr32f rotMatr1, CvMatr32f rotMatr2,
+ CvVect32f transVect1,CvVect32f transVect2,
+ CvVect32f epipole1,
+ CvVect32f epipole2)
+{
+
+ /* Copy matrix */
+
+ CvMat ccamMatr1 = cvMat(3,3,CV_MAT32F,camMatr1);
+ CvMat ccamMatr2 = cvMat(3,3,CV_MAT32F,camMatr2);
+ CvMat crotMatr1 = cvMat(3,3,CV_MAT32F,rotMatr1);
+ CvMat crotMatr2 = cvMat(3,3,CV_MAT32F,rotMatr2);
+ CvMat ctransVect1 = cvMat(3,1,CV_MAT32F,transVect1);
+ CvMat ctransVect2 = cvMat(3,1,CV_MAT32F,transVect2);
+ CvMat cepipole1 = cvMat(3,1,CV_MAT32F,epipole1);
+ CvMat cepipole2 = cvMat(3,1,CV_MAT32F,epipole2);
+
+
+ CvMat cmatrP1 = cvMat(3,3,CV_MAT32F,0); cvmAlloc(&cmatrP1);
+ CvMat cmatrP2 = cvMat(3,3,CV_MAT32F,0); cvmAlloc(&cmatrP2);
+ CvMat cvectp1 = cvMat(3,1,CV_MAT32F,0); cvmAlloc(&cvectp1);
+ CvMat cvectp2 = cvMat(3,1,CV_MAT32F,0); cvmAlloc(&cvectp2);
+ CvMat ctmpF1 = cvMat(3,1,CV_MAT32F,0); cvmAlloc(&ctmpF1);
+ CvMat ctmpM1 = cvMat(3,3,CV_MAT32F,0); cvmAlloc(&ctmpM1);
+ CvMat ctmpM2 = cvMat(3,3,CV_MAT32F,0); cvmAlloc(&ctmpM2);
+ CvMat cinvP1 = cvMat(3,3,CV_MAT32F,0); cvmAlloc(&cinvP1);
+ CvMat cinvP2 = cvMat(3,3,CV_MAT32F,0); cvmAlloc(&cinvP2);
+ CvMat ctmpMatr = cvMat(3,3,CV_MAT32F,0); cvmAlloc(&ctmpMatr);
+ CvMat ctmpVect1 = cvMat(3,1,CV_MAT32F,0); cvmAlloc(&ctmpVect1);
+ CvMat ctmpVect2 = cvMat(3,1,CV_MAT32F,0); cvmAlloc(&ctmpVect2);
+ CvMat cmatrF1 = cvMat(3,3,CV_MAT32F,0); cvmAlloc(&cmatrF1);
+ CvMat ctmpF = cvMat(3,3,CV_MAT32F,0); cvmAlloc(&ctmpF);
+ CvMat ctmpE1 = cvMat(3,1,CV_MAT32F,0); cvmAlloc(&ctmpE1);
+ CvMat ctmpE2 = cvMat(3,1,CV_MAT32F,0); cvmAlloc(&ctmpE2);
+
+ /* Compute first */
+ cvmMul( &ccamMatr1, &crotMatr1, &cmatrP1);
+ cvmInvert( &cmatrP1,&cinvP1 );
+ cvmMul( &ccamMatr1, &ctransVect1, &cvectp1 );
+
+ /* Compute second */
+ cvmMul( &ccamMatr2, &crotMatr2, &cmatrP2 );
+ cvmInvert( &cmatrP2,&cinvP2 );
+ cvmMul( &ccamMatr2, &ctransVect2, &cvectp2 );
+
+ cvmMul( &cmatrP1, &cinvP2, &ctmpM1);
+ cvmMul( &ctmpM1, &cvectp2, &ctmpVect1);
+ cvmSub( &cvectp1,&ctmpVect1,&ctmpE1);
+
+ cvmMul( &cmatrP2, &cinvP1, &ctmpM2);
+ cvmMul( &ctmpM2, &cvectp1, &ctmpVect2);
+ cvmSub( &cvectp2, &ctmpVect2, &ctmpE2);
+
+
+ /* Need scale */
+
+ cvmScale(&ctmpE1,&cepipole1,1.0);
+ cvmScale(&ctmpE2,&cepipole2,1.0);
+
+ cvmFree(&cmatrP1);
+ cvmFree(&cmatrP1);
+ cvmFree(&cvectp1);
+ cvmFree(&cvectp2);
+ cvmFree(&ctmpF1);
+ cvmFree(&ctmpM1);
+ cvmFree(&ctmpM2);
+ cvmFree(&cinvP1);
+ cvmFree(&cinvP2);
+ cvmFree(&ctmpMatr);
+ cvmFree(&ctmpVect1);
+ cvmFree(&ctmpVect2);
+ cvmFree(&cmatrF1);
+ cvmFree(&ctmpF);
+ cvmFree(&ctmpE1);
+ cvmFree(&ctmpE2);
+
+ return CV_NO_ERR;
+}/* cvComputeEpipoles */
+
+
+/* Compute epipoles for fundamental matrix */
+int cvComputeEpipolesFromFundMatrix(CvMatr32f fundMatr,
+ CvPoint3D32f* epipole1,
+ CvPoint3D32f* epipole2)
+{
+ /* Decompose fundamental matrix using SVD ( A = U W V') */
+ CvMat fundMatrC = cvMat(3,3,CV_MAT32F,fundMatr);
+
+ CvMat* matrW = cvCreateMat(3,3,CV_MAT32F);
+ CvMat* matrU = cvCreateMat(3,3,CV_MAT32F);
+ CvMat* matrV = cvCreateMat(3,3,CV_MAT32F);
+
+ /* From svd we need just last vector of U and V or last row from U' and V' */
+ /* We get transposed matrixes U and V */
+ cvSVD(&fundMatrC,matrW,matrU,matrV,CV_SVD_V_T|CV_SVD_U_T);
+
+ /* Get last row from U' and compute epipole1 */
+ epipole1->x = matrU->data.fl[6];
+ epipole1->y = matrU->data.fl[7];
+ epipole1->z = matrU->data.fl[8];
+
+ /* Get last row from V' and compute epipole2 */
+ epipole2->x = matrV->data.fl[6];
+ epipole2->y = matrV->data.fl[7];
+ epipole2->z = matrV->data.fl[8];
+
+ cvReleaseMat(&matrW);
+ cvReleaseMat(&matrU);
+ cvReleaseMat(&matrV);
+ return CV_OK;
+}
+
+int cvConvertEssential2Fundamental( CvMatr32f essMatr,
+ CvMatr32f fundMatr,
+ CvMatr32f cameraMatr1,
+ CvMatr32f cameraMatr2)
+{/* Fund = inv(CM1') * Ess * inv(CM2) */
+
+ CvMat essMatrC = cvMat(3,3,CV_MAT32F,essMatr);
+ CvMat fundMatrC = cvMat(3,3,CV_MAT32F,fundMatr);
+ CvMat cameraMatr1C = cvMat(3,3,CV_MAT32F,cameraMatr1);
+ CvMat cameraMatr2C = cvMat(3,3,CV_MAT32F,cameraMatr2);
+
+ CvMat* invCM2 = cvCreateMat(3,3,CV_MAT32F);
+ CvMat* tmpMatr = cvCreateMat(3,3,CV_MAT32F);
+ CvMat* invCM1T = cvCreateMat(3,3,CV_MAT32F);
+
+ cvTranspose(&cameraMatr1C,tmpMatr);
+ cvInvert(tmpMatr,invCM1T);
+ cvmMul(invCM1T,&essMatrC,tmpMatr);
+ cvInvert(&cameraMatr2C,invCM2);
+ cvmMul(tmpMatr,invCM2,&fundMatrC);
+
+ /* Scale fundamental matrix */
+ double scale;
+ scale = 1.0/fundMatrC.data.fl[8];
+ cvConvertScale(&fundMatrC,&fundMatrC,scale);
+
+ cvReleaseMat(&invCM2);
+ cvReleaseMat(&tmpMatr);
+ cvReleaseMat(&invCM1T);
+
+ return CV_OK;
+}
+
+/* Compute essential matrix */
+
+int cvComputeEssentialMatrix( CvMatr32f rotMatr,
+ CvMatr32f transVect,
+ CvMatr32f essMatr)
+{
+ float transMatr[9];
+
+ /* Make antisymmetric matrix from transpose vector */
+ transMatr[0] = 0;
+ transMatr[1] = - transVect[2];
+ transMatr[2] = transVect[1];
+
+ transMatr[3] = transVect[2];
+ transMatr[4] = 0;
+ transMatr[5] = - transVect[0];
+
+ transMatr[6] = - transVect[1];
+ transMatr[7] = transVect[0];
+ transMatr[8] = 0;
+
+ icvMulMatrix_32f(transMatr,3,3,rotMatr,3,3,essMatr);
+
+ return CV_OK;
+}
+
+
diff --git a/cvaux/src/cvface.cpp b/cvaux/src/cvface.cpp
new file mode 100644
index 0000000..01e6dd4
--- /dev/null
+++ b/cvaux/src/cvface.cpp
@@ -0,0 +1,354 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+///////////////////////////////////////////////
+//// Created by Khudyakov V.A. bober@gorodok.net
+//////////////////////////////////////////////
+
+#include "_cvaux.h"
+#include "_cvfacedetection.h"
+
+Face::Face(FaceTemplate * lpFaceTemplate)
+{
+ //init number of face elements;
+ m_lFaceFeaturesNumber = lpFaceTemplate->GetCount();
+
+ //init array of numbers of foundet face elements of each type
+ m_lplFaceFeaturesCount = new long[m_lFaceFeaturesNumber];
+ memset(m_lplFaceFeaturesCount,0,m_lFaceFeaturesNumber*sizeof(long));
+
+ //init array of ideal face features
+ m_lpIdealFace = new FaceFeature[m_lFaceFeaturesNumber];
+
+ //init array of founded features
+ m_lppFoundedFaceFeatures = new FaceFeature*[m_lFaceFeaturesNumber];
+
+ for (int i = 0;i < m_lFaceFeaturesNumber;i ++)
+ {
+ m_lppFoundedFaceFeatures[i] = (new FaceFeature[3*MAX_LAYERS]);
+ }
+
+ //set start weight 0
+ m_dWeight = 0;
+
+}//Face::Face(FaceTemplate * lpFaceTemplate)
+
+Face::~Face()
+{
+ for (int i = 0;i < m_lFaceFeaturesNumber;i ++)
+ {
+ delete [] (m_lppFoundedFaceFeatures[i]);
+ }
+ delete [] m_lppFoundedFaceFeatures;
+
+
+ delete [] m_lplFaceFeaturesCount;
+ delete [] m_lpIdealFace;
+
+}//Face::~Face()
+
+
+#define UP_SCALE 1
+#define DOWN_SCALE 2
+
+
+////////////
+//class RFace(rect based face)
+////////////
+RFace::RFace(FaceTemplate * lpFaceTemplate):Face(lpFaceTemplate)
+{
+ //init ideal face
+ FaceFeature * lpTmp = lpFaceTemplate->GetFeatures();
+
+ for (int j = 0;j < m_lFaceFeaturesNumber;j ++)
+ {
+ CvRect * lpTmpRect = NULL;
+ lpTmpRect = new CvRect;
+ *lpTmpRect = *(CvRect*)lpTmp[j].GetContour();
+
+ m_lpIdealFace[j].SetContour( lpTmpRect );
+ m_lpIdealFace[j].SetWeight( lpTmp[j].GetWeight() );
+ m_lpIdealFace[j].SetFeature( lpTmp[j].isFaceFeature() );
+
+ }
+
+ m_bIsGenerated = false;
+}//RFace::RFace(FaceTemplate * lpFaceTemplate)
+
+RFace::~RFace()
+{
+
+}//RFace::~RFace()
+
+inline bool RFace::isPointInRect(CvPoint p,CvRect rect)
+{
+ if ( (p.x >= rect.x) && (p.y >= rect.y) && (p.x <= rect.x + rect.width) && (p.y <= rect.y + rect.height) )
+ return true;
+
+ return false;
+}//inline bool RFace::isPointInRect(CvPoint,CvRect rect)
+
+double RFace::GetWeight()
+{
+ return m_dWeight;
+}//double RFace::GetWeight()
+
+
+bool RFace::CheckElem(void * lpCandidat,void * lpIdeal)
+{
+
+ CvRect IdealRect = *(CvRect*)lpIdeal;
+ CvRect Rect = *(CvRect*)lpCandidat;
+
+ if (Rect.height > Rect.width)
+ return false;
+
+ long SizeIdeal = IdealRect.width*IdealRect.height;
+ long Size = Rect.width*Rect.height;
+
+ if ( (Size > SizeIdeal) || ( Size < (SizeIdeal/5) ) )
+ return false;
+
+// CvRect UpRect;
+// CvRect DownRect;
+// ResizeRect(IdealRect,&UpRect,UP_SCALE,7);
+// ResizeRect(IdealRect,&DownRect,DOWN_SCALE,7);
+
+ long x = Rect.x + cvRound(Rect.width/2);
+ long y = Rect.y + cvRound(Rect.height/2);
+
+ if ( isPointInRect(cvPoint(x,y),IdealRect) )
+ return true;
+
+// if ( isPointInRect(cvPoint(Rect.x,Rect.y),UpRect) &&
+// isPointInRect(cvPoint(Rect.x + Rect.width,Rect.y + Rect.height),UpRect ) &&
+// isPointInRect(cvPoint(DownRect.x,DownRect.y),Rect) &&
+// isPointInRect(cvPoint(DownRect.x + DownRect.width,DownRect.y + DownRect.height),Rect) )
+// return true;
+
+
+// if ( isPointInRect(cvPoint(Rect.x,Rect.y),IdealRect) &&
+// isPointInRect(cvPoint(Rect.x + Rect.width,Rect.y + Rect.height),IdealRect ) )
+// return true;
+
+ return false;
+}//inline bool RFace::CheckElem(CvRect rect)
+
+
+
+void RFace::CalculateError(FaceData * lpFaceData)
+{
+ CvRect LeftEyeRect = lpFaceData->LeftEyeRect;
+ CvRect RightEyeRect = lpFaceData->RightEyeRect;
+ CvRect MouthRect = lpFaceData->MouthRect;
+
+ long LeftSquare = LeftEyeRect.width*LeftEyeRect.height;
+ long RightSquare = RightEyeRect.width*RightEyeRect.height;
+
+ long dy = LeftEyeRect.y - RightEyeRect.y;
+
+ long dx1 = LeftEyeRect.x + LeftEyeRect.width/2 - MouthRect.x;
+ long dx2 = RightEyeRect.x + RightEyeRect.width/2 - MouthRect.x - MouthRect.width;
+
+
+ lpFaceData->Error = (double)(LeftSquare - RightSquare)*(double)(LeftSquare - RightSquare)/((double)(LeftSquare + RightSquare)*(LeftSquare + RightSquare)) +
+ (double)(dy*dy)/((double)(LeftEyeRect.height + RightEyeRect.height)*(LeftEyeRect.height + RightEyeRect.height)) +
+ (double)(dx1*dx1)/((double)MouthRect.width*MouthRect.width) +
+ (double)(dx2*dx2)/((double)MouthRect.width*MouthRect.width);
+
+}//void RFace::CalculateError(FaceData * lpFaceData)
+
+#define MAX_ERROR 0xFFFFFFFF
+
+void RFace::CreateFace(void * lpData)
+{
+ FaceData Data;
+
+ double Error = MAX_ERROR;
+ double CurError = MAX_ERROR;
+
+ FaceData * lpFaceData = (FaceData*)lpData;
+
+ int im = 0;//mouth was find
+ int jl = 0;//left eye was find
+ int kr = 0;//right eye was find
+
+ long MouthNumber = 0;
+ long LeftEyeNumber = 0;
+ long RightEyeNumber = 0;
+
+ for (int i = 0;i < m_lplFaceFeaturesCount[0] + 1;i ++)
+ {
+
+ if ( !m_lplFaceFeaturesCount[0] )
+ Data.MouthRect = *(CvRect*)m_lpIdealFace[0].GetContour();
+ else
+ {
+ if ( i != m_lplFaceFeaturesCount[0] )
+ Data.MouthRect = *(CvRect*)m_lppFoundedFaceFeatures[0][i].GetContour();
+ im = 1;
+ }
+
+
+ for (int j = 0;j < m_lplFaceFeaturesCount[1] + 1;j ++)
+ {
+
+ if ( !m_lplFaceFeaturesCount[1] )
+ Data.LeftEyeRect = *(CvRect*)m_lpIdealFace[1].GetContour();
+ else
+ {
+ if (j != m_lplFaceFeaturesCount[1] )
+ Data.LeftEyeRect = *(CvRect*)m_lppFoundedFaceFeatures[1][j].GetContour();
+ jl = 1;
+ }
+
+
+ for (int k = 0;k < m_lplFaceFeaturesCount[2] + 1;k ++)
+ {
+
+ if ( !m_lplFaceFeaturesCount[2] )
+ Data.RightEyeRect = *(CvRect*)m_lpIdealFace[2].GetContour();
+ else
+ {
+ if (k != m_lplFaceFeaturesCount[2] )
+ Data.RightEyeRect = *(CvRect*)m_lppFoundedFaceFeatures[2][k].GetContour();
+ kr = 1;
+ }
+
+ CalculateError(&Data);
+
+ if ( (im + jl + kr) )
+ {
+ Error = Data.Error/(im + jl + kr);
+ }else
+ Error = MAX_ERROR;
+
+ if (CurError > Error)
+ {
+ CurError = Error;
+ MouthNumber = i;
+ LeftEyeNumber = j;
+ RightEyeNumber = k;
+ }
+
+ }
+
+
+ }
+
+ }
+
+ if ( m_lplFaceFeaturesCount[0] )
+ lpFaceData->MouthRect = *(CvRect*)m_lppFoundedFaceFeatures[0][MouthNumber].GetContour();
+ else
+ lpFaceData->MouthRect = *(CvRect*)m_lpIdealFace[0].GetContour();
+
+ if ( m_lplFaceFeaturesCount[1] )
+ lpFaceData->LeftEyeRect = *(CvRect*)m_lppFoundedFaceFeatures[1][LeftEyeNumber].GetContour();
+ else
+ lpFaceData->LeftEyeRect = *(CvRect*)m_lpIdealFace[1].GetContour();
+
+ if ( m_lplFaceFeaturesCount[2] )
+ lpFaceData->RightEyeRect = *(CvRect*)m_lppFoundedFaceFeatures[2][RightEyeNumber].GetContour();
+ else
+ lpFaceData->RightEyeRect = *(CvRect*)m_lpIdealFace[2].GetContour();
+
+ lpFaceData->Error = CurError;
+
+}//void * RFace::CreateFace()
+
+void RFace::Show(IplImage * Image)
+{
+ for (int i = 0;i < m_lFaceFeaturesNumber;i ++)
+ {
+ if (m_lplFaceFeaturesCount[i])
+ {
+ for (int j = 0;j < m_lplFaceFeaturesCount[i];j ++)
+ {
+ CvRect rect = *(CvRect*)m_lppFoundedFaceFeatures[i][j].GetContour();
+ CvPoint p1 = cvPoint(rect.x,rect.y);
+ CvPoint p2 = cvPoint(rect.x + rect.width,rect.y + rect.height);
+ cvRectangle(Image,p1,p2,CV_RGB(255,0,0),1);
+ }
+ }
+ }
+
+}//void RFace::Show(IplImage * Image)
+
+void RFace::ShowIdeal(IplImage* Image)
+{
+ for (int i = 0;i < m_lFaceFeaturesNumber;i ++)
+ {
+ CvRect Rect = *(CvRect*)m_lpIdealFace[i].GetContour();
+ CvPoint p1 = cvPoint(Rect.x,Rect.y);
+ CvPoint p2 = cvPoint(Rect.x + Rect.width,Rect.y + Rect.height);
+ cvRectangle(Image,p1,p2,CV_RGB(0,0,255),1);
+ }
+}//void RFace::ShowIdeal(IplImage* Image)
+
+
+inline void RFace::ResizeRect(CvRect Rect,CvRect * lpRect,long lDir,long lD)
+{
+ if (lDir == UP_SCALE)
+ {
+ lpRect->x = Rect.x - lD;
+ lpRect->y = Rect.y - lD;
+ lpRect->width = Rect.width + 2*lD;
+ lpRect->height = Rect.height + 2*lD;
+ }
+ if (lDir == DOWN_SCALE)
+ {
+ lpRect->x = Rect.x + lD;
+ lpRect->y = Rect.y + lD;
+ if (Rect.width - 2*lD >= 0)
+ {
+ lpRect->width = Rect.width - 2*lD;
+ }else
+ lpRect->width = 0;
+
+ if (Rect.height - 2*lD >= 0)
+ {
+ lpRect->height = Rect.height - 2*lD;
+ }else
+ lpRect->height = 0;
+ }
+
+}// inline void RFace::ResizeRect(CvRect * lpRect,long lDir,long lD)
+
diff --git a/cvaux/src/cvfacedetection.cpp b/cvaux/src/cvfacedetection.cpp
new file mode 100644
index 0000000..da04df7
--- /dev/null
+++ b/cvaux/src/cvfacedetection.cpp
@@ -0,0 +1,486 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+///////////////////////////////////////////////
+//// Created by Khudyakov V.A. bober@gorodok.net
+//////////////////////////////////////////////
+// FaceDetection.cpp: implementation of the FaceDetection class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "_cvaux.h"
+#include "_cvfacedetection.h"
+
+
+int CV_CDECL CompareContourRect(const void* el1, const void* el2, void* userdata);
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+FaceDetection::FaceDetection()
+{
+
+ m_imgGray = NULL;
+ m_imgThresh = NULL;
+ m_mstgContours = NULL;
+ memset(m_seqContours, 0, sizeof(CvSeq*) * MAX_LAYERS);
+ m_mstgRects = NULL;
+ m_seqRects = NULL;
+ m_iNumLayers = 16;
+ assert(m_iNumLayers <= MAX_LAYERS);
+ m_pFaceList = new List();
+
+
+
+ m_bBoosting = false;
+
+}// FaceDetection()
+
+FaceDetection::~FaceDetection()
+{
+ if (m_imgGray)
+ cvReleaseImage(&m_imgGray);
+
+ if (m_imgThresh)
+ cvReleaseImage(&m_imgThresh);
+
+ if (m_mstgContours)
+ cvReleaseMemStorage(&m_mstgContours);
+
+ if (m_mstgRects)
+ cvReleaseMemStorage(&m_mstgRects);
+
+
+}// ~FaceDetection()
+
+void FaceDetection::FindContours(IplImage* imgGray)
+{
+ ReallocImage(&m_imgThresh, cvGetSize(imgGray), 1);
+ if (NULL == m_imgThresh)
+ return;
+ //
+ int iNumLayers = m_iNumLayers;
+ int iMinLevel = 0, iMaxLevel = 255, iStep = 255 / iNumLayers;
+ ThresholdingParam(imgGray, iNumLayers, iMinLevel, iMaxLevel, iStep);
+ // init
+ cvReleaseMemStorage(&m_mstgContours);
+ m_mstgContours = cvCreateMemStorage();
+ if (NULL == m_mstgContours)
+ return;
+ memset(m_seqContours, 0, sizeof(CvSeq*) * MAX_LAYERS);
+
+ cvReleaseMemStorage(&m_mstgRects);
+ m_mstgRects = cvCreateMemStorage();
+ if (NULL == m_mstgRects)
+ return;
+ m_seqRects = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvContourRect), m_mstgRects);
+ if (NULL == m_seqRects)
+ return;
+ // find contours
+ for (int l = iMinLevel, i = 0; l < iMaxLevel; l += iStep, i++)
+ {
+ cvThreshold(imgGray, m_imgThresh, (double)l, (double)255, CV_THRESH_BINARY);
+ if (cvFindContours(m_imgThresh, m_mstgContours, &m_seqContours[i], sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE))
+ AddContours2Rect(m_seqContours[i], l, i);
+ }
+ // sort rects
+ cvSeqSort(m_seqRects, CompareContourRect, NULL);
+}// void FaceDetection::FindContours(IplImage* imgGray)
+
+#define GIST_STEP 10
+#define GIST_NUM (256 / GIST_STEP)
+#define GIST_MIN 32
+
+void FaceDetection::ThresholdingParam(IplImage *imgGray, int iNumLayers, int &iMinLevel, int &iMaxLevel, int &iStep)
+{
+ assert(imgGray != NULL);
+ assert(imgGray->nChannels == 1);
+ int i, j;
+ // create gistogramm
+ uchar* buffImg = (uchar*)imgGray->imageData;
+ int gistImg[GIST_NUM + 1] = {0};
+
+ for (j = 0; j < imgGray->height; j ++)
+ {
+ for (i = 0; i < imgGray->width; i ++)
+ {
+ int ind = buffImg[i] / GIST_STEP;
+ gistImg[ind] ++;
+ }
+ buffImg += imgGray->widthStep;
+ }
+ // params
+
+ for (i = 0; i <= GIST_NUM; i ++)
+ {
+ if (gistImg[i] >= GIST_MIN)
+ break;
+ }
+
+ iMinLevel = i * GIST_STEP;
+
+ for (i = GIST_NUM; i >= 0; i --)
+ {
+ if (gistImg[i] >= GIST_MIN)
+ break;
+ }
+
+ iMaxLevel = i * GIST_STEP;
+
+ int dLevels = iMaxLevel - iMinLevel;
+ if (dLevels <= 0)
+ {
+ iMinLevel = 0;
+ iMaxLevel = 255;
+ }
+ else if (dLevels <= iNumLayers)
+ {
+ iMinLevel = iMaxLevel - iNumLayers;
+ if (iMinLevel < 0)
+ {
+ iMinLevel = 0;
+ iMaxLevel = iNumLayers;
+ }
+ }
+ iStep = (iMaxLevel - iMinLevel) / iNumLayers;
+
+}// void FaceDetection::ThresholdingParam(IplImage *imgGray, int iNumLayers, int &iMinLevel, int &iMaxLevel, int &iStep)
+
+#ifndef MAX_ERROR
+#define MAX_ERROR 0xFFFFFFFF
+#endif //MAX_ERROR
+
+
+void FaceDetection::CreateResults(CvSeq * lpSeq)
+{
+
+ Face * tmp;
+
+ double Max = 0;
+ double CurStat = 0;
+
+ FaceData tmpData;
+ if (m_bBoosting)
+ {
+ tmp = m_pFaceList->GetData();
+ tmp->CreateFace(&tmpData);
+
+ CvFace tmpFace;
+ tmpFace.MouthRect = tmpData.MouthRect;
+ tmpFace.LeftEyeRect = tmpData.LeftEyeRect;
+ tmpFace.RightEyeRect = tmpData.RightEyeRect;
+
+ cvSeqPush(lpSeq,&tmpFace);
+
+ }else
+ {
+ while ( (tmp = m_pFaceList->GetData()) != 0 )
+ {
+ CurStat = tmp->GetWeight();
+ if (CurStat > Max)
+ Max = CurStat;
+ }
+
+ while ( (tmp = m_pFaceList->GetData()) != 0 )
+ {
+ tmp->CreateFace(&tmpData);
+ CurStat = tmp->GetWeight();
+
+ if (CurStat == Max)
+ {
+ CvFace tmpFace;
+ tmpFace.MouthRect = tmpData.MouthRect;
+ tmpFace.LeftEyeRect = tmpData.LeftEyeRect;
+ tmpFace.RightEyeRect = tmpData.RightEyeRect;
+ cvSeqPush(lpSeq,&tmpFace);
+
+
+ }
+ }
+ }
+}// void FaceDetection::DrawResult(IplImage* img)
+
+void FaceDetection::ResetImage()
+{
+ delete m_pFaceList;
+ m_pFaceList = new List();
+
+}//FaceDetection::ResetImage
+
+void FaceDetection::AddContours2Rect(CvSeq *seq, int color, int iLayer)
+{
+ assert(m_mstgRects != NULL);
+ assert(m_seqRects != NULL);
+
+ CvContourRect cr;
+ for (CvSeq* external = seq; external; external = external->h_next)
+ {
+ cr.r = cvContourBoundingRect(external, 1 );
+ cr.pCenter.x = cr.r.x + cr.r.width / 2;
+ cr.pCenter.y = cr.r.y + cr.r.height / 2;
+ cr.iNumber = iLayer;
+ cr.iType = 6;
+ cr.iFlags = 0;
+ cr.seqContour = external;
+ cr.iContourLength = external->total;
+ cr.iColor = color;
+ cvSeqPush(m_seqRects, &cr);
+ for (CvSeq* internal = external->v_next; internal; internal = internal->h_next)
+ {
+ cr.r = cvContourBoundingRect(internal, 0);
+ cr.pCenter.x = cr.r.x + cr.r.width / 2;
+ cr.pCenter.y = cr.r.y + cr.r.height / 2;
+ cr.iNumber = iLayer;
+ cr.iType = 12;
+ cr.iFlags = 0;
+ cr.seqContour = internal;
+ cr.iContourLength = internal->total;
+ cr.iColor = color;
+ cvSeqPush(m_seqRects, &cr);
+ }
+ }
+}// void FaceDetection::AddContours2Rect(CvSeq *seq, int color, int iLayer)
+
+int CV_CDECL CompareContourRect(const void* el1, const void* el2, void* /*userdata*/)
+{
+ return (((CvContourRect*)el1)->pCenter.y - ((CvContourRect*)el2)->pCenter.y);
+}// int CV_CDECL CompareContourRect(const void* el1, const void* el2, void* userdata)
+
+void FaceDetection::FindFace(IplImage *img)
+{
+ // find all contours
+ FindContours(img);
+ //
+ ResetImage();
+
+ if (m_bBoosting)
+ PostBoostingFindCandidats(img);
+ else
+ FindCandidats();
+
+}// void FaceDetection::FindFace(IplImage *img)
+
+
+void FaceDetection::FindCandidats()
+{
+ bool bFound1 = false;
+ MouthFaceTemplate * lpFaceTemplate1;
+ RFace * lpFace1;
+ bool bInvalidRect1 = false;
+ CvRect * lpRect1 = NULL;
+
+ for (int i = 0; i < m_seqRects->total; i++)
+ {
+ CvContourRect* pRect = (CvContourRect*)cvGetSeqElem(m_seqRects, i);
+ CvRect rect = pRect->r;
+ if (rect.width >= 2*rect.height)
+ {
+
+ lpFaceTemplate1 = new MouthFaceTemplate(3,rect,3*(double)rect.width/(double)4,
+ 3*(double)rect.width/(double)4,
+ (double)rect.width/(double)2,
+ (double)rect.width/(double)2);
+
+
+ lpFace1 = new RFace(lpFaceTemplate1);
+
+ for (int j = 0; j < m_seqRects->total; j++)
+ {
+ CvContourRect* pRect = (CvContourRect*)cvGetSeqElem(m_seqRects, j);
+
+ if ( !bInvalidRect1 )
+ {
+ lpRect1 = NULL;
+ lpRect1 = new CvRect();
+ *lpRect1 = pRect->r;
+ }else
+ {
+ delete lpRect1;
+ lpRect1 = new CvRect();
+ *lpRect1 = pRect->r;
+ }
+
+
+ if ( lpFace1->isFeature(lpRect1) )
+ {
+ bFound1 = true;
+ bInvalidRect1 = false;
+ }else
+ bInvalidRect1 = true;
+
+
+ }
+
+
+ if (bFound1)
+ {
+ m_pFaceList->AddElem(lpFace1);
+ bFound1 = false;
+ lpFace1 = NULL;
+ }else
+ {
+ delete lpFace1;
+ lpFace1 = NULL;
+ }
+
+
+ delete lpFaceTemplate1;
+ }
+
+ }
+
+}
+
+
+void FaceDetection::PostBoostingFindCandidats(IplImage * FaceImage)
+{
+ BoostingFaceTemplate * lpFaceTemplate1;
+ RFace * lpFace1;
+ bool bInvalidRect1 = false;
+ CvRect * lpRect1 = NULL;
+
+ if ( ( !FaceImage->roi ) )
+ lpFaceTemplate1 = new BoostingFaceTemplate(3,cvRect(0,0,FaceImage->width,FaceImage->height));
+ else
+ lpFaceTemplate1 = new BoostingFaceTemplate(3,cvRect(FaceImage->roi->xOffset,FaceImage->roi->yOffset,
+ FaceImage->roi->width,FaceImage->roi->height));
+
+ lpFace1 = new RFace(lpFaceTemplate1);
+
+ for (int i = 0; i < m_seqRects->total; i++)
+ {
+ CvContourRect* pRect = (CvContourRect*)cvGetSeqElem(m_seqRects, i);
+
+ if ( !bInvalidRect1 )
+ {
+ lpRect1 = NULL;
+ lpRect1 = new CvRect();
+ *lpRect1 = pRect->r;
+ }else
+ {
+ delete lpRect1;
+ lpRect1 = new CvRect();
+ *lpRect1 = pRect->r;
+ }
+
+
+ if ( lpFace1->isFeature(lpRect1) )
+ {
+ //bFound1 = true;
+ bInvalidRect1 = false;
+ }else
+ bInvalidRect1 = true;
+
+
+ }
+
+ m_pFaceList->AddElem(lpFace1);
+
+ delete lpFaceTemplate1;
+
+}//void FaceDetection::PostBoostingFindCandidats(IplImage * FaceImage)
+
+/////////////////////////
+//class Face
+
+
+
+//////
+//List Class
+/////
+ListElem::ListElem()
+{
+ m_pNext = this;
+ m_pPrev = this;
+ m_pFace = NULL;
+}///ListElem::ListElem()
+
+ListElem::ListElem(Face * pFace,ListElem * pHead)
+{
+ m_pNext = pHead;
+ m_pPrev = pHead->m_pPrev;
+ pHead->m_pPrev->m_pNext = this;
+ pHead->m_pPrev = this;
+
+ m_pFace = pFace;
+}//ListElem::ListElem(Face * pFace)
+
+
+
+ListElem::~ListElem()
+{
+ delete m_pFace;
+ m_pNext->m_pPrev = m_pPrev;
+ m_pPrev->m_pNext = m_pNext;
+
+}//ListElem::~ListElem()
+
+List::List()
+{
+ m_pHead = new ListElem();
+ m_FacesCount = 0;
+ m_pCurElem = m_pHead;
+}//List::List()
+
+List::~List()
+{
+ void * tmp;
+ while((tmp = m_pHead->m_pNext->m_pFace) != 0)
+ delete m_pHead->m_pNext;
+
+ delete m_pHead;
+
+}//List::~List()
+
+
+int List::AddElem(Face * pFace)
+{
+ new ListElem(pFace,m_pHead);
+ return m_FacesCount++;
+}//List::AddElem(Face * pFace)
+
+Face * List::GetData()
+{
+ m_pCurElem = m_pCurElem->m_pNext;
+ return m_pCurElem->m_pFace;
+}//Face * List::GetData()
+
+
diff --git a/cvaux/src/cvfacetemplate.cpp b/cvaux/src/cvfacetemplate.cpp
new file mode 100644
index 0000000..b5b9cf2
--- /dev/null
+++ b/cvaux/src/cvfacetemplate.cpp
@@ -0,0 +1,86 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+///////////////////////////////////////////////
+//// Created by Khudyakov V.A. bober@gorodok.net
+//////////////////////////////////////////////
+
+#include "_cvaux.h"
+#include "_cvfacedetection.h"
+
+///class FaceFeature
+FaceFeature::FaceFeature(double dWeight,void * lpContour,bool bIsFeature)
+{
+ m_lpContour = lpContour;
+ m_dWeight = dWeight;
+ m_bIsFaceFeature = bIsFeature;
+}//FaceFeature::FaceFeature(long lWeight,void * lpContour)
+
+FaceFeature::~FaceFeature()
+{
+ if (m_lpContour)
+ delete (char*)m_lpContour;
+}//FaceFeature::~FaceFeature()
+
+FaceFeature::FaceFeature()
+{
+ m_lpContour = NULL;
+ m_dWeight = 0;
+ m_bIsFaceFeature = false;
+}
+
+
+////class FaceTemplate
+
+FaceTemplate::~FaceTemplate()
+{
+ delete [] m_lpFeaturesList;
+}//FaceTemplate::~FaceTemplate()
+
+
+/////
+//class RFaceTemplate
+/////
+
+
+MouthFaceTemplate::~MouthFaceTemplate()
+{
+
+}//RFaceTemplate::~RFaceTemplate()
diff --git a/cvaux/src/cvfindface.cpp b/cvaux/src/cvfindface.cpp
new file mode 100644
index 0000000..6353888
--- /dev/null
+++ b/cvaux/src/cvfindface.cpp
@@ -0,0 +1,68 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+///////////////////////////////////////////////
+//// Created by Khudyakov V.A. bober@gorodok.net
+//////////////////////////////////////////////
+
+#include "_cvaux.h"
+#include "_cvfacedetection.h"
+
+CvSeq * cvFindFace(IplImage * Image,CvMemStorage* lpStorage)
+{
+ FaceDetection FD;
+ FD.SetBoosting(false);
+ FD.FindFace(Image);
+ CvSeq * lpSeq = cvCreateSeq(0,sizeof(*lpSeq),sizeof(CvFace),lpStorage);
+ FD.CreateResults(lpSeq);
+ return lpSeq;
+}//cvFindFace(IplImage * Image)
+
+CvSeq * cvPostBoostingFindFace(IplImage * Image,CvMemStorage* lpStorage)
+{
+ FaceDetection FD;
+ FD.SetBoosting(true);
+ FD.FindFace(Image);
+ CvSeq * lpSeq = cvCreateSeq(0,sizeof(*lpSeq),sizeof(CvFace),lpStorage);
+ FD.CreateResults(lpSeq);
+
+ return lpSeq;
+}//cvPostBoostingFindFace(IplImage * Image)
+
diff --git a/cvaux/src/cvfindhandregion.cpp b/cvaux/src/cvfindhandregion.cpp
new file mode 100644
index 0000000..bedcbcb
--- /dev/null
+++ b/cvaux/src/cvfindhandregion.cpp
@@ -0,0 +1,645 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cvaux.h"
+
+#define _CV_NORM_L2(a) (float)(icvSqrt32f(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]))
+#define _CV_NORM_L22(a) (float)(a[0]*a[0] + a[1]*a[1] + a[2]*a[2])
+
+/****************************************************************************************\
+
+ find region where hand is (for gesture recognition)
+ flag = 0 (use left bucket) flag = 1 (use right bucket)
+
+\****************************************************************************************/
+
+static CvStatus CV_STDCALL
+icvFindHandRegion( CvPoint3D32f * points, int count,
+ CvSeq * indexs,
+ float *line, CvSize2D32f size, int flag,
+ CvPoint3D32f * center,
+ CvMemStorage * storage, CvSeq ** numbers )
+{
+
+/* IppmVect32f sub, cros; */
+ float *sub, *cros;
+ CvSeqWriter writer;
+ CvSeqReader reader;
+
+ CvStatus status;
+ int nbins = 20, i, l, i_point, left, right;
+ int *bin_counts = 0; // pointer to the point's counter in the bickets
+ int low_count; // low threshold
+
+ CvPoint *tmp_number = 0, *pt;
+ float value, vmin, vmax, vl, bsize, vc;
+ float hand_length, hand_length2, hand_left, hand_right;
+ float threshold, threshold2;
+ float *vv = 0;
+ float a[3];
+
+ status = CV_OK;
+
+ hand_length = size.width;
+ hand_length2 = hand_length / 2;
+
+ threshold = (float) (size.height * 3 / 5.);
+ threshold2 = threshold * threshold;
+
+/* low_count = count/nbins; */
+ low_count = (int) (count / 60.);
+
+ assert( points != NULL && line != NULL );
+ if( points == NULL || line == NULL )
+ return CV_NULLPTR_ERR;
+
+ assert( count > 5 );
+ if( count < 5 )
+ return CV_BADFLAG_ERR;
+
+ assert( flag == 0 || flag == 1 );
+ if( flag != 0 && flag != 1 )
+ return CV_BADFLAG_ERR;
+
+/* create vectors */
+ sub = icvCreateVector_32f( 3 );
+ cros = icvCreateVector_32f( 3 );
+ if( sub == NULL || cros == NULL )
+ return CV_OUTOFMEM_ERR;
+
+/* alloc memory for the point's projections on the line */
+ vv = (float *) cvAlloc( count * sizeof( float ));
+
+ if( vv == NULL )
+ return CV_OUTOFMEM_ERR;
+
+/* alloc memory for the point's counter in the bickets */
+ bin_counts = (int *) cvAlloc( nbins * sizeof( int ));
+
+ if( bin_counts == NULL )
+ {
+ status = CV_OUTOFMEM_ERR;
+ goto M_END;
+ }
+ memset( bin_counts, 0, nbins * sizeof( int ));
+
+ cvStartReadSeq( indexs, &reader, 0 );
+
+/* alloc memory for the temporale point's numbers */
+ tmp_number = (CvPoint *) cvAlloc( count * sizeof( CvPoint ));
+ if( tmp_number == NULL )
+ {
+ status = CV_OUTOFMEM_ERR;
+ goto M_END;
+ }
+
+/* find min and max point's projection on the line */
+ vmin = 1000;
+ vmax = -1000;
+ i_point = 0;
+ for( i = 0; i < count; i++ )
+ {
+/*
+ icvSubVector_32f ((IppmVect32f )&points[i], (IppmVect32f )&line[3], sub, 3);
+
+ icvCrossProduct2L_32f ((IppmVect32f )&line[0], sub, cros);
+*/
+
+ sub[0] = points[i].x - line[3];
+ sub[1] = points[i].y - line[4];
+ sub[2] = points[i].z - line[5];
+ a[0] = sub[0] * line[1] - sub[1] * line[0];
+ a[1] = sub[1] * line[2] - sub[2] * line[1];
+ a[2] = sub[2] * line[0] - sub[0] * line[2];
+
+/* if(IPPI_NORM_L22 ( cros ) < threshold2) */
+ if( _CV_NORM_L22( a ) < threshold2 )
+ {
+ value = (float)icvDotProduct_32f( sub, &line[0], 3 );
+ if( value > vmax )
+ vmax = value;
+ if( value < vmin )
+ vmin = value;
+
+ vv[i_point] = value;
+
+ pt = (CvPoint*)cvGetSeqElem( indexs, i );
+ tmp_number[i_point] = *pt;
+ i_point++;
+ }
+ }
+
+/* compute the length of one bucket */
+ vl = vmax - vmin;
+ bsize = vl / nbins;
+
+/* compute the number of points in each bucket */
+ for( i = 0; i < i_point; i++ )
+ {
+ l = cvRound( (vv[i] - vmin) / bsize );
+ bin_counts[l]++;
+ }
+
+ *numbers = cvCreateSeq( CV_SEQ_POINT_SET, sizeof( CvSeq ), sizeof( CvPoint ), storage );
+ assert( numbers != 0 );
+ if( numbers == NULL )
+ {
+ status = CV_OUTOFMEM_ERR;
+ goto M_END;
+ }
+
+ cvStartAppendToSeq( *numbers, &writer );
+
+ if( flag == 0 )
+ {
+/* find the leftmost bucket */
+ for( l = 0; l < nbins; l++ )
+ {
+ if( bin_counts[l] > low_count )
+ break;
+ }
+ left = l;
+
+/* compute center point of the left hand */
+ hand_left = vmin + left * bsize;
+ vc = hand_left + hand_length2;
+ hand_right = hand_left + hand_length;
+ }
+ else
+ {
+/* find the rightmost bucket */
+ for( l = nbins - 1; l >= 0; l-- )
+ {
+ if( bin_counts[l] > low_count )
+ break;
+ }
+ right = l;
+
+/* compute center point of the right hand */
+ hand_right = vmax - (nbins - right - 1) * bsize;
+ vc = hand_right - hand_length2;
+ hand_left = hand_right - hand_length;
+ }
+
+ icvScaleVector_32f( &line[0], sub, 3, vc );
+ icvAddVector_32f( &line[3], sub, (float *) center, 3 );
+
+/* select hand's points and calculate mean value */
+
+ //ss.x = ss.y = ss.z = 0;
+ for( l = 0; l < i_point; l++ )
+ {
+ if( vv[l] >= hand_left && vv[l] <= hand_right )
+ {
+ CV_WRITE_SEQ_ELEM( tmp_number[l], writer );
+
+ }
+ }
+
+ cvEndWriteSeq( &writer );
+
+ M_END:
+ if( tmp_number != NULL )
+ cvFree( &tmp_number );
+ if( bin_counts != NULL )
+ cvFree( &bin_counts );
+ if( vv != NULL )
+ cvFree( &vv );
+ if( sub != NULL ) icvDeleteVector (sub);
+ if( cros != NULL ) icvDeleteVector (cros);
+
+ return status;
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+#define _CV_NORM_L31(a) (float)(icvSqrt32f(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]))
+#define _CV_NORM_L32(a) (float)(a[0]*a[0] + a[1]*a[1] + a[2]*a[2])
+
+/****************************************************************************************\
+
+ find region where hand is (for gesture recognition)
+ flag = 0 (use left bucket) flag = 1 (use right bucket)
+
+\****************************************************************************************/
+
+static CvStatus CV_STDCALL
+icvFindHandRegionA( CvPoint3D32f * points, int count,
+ CvSeq * indexs,
+ float *line, CvSize2D32f size, int jc,
+ CvPoint3D32f * center,
+ CvMemStorage * storage, CvSeq ** numbers )
+{
+
+/* IppmVect32f sub, cros; */
+ float *sub, *cros;
+ float eps = (float) 0.01;
+ CvSeqWriter writer;
+ CvSeqReader reader;
+
+ CvStatus status;
+ float gor[3] = { 1, 0, 0 };
+ float ver[3] = { 0, 1, 0 };
+
+ int nbins = 20, i, l, i_point, left, right, jmin, jmax, jl;
+ int j_left, j_right;
+ int *bin_counts = 0; // pointer to the point's counter in the bickets
+
+// int *bin_countsj = 0; // pointer to the index's counter in the bickets
+ int low_count; // low threshold
+
+ CvPoint *tmp_number = 0, *pt;
+ float value, vmin, vmax, vl, bsize, bsizej, vc, vcl, vcr;
+ double v_ver, v_gor;
+ float hand_length, hand_length2, hand_left, hand_right;
+ float threshold, threshold2;
+ float *vv = 0;
+ float a[3];
+ char log;
+
+ status = CV_OK;
+
+ hand_length = size.width;
+ hand_length2 = hand_length / 2;
+
+ threshold = (float) (size.height * 3 / 5.);
+ threshold2 = threshold * threshold;
+
+/* low_count = count/nbins; */
+ low_count = (int) (count / 60.);
+
+ assert( points != NULL && line != NULL );
+ if( points == NULL || line == NULL )
+ return CV_NULLPTR_ERR;
+
+ assert( count > 5 );
+ if( count < 5 )
+ return CV_BADFLAG_ERR;
+
+/* create vectors */
+ sub = icvCreateVector_32f( 3 );
+ cros = icvCreateVector_32f( 3 );
+ if( sub == NULL || cros == NULL )
+ return CV_OUTOFMEM_ERR;
+
+/* alloc memory for the point's projections on the line */
+ vv = (float *) cvAlloc( count * sizeof( float ));
+
+ if( vv == NULL )
+ return CV_OUTOFMEM_ERR;
+
+/* alloc memory for the point's counter in the bickets */
+ bin_counts = (int *) cvAlloc( nbins * sizeof( int ));
+
+ if( bin_counts == NULL )
+ {
+ status = CV_OUTOFMEM_ERR;
+ goto M_END;
+ }
+ memset( bin_counts, 0, nbins * sizeof( int ));
+
+/* alloc memory for the point's counter in the bickets */
+// bin_countsj = (int*) icvAlloc(nbins*sizeof(int));
+// if(bin_countsj == NULL) {status = CV_OUTOFMEM_ERR; goto M_END;}
+// memset(bin_countsj,0,nbins*sizeof(int));
+
+ cvStartReadSeq( indexs, &reader, 0 );
+
+/* alloc memory for the temporale point's numbers */
+ tmp_number = (CvPoint *) cvAlloc( count * sizeof( CvPoint ));
+ if( tmp_number == NULL )
+ {
+ status = CV_OUTOFMEM_ERR;
+ goto M_END;
+ }
+
+/* find min and max point's projection on the line */
+ vmin = 1000;
+ vmax = -1000;
+ jmin = 1000;
+ jmax = -1000;
+ i_point = 0;
+ for( i = 0; i < count; i++ )
+ {
+/*
+ icvSubVector_32f ((IppmVect32f )&points[i], (IppmVect32f )&line[3], sub, 3);
+
+ icvCrossProduct2L_32f ((IppmVect32f )&line[0], sub, cros);
+*/
+
+ sub[0] = points[i].x - line[3];
+ sub[1] = points[i].y - line[4];
+ sub[2] = points[i].z - line[5];
+
+// if(fabs(sub[0])<eps||fabs(sub[1])<eps||fabs(sub[2])<eps) continue;
+
+ a[0] = sub[0] * line[1] - sub[1] * line[0];
+ a[1] = sub[1] * line[2] - sub[2] * line[1];
+ a[2] = sub[2] * line[0] - sub[0] * line[2];
+
+ v_gor = icvDotProduct_32f( gor, &line[0], 3 );
+ v_ver = icvDotProduct_32f( ver, &line[0], 3 );
+
+ if( v_ver > v_gor )
+ log = true;
+ else
+ log = false;
+
+
+/* if(IPPI_NORM_L22 ( cros ) < threshold2) */
+/*
+ if(fabs(a[0])<eps && fabs(a[1])<eps && fabs(a[2])<eps)
+ {
+ icvDotProduct_32f( sub, &line[0], 3, &value);
+ if(value > vmax) vmax = value;
+ if(value < vmin) vmin = value;
+
+ vv[i_point] = value;
+
+ pt = (CvPoint* )icvGetSeqElem ( indexs, i, 0);
+
+ if(pt->x > jmax) jmax = pt->x;
+ if(pt->x < jmin) jmin = pt->x;
+
+ tmp_number[i_point] = *pt;
+ i_point++;
+ }
+ else
+*/
+ {
+ if( _CV_NORM_L32( a ) < threshold2 )
+ {
+ value = (float)icvDotProduct_32f( sub, &line[0], 3 );
+ if( value > vmax )
+ vmax = value;
+ if( value < vmin )
+ vmin = value;
+
+ vv[i_point] = value;
+
+ pt = (CvPoint*)cvGetSeqElem( indexs, i );
+
+ if( !log )
+ {
+ if( pt->x > jmax )
+ jmax = pt->x;
+ if( pt->x < jmin )
+ jmin = pt->x;
+ }
+ else
+ {
+ if( pt->y > jmax )
+ jmax = pt->y;
+ if( pt->y < jmin )
+ jmin = pt->y;
+ }
+
+
+ tmp_number[i_point] = *pt;
+ i_point++;
+ }
+ }
+ }
+
+/* compute the length of one bucket along the line */
+ vl = vmax - vmin;
+
+/* examining on the arm's existence */
+ if( vl < eps )
+ {
+ *numbers = NULL;
+ status = CV_OK;
+ goto M_END;
+ }
+
+ bsize = vl / nbins;
+
+/* compute the number of points in each bucket along the line */
+ for( i = 0; i < i_point; i++ )
+ {
+ l = cvRound( (vv[i] - vmin) / bsize );
+ bin_counts[l]++;
+ }
+
+ /* compute the length of one bucket along the X axe */
+ jl = jmax - jmin;
+ if( jl <= 1 )
+ {
+ *numbers = NULL;
+ status = CV_OK;
+ goto M_END;
+ }
+
+ bsizej = (float) (jl / (nbins + 0.));
+
+/* compute the number of points in each bucket along the X axe */
+// for(i=0;i<i_point;i++)
+// {
+// l = cvRound((tmp_number[i].x - jmin)/bsizej);
+// bin_countsj[l]++;
+// }
+
+
+ left = right = -1;
+
+/* find the leftmost and the rightmost buckets */
+ for( l = 0; l < nbins; l++ )
+ {
+ if( bin_counts[l] > low_count && left == -1 )
+ left = l;
+ else if( bin_counts[l] > low_count && left >= 0 )
+ right = l;
+
+ }
+
+/* compute center point of the left hand */
+ if( left == -1 && right == -1 )
+ {
+ *numbers = NULL;
+ status = CV_OK;
+ goto M_END;
+ }
+
+ hand_left = vmin + left * bsize;
+ j_left = (int) (jmin + left * bsizej);
+
+ vcl = hand_left + hand_length2;
+
+/* compute center point of the right hand */
+ hand_right = vmax - (nbins - right - 1) * bsize;
+ vcr = hand_right - hand_length2;
+
+ j_right = (int) (jmax - (nbins - right - 1) * bsizej);
+
+ j_left = abs( j_left - jc );
+ j_right = abs( j_right - jc );
+
+ if( j_left <= j_right )
+ {
+ hand_right = hand_left + hand_length;
+ vc = vcl;
+ }
+ else
+ {
+ hand_left = hand_right - hand_length;
+ vc = vcr;
+ }
+
+ icvScaleVector_32f( &line[0], sub, 3, vc );
+ icvAddVector_32f( &line[3], sub, (float *) center, 3 );
+
+/* select hand's points and calculate mean value */
+ *numbers = cvCreateSeq( CV_SEQ_POINT_SET, sizeof( CvSeq ), sizeof( CvPoint ), storage );
+ assert( *numbers != 0 );
+ if( *numbers == NULL )
+ {
+ status = CV_OUTOFMEM_ERR;
+ goto M_END;
+ }
+
+ cvStartAppendToSeq( *numbers, &writer );
+
+ for( l = 0; l < i_point; l++ )
+ {
+ if( vv[l] >= hand_left && vv[l] <= hand_right )
+ {
+ CV_WRITE_SEQ_ELEM( tmp_number[l], writer );
+
+ }
+ }
+
+ cvEndWriteSeq( &writer );
+
+ M_END:
+ if( tmp_number != NULL )
+ cvFree( &tmp_number );
+// if(bin_countsj != NULL) cvFree( &bin_countsj );
+ if( bin_counts != NULL )
+ cvFree( &bin_counts );
+
+ if( vv != NULL )
+ cvFree( &vv );
+
+ if( sub != NULL ) icvDeleteVector (sub);
+ if( cros != NULL ) icvDeleteVector (cros);
+
+ return status;
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvFindHandRegion
+// Purpose: finds hand region in range image data
+// Context:
+// Parameters:
+// points - pointer to the input point's set.
+// count - the number of the input points.
+// indexs - pointer to the input sequence of the point's indexes
+// line - pointer to the 3D-line
+// size - size of the hand in meters
+// flag - hand direction's flag (0 - left, -1 - right,
+// otherwise j-index of the initial image center)
+// center - pointer to the output hand center
+// storage - pointer to the memory storage
+// numbers - pointer to the output sequence of the point's indexes inside
+// hand region
+//
+// Notes:
+//F*/
+CV_IMPL void
+cvFindHandRegion( CvPoint3D32f * points, int count,
+ CvSeq * indexs,
+ float *line, CvSize2D32f size, int flag,
+ CvPoint3D32f * center, CvMemStorage * storage, CvSeq ** numbers )
+{
+ CV_FUNCNAME( "cvFindHandRegion" );
+ __BEGIN__;
+
+ if(flag == 0 || flag == -1)
+ {
+ IPPI_CALL( icvFindHandRegion( points, count, indexs, line, size, -flag,
+ center, storage, numbers ));
+ }
+ else
+ IPPI_CALL( icvFindHandRegionA( points, count, indexs, line, size, flag,
+ center, storage, numbers ));
+
+ __CLEANUP__;
+ __END__;
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvFindHandRegionA
+// Purpose: finds hand region in range image data
+// Context:
+// Parameters:
+// points - pointer to the input point's set.
+// count - the number of the input points.
+// indexs - pointer to the input sequence of the point's indexes
+// line - pointer to the 3D-line
+// size - size of the hand in meters
+// jc - j-index of the initial image center
+// center - pointer to the output hand center
+// storage - pointer to the memory storage
+// numbers - pointer to the output sequence of the point's indexes inside
+// hand region
+//
+// Notes:
+//F*/
+CV_IMPL void
+cvFindHandRegionA( CvPoint3D32f * points, int count,
+ CvSeq * indexs,
+ float *line, CvSize2D32f size, int jc,
+ CvPoint3D32f * center, CvMemStorage * storage, CvSeq ** numbers )
+{
+ CV_FUNCNAME( "cvFindHandRegionA" );
+ __BEGIN__;
+
+ IPPI_CALL( icvFindHandRegionA( points, count, indexs, line, size, jc,
+ center, storage, numbers ));
+ __CLEANUP__;
+ __END__;
+}
+
diff --git a/cvaux/src/cvhmm.cpp b/cvaux/src/cvhmm.cpp
new file mode 100644
index 0000000..65e0b2f
--- /dev/null
+++ b/cvaux/src/cvhmm.cpp
@@ -0,0 +1,1770 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+#define LN2PI 1.837877f
+#define BIG_FLT 1.e+10f
+
+
+#define _CV_ERGODIC 1
+#define _CV_CAUSAL 2
+
+#define _CV_LAST_STATE 1
+#define _CV_BEST_STATE 2
+
+
+//*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: _cvCreateObsInfo
+// Purpose: The function allocates memory for CvImgObsInfo structure
+// and its inner stuff
+// Context:
+// Parameters: obs_info - addres of pointer to CvImgObsInfo structure
+// num_hor_obs - number of horizontal observation vectors
+// num_ver_obs - number of horizontal observation vectors
+// obs_size - length of observation vector
+//
+// Returns: error status
+//
+// Notes:
+//F*/
+static CvStatus CV_STDCALL icvCreateObsInfo( CvImgObsInfo** obs_info,
+ CvSize num_obs, int obs_size )
+{
+ int total = num_obs.height * num_obs.width;
+
+ CvImgObsInfo* obs = (CvImgObsInfo*)cvAlloc( sizeof( CvImgObsInfo) );
+
+ obs->obs_x = num_obs.width;
+ obs->obs_y = num_obs.height;
+
+ obs->obs = (float*)cvAlloc( total * obs_size * sizeof(float) );
+
+ obs->state = (int*)cvAlloc( 2 * total * sizeof(int) );
+ obs->mix = (int*)cvAlloc( total * sizeof(int) );
+
+ obs->obs_size = obs_size;
+
+ obs_info[0] = obs;
+
+ return CV_NO_ERR;
+}
+
+static CvStatus CV_STDCALL icvReleaseObsInfo( CvImgObsInfo** p_obs_info )
+{
+ CvImgObsInfo* obs_info = p_obs_info[0];
+
+ cvFree( &(obs_info->obs) );
+ cvFree( &(obs_info->mix) );
+ cvFree( &(obs_info->state) );
+ cvFree( &(obs_info) );
+
+ p_obs_info[0] = NULL;
+
+ return CV_NO_ERR;
+}
+
+
+//*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvCreate2DHMM
+// Purpose: The function allocates memory for 2-dimensional embedded HMM model
+// and its inner stuff
+// Context:
+// Parameters: hmm - addres of pointer to CvEHMM structure
+// state_number - array of hmm sizes (size of array == state_number[0]+1 )
+// num_mix - number of gaussian mixtures in low-level HMM states
+// size of array is defined by previous array values
+// obs_size - length of observation vectors
+//
+// Returns: error status
+//
+// Notes: state_number[0] - number of states in external HMM.
+// state_number[i] - number of states in embedded HMM
+//
+// example for face recognition: state_number = { 5 3 6 6 6 3 },
+// length of num_mix array = 3+6+6+6+3 = 24//
+//
+//F*/
+static CvStatus CV_STDCALL icvCreate2DHMM( CvEHMM** this_hmm,
+ int* state_number, int* num_mix, int obs_size )
+{
+ int i;
+ int real_states = 0;
+
+ CvEHMMState* all_states;
+ CvEHMM* hmm;
+ int total_mix = 0;
+ float* pointers;
+
+ //compute total number of states of all level in 2d EHMM
+ for( i = 1; i <= state_number[0]; i++ )
+ {
+ real_states += state_number[i];
+ }
+
+ /* allocate memory for all hmms (from all levels) */
+ hmm = (CvEHMM*)cvAlloc( (state_number[0] + 1) * sizeof(CvEHMM) );
+
+ /* set number of superstates */
+ hmm[0].num_states = state_number[0];
+ hmm[0].level = 1;
+
+ /* allocate memory for all states */
+ all_states = (CvEHMMState *)cvAlloc( real_states * sizeof( CvEHMMState ) );
+
+ /* assign number of mixtures */
+ for( i = 0; i < real_states; i++ )
+ {
+ all_states[i].num_mix = num_mix[i];
+ }
+
+ /* compute size of inner of all real states */
+ for( i = 0; i < real_states; i++ )
+ {
+ total_mix += num_mix[i];
+ }
+ /* allocate memory for states stuff */
+ pointers = (float*)cvAlloc( total_mix * (2/*for mu invvar */ * obs_size +
+ 2/*for weight and log_var_val*/ ) * sizeof( float) );
+
+ /* organize memory */
+ for( i = 0; i < real_states; i++ )
+ {
+ all_states[i].mu = pointers; pointers += num_mix[i] * obs_size;
+ all_states[i].inv_var = pointers; pointers += num_mix[i] * obs_size;
+
+ all_states[i].log_var_val = pointers; pointers += num_mix[i];
+ all_states[i].weight = pointers; pointers += num_mix[i];
+ }
+
+ /* set pointer to embedded hmm array */
+ hmm->u.ehmm = hmm + 1;
+
+ for( i = 0; i < hmm[0].num_states; i++ )
+ {
+ hmm[i+1].u.state = all_states;
+ all_states += state_number[i+1];
+ hmm[i+1].num_states = state_number[i+1];
+ }
+
+ for( i = 0; i <= state_number[0]; i++ )
+ {
+ hmm[i].transP = icvCreateMatrix_32f( hmm[i].num_states, hmm[i].num_states );
+ hmm[i].obsProb = NULL;
+ hmm[i].level = i ? 0 : 1;
+ }
+
+ /* if all ok - return pointer */
+ *this_hmm = hmm;
+ return CV_NO_ERR;
+}
+
+static CvStatus CV_STDCALL icvRelease2DHMM( CvEHMM** phmm )
+{
+ CvEHMM* hmm = phmm[0];
+ int i;
+ for( i = 0; i < hmm[0].num_states + 1; i++ )
+ {
+ icvDeleteMatrix( hmm[i].transP );
+ }
+
+ if (hmm->obsProb != NULL)
+ {
+ int* tmp = ((int*)(hmm->obsProb)) - 3;
+ cvFree( &(tmp) );
+ }
+
+ cvFree( &(hmm->u.ehmm->u.state->mu) );
+ cvFree( &(hmm->u.ehmm->u.state) );
+
+
+ /* free hmm structures */
+ cvFree( phmm );
+
+ phmm[0] = NULL;
+
+ return CV_NO_ERR;
+}
+
+/* distance between 2 vectors */
+static float icvSquareDistance( CvVect32f v1, CvVect32f v2, int len )
+{
+ int i;
+ double dist0 = 0;
+ double dist1 = 0;
+
+ for( i = 0; i <= len - 4; i += 4 )
+ {
+ double t0 = v1[i] - v2[i];
+ double t1 = v1[i+1] - v2[i+1];
+ dist0 += t0*t0;
+ dist1 += t1*t1;
+
+ t0 = v1[i+2] - v2[i+2];
+ t1 = v1[i+3] - v2[i+3];
+ dist0 += t0*t0;
+ dist1 += t1*t1;
+ }
+
+ for( ; i < len; i++ )
+ {
+ double t0 = v1[i] - v2[i];
+ dist0 += t0*t0;
+ }
+
+ return (float)(dist0 + dist1);
+}
+
+/*can be used in CHMM & DHMM */
+static CvStatus CV_STDCALL
+icvUniformImgSegm( CvImgObsInfo* obs_info, CvEHMM* hmm )
+{
+#if 1
+ /* implementation is very bad */
+ int i, j, counter = 0;
+ CvEHMMState* first_state;
+ float inv_x = 1.f/obs_info->obs_x;
+ float inv_y = 1.f/obs_info->obs_y;
+
+ /* check arguments */
+ if ( !obs_info || !hmm ) return CV_NULLPTR_ERR;
+
+ first_state = hmm->u.ehmm->u.state;
+
+ for (i = 0; i < obs_info->obs_y; i++)
+ {
+ //bad line (division )
+ int superstate = (int)((i * hmm->num_states)*inv_y);/* /obs_info->obs_y; */
+
+ int index = (int)(hmm->u.ehmm[superstate].u.state - first_state);
+
+ for (j = 0; j < obs_info->obs_x; j++, counter++)
+ {
+ int state = (int)((j * hmm->u.ehmm[superstate].num_states)* inv_x); /* / obs_info->obs_x; */
+
+ obs_info->state[2 * counter] = superstate;
+ obs_info->state[2 * counter + 1] = state + index;
+ }
+ }
+#else
+ //this is not ready yet
+
+ int i,j,k,m;
+ CvEHMMState* first_state = hmm->u.ehmm->u.state;
+
+ /* check bad arguments */
+ if ( hmm->num_states > obs_info->obs_y ) return CV_BADSIZE_ERR;
+
+ //compute vertical subdivision
+ float row_per_state = (float)obs_info->obs_y / hmm->num_states;
+ float col_per_state[1024]; /* maximum 1024 superstates */
+
+ //for every horizontal band compute subdivision
+ for( i = 0; i < hmm->num_states; i++ )
+ {
+ CvEHMM* ehmm = &(hmm->u.ehmm[i]);
+ col_per_state[i] = (float)obs_info->obs_x / ehmm->num_states;
+ }
+
+ //compute state bounds
+ int ss_bound[1024];
+ for( i = 0; i < hmm->num_states - 1; i++ )
+ {
+ ss_bound[i] = floor( row_per_state * ( i+1 ) );
+ }
+ ss_bound[hmm->num_states - 1] = obs_info->obs_y;
+
+ //work inside every superstate
+
+ int row = 0;
+
+ for( i = 0; i < hmm->num_states; i++ )
+ {
+ CvEHMM* ehmm = &(hmm->u.ehmm[i]);
+ int index = ehmm->u.state - first_state;
+
+ //calc distribution in superstate
+ int es_bound[1024];
+ for( j = 0; j < ehmm->num_states - 1; j++ )
+ {
+ es_bound[j] = floor( col_per_state[i] * ( j+1 ) );
+ }
+ es_bound[ehmm->num_states - 1] = obs_info->obs_x;
+
+ //assign states to first row of superstate
+ int col = 0;
+ for( j = 0; j < ehmm->num_states; j++ )
+ {
+ for( k = col; k < es_bound[j]; k++, col++ )
+ {
+ obs_info->state[row * obs_info->obs_x + 2 * k] = i;
+ obs_info->state[row * obs_info->obs_x + 2 * k + 1] = j + index;
+ }
+ col = es_bound[j];
+ }
+
+ //copy the same to other rows of superstate
+ for( m = row; m < ss_bound[i]; m++ )
+ {
+ memcpy( &(obs_info->state[m * obs_info->obs_x * 2]),
+ &(obs_info->state[row * obs_info->obs_x * 2]), obs_info->obs_x * 2 * sizeof(int) );
+ }
+
+ row = ss_bound[i];
+ }
+
+#endif
+
+ return CV_NO_ERR;
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: InitMixSegm
+// Purpose: The function implements the mixture segmentation of the states of the
+// embedded HMM
+// Context: used with the Viterbi training of the embedded HMM
+// Function uses K-Means algorithm for clustering
+//
+// Parameters: obs_info_array - array of pointers to image observations
+// num_img - length of above array
+// hmm - pointer to HMM structure
+//
+// Returns: error status
+//
+// Notes:
+//F*/
+static CvStatus CV_STDCALL
+icvInitMixSegm( CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm )
+{
+ int k, i, j;
+ int* num_samples; /* number of observations in every state */
+ int* counter; /* array of counters for every state */
+
+ int** a_class; /* for every state - characteristic array */
+
+ CvVect32f** samples; /* for every state - pointer to observation vectors */
+ int*** samples_mix; /* for every state - array of pointers to vectors mixtures */
+
+ CvTermCriteria criteria = cvTermCriteria( CV_TERMCRIT_EPS|CV_TERMCRIT_ITER,
+ 1000, /* iter */
+ 0.01f ); /* eps */
+
+ int total = 0;
+
+ CvEHMMState* first_state = hmm->u.ehmm->u.state;
+
+ for( i = 0 ; i < hmm->num_states; i++ )
+ {
+ total += hmm->u.ehmm[i].num_states;
+ }
+
+ /* for every state integer is allocated - number of vectors in state */
+ num_samples = (int*)cvAlloc( total * sizeof(int) );
+
+ /* integer counter is allocated for every state */
+ counter = (int*)cvAlloc( total * sizeof(int) );
+
+ samples = (CvVect32f**)cvAlloc( total * sizeof(CvVect32f*) );
+ samples_mix = (int***)cvAlloc( total * sizeof(int**) );
+
+ /* clear */
+ memset( num_samples, 0 , total*sizeof(int) );
+ memset( counter, 0 , total*sizeof(int) );
+
+
+ /* for every state the number of vectors which belong to it is computed (smth. like histogram) */
+ for (k = 0; k < num_img; k++)
+ {
+ CvImgObsInfo* obs = obs_info_array[k];
+ int count = 0;
+
+ for (i = 0; i < obs->obs_y; i++)
+ {
+ for (j = 0; j < obs->obs_x; j++, count++)
+ {
+ int state = obs->state[ 2 * count + 1];
+ num_samples[state] += 1;
+ }
+ }
+ }
+
+ /* for every state int* is allocated */
+ a_class = (int**)cvAlloc( total*sizeof(int*) );
+
+ for (i = 0; i < total; i++)
+ {
+ a_class[i] = (int*)cvAlloc( num_samples[i] * sizeof(int) );
+ samples[i] = (CvVect32f*)cvAlloc( num_samples[i] * sizeof(CvVect32f) );
+ samples_mix[i] = (int**)cvAlloc( num_samples[i] * sizeof(int*) );
+ }
+
+ /* for every state vectors which belong to state are gathered */
+ for (k = 0; k < num_img; k++)
+ {
+ CvImgObsInfo* obs = obs_info_array[k];
+ int num_obs = ( obs->obs_x ) * ( obs->obs_y );
+ float* vector = obs->obs;
+
+ for (i = 0; i < num_obs; i++, vector+=obs->obs_size )
+ {
+ int state = obs->state[2*i+1];
+
+ samples[state][counter[state]] = vector;
+ samples_mix[state][counter[state]] = &(obs->mix[i]);
+ counter[state]++;
+ }
+ }
+
+ /* clear counters */
+ memset( counter, 0, total*sizeof(int) );
+
+ /* do the actual clustering using the K Means algorithm */
+ for (i = 0; i < total; i++)
+ {
+ if ( first_state[i].num_mix == 1)
+ {
+ for (k = 0; k < num_samples[i]; k++)
+ {
+ /* all vectors belong to one mixture */
+ a_class[i][k] = 0;
+ }
+ }
+ else if( num_samples[i] )
+ {
+ /* clusterize vectors */
+ cvKMeans( first_state[i].num_mix, samples[i], num_samples[i],
+ obs_info_array[0]->obs_size, criteria, a_class[i] );
+ }
+ }
+
+ /* for every vector number of mixture is assigned */
+ for( i = 0; i < total; i++ )
+ {
+ for (j = 0; j < num_samples[i]; j++)
+ {
+ samples_mix[i][j][0] = a_class[i][j];
+ }
+ }
+
+ for (i = 0; i < total; i++)
+ {
+ cvFree( &(a_class[i]) );
+ cvFree( &(samples[i]) );
+ cvFree( &(samples_mix[i]) );
+ }
+
+ cvFree( &a_class );
+ cvFree( &samples );
+ cvFree( &samples_mix );
+ cvFree( &counter );
+ cvFree( &num_samples );
+
+ return CV_NO_ERR;
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: ComputeUniModeGauss
+// Purpose: The function computes the Gaussian pdf for a sample vector
+// Context:
+// Parameters: obsVeq - pointer to the sample vector
+// mu - pointer to the mean vector of the Gaussian pdf
+// var - pointer to the variance vector of the Gaussian pdf
+// VecSize - the size of sample vector
+//
+// Returns: the pdf of the sample vector given the specified Gaussian
+//
+// Notes:
+//F*/
+/*static float icvComputeUniModeGauss(CvVect32f vect, CvVect32f mu,
+ CvVect32f inv_var, float log_var_val, int vect_size)
+{
+ int n;
+ double tmp;
+ double prob;
+
+ prob = -log_var_val;
+
+ for (n = 0; n < vect_size; n++)
+ {
+ tmp = (vect[n] - mu[n]) * inv_var[n];
+ prob = prob - tmp * tmp;
+ }
+ //prob *= 0.5f;
+
+ return (float)prob;
+}*/
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: ComputeGaussMixture
+// Purpose: The function computes the mixture Gaussian pdf of a sample vector.
+// Context:
+// Parameters: obsVeq - pointer to the sample vector
+// mu - two-dimensional pointer to the mean vector of the Gaussian pdf;
+// the first dimension is indexed over the number of mixtures and
+// the second dimension is indexed along the size of the mean vector
+// var - two-dimensional pointer to the variance vector of the Gaussian pdf;
+// the first dimension is indexed over the number of mixtures and
+// the second dimension is indexed along the size of the variance vector
+// VecSize - the size of sample vector
+// weight - pointer to the wights of the Gaussian mixture
+// NumMix - the number of Gaussian mixtures
+//
+// Returns: the pdf of the sample vector given the specified Gaussian mixture.
+//
+// Notes:
+//F*/
+/* Calculate probability of observation at state in logarithmic scale*/
+/*static float
+icvComputeGaussMixture( CvVect32f vect, float* mu,
+ float* inv_var, float* log_var_val,
+ int vect_size, float* weight, int num_mix )
+{
+ double prob, l_prob;
+
+ prob = 0.0f;
+
+ if (num_mix == 1)
+ {
+ return icvComputeUniModeGauss( vect, mu, inv_var, log_var_val[0], vect_size);
+ }
+ else
+ {
+ int m;
+ for (m = 0; m < num_mix; m++)
+ {
+ if ( weight[m] > 0.0)
+ {
+ l_prob = icvComputeUniModeGauss(vect, mu + m*vect_size,
+ inv_var + m * vect_size,
+ log_var_val[m],
+ vect_size);
+
+ prob = prob + weight[m]*exp((double)l_prob);
+ }
+ }
+ prob = log(prob);
+ }
+ return (float)prob;
+}*/
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: EstimateObsProb
+// Purpose: The function computes the probability of every observation in every state
+// Context:
+// Parameters: obs_info - observations
+// hmm - hmm
+// Returns: error status
+//
+// Notes:
+//F*/
+static CvStatus CV_STDCALL icvEstimateObsProb( CvImgObsInfo* obs_info, CvEHMM* hmm )
+{
+ int i, j;
+ int total_states = 0;
+
+ /* check if matrix exist and check current size
+ if not sufficient - realloc */
+ int status = 0; /* 1 - not allocated, 2 - allocated but small size,
+ 3 - size is enough, but distribution is bad, 0 - all ok */
+
+ for( j = 0; j < hmm->num_states; j++ )
+ {
+ total_states += hmm->u.ehmm[j].num_states;
+ }
+
+ if ( hmm->obsProb == NULL )
+ {
+ /* allocare memory */
+ int need_size = ( obs_info->obs_x * obs_info->obs_y * total_states * sizeof(float) +
+ obs_info->obs_y * hmm->num_states * sizeof( CvMatr32f) );
+
+ int* buffer = (int*)cvAlloc( need_size + 3 * sizeof(int) );
+ buffer[0] = need_size;
+ buffer[1] = obs_info->obs_y;
+ buffer[2] = obs_info->obs_x;
+ hmm->obsProb = (float**) (buffer + 3);
+ status = 3;
+
+ }
+ else
+ {
+ /* check current size */
+ int* total= (int*)(((int*)(hmm->obsProb)) - 3);
+ int need_size = ( obs_info->obs_x * obs_info->obs_y * total_states * sizeof(float) +
+ obs_info->obs_y * hmm->num_states * sizeof( CvMatr32f/*(float*)*/ ) );
+
+ assert( sizeof(float*) == sizeof(int) );
+
+ if ( need_size > (*total) )
+ {
+ int* buffer = ((int*)(hmm->obsProb)) - 3;
+ cvFree( &buffer);
+ buffer = (int*)cvAlloc( need_size + 3 * sizeof(int));
+ buffer[0] = need_size;
+ buffer[1] = obs_info->obs_y;
+ buffer[2] = obs_info->obs_x;
+
+ hmm->obsProb = (float**)(buffer + 3);
+
+ status = 3;
+ }
+ }
+ if (!status)
+ {
+ int* obsx = ((int*)(hmm->obsProb)) - 1;
+ int* obsy = ((int*)(hmm->obsProb)) - 2;
+
+ assert( (*obsx > 0) && (*obsy > 0) );
+
+ /* is good distribution? */
+ if ( (obs_info->obs_x > (*obsx) ) || (obs_info->obs_y > (*obsy) ) )
+ status = 3;
+ }
+
+ /* if bad status - do reallocation actions */
+ assert( (status == 0) || (status == 3) );
+
+ if ( status )
+ {
+ float** tmp = hmm->obsProb;
+ float* tmpf;
+
+ /* distribute pointers of ehmm->obsProb */
+ for( i = 0; i < hmm->num_states; i++ )
+ {
+ hmm->u.ehmm[i].obsProb = tmp;
+ tmp += obs_info->obs_y;
+ }
+
+ tmpf = (float*)tmp;
+
+ /* distribute pointers of ehmm->obsProb[j] */
+ for( i = 0; i < hmm->num_states; i++ )
+ {
+ CvEHMM* ehmm = &( hmm->u.ehmm[i] );
+
+ for( j = 0; j < obs_info->obs_y; j++ )
+ {
+ ehmm->obsProb[j] = tmpf;
+ tmpf += ehmm->num_states * obs_info->obs_x;
+ }
+ }
+ }/* end of pointer distribution */
+
+#if 1
+ {
+#define MAX_BUF_SIZE 1200
+ float local_log_mix_prob[MAX_BUF_SIZE];
+ double local_mix_prob[MAX_BUF_SIZE];
+ int vect_size = obs_info->obs_size;
+ CvStatus res = CV_NO_ERR;
+
+ float* log_mix_prob = local_log_mix_prob;
+ double* mix_prob = local_mix_prob;
+
+ int max_size = 0;
+ int obs_x = obs_info->obs_x;
+
+ /* calculate temporary buffer size */
+ for( i = 0; i < hmm->num_states; i++ )
+ {
+ CvEHMM* ehmm = &(hmm->u.ehmm[i]);
+ CvEHMMState* state = ehmm->u.state;
+
+ int max_mix = 0;
+ for( j = 0; j < ehmm->num_states; j++ )
+ {
+ int t = state[j].num_mix;
+ if( max_mix < t ) max_mix = t;
+ }
+ max_mix *= ehmm->num_states;
+ if( max_size < max_mix ) max_size = max_mix;
+ }
+
+ max_size *= obs_x * vect_size;
+
+ /* allocate buffer */
+ if( max_size > MAX_BUF_SIZE )
+ {
+ log_mix_prob = (float*)cvAlloc( max_size*(sizeof(float) + sizeof(double)));
+ if( !log_mix_prob ) return CV_OUTOFMEM_ERR;
+ mix_prob = (double*)(log_mix_prob + max_size);
+ }
+
+ memset( log_mix_prob, 0, max_size*sizeof(float));
+
+ /*****************computing probabilities***********************/
+
+ /* loop through external states */
+ for( i = 0; i < hmm->num_states; i++ )
+ {
+ CvEHMM* ehmm = &(hmm->u.ehmm[i]);
+ CvEHMMState* state = ehmm->u.state;
+
+ int max_mix = 0;
+ int n_states = ehmm->num_states;
+
+ /* determine maximal number of mixtures (again) */
+ for( j = 0; j < ehmm->num_states; j++ )
+ {
+ int t = state[j].num_mix;
+ if( max_mix < t ) max_mix = t;
+ }
+
+ /* loop through rows of the observation matrix */
+ for( j = 0; j < obs_info->obs_y; j++ )
+ {
+ int m, n;
+
+ float* obs = obs_info->obs + j * obs_x * vect_size;
+ float* log_mp = max_mix > 1 ? log_mix_prob : ehmm->obsProb[j];
+ double* mp = mix_prob;
+
+ /* several passes are done below */
+
+ /* 1. calculate logarithms of probabilities for each mixture */
+
+ /* loop through mixtures */
+ for( m = 0; m < max_mix; m++ )
+ {
+ /* set pointer to first observation in the line */
+ float* vect = obs;
+
+ /* cycles through obseravtions in the line */
+ for( n = 0; n < obs_x; n++, vect += vect_size, log_mp += n_states )
+ {
+ int k, l;
+ for( l = 0; l < n_states; l++ )
+ {
+ if( state[l].num_mix > m )
+ {
+ float* mu = state[l].mu + m*vect_size;
+ float* inv_var = state[l].inv_var + m*vect_size;
+ double prob = -state[l].log_var_val[m];
+ for( k = 0; k < vect_size; k++ )
+ {
+ double t = (vect[k] - mu[k])*inv_var[k];
+ prob -= t*t;
+ }
+ log_mp[l] = MAX( (float)prob, -500 );
+ }
+ }
+ }
+ }
+
+ /* skip the rest if there is a single mixture */
+ if( max_mix == 1 ) continue;
+
+ /* 2. calculate exponent of log_mix_prob
+ (i.e. probability for each mixture) */
+ cvbFastExp( log_mix_prob, mix_prob, max_mix * obs_x * n_states );
+
+ /* 3. sum all mixtures with weights */
+ /* 3a. first mixture - simply scale by weight */
+ for( n = 0; n < obs_x; n++, mp += n_states )
+ {
+ int l;
+ for( l = 0; l < n_states; l++ )
+ {
+ mp[l] *= state[l].weight[0];
+ }
+ }
+
+ /* 3b. add other mixtures */
+ for( m = 1; m < max_mix; m++ )
+ {
+ int ofs = -m*obs_x*n_states;
+ for( n = 0; n < obs_x; n++, mp += n_states )
+ {
+ int l;
+ for( l = 0; l < n_states; l++ )
+ {
+ if( m < state[l].num_mix )
+ {
+ mp[l + ofs] += mp[l] * state[l].weight[m];
+ }
+ }
+ }
+ }
+
+ /* 4. Put logarithms of summary probabilities to the destination matrix */
+ cvbFastLog( mix_prob, ehmm->obsProb[j], obs_x * n_states );
+ }
+ }
+
+ if( log_mix_prob != local_log_mix_prob ) cvFree( &log_mix_prob );
+ return res;
+#undef MAX_BUF_SIZE
+ }
+#else
+ for( i = 0; i < hmm->num_states; i++ )
+ {
+ CvEHMM* ehmm = &(hmm->u.ehmm[i]);
+ CvEHMMState* state = ehmm->u.state;
+
+ for( j = 0; j < obs_info->obs_y; j++ )
+ {
+ int k,m;
+
+ int obs_index = j * obs_info->obs_x;
+
+ float* B = ehmm->obsProb[j];
+
+ /* cycles through obs and states */
+ for( k = 0; k < obs_info->obs_x; k++ )
+ {
+ CvVect32f vect = (obs_info->obs) + (obs_index + k) * vect_size;
+
+ float* matr_line = B + k * ehmm->num_states;
+
+ for( m = 0; m < ehmm->num_states; m++ )
+ {
+ matr_line[m] = icvComputeGaussMixture( vect, state[m].mu, state[m].inv_var,
+ state[m].log_var_val, vect_size, state[m].weight,
+ state[m].num_mix );
+ }
+ }
+ }
+ }
+#endif
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: EstimateTransProb
+// Purpose: The function calculates the state and super state transition probabilities
+// of the model given the images,
+// the state segmentation and the input parameters
+// Context:
+// Parameters: obs_info_array - array of pointers to image observations
+// num_img - length of above array
+// hmm - pointer to HMM structure
+// Returns: void
+//
+// Notes:
+//F*/
+static CvStatus CV_STDCALL
+icvEstimateTransProb( CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm )
+{
+ int i, j, k;
+
+ CvEHMMState* first_state = hmm->u.ehmm->u.state;
+ /* as a counter we will use transP matrix */
+
+ /* initialization */
+
+ /* clear transP */
+ icvSetZero_32f( hmm->transP, hmm->num_states, hmm->num_states );
+ for (i = 0; i < hmm->num_states; i++ )
+ {
+ icvSetZero_32f( hmm->u.ehmm[i].transP , hmm->u.ehmm[i].num_states, hmm->u.ehmm[i].num_states );
+ }
+
+ /* compute the counters */
+ for (i = 0; i < num_img; i++)
+ {
+ int counter = 0;
+ CvImgObsInfo* info = obs_info_array[i];
+
+ for (j = 0; j < info->obs_y; j++)
+ {
+ for (k = 0; k < info->obs_x; k++, counter++)
+ {
+ /* compute how many transitions from state to state
+ occured both in horizontal and vertical direction */
+ int superstate, state;
+ int nextsuperstate, nextstate;
+ int begin_ind;
+
+ superstate = info->state[2 * counter];
+ begin_ind = (int)(hmm->u.ehmm[superstate].u.state - first_state);
+ state = info->state[ 2 * counter + 1] - begin_ind;
+
+ if (j < info->obs_y - 1)
+ {
+ int transP_size = hmm->num_states;
+
+ nextsuperstate = info->state[ 2*(counter + info->obs_x) ];
+
+ hmm->transP[superstate * transP_size + nextsuperstate] += 1;
+ }
+
+ if (k < info->obs_x - 1)
+ {
+ int transP_size = hmm->u.ehmm[superstate].num_states;
+
+ nextstate = info->state[2*(counter+1) + 1] - begin_ind;
+ hmm->u.ehmm[superstate].transP[ state * transP_size + nextstate] += 1;
+ }
+ }
+ }
+ }
+ /* estimate superstate matrix */
+ for( i = 0; i < hmm->num_states; i++)
+ {
+ float total = 0;
+ float inv_total;
+ for( j = 0; j < hmm->num_states; j++)
+ {
+ total += hmm->transP[i * hmm->num_states + j];
+ }
+ //assert( total );
+
+ inv_total = total ? 1.f/total : 0;
+
+ for( j = 0; j < hmm->num_states; j++)
+ {
+ hmm->transP[i * hmm->num_states + j] =
+ hmm->transP[i * hmm->num_states + j] ?
+ (float)log( hmm->transP[i * hmm->num_states + j] * inv_total ) : -BIG_FLT;
+ }
+ }
+
+ /* estimate other matrices */
+ for( k = 0; k < hmm->num_states; k++ )
+ {
+ CvEHMM* ehmm = &(hmm->u.ehmm[k]);
+
+ for( i = 0; i < ehmm->num_states; i++)
+ {
+ float total = 0;
+ float inv_total;
+ for( j = 0; j < ehmm->num_states; j++)
+ {
+ total += ehmm->transP[i*ehmm->num_states + j];
+ }
+ //assert( total );
+ inv_total = total ? 1.f/total : 0;
+
+ for( j = 0; j < ehmm->num_states; j++)
+ {
+ ehmm->transP[i * ehmm->num_states + j] =
+ (ehmm->transP[i * ehmm->num_states + j]) ?
+ (float)log( ehmm->transP[i * ehmm->num_states + j] * inv_total) : -BIG_FLT ;
+ }
+ }
+ }
+ return CV_NO_ERR;
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: MixSegmL2
+// Purpose: The function implements the mixture segmentation of the states of the
+// embedded HMM
+// Context: used with the Viterbi training of the embedded HMM
+//
+// Parameters:
+// obs_info_array
+// num_img
+// hmm
+// Returns: void
+//
+// Notes:
+//F*/
+static CvStatus CV_STDCALL
+icvMixSegmL2( CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm )
+{
+ int k, i, j, m;
+
+ CvEHMMState* state = hmm->u.ehmm[0].u.state;
+
+
+ for (k = 0; k < num_img; k++)
+ {
+ int counter = 0;
+ CvImgObsInfo* info = obs_info_array[k];
+
+ for (i = 0; i < info->obs_y; i++)
+ {
+ for (j = 0; j < info->obs_x; j++, counter++)
+ {
+ int e_state = info->state[2 * counter + 1];
+ float min_dist;
+
+ min_dist = icvSquareDistance((info->obs) + (counter * info->obs_size),
+ state[e_state].mu, info->obs_size);
+ info->mix[counter] = 0;
+
+ for (m = 1; m < state[e_state].num_mix; m++)
+ {
+ float dist=icvSquareDistance( (info->obs) + (counter * info->obs_size),
+ state[e_state].mu + m * info->obs_size,
+ info->obs_size);
+ if (dist < min_dist)
+ {
+ min_dist = dist;
+ /* assign mixture with smallest distance */
+ info->mix[counter] = m;
+ }
+ }
+ }
+ }
+ }
+ return CV_NO_ERR;
+}
+
+/*
+CvStatus icvMixSegmProb(CvImgObsInfo* obs_info, int num_img, CvEHMM* hmm )
+{
+ int k, i, j, m;
+
+ CvEHMMState* state = hmm->ehmm[0].state_info;
+
+
+ for (k = 0; k < num_img; k++)
+ {
+ int counter = 0;
+ CvImgObsInfo* info = obs_info + k;
+
+ for (i = 0; i < info->obs_y; i++)
+ {
+ for (j = 0; j < info->obs_x; j++, counter++)
+ {
+ int e_state = info->in_state[counter];
+ float max_prob;
+
+ max_prob = icvComputeUniModeGauss( info->obs[counter], state[e_state].mu[0],
+ state[e_state].inv_var[0],
+ state[e_state].log_var[0],
+ info->obs_size );
+ info->mix[counter] = 0;
+
+ for (m = 1; m < state[e_state].num_mix; m++)
+ {
+ float prob=icvComputeUniModeGauss(info->obs[counter], state[e_state].mu[m],
+ state[e_state].inv_var[m],
+ state[e_state].log_var[m],
+ info->obs_size);
+ if (prob > max_prob)
+ {
+ max_prob = prob;
+ // assign mixture with greatest probability.
+ info->mix[counter] = m;
+ }
+ }
+ }
+ }
+ }
+
+ return CV_NO_ERR;
+}
+*/
+static CvStatus CV_STDCALL
+icvViterbiSegmentation( int num_states, int /*num_obs*/, CvMatr32f transP,
+ CvMatr32f B, int start_obs, int prob_type,
+ int** q, int min_num_obs, int max_num_obs,
+ float* prob )
+{
+ // memory allocation
+ int i, j, last_obs;
+ int m_HMMType = _CV_ERGODIC; /* _CV_CAUSAL or _CV_ERGODIC */
+
+ int m_ProbType = prob_type; /* _CV_LAST_STATE or _CV_BEST_STATE */
+
+ int m_minNumObs = min_num_obs; /*??*/
+ int m_maxNumObs = max_num_obs; /*??*/
+
+ int m_numStates = num_states;
+
+ float* m_pi = (float*)cvAlloc( num_states* sizeof(float) );
+ CvMatr32f m_a = transP;
+
+ // offset brobability matrix to starting observation
+ CvMatr32f m_b = B + start_obs * num_states;
+ //so m_xl will not be used more
+
+ //m_xl = start_obs;
+
+ /* if (muDur != NULL){
+ m_d = new int[m_numStates];
+ m_l = new double[m_numStates];
+ for (i = 0; i < m_numStates; i++){
+ m_l[i] = muDur[i];
+ }
+ }
+ else{
+ m_d = NULL;
+ m_l = NULL;
+ }
+ */
+
+ CvMatr32f m_Gamma = icvCreateMatrix_32f( num_states, m_maxNumObs );
+ int* m_csi = (int*)cvAlloc( num_states * m_maxNumObs * sizeof(int) );
+
+ //stores maximal result for every ending observation */
+ CvVect32f m_MaxGamma = prob;
+
+
+// assert( m_xl + max_num_obs <= num_obs );
+
+ /*??m_q = new int*[m_maxNumObs - m_minNumObs];
+ ??for (i = 0; i < m_maxNumObs - m_minNumObs; i++)
+ ?? m_q[i] = new int[m_minNumObs + i + 1];
+ */
+
+ /******************************************************************/
+ /* Viterbi initialization */
+ /* set initial state probabilities, in logarithmic scale */
+ for (i = 0; i < m_numStates; i++)
+ {
+ m_pi[i] = -BIG_FLT;
+ }
+ m_pi[0] = 0.0f;
+
+ for (i = 0; i < num_states; i++)
+ {
+ m_Gamma[0 * num_states + i] = m_pi[i] + m_b[0 * num_states + i];
+ m_csi[0 * num_states + i] = 0;
+ }
+
+ /******************************************************************/
+ /* Viterbi recursion */
+
+ if ( m_HMMType == _CV_CAUSAL ) //causal model
+ {
+ int t,j;
+
+ for (t = 1 ; t < m_maxNumObs; t++)
+ {
+ // evaluate self-to-self transition for state 0
+ m_Gamma[t * num_states + 0] = m_Gamma[(t-1) * num_states + 0] + m_a[0];
+ m_csi[t * num_states + 0] = 0;
+
+ for (j = 1; j < num_states; j++)
+ {
+ float self = m_Gamma[ (t-1) * num_states + j] + m_a[ j * num_states + j];
+ float prev = m_Gamma[ (t-1) * num_states +(j-1)] + m_a[ (j-1) * num_states + j];
+
+ if ( prev > self )
+ {
+ m_csi[t * num_states + j] = j-1;
+ m_Gamma[t * num_states + j] = prev;
+ }
+ else
+ {
+ m_csi[t * num_states + j] = j;
+ m_Gamma[t * num_states + j] = self;
+ }
+
+ m_Gamma[t * num_states + j] = m_Gamma[t * num_states + j] + m_b[t * num_states + j];
+ }
+ }
+ }
+ else if ( m_HMMType == _CV_ERGODIC ) //ergodic model
+ {
+ int t;
+ for (t = 1 ; t < m_maxNumObs; t++)
+ {
+ for (j = 0; j < num_states; j++)
+ {
+ int i;
+ m_Gamma[ t*num_states + j] = m_Gamma[(t-1) * num_states + 0] + m_a[0*num_states+j];
+ m_csi[t *num_states + j] = 0;
+
+ for (i = 1; i < num_states; i++)
+ {
+ float currGamma = m_Gamma[(t-1) *num_states + i] + m_a[i *num_states + j];
+ if (currGamma > m_Gamma[t *num_states + j])
+ {
+ m_Gamma[t * num_states + j] = currGamma;
+ m_csi[t * num_states + j] = i;
+ }
+ }
+ m_Gamma[t *num_states + j] = m_Gamma[t *num_states + j] + m_b[t * num_states + j];
+ }
+ }
+ }
+
+ for( last_obs = m_minNumObs-1, i = 0; last_obs < m_maxNumObs; last_obs++, i++ )
+ {
+ int t;
+
+ /******************************************************************/
+ /* Viterbi termination */
+
+ if ( m_ProbType == _CV_LAST_STATE )
+ {
+ m_MaxGamma[i] = m_Gamma[last_obs * num_states + num_states - 1];
+ q[i][last_obs] = num_states - 1;
+ }
+ else if( m_ProbType == _CV_BEST_STATE )
+ {
+ int k;
+ q[i][last_obs] = 0;
+ m_MaxGamma[i] = m_Gamma[last_obs * num_states + 0];
+
+ for(k = 1; k < num_states; k++)
+ {
+ if ( m_Gamma[last_obs * num_states + k] > m_MaxGamma[i] )
+ {
+ m_MaxGamma[i] = m_Gamma[last_obs * num_states + k];
+ q[i][last_obs] = k;
+ }
+ }
+ }
+
+ /******************************************************************/
+ /* Viterbi backtracking */
+ for (t = last_obs-1; t >= 0; t--)
+ {
+ q[i][t] = m_csi[(t+1) * num_states + q[i][t+1] ];
+ }
+ }
+
+ /* memory free */
+ cvFree( &m_pi );
+ cvFree( &m_csi );
+ icvDeleteMatrix( m_Gamma );
+
+ return CV_NO_ERR;
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvEViterbi
+// Purpose: The function calculates the embedded Viterbi algorithm
+// for 1 image
+// Context:
+// Parameters:
+// obs_info - observations
+// hmm - HMM
+//
+// Returns: the Embedded Viterbi probability (float)
+// and do state segmentation of observations
+//
+// Notes:
+//F*/
+static float CV_STDCALL icvEViterbi( CvImgObsInfo* obs_info, CvEHMM* hmm )
+{
+ int i, j, counter;
+ float log_likelihood;
+
+ float inv_obs_x = 1.f / obs_info->obs_x;
+
+ CvEHMMState* first_state = hmm->u.ehmm->u.state;
+
+ /* memory allocation for superB */
+ CvMatr32f superB = icvCreateMatrix_32f(hmm->num_states, obs_info->obs_y );
+
+ /* memory allocation for q */
+ int*** q = (int***)cvAlloc( hmm->num_states * sizeof(int**) );
+ int* super_q = (int*)cvAlloc( obs_info->obs_y * sizeof(int) );
+
+ for (i = 0; i < hmm->num_states; i++)
+ {
+ q[i] = (int**)cvAlloc( obs_info->obs_y * sizeof(int*) );
+
+ for (j = 0; j < obs_info->obs_y ; j++)
+ {
+ q[i][j] = (int*)cvAlloc( obs_info->obs_x * sizeof(int) );
+ }
+ }
+
+ /* start Viterbi segmentation */
+ for (i = 0; i < hmm->num_states; i++)
+ {
+ CvEHMM* ehmm = &(hmm->u.ehmm[i]);
+
+ for (j = 0; j < obs_info->obs_y; j++)
+ {
+ float max_gamma;
+
+ /* 1D HMM Viterbi segmentation */
+ icvViterbiSegmentation( ehmm->num_states, obs_info->obs_x,
+ ehmm->transP, ehmm->obsProb[j], 0,
+ _CV_LAST_STATE, &q[i][j], obs_info->obs_x,
+ obs_info->obs_x, &max_gamma);
+
+ superB[j * hmm->num_states + i] = max_gamma * inv_obs_x;
+ }
+ }
+
+ /* perform global Viterbi segmentation (i.e. process higher-level HMM) */
+
+ icvViterbiSegmentation( hmm->num_states, obs_info->obs_y,
+ hmm->transP, superB, 0,
+ _CV_LAST_STATE, &super_q, obs_info->obs_y,
+ obs_info->obs_y, &log_likelihood );
+
+ log_likelihood /= obs_info->obs_y ;
+
+
+ counter = 0;
+ /* assign new state to observation vectors */
+ for (i = 0; i < obs_info->obs_y; i++)
+ {
+ for (j = 0; j < obs_info->obs_x; j++, counter++)
+ {
+ int superstate = super_q[i];
+ int state = (int)(hmm->u.ehmm[superstate].u.state - first_state);
+
+ obs_info->state[2 * counter] = superstate;
+ obs_info->state[2 * counter + 1] = state + q[superstate][i][j];
+ }
+ }
+
+ /* memory deallocation for superB */
+ icvDeleteMatrix( superB );
+
+ /*memory deallocation for q */
+ for (i = 0; i < hmm->num_states; i++)
+ {
+ for (j = 0; j < obs_info->obs_y ; j++)
+ {
+ cvFree( &q[i][j] );
+ }
+ cvFree( &q[i] );
+ }
+
+ cvFree( &q );
+ cvFree( &super_q );
+
+ return log_likelihood;
+}
+
+static CvStatus CV_STDCALL
+icvEstimateHMMStateParams( CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm )
+{
+ /* compute gamma, weights, means, vars */
+ int k, i, j, m;
+ int total = 0;
+ int vect_len = obs_info_array[0]->obs_size;
+
+ float start_log_var_val = LN2PI * vect_len;
+
+ CvVect32f tmp_vect = icvCreateVector_32f( vect_len );
+
+ CvEHMMState* first_state = hmm->u.ehmm[0].u.state;
+
+ assert( sizeof(float) == sizeof(int) );
+
+ for(i = 0; i < hmm->num_states; i++ )
+ {
+ total+= hmm->u.ehmm[i].num_states;
+ }
+
+ /***************Gamma***********************/
+ /* initialize gamma */
+ for( i = 0; i < total; i++ )
+ {
+ for (m = 0; m < first_state[i].num_mix; m++)
+ {
+ ((int*)(first_state[i].weight))[m] = 0;
+ }
+ }
+
+ /* maybe gamma must be computed in mixsegm process ?? */
+
+ /* compute gamma */
+ for (k = 0; k < num_img; k++)
+ {
+ CvImgObsInfo* info = obs_info_array[k];
+ int num_obs = info->obs_y * info->obs_x;
+
+ for (i = 0; i < num_obs; i++)
+ {
+ int state, mixture;
+ state = info->state[2*i + 1];
+ mixture = info->mix[i];
+ /* computes gamma - number of observations corresponding
+ to every mixture of every state */
+ ((int*)(first_state[state].weight))[mixture] += 1;
+ }
+ }
+ /***************Mean and Var***********************/
+ /* compute means and variances of every item */
+ /* initially variance placed to inv_var */
+ /* zero mean and variance */
+ for (i = 0; i < total; i++)
+ {
+ memset( (void*)first_state[i].mu, 0, first_state[i].num_mix * vect_len *
+ sizeof(float) );
+ memset( (void*)first_state[i].inv_var, 0, first_state[i].num_mix * vect_len *
+ sizeof(float) );
+ }
+
+ /* compute sums */
+ for (i = 0; i < num_img; i++)
+ {
+ CvImgObsInfo* info = obs_info_array[i];
+ int total_obs = info->obs_x * info->obs_y;
+
+ float* vector = info->obs;
+
+ for (j = 0; j < total_obs; j++, vector+=vect_len )
+ {
+ int state = info->state[2 * j + 1];
+ int mixture = info->mix[j];
+
+ CvVect32f mean = first_state[state].mu + mixture * vect_len;
+ CvVect32f mean2 = first_state[state].inv_var + mixture * vect_len;
+
+ icvAddVector_32f( mean, vector, mean, vect_len );
+ for( k = 0; k < vect_len; k++ )
+ mean2[k] += vector[k]*vector[k];
+ }
+ }
+
+ /*compute the means and variances */
+ /* assume gamma already computed */
+ for (i = 0; i < total; i++)
+ {
+ CvEHMMState* state = &(first_state[i]);
+
+ for (m = 0; m < state->num_mix; m++)
+ {
+ int k;
+ CvVect32f mu = state->mu + m * vect_len;
+ CvVect32f invar = state->inv_var + m * vect_len;
+
+ if ( ((int*)state->weight)[m] > 1)
+ {
+ float inv_gamma = 1.f/((int*)(state->weight))[m];
+
+ icvScaleVector_32f( mu, mu, vect_len, inv_gamma);
+ icvScaleVector_32f( invar, invar, vect_len, inv_gamma);
+ }
+
+ icvMulVectors_32f(mu, mu, tmp_vect, vect_len);
+ icvSubVector_32f( invar, tmp_vect, invar, vect_len);
+
+ /* low bound of variance - 100 (Ara's experimental result) */
+ for( k = 0; k < vect_len; k++ )
+ {
+ invar[k] = (invar[k] > 100.f) ? invar[k] : 100.f;
+ }
+
+ /* compute log_var */
+ state->log_var_val[m] = start_log_var_val;
+ for( k = 0; k < vect_len; k++ )
+ {
+ state->log_var_val[m] += (float)log( invar[k] );
+ }
+
+ /* SMOLI 27.10.2000 */
+ state->log_var_val[m] *= 0.5;
+
+
+ /* compute inv_var = 1/sqrt(2*variance) */
+ icvScaleVector_32f(invar, invar, vect_len, 2.f );
+ cvbInvSqrt( invar, invar, vect_len );
+ }
+ }
+
+ /***************Weights***********************/
+ /* normilize gammas - i.e. compute mixture weights */
+
+ //compute weights
+ for (i = 0; i < total; i++)
+ {
+ int gamma_total = 0;
+ float norm;
+
+ for (m = 0; m < first_state[i].num_mix; m++)
+ {
+ gamma_total += ((int*)(first_state[i].weight))[m];
+ }
+
+ norm = gamma_total ? (1.f/(float)gamma_total) : 0.f;
+
+ for (m = 0; m < first_state[i].num_mix; m++)
+ {
+ first_state[i].weight[m] = ((int*)(first_state[i].weight))[m] * norm;
+ }
+ }
+
+ icvDeleteVector( tmp_vect);
+ return CV_NO_ERR;
+}
+
+/*
+CvStatus icvLightingCorrection8uC1R( uchar* img, CvSize roi, int src_step )
+{
+ int i, j;
+ int width = roi.width;
+ int height = roi.height;
+
+ float x1, x2, y1, y2;
+ int f[3] = {0, 0, 0};
+ float a[3] = {0, 0, 0};
+
+ float h1;
+ float h2;
+
+ float c1,c2;
+
+ float min = FLT_MAX;
+ float max = -FLT_MAX;
+ float correction;
+
+ float* float_img = icvAlloc( width * height * sizeof(float) );
+
+ x1 = width * (width + 1) / 2.0f; // Sum (1, ... , width)
+ x2 = width * (width + 1 ) * (2 * width + 1) / 6.0f; // Sum (1^2, ... , width^2)
+ y1 = height * (height + 1)/2.0f; // Sum (1, ... , width)
+ y2 = height * (height + 1 ) * (2 * height + 1) / 6.0f; // Sum (1^2, ... , width^2)
+
+
+ // extract grayvalues
+ for (i = 0; i < height; i++)
+ {
+ for (j = 0; j < width; j++)
+ {
+ f[2] = f[2] + j * img[i*src_step + j];
+ f[1] = f[1] + i * img[i*src_step + j];
+ f[0] = f[0] + img[i*src_step + j];
+ }
+ }
+
+ h1 = (float)f[0] * (float)x1 / (float)width;
+ h2 = (float)f[0] * (float)y1 / (float)height;
+
+ a[2] = ((float)f[2] - h1) / (float)(x2*height - x1*x1*height/(float)width);
+ a[1] = ((float)f[1] - h2) / (float)(y2*width - y1*y1*width/(float)height);
+ a[0] = (float)f[0]/(float)(width*height) - (float)y1*a[1]/(float)height -
+ (float)x1*a[2]/(float)width;
+
+ for (i = 0; i < height; i++)
+ {
+ for (j = 0; j < width; j++)
+ {
+
+ correction = a[0] + a[1]*(float)i + a[2]*(float)j;
+
+ float_img[i*width + j] = img[i*src_step + j] - correction;
+
+ if (float_img[i*width + j] < min) min = float_img[i*width+j];
+ if (float_img[i*width + j] > max) max = float_img[i*width+j];
+ }
+ }
+
+ //rescaling to the range 0:255
+ c2 = 0;
+ if (max == min)
+ c2 = 255.0f;
+ else
+ c2 = 255.0f/(float)(max - min);
+
+ c1 = (-(float)min)*c2;
+
+ for (i = 0; i < height; i++)
+ {
+ for (j = 0; j < width; j++)
+ {
+ int value = (int)floor(c2*float_img[i*width + j] + c1);
+ if (value < 0) value = 0;
+ if (value > 255) value = 255;
+ img[i*src_step + j] = (uchar)value;
+ }
+ }
+
+ cvFree( &float_img );
+ return CV_NO_ERR;
+}
+
+
+CvStatus icvLightingCorrection( icvImage* img )
+{
+ CvSize roi;
+ if ( img->type != IPL_DEPTH_8U || img->channels != 1 )
+ return CV_BADFACTOR_ERR;
+
+ roi = _cvSize( img->roi.width, img->roi.height );
+
+ return _cvLightingCorrection8uC1R( img->data + img->roi.y * img->step + img->roi.x,
+ roi, img->step );
+
+}
+
+*/
+
+CV_IMPL CvEHMM*
+cvCreate2DHMM( int *state_number, int *num_mix, int obs_size )
+{
+ CvEHMM* hmm = 0;
+
+ CV_FUNCNAME( "cvCreate2DHMM" );
+
+ __BEGIN__;
+
+ IPPI_CALL( icvCreate2DHMM( &hmm, state_number, num_mix, obs_size ));
+
+ __END__;
+
+ return hmm;
+}
+
+CV_IMPL void
+cvRelease2DHMM( CvEHMM ** hmm )
+{
+ CV_FUNCNAME( "cvRelease2DHMM" );
+
+ __BEGIN__;
+
+ IPPI_CALL( icvRelease2DHMM( hmm ));
+ __END__;
+}
+
+CV_IMPL CvImgObsInfo*
+cvCreateObsInfo( CvSize num_obs, int obs_size )
+{
+ CvImgObsInfo *obs_info = 0;
+
+ CV_FUNCNAME( "cvCreateObsInfo" );
+
+ __BEGIN__;
+
+ IPPI_CALL( icvCreateObsInfo( &obs_info, num_obs, obs_size ));
+
+ __END__;
+
+ return obs_info;
+}
+
+CV_IMPL void
+cvReleaseObsInfo( CvImgObsInfo ** obs_info )
+{
+ CV_FUNCNAME( "cvReleaseObsInfo" );
+
+ __BEGIN__;
+
+ IPPI_CALL( icvReleaseObsInfo( obs_info ));
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvUniformImgSegm( CvImgObsInfo * obs_info, CvEHMM * hmm )
+{
+ CV_FUNCNAME( "cvUniformImgSegm" );
+
+ __BEGIN__;
+
+ IPPI_CALL( icvUniformImgSegm( obs_info, hmm ));
+ __CLEANUP__;
+ __END__;
+}
+
+CV_IMPL void
+cvInitMixSegm( CvImgObsInfo ** obs_info_array, int num_img, CvEHMM * hmm )
+{
+ CV_FUNCNAME( "cvInitMixSegm" );
+
+ __BEGIN__;
+
+ IPPI_CALL( icvInitMixSegm( obs_info_array, num_img, hmm ));
+
+ __END__;
+}
+
+CV_IMPL void
+cvEstimateHMMStateParams( CvImgObsInfo ** obs_info_array, int num_img, CvEHMM * hmm )
+{
+ CV_FUNCNAME( "cvEstimateHMMStateParams" );
+
+ __BEGIN__;
+
+ IPPI_CALL( icvEstimateHMMStateParams( obs_info_array, num_img, hmm ));
+
+ __END__;
+}
+
+CV_IMPL void
+cvEstimateTransProb( CvImgObsInfo ** obs_info_array, int num_img, CvEHMM * hmm )
+{
+ CV_FUNCNAME( "cvEstimateTransProb" );
+
+ __BEGIN__;
+
+ IPPI_CALL( icvEstimateTransProb( obs_info_array, num_img, hmm ));
+
+ __END__;
+
+}
+
+CV_IMPL void
+cvEstimateObsProb( CvImgObsInfo * obs_info, CvEHMM * hmm )
+{
+ CV_FUNCNAME( "cvEstimateObsProb" );
+
+ __BEGIN__;
+
+ IPPI_CALL( icvEstimateObsProb( obs_info, hmm ));
+
+ __END__;
+}
+
+CV_IMPL float
+cvEViterbi( CvImgObsInfo * obs_info, CvEHMM * hmm )
+{
+ float result = FLT_MAX;
+
+ CV_FUNCNAME( "cvEViterbi" );
+
+ __BEGIN__;
+
+ if( (obs_info == NULL) || (hmm == NULL) )
+ CV_ERROR( CV_BadDataPtr, "Null pointer." );
+
+ result = icvEViterbi( obs_info, hmm );
+
+ __END__;
+
+ return result;
+}
+
+CV_IMPL void
+cvMixSegmL2( CvImgObsInfo ** obs_info_array, int num_img, CvEHMM * hmm )
+{
+ CV_FUNCNAME( "cvMixSegmL2" );
+
+ __BEGIN__;
+
+ IPPI_CALL( icvMixSegmL2( obs_info_array, num_img, hmm ));
+
+ __END__;
+}
+
+/* End of file */
+
diff --git a/cvaux/src/cvhmm1d.cpp b/cvaux/src/cvhmm1d.cpp
new file mode 100644
index 0000000..8208e6e
--- /dev/null
+++ b/cvaux/src/cvhmm1d.cpp
@@ -0,0 +1,1151 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+
+#include "_cvaux.h"
+
+#if 0
+
+#define LN2PI 1.837877f
+#define BIG_FLT 1.e+10f
+
+
+#define _CV_ERGODIC 1
+#define _CV_CAUSAL 2
+
+#define _CV_LAST_STATE 1
+#define _CV_BEST_STATE 2
+
+//*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvForward1DHMM
+// Purpose: The function performs baum-welsh algorithm
+// Context:
+// Parameters: obs_info - addres of pointer to CvImgObsInfo structure
+// num_hor_obs - number of horizontal observation vectors
+// num_ver_obs - number of horizontal observation vectors
+// obs_size - length of observation vector
+//
+// Returns: error status
+//
+// Notes:
+//F*/
+#if 0
+CvStatus icvForward1DHMM( int num_states, int num_obs, CvMatr64d A,
+ CvMatr64d B,
+ double* scales)
+{
+ // assume that observation and transition
+ // probabilities already computed
+ int m_HMMType = _CV_CAUSAL;
+ double* m_pi = icvAlloc( num_states* sizeof( double) );
+
+ /* alpha is matrix
+ rows throuhg states
+ columns through time
+ */
+ double* alpha = icvAlloc( num_states*num_obs * sizeof( double ) );
+
+ /* All calculations will be in non-logarithmic domain */
+
+ /* Initialization */
+ /* set initial state probabilities */
+ m_pi[0] = 1;
+ for (i = 1; i < num_states; i++)
+ {
+ m_pi[i] = 0.0;
+ }
+
+ for (i = 0; i < num_states; i++)
+ {
+ alpha[i] = m_pi[i] * m_b[ i];
+ }
+
+ /******************************************************************/
+ /* Induction */
+
+ if ( m_HMMType == _CV_ERGODIC )
+ {
+ int t;
+ for (t = 1 ; t < num_obs; t++)
+ {
+ for (j = 0; j < num_states; j++)
+ {
+ double sum = 0.0;
+ int i;
+
+ for (i = 0; i < num_states; i++)
+ {
+ sum += alpha[(t - 1) * num_states + i] * A[i * num_states + j];
+ }
+
+ alpha[(t - 1) * num_states + j] = sum * B[t * num_states + j];
+
+ /* add computed alpha to scale factor */
+ sum_alpha += alpha[(t - 1) * num_states + j];
+ }
+
+ double scale = 1/sum_alpha;
+
+ /* scale alpha */
+ for (j = 0; j < num_states; j++)
+ {
+ alpha[(t - 1) * num_states + j] *= scale;
+ }
+
+ scales[t] = scale;
+
+ }
+ }
+
+#endif
+
+
+
+//*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvCreateObsInfo
+// Purpose: The function allocates memory for CvImgObsInfo structure
+// and its inner stuff
+// Context:
+// Parameters: obs_info - addres of pointer to CvImgObsInfo structure
+// num_hor_obs - number of horizontal observation vectors
+// num_ver_obs - number of horizontal observation vectors
+// obs_size - length of observation vector
+//
+// Returns: error status
+//
+// Notes:
+//F*/
+/*CvStatus icvCreateObsInfo( CvImgObsInfo** obs_info,
+ CvSize num_obs, int obs_size )
+{
+ int total = num_obs.height * num_obs.width;
+
+ CvImgObsInfo* obs = (CvImgObsInfo*)icvAlloc( sizeof( CvImgObsInfo) );
+
+ obs->obs_x = num_obs.width;
+ obs->obs_y = num_obs.height;
+
+ obs->obs = (float*)icvAlloc( total * obs_size * sizeof(float) );
+
+ obs->state = (int*)icvAlloc( 2 * total * sizeof(int) );
+ obs->mix = (int*)icvAlloc( total * sizeof(int) );
+
+ obs->obs_size = obs_size;
+
+ obs_info[0] = obs;
+
+ return CV_NO_ERR;
+}*/
+
+/*CvStatus icvReleaseObsInfo( CvImgObsInfo** p_obs_info )
+{
+ CvImgObsInfo* obs_info = p_obs_info[0];
+
+ icvFree( &(obs_info->obs) );
+ icvFree( &(obs_info->mix) );
+ icvFree( &(obs_info->state) );
+ icvFree( &(obs_info) );
+
+ p_obs_info[0] = NULL;
+
+ return CV_NO_ERR;
+} */
+
+
+//*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvCreate1DHMM
+// Purpose: The function allocates memory for 1-dimensional HMM
+// and its inner stuff
+// Context:
+// Parameters: hmm - addres of pointer to CvEHMM structure
+// state_number - number of states in HMM
+// num_mix - number of gaussian mixtures in HMM states
+// size of array is defined by previous parameter
+// obs_size - length of observation vectors
+//
+// Returns: error status
+// Notes:
+//F*/
+CvStatus icvCreate1DHMM( CvEHMM** this_hmm,
+ int state_number, int* num_mix, int obs_size )
+{
+ int i;
+ int real_states = state_number;
+
+ CvEHMMState* all_states;
+ CvEHMM* hmm;
+ int total_mix = 0;
+ float* pointers;
+
+ /* allocate memory for hmm */
+ hmm = (CvEHMM*)icvAlloc( sizeof(CvEHMM) );
+
+ /* set number of superstates */
+ hmm->num_states = state_number;
+ hmm->level = 0;
+
+ /* allocate memory for all states */
+ all_states = (CvEHMMState *)icvAlloc( real_states * sizeof( CvEHMMState ) );
+
+ /* assign number of mixtures */
+ for( i = 0; i < real_states; i++ )
+ {
+ all_states[i].num_mix = num_mix[i];
+ }
+
+ /* compute size of inner of all real states */
+ for( i = 0; i < real_states; i++ )
+ {
+ total_mix += num_mix[i];
+ }
+ /* allocate memory for states stuff */
+ pointers = (float*)icvAlloc( total_mix * (2/*for mu invvar */ * obs_size +
+ 2/*for weight and log_var_val*/ ) * sizeof( float) );
+
+ /* organize memory */
+ for( i = 0; i < real_states; i++ )
+ {
+ all_states[i].mu = pointers; pointers += num_mix[i] * obs_size;
+ all_states[i].inv_var = pointers; pointers += num_mix[i] * obs_size;
+
+ all_states[i].log_var_val = pointers; pointers += num_mix[i];
+ all_states[i].weight = pointers; pointers += num_mix[i];
+ }
+ hmm->u.state = all_states;
+
+ hmm->transP = icvCreateMatrix_32f( hmm->num_states, hmm->num_states );
+ hmm->obsProb = NULL;
+
+ /* if all ok - return pointer */
+ *this_hmm = hmm;
+ return CV_NO_ERR;
+}
+
+CvStatus icvRelease1DHMM( CvEHMM** phmm )
+{
+ CvEHMM* hmm = phmm[0];
+ icvDeleteMatrix( hmm->transP );
+
+ if (hmm->obsProb != NULL)
+ {
+ int* tmp = ((int*)(hmm->obsProb)) - 3;
+ icvFree( &(tmp) );
+ }
+
+ icvFree( &(hmm->u.state->mu) );
+ icvFree( &(hmm->u.state) );
+
+ phmm[0] = NULL;
+
+ return CV_NO_ERR;
+}
+
+/*can be used in CHMM & DHMM */
+CvStatus icvUniform1DSegm( Cv1DObsInfo* obs_info, CvEHMM* hmm )
+{
+ /* implementation is very bad */
+ int i;
+ CvEHMMState* first_state;
+
+ /* check arguments */
+ if ( !obs_info || !hmm ) return CV_NULLPTR_ERR;
+
+ first_state = hmm->u.state;
+
+ for (i = 0; i < obs_info->obs_x; i++)
+ {
+ //bad line (division )
+ int state = (i * hmm->num_states)/obs_info->obs_x;
+ obs_info->state[i] = state;
+ }
+ return CV_NO_ERR;
+}
+
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: InitMixSegm
+// Purpose: The function implements the mixture segmentation of the states of the embedded HMM
+// Context: used with the Viterbi training of the embedded HMM
+// Function uses K-Means algorithm for clustering
+//
+// Parameters: obs_info_array - array of pointers to image observations
+// num_img - length of above array
+// hmm - pointer to HMM structure
+//
+// Returns: error status
+//
+// Notes:
+//F*/
+CvStatus icvInit1DMixSegm(Cv1DObsInfo** obs_info_array, int num_img, CvEHMM* hmm)
+{
+ int k, i, j;
+ int* num_samples; /* number of observations in every state */
+ int* counter; /* array of counters for every state */
+
+ int** a_class; /* for every state - characteristic array */
+
+ CvVect32f** samples; /* for every state - pointer to observation vectors */
+ int*** samples_mix; /* for every state - array of pointers to vectors mixtures */
+
+ CvTermCriteria criteria = cvTermCriteria( CV_TERMCRIT_EPS|CV_TERMCRIT_ITER,
+ 1000, /* iter */
+ 0.01f ); /* eps */
+
+ int total = hmm->num_states;
+ CvEHMMState* first_state = hmm->u.state;
+
+ /* for every state integer is allocated - number of vectors in state */
+ num_samples = (int*)icvAlloc( total * sizeof(int) );
+
+ /* integer counter is allocated for every state */
+ counter = (int*)icvAlloc( total * sizeof(int) );
+
+ samples = (CvVect32f**)icvAlloc( total * sizeof(CvVect32f*) );
+ samples_mix = (int***)icvAlloc( total * sizeof(int**) );
+
+ /* clear */
+ memset( num_samples, 0 , total*sizeof(int) );
+ memset( counter, 0 , total*sizeof(int) );
+
+
+ /* for every state the number of vectors which belong to it is computed (smth. like histogram) */
+ for (k = 0; k < num_img; k++)
+ {
+ CvImgObsInfo* obs = obs_info_array[k];
+
+ for (i = 0; i < obs->obs_x; i++)
+ {
+ int state = obs->state[ i ];
+ num_samples[state] += 1;
+ }
+ }
+
+ /* for every state int* is allocated */
+ a_class = (int**)icvAlloc( total*sizeof(int*) );
+
+ for (i = 0; i < total; i++)
+ {
+ a_class[i] = (int*)icvAlloc( num_samples[i] * sizeof(int) );
+ samples[i] = (CvVect32f*)icvAlloc( num_samples[i] * sizeof(CvVect32f) );
+ samples_mix[i] = (int**)icvAlloc( num_samples[i] * sizeof(int*) );
+ }
+
+ /* for every state vectors which belong to state are gathered */
+ for (k = 0; k < num_img; k++)
+ {
+ CvImgObsInfo* obs = obs_info_array[k];
+ int num_obs = obs->obs_x;
+ float* vector = obs->obs;
+
+ for (i = 0; i < num_obs; i++, vector+=obs->obs_size )
+ {
+ int state = obs->state[i];
+
+ samples[state][counter[state]] = vector;
+ samples_mix[state][counter[state]] = &(obs->mix[i]);
+ counter[state]++;
+ }
+ }
+
+ /* clear counters */
+ memset( counter, 0, total*sizeof(int) );
+
+ /* do the actual clustering using the K Means algorithm */
+ for (i = 0; i < total; i++)
+ {
+ if ( first_state[i].num_mix == 1)
+ {
+ for (k = 0; k < num_samples[i]; k++)
+ {
+ /* all vectors belong to one mixture */
+ a_class[i][k] = 0;
+ }
+ }
+ else if( num_samples[i] )
+ {
+ /* clusterize vectors */
+ icvKMeans( first_state[i].num_mix, samples[i], num_samples[i],
+ obs_info_array[0]->obs_size, criteria, a_class[i] );
+ }
+ }
+
+ /* for every vector number of mixture is assigned */
+ for( i = 0; i < total; i++ )
+ {
+ for (j = 0; j < num_samples[i]; j++)
+ {
+ samples_mix[i][j][0] = a_class[i][j];
+ }
+ }
+
+ for (i = 0; i < total; i++)
+ {
+ icvFree( &(a_class[i]) );
+ icvFree( &(samples[i]) );
+ icvFree( &(samples_mix[i]) );
+ }
+
+ icvFree( &a_class );
+ icvFree( &samples );
+ icvFree( &samples_mix );
+ icvFree( &counter );
+ icvFree( &num_samples );
+
+
+ return CV_NO_ERR;
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: ComputeUniModeGauss
+// Purpose: The function computes the Gaussian pdf for a sample vector
+// Context:
+// Parameters: obsVeq - pointer to the sample vector
+// mu - pointer to the mean vector of the Gaussian pdf
+// var - pointer to the variance vector of the Gaussian pdf
+// VecSize - the size of sample vector
+//
+// Returns: the pdf of the sample vector given the specified Gaussian
+//
+// Notes:
+//F*/
+/*float icvComputeUniModeGauss(CvVect32f vect, CvVect32f mu,
+ CvVect32f inv_var, float log_var_val, int vect_size)
+{
+ int n;
+ double tmp;
+ double prob;
+
+ prob = -log_var_val;
+
+ for (n = 0; n < vect_size; n++)
+ {
+ tmp = (vect[n] - mu[n]) * inv_var[n];
+ prob = prob - tmp * tmp;
+ }
+ //prob *= 0.5f;
+
+ return (float)prob;
+}*/
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: ComputeGaussMixture
+// Purpose: The function computes the mixture Gaussian pdf of a sample vector.
+// Context:
+// Parameters: obsVeq - pointer to the sample vector
+// mu - two-dimensional pointer to the mean vector of the Gaussian pdf;
+// the first dimension is indexed over the number of mixtures and
+// the second dimension is indexed along the size of the mean vector
+// var - two-dimensional pointer to the variance vector of the Gaussian pdf;
+// the first dimension is indexed over the number of mixtures and
+// the second dimension is indexed along the size of the variance vector
+// VecSize - the size of sample vector
+// weight - pointer to the wights of the Gaussian mixture
+// NumMix - the number of Gaussian mixtures
+//
+// Returns: the pdf of the sample vector given the specified Gaussian mixture.
+//
+// Notes:
+//F*/
+/* Calculate probability of observation at state in logarithmic scale*/
+/*float icvComputeGaussMixture( CvVect32f vect, float* mu,
+ float* inv_var, float* log_var_val,
+ int vect_size, float* weight, int num_mix )
+{
+ double prob, l_prob;
+
+ prob = 0.0f;
+
+ if (num_mix == 1)
+ {
+ return icvComputeUniModeGauss( vect, mu, inv_var, log_var_val[0], vect_size);
+ }
+ else
+ {
+ int m;
+ for (m = 0; m < num_mix; m++)
+ {
+ if ( weight[m] > 0.0)
+ {
+ l_prob = icvComputeUniModeGauss(vect, mu + m*vect_size,
+ inv_var + m * vect_size,
+ log_var_val[m],
+ vect_size);
+
+ prob = prob + weight[m]*exp((double)l_prob);
+ }
+ }
+ prob = log(prob);
+ }
+ return (float)prob;
+}
+*/
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: EstimateObsProb
+// Purpose: The function computes the probability of every observation in every state
+// Context:
+// Parameters: obs_info - observations
+// hmm - hmm
+// Returns: error status
+//
+// Notes:
+//F*/
+CvStatus icvEstimate1DObsProb(CvImgObsInfo* obs_info, CvEHMM* hmm )
+{
+ int j;
+ int total_states = 0;
+
+ /* check if matrix exist and check current size
+ if not sufficient - realloc */
+ int status = 0; /* 1 - not allocated, 2 - allocated but small size,
+ 3 - size is enough, but distribution is bad, 0 - all ok */
+
+ /*for( j = 0; j < hmm->num_states; j++ )
+ {
+ total_states += hmm->u.ehmm[j].num_states;
+ }*/
+ total_states = hmm->num_states;
+
+ if ( hmm->obsProb == NULL )
+ {
+ /* allocare memory */
+ int need_size = ( obs_info->obs_x /* * obs_info->obs_y*/ * total_states * sizeof(float) /* +
+ obs_info->obs_y * hmm->num_states * sizeof( CvMatr32f) */);
+
+ int* buffer = (int*)icvAlloc( need_size + 3 * sizeof(int) );
+ buffer[0] = need_size;
+ buffer[1] = obs_info->obs_y;
+ buffer[2] = obs_info->obs_x;
+ hmm->obsProb = (float**) (buffer + 3);
+ status = 3;
+
+ }
+ else
+ {
+ /* check current size */
+ int* total= (int*)(((int*)(hmm->obsProb)) - 3);
+ int need_size = ( obs_info->obs_x /* * obs_info->obs_y*/ * total_states * sizeof(float) /* +
+ obs_info->obs_y * hmm->num_states * sizeof( CvMatr32f(float*) )*/ );
+
+ assert( sizeof(float*) == sizeof(int) );
+
+ if ( need_size > (*total) )
+ {
+ int* buffer = ((int*)(hmm->obsProb)) - 3;
+ icvFree( &buffer);
+ buffer = (int*)icvAlloc( need_size + 3);
+ buffer[0] = need_size;
+ buffer[1] = obs_info->obs_y;
+ buffer[2] = obs_info->obs_x;
+
+ hmm->obsProb = (float**)(buffer + 3);
+
+ status = 3;
+ }
+ }
+ if (!status)
+ {
+ int* obsx = ((int*)(hmm->obsProb)) - 1;
+ //int* obsy = ((int*)(hmm->obsProb)) - 2;
+
+ assert( /*(*obsy > 0) &&*/ (*obsx > 0) );
+
+ /* is good distribution? */
+ if ( (obs_info->obs_x > (*obsx) ) /* || (obs_info->obs_y > (*obsy) ) */ )
+ status = 3;
+ }
+
+ assert( (status == 0) || (status == 3) );
+ /* if bad status - do reallocation actions */
+ if ( status )
+ {
+ float** tmp = hmm->obsProb;
+ //float* tmpf;
+
+ /* distribute pointers of ehmm->obsProb */
+/* for( i = 0; i < hmm->num_states; i++ )
+ {
+ hmm->u.ehmm[i].obsProb = tmp;
+ tmp += obs_info->obs_y;
+ }
+*/
+ //tmpf = (float*)tmp;
+
+ /* distribute pointers of ehmm->obsProb[j] */
+/* for( i = 0; i < hmm->num_states; i++ )
+ {
+ CvEHMM* ehmm = &( hmm->u.ehmm[i] );
+
+ for( j = 0; j < obs_info->obs_y; j++ )
+ {
+ ehmm->obsProb[j] = tmpf;
+ tmpf += ehmm->num_states * obs_info->obs_x;
+ }
+ }
+*/
+ hmm->obsProb = tmp;
+
+ }/* end of pointer distribution */
+
+#if 1
+ {
+#define MAX_BUF_SIZE 1200
+ float local_log_mix_prob[MAX_BUF_SIZE];
+ double local_mix_prob[MAX_BUF_SIZE];
+ int vect_size = obs_info->obs_size;
+ CvStatus res = CV_NO_ERR;
+
+ float* log_mix_prob = local_log_mix_prob;
+ double* mix_prob = local_mix_prob;
+
+ int max_size = 0;
+ int obs_x = obs_info->obs_x;
+
+ /* calculate temporary buffer size */
+ //for( i = 0; i < hmm->num_states; i++ )
+ //{
+ // CvEHMM* ehmm = &(hmm->u.ehmm[i]);
+ CvEHMMState* state = hmm->u.state;
+
+ int max_mix = 0;
+ for( j = 0; j < hmm->num_states; j++ )
+ {
+ int t = state[j].num_mix;
+ if( max_mix < t ) max_mix = t;
+ }
+ max_mix *= hmm->num_states;
+ /*if( max_size < max_mix )*/ max_size = max_mix;
+ //}
+
+ max_size *= obs_x * vect_size;
+
+ /* allocate buffer */
+ if( max_size > MAX_BUF_SIZE )
+ {
+ log_mix_prob = (float*)icvAlloc( max_size*(sizeof(float) + sizeof(double)));
+ if( !log_mix_prob ) return CV_OUTOFMEM_ERR;
+ mix_prob = (double*)(log_mix_prob + max_size);
+ }
+
+ memset( log_mix_prob, 0, max_size*sizeof(float));
+
+ /*****************computing probabilities***********************/
+
+ /* loop through external states */
+ //for( i = 0; i < hmm->num_states; i++ )
+ {
+ // CvEHMM* ehmm = &(hmm->u.ehmm[i]);
+ CvEHMMState* state = hmm->u.state;
+
+ int max_mix = 0;
+ int n_states = hmm->num_states;
+
+ /* determine maximal number of mixtures (again) */
+ for( j = 0; j < hmm->num_states; j++ )
+ {
+ int t = state[j].num_mix;
+ if( max_mix < t ) max_mix = t;
+ }
+
+ /* loop through rows of the observation matrix */
+ //for( j = 0; j < obs_info->obs_y; j++ )
+ {
+ int m, n;
+
+ float* obs = obs_info->obs;/* + j * obs_x * vect_size; */
+ float* log_mp = max_mix > 1 ? log_mix_prob : (float*)(hmm->obsProb);
+ double* mp = mix_prob;
+
+ /* several passes are done below */
+
+ /* 1. calculate logarithms of probabilities for each mixture */
+
+ /* loop through mixtures */
+ /* !!!! */ for( m = 0; m < max_mix; m++ )
+ {
+ /* set pointer to first observation in the line */
+ float* vect = obs;
+
+ /* cycles through obseravtions in the line */
+ for( n = 0; n < obs_x; n++, vect += vect_size, log_mp += n_states )
+ {
+ int k, l;
+ for( l = 0; l < n_states; l++ )
+ {
+ if( state[l].num_mix > m )
+ {
+ float* mu = state[l].mu + m*vect_size;
+ float* inv_var = state[l].inv_var + m*vect_size;
+ double prob = -state[l].log_var_val[m];
+ for( k = 0; k < vect_size; k++ )
+ {
+ double t = (vect[k] - mu[k])*inv_var[k];
+ prob -= t*t;
+ }
+ log_mp[l] = MAX( (float)prob, -500 );
+ }
+ }
+ }
+ }
+
+ /* skip the rest if there is a single mixture */
+ if( max_mix != 1 )
+ {
+ /* 2. calculate exponent of log_mix_prob
+ (i.e. probability for each mixture) */
+ res = icvbExp_32f64f( log_mix_prob, mix_prob,
+ max_mix * obs_x * n_states );
+ if( res < 0 ) goto processing_exit;
+
+ /* 3. sum all mixtures with weights */
+ /* 3a. first mixture - simply scale by weight */
+ for( n = 0; n < obs_x; n++, mp += n_states )
+ {
+ int l;
+ for( l = 0; l < n_states; l++ )
+ {
+ mp[l] *= state[l].weight[0];
+ }
+ }
+
+ /* 3b. add other mixtures */
+ for( m = 1; m < max_mix; m++ )
+ {
+ int ofs = -m*obs_x*n_states;
+ for( n = 0; n < obs_x; n++, mp += n_states )
+ {
+ int l;
+ for( l = 0; l < n_states; l++ )
+ {
+ if( m < state[l].num_mix )
+ {
+ mp[l + ofs] += mp[l] * state[l].weight[m];
+ }
+ }
+ }
+ }
+
+ /* 4. Put logarithms of summary probabilities to the destination matrix */
+ res = icvbLog_64f32f( mix_prob, (float*)(hmm->obsProb),//[j],
+ obs_x * n_states );
+ if( res < 0 ) goto processing_exit;
+ }
+ }
+ }
+
+processing_exit:
+
+ if( log_mix_prob != local_log_mix_prob ) icvFree( &log_mix_prob );
+ return res;
+#undef MAX_BUF_SIZE
+ }
+#else
+/* for( i = 0; i < hmm->num_states; i++ )
+ {
+ CvEHMM* ehmm = &(hmm->u.ehmm[i]);
+ CvEHMMState* state = ehmm->u.state;
+
+ for( j = 0; j < obs_info->obs_y; j++ )
+ {
+ int k,m;
+
+ int obs_index = j * obs_info->obs_x;
+
+ float* B = ehmm->obsProb[j];
+
+ // cycles through obs and states
+ for( k = 0; k < obs_info->obs_x; k++ )
+ {
+ CvVect32f vect = (obs_info->obs) + (obs_index + k) * vect_size;
+
+ float* matr_line = B + k * ehmm->num_states;
+
+ for( m = 0; m < ehmm->num_states; m++ )
+ {
+ matr_line[m] = icvComputeGaussMixture( vect, state[m].mu, state[m].inv_var,
+ state[m].log_var_val, vect_size, state[m].weight,
+ state[m].num_mix );
+ }
+ }
+ }
+ }
+*/
+#endif
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: EstimateTransProb
+// Purpose: The function calculates the state and super state transition probabilities
+// of the model given the images,
+// the state segmentation and the input parameters
+// Context:
+// Parameters: obs_info_array - array of pointers to image observations
+// num_img - length of above array
+// hmm - pointer to HMM structure
+// Returns: void
+//
+// Notes:
+//F*/
+CvStatus icvEstimate1DTransProb( Cv1DObsInfo** obs_info_array,
+ int num_seq,
+ CvEHMM* hmm )
+{
+ int i, j, k;
+
+ /* as a counter we will use transP matrix */
+
+ /* initialization */
+
+ /* clear transP */
+ icvSetZero_32f( hmm->transP, hmm->num_states, hmm->num_states );
+
+
+ /* compute the counters */
+ for (i = 0; i < num_seq; i++)
+ {
+ int counter = 0;
+ Cv1DObsInfo* info = obs_info_array[i];
+
+ for (k = 0; k < info->obs_x; k++, counter++)
+ {
+ /* compute how many transitions from state to state
+ occured */
+ int state;
+ int nextstate;
+
+ state = info->state[counter];
+
+ if (k < info->obs_x - 1)
+ {
+ int transP_size = hmm->num_states;
+
+ nextstate = info->state[counter+1];
+ hmm->transP[ state * transP_size + nextstate] += 1;
+ }
+ }
+ }
+
+ /* estimate superstate matrix */
+ for( i = 0; i < hmm->num_states; i++)
+ {
+ float total = 0;
+ float inv_total;
+ for( j = 0; j < hmm->num_states; j++)
+ {
+ total += hmm->transP[i * hmm->num_states + j];
+ }
+ //assert( total );
+
+ inv_total = total ? 1.f/total : 0;
+
+ for( j = 0; j < hmm->num_states; j++)
+ {
+ hmm->transP[i * hmm->num_states + j] =
+ hmm->transP[i * hmm->num_states + j] ?
+ (float)log( hmm->transP[i * hmm->num_states + j] * inv_total ) : -BIG_FLT;
+ }
+ }
+
+ return CV_NO_ERR;
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: MixSegmL2
+// Purpose: The function implements the mixture segmentation of the states of the embedded HMM
+// Context: used with the Viterbi training of the embedded HMM
+//
+// Parameters:
+// obs_info_array
+// num_img
+// hmm
+// Returns: void
+//
+// Notes:
+//F*/
+CvStatus icv1DMixSegmL2(CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm )
+{
+ int k, i, m;
+
+ CvEHMMState* state = hmm->u.state;
+
+ for (k = 0; k < num_img; k++)
+ {
+ //int counter = 0;
+ CvImgObsInfo* info = obs_info_array[k];
+
+ for (i = 0; i < info->obs_x; i++)
+ {
+ int e_state = info->state[i];
+ float min_dist;
+
+ min_dist = icvSquareDistance((info->obs) + (i * info->obs_size),
+ state[e_state].mu, info->obs_size);
+ info->mix[i] = 0;
+
+ for (m = 1; m < state[e_state].num_mix; m++)
+ {
+ float dist=icvSquareDistance( (info->obs) + (i * info->obs_size),
+ state[e_state].mu + m * info->obs_size,
+ info->obs_size);
+ if (dist < min_dist)
+ {
+ min_dist = dist;
+ /* assign mixture with smallest distance */
+ info->mix[i] = m;
+ }
+ }
+ }
+ }
+ return CV_NO_ERR;
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvEViterbi
+// Purpose: The function calculates the embedded Viterbi algorithm
+// for 1 image
+// Context:
+// Parameters:
+// obs_info - observations
+// hmm - HMM
+//
+// Returns: the Embedded Viterbi probability (float)
+// and do state segmentation of observations
+//
+// Notes:
+//F*/
+float icvViterbi(Cv1DObsInfo* obs_info, CvEHMM* hmm)
+{
+ int i, counter;
+ float log_likelihood;
+
+ //CvEHMMState* first_state = hmm->u.state;
+
+ /* memory allocation for superB */
+ /*CvMatr32f superB = picvCreateMatrix_32f(hmm->num_states, obs_info->obs_x );*/
+
+ /* memory allocation for q */
+ int* super_q = (int*)icvAlloc( obs_info->obs_x * sizeof(int) );
+
+ /* perform Viterbi segmentation (process 1D HMM) */
+ icvViterbiSegmentation( hmm->num_states, obs_info->obs_x,
+ hmm->transP, (float*)(hmm->obsProb), 0,
+ _CV_LAST_STATE, &super_q, obs_info->obs_x,
+ obs_info->obs_x, &log_likelihood );
+
+ log_likelihood /= obs_info->obs_x ;
+
+ counter = 0;
+ /* assign new state to observation vectors */
+ for (i = 0; i < obs_info->obs_x; i++)
+ {
+ int state = super_q[i];
+ obs_info->state[i] = state;
+ }
+
+ /* memory deallocation for superB */
+ /*picvDeleteMatrix( superB );*/
+ icvFree( &super_q );
+
+ return log_likelihood;
+}
+
+CvStatus icvEstimate1DHMMStateParams(CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm)
+
+{
+ /* compute gamma, weights, means, vars */
+ int k, i, j, m;
+ int counter = 0;
+ int total = 0;
+ int vect_len = obs_info_array[0]->obs_size;
+
+ float start_log_var_val = LN2PI * vect_len;
+
+ CvVect32f tmp_vect = icvCreateVector_32f( vect_len );
+
+ CvEHMMState* first_state = hmm->u.state;
+
+ assert( sizeof(float) == sizeof(int) );
+
+ total+= hmm->num_states;
+
+ /***************Gamma***********************/
+ /* initialize gamma */
+ for( i = 0; i < total; i++ )
+ {
+ for (m = 0; m < first_state[i].num_mix; m++)
+ {
+ ((int*)(first_state[i].weight))[m] = 0;
+ }
+ }
+
+ /* maybe gamma must be computed in mixsegm process ?? */
+
+ /* compute gamma */
+ counter = 0;
+ for (k = 0; k < num_img; k++)
+ {
+ CvImgObsInfo* info = obs_info_array[k];
+ int num_obs = info->obs_y * info->obs_x;
+
+ for (i = 0; i < num_obs; i++)
+ {
+ int state, mixture;
+ state = info->state[i];
+ mixture = info->mix[i];
+ /* computes gamma - number of observations corresponding
+ to every mixture of every state */
+ ((int*)(first_state[state].weight))[mixture] += 1;
+ }
+ }
+ /***************Mean and Var***********************/
+ /* compute means and variances of every item */
+ /* initially variance placed to inv_var */
+ /* zero mean and variance */
+ for (i = 0; i < total; i++)
+ {
+ memset( (void*)first_state[i].mu, 0, first_state[i].num_mix * vect_len *
+ sizeof(float) );
+ memset( (void*)first_state[i].inv_var, 0, first_state[i].num_mix * vect_len *
+ sizeof(float) );
+ }
+
+ /* compute sums */
+ for (i = 0; i < num_img; i++)
+ {
+ CvImgObsInfo* info = obs_info_array[i];
+ int total_obs = info->obs_x;// * info->obs_y;
+
+ float* vector = info->obs;
+
+ for (j = 0; j < total_obs; j++, vector+=vect_len )
+ {
+ int state = info->state[j];
+ int mixture = info->mix[j];
+
+ CvVect32f mean = first_state[state].mu + mixture * vect_len;
+ CvVect32f mean2 = first_state[state].inv_var + mixture * vect_len;
+
+ icvAddVector_32f( mean, vector, mean, vect_len );
+ icvAddSquare_32f_C1IR( vector, vect_len * sizeof(float),
+ mean2, vect_len * sizeof(float), cvSize(vect_len, 1) );
+ }
+ }
+
+ /*compute the means and variances */
+ /* assume gamma already computed */
+ counter = 0;
+ for (i = 0; i < total; i++)
+ {
+ CvEHMMState* state = &(first_state[i]);
+
+ for (m = 0; m < state->num_mix; m++)
+ {
+ int k;
+ CvVect32f mu = state->mu + m * vect_len;
+ CvVect32f invar = state->inv_var + m * vect_len;
+
+ if ( ((int*)state->weight)[m] > 1)
+ {
+ float inv_gamma = 1.f/((int*)(state->weight))[m];
+
+ icvScaleVector_32f( mu, mu, vect_len, inv_gamma);
+ icvScaleVector_32f( invar, invar, vect_len, inv_gamma);
+ }
+
+ icvMulVectors_32f(mu, mu, tmp_vect, vect_len);
+ icvSubVector_32f( invar, tmp_vect, invar, vect_len);
+
+ /* low bound of variance - 0.01 (Ara's experimental result) */
+ for( k = 0; k < vect_len; k++ )
+ {
+ invar[k] = (invar[k] > 0.01f) ? invar[k] : 0.01f;
+ }
+
+ /* compute log_var */
+ state->log_var_val[m] = start_log_var_val;
+ for( k = 0; k < vect_len; k++ )
+ {
+ state->log_var_val[m] += (float)log( invar[k] );
+ }
+
+ state->log_var_val[m] *= 0.5;
+
+ /* compute inv_var = 1/sqrt(2*variance) */
+ icvScaleVector_32f(invar, invar, vect_len, 2.f );
+ icvbInvSqrt_32f(invar, invar, vect_len );
+ }
+ }
+
+ /***************Weights***********************/
+ /* normilize gammas - i.e. compute mixture weights */
+
+ //compute weights
+ for (i = 0; i < total; i++)
+ {
+ int gamma_total = 0;
+ float norm;
+
+ for (m = 0; m < first_state[i].num_mix; m++)
+ {
+ gamma_total += ((int*)(first_state[i].weight))[m];
+ }
+
+ norm = gamma_total ? (1.f/(float)gamma_total) : 0.f;
+
+ for (m = 0; m < first_state[i].num_mix; m++)
+ {
+ first_state[i].weight[m] = ((int*)(first_state[i].weight))[m] * norm;
+ }
+ }
+
+ icvDeleteVector( tmp_vect);
+ return CV_NO_ERR;
+}
+
+
+
+
+
+#endif
+
diff --git a/cvaux/src/cvhmmobs.cpp b/cvaux/src/cvhmmobs.cpp
new file mode 100644
index 0000000..bbac714
--- /dev/null
+++ b/cvaux/src/cvhmmobs.cpp
@@ -0,0 +1,634 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cvaux.h"
+
+//*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvImgToObs_DCT_8u32f_C1R
+// Purpose: The function takes as input an image and returns the sequnce of observations
+// to be used with an embedded HMM; Each observation is top-left block of DCT
+// coefficient matrix.
+// Context:
+// Parameters: img - pointer to the original image ROI
+// imgStep - full row width of the image in bytes
+// roi - width and height of ROI in pixels
+// obs - pointer to resultant observation vectors
+// dctSize - size of the block for which DCT is calculated
+// obsSize - size of top-left block of DCT coeffs matrix, which is treated
+// as observation. Each observation vector consists of
+// obsSize.width * obsSize.height floats.
+// The following conditions should be satisfied:
+// 0 < objSize.width <= dctSize.width,
+// 0 < objSize.height <= dctSize.height.
+// delta - dctBlocks are overlapped and this parameter specifies horizontal
+// and vertical shift.
+// Returns:
+// CV_NO_ERR or error code
+// Notes:
+// The algorithm is following:
+// 1. First, number of observation vectors per row and per column are calculated:
+//
+// Nx = floor((roi.width - dctSize.width + delta.width)/delta.width);
+// Ny = floor((roi.height - dctSize.height + delta.height)/delta.height);
+//
+// So, total number of observation vectors is Nx*Ny, and total size of
+// array obs must be >= Nx*Ny*obsSize.width*obsSize.height*sizeof(float).
+// 2. Observation vectors are calculated in the following loop
+// ( actual implementation may be different ), where
+// I[x1:x2,y1:y2] means block of pixels from source image with
+// x1 <= x < x2, y1 <= y < y2,
+// D[x1:x2,y1:y2] means sub matrix of DCT matrix D.
+// O[x,y] means observation vector that corresponds to position
+// (x*delta.width,y*delta.height) in the source image
+// ( all indices are counted from 0 ).
+//
+// for( y = 0; y < Ny; y++ )
+// {
+// for( x = 0; x < Nx; x++ )
+// {
+// D = DCT(I[x*delta.width : x*delta.width + dctSize.width,
+// y*delta.height : y*delta.height + dctSize.height]);
+// O[x,y] = D[0:obsSize.width, 0:obsSize.height];
+// }
+// }
+//F*/
+
+/*comment out the following line to make DCT be calculated in floating-point arithmetics*/
+//#define _CV_INT_DCT
+
+/* for integer DCT only */
+#define DCT_SCALE 15
+
+#ifdef _CV_INT_DCT
+typedef int work_t;
+
+#define DESCALE CV_DESCALE
+#define SCALE(x) CV_FLT_TO_FIX((x),DCT_SCALE)
+#else
+typedef float work_t;
+
+#define DESCALE(x,n) (float)(x)
+#define SCALE(x) (float)(x)
+#endif
+
+/* calculate dct transform matrix */
+static void icvCalcDCTMatrix( work_t * cfs, int n );
+
+#define MAX_DCT_SIZE 32
+
+static CvStatus CV_STDCALL
+icvImgToObs_DCT_8u32f_C1R( uchar * img, int imgStep, CvSize roi,
+ float *obs, CvSize dctSize,
+ CvSize obsSize, CvSize delta )
+{
+ /* dct transform matrices: horizontal and vertical */
+ work_t tab_x[MAX_DCT_SIZE * MAX_DCT_SIZE / 2 + 2];
+ work_t tab_y[MAX_DCT_SIZE * MAX_DCT_SIZE / 2 + 2];
+
+ /* temporary buffers for dct */
+ work_t temp0[MAX_DCT_SIZE * 4];
+ work_t temp1[MAX_DCT_SIZE * 4];
+ work_t *buffer = 0;
+ work_t *buf_limit;
+
+ double s;
+
+ int y;
+ int Nx, Ny;
+
+ int n1 = dctSize.height, m1 = n1 / 2;
+ int n2 = dctSize.width, m2 = n2 / 2;
+
+ if( !img || !obs )
+ return CV_NULLPTR_ERR;
+
+ if( roi.width <= 0 || roi.height <= 0 )
+ return CV_BADSIZE_ERR;
+
+ if( delta.width <= 0 || delta.height <= 0 )
+ return CV_BADRANGE_ERR;
+
+ if( obsSize.width <= 0 || dctSize.width < obsSize.width ||
+ obsSize.height <= 0 || dctSize.height < obsSize.height )
+ return CV_BADRANGE_ERR;
+
+ if( dctSize.width > MAX_DCT_SIZE || dctSize.height > MAX_DCT_SIZE )
+ return CV_BADRANGE_ERR;
+
+ Nx = (roi.width - dctSize.width + delta.width) / delta.width;
+ Ny = (roi.height - dctSize.height + delta.height) / delta.height;
+
+ if( Nx <= 0 || Ny <= 0 )
+ return CV_BADRANGE_ERR;
+
+ buffer = (work_t *)cvAlloc( roi.width * obsSize.height * sizeof( buffer[0] ));
+ if( !buffer )
+ return CV_OUTOFMEM_ERR;
+
+ icvCalcDCTMatrix( tab_x, dctSize.width );
+ icvCalcDCTMatrix( tab_y, dctSize.height );
+
+ buf_limit = buffer + obsSize.height * roi.width;
+
+ for( y = 0; y < Ny; y++, img += delta.height * imgStep )
+ {
+ int x, i, j, k;
+ work_t k0 = 0;
+
+ /* do transfroms for each column. Calc only first obsSize.height DCT coefficients */
+ for( x = 0; x < roi.width; x++ )
+ {
+ float is = 0;
+ work_t *buf = buffer + x;
+ work_t *tab = tab_y + 2;
+
+ if( n1 & 1 )
+ {
+ is = img[x + m1 * imgStep];
+ k0 = ((work_t) is) * tab[-1];
+ }
+
+ /* first coefficient */
+ for( j = 0; j < m1; j++ )
+ {
+ float t0 = img[x + j * imgStep];
+ float t1 = img[x + (n1 - 1 - j) * imgStep];
+ float t2 = t0 + t1;
+
+ t0 -= t1;
+ temp0[j] = (work_t) t2;
+ is += t2;
+ temp1[j] = (work_t) t0;
+ }
+
+ buf[0] = DESCALE( is * tab[-2], PASS1_SHIFT );
+ if( (buf += roi.width) >= buf_limit )
+ continue;
+
+ /* other coefficients */
+ for( ;; )
+ {
+ s = 0;
+
+ for( k = 0; k < m1; k++ )
+ s += temp1[k] * tab[k];
+
+ buf[0] = DESCALE( s, PASS1_SHIFT );
+ if( (buf += roi.width) >= buf_limit )
+ break;
+
+ tab += m1;
+ s = 0;
+
+ if( n1 & 1 )
+ {
+ k0 = -k0;
+ s = k0;
+ }
+ for( k = 0; k < m1; k++ )
+ s += temp0[k] * tab[k];
+
+ buf[0] = DESCALE( s, PASS1_SHIFT );
+ tab += m1;
+
+ if( (buf += roi.width) >= buf_limit )
+ break;
+ }
+ }
+
+ k0 = 0;
+
+ /* do transforms for rows. */
+ for( x = 0; x + dctSize.width <= roi.width; x += delta.width )
+ {
+ for( i = 0; i < obsSize.height; i++ )
+ {
+ work_t *buf = buffer + x + roi.width * i;
+ work_t *tab = tab_x + 2;
+ float *obs_limit = obs + obsSize.width;
+
+ s = 0;
+
+ if( n2 & 1 )
+ {
+ s = buf[m2];
+ k0 = (work_t) (s * tab[-1]);
+ }
+
+ /* first coefficient */
+ for( j = 0; j < m2; j++ )
+ {
+ work_t t0 = buf[j];
+ work_t t1 = buf[n2 - 1 - j];
+ work_t t2 = t0 + t1;
+
+ t0 -= t1;
+ temp0[j] = (work_t) t2;
+ s += t2;
+ temp1[j] = (work_t) t0;
+ }
+
+ *obs++ = (float) DESCALE( s * tab[-2], PASS2_SHIFT );
+
+ if( obs == obs_limit )
+ continue;
+
+ /* other coefficients */
+ for( ;; )
+ {
+ s = 0;
+
+ for( k = 0; k < m2; k++ )
+ s += temp1[k] * tab[k];
+
+ obs[0] = (float) DESCALE( s, PASS2_SHIFT );
+ if( ++obs == obs_limit )
+ break;
+
+ tab += m2;
+
+ s = 0;
+
+ if( n2 & 1 )
+ {
+ k0 = -k0;
+ s = k0;
+ }
+ for( k = 0; k < m2; k++ )
+ s += temp0[k] * tab[k];
+ obs[0] = (float) DESCALE( s, PASS2_SHIFT );
+
+ tab += m2;
+ if( ++obs == obs_limit )
+ break;
+ }
+ }
+ }
+ }
+
+ cvFree( &buffer );
+ return CV_NO_ERR;
+}
+
+
+static CvStatus CV_STDCALL
+icvImgToObs_DCT_32f_C1R( float * img, int imgStep, CvSize roi,
+ float *obs, CvSize dctSize,
+ CvSize obsSize, CvSize delta )
+{
+ /* dct transform matrices: horizontal and vertical */
+ work_t tab_x[MAX_DCT_SIZE * MAX_DCT_SIZE / 2 + 2];
+ work_t tab_y[MAX_DCT_SIZE * MAX_DCT_SIZE / 2 + 2];
+
+ /* temporary buffers for dct */
+ work_t temp0[MAX_DCT_SIZE * 4];
+ work_t temp1[MAX_DCT_SIZE * 4];
+ work_t *buffer = 0;
+ work_t *buf_limit;
+
+ double s;
+
+ int y;
+ int Nx, Ny;
+
+ int n1 = dctSize.height, m1 = n1 / 2;
+ int n2 = dctSize.width, m2 = n2 / 2;
+
+ if( !img || !obs )
+ return CV_NULLPTR_ERR;
+
+ if( roi.width <= 0 || roi.height <= 0 )
+ return CV_BADSIZE_ERR;
+
+ if( delta.width <= 0 || delta.height <= 0 )
+ return CV_BADRANGE_ERR;
+
+ if( obsSize.width <= 0 || dctSize.width < obsSize.width ||
+ obsSize.height <= 0 || dctSize.height < obsSize.height )
+ return CV_BADRANGE_ERR;
+
+ if( dctSize.width > MAX_DCT_SIZE || dctSize.height > MAX_DCT_SIZE )
+ return CV_BADRANGE_ERR;
+
+ Nx = (roi.width - dctSize.width + delta.width) / delta.width;
+ Ny = (roi.height - dctSize.height + delta.height) / delta.height;
+
+ if( Nx <= 0 || Ny <= 0 )
+ return CV_BADRANGE_ERR;
+
+ buffer = (work_t *)cvAlloc( roi.width * obsSize.height * sizeof( buffer[0] ));
+ if( !buffer )
+ return CV_OUTOFMEM_ERR;
+
+ icvCalcDCTMatrix( tab_x, dctSize.width );
+ icvCalcDCTMatrix( tab_y, dctSize.height );
+
+ buf_limit = buffer + obsSize.height * roi.width;
+
+ imgStep /= sizeof(img[0]);
+
+ for( y = 0; y < Ny; y++, img += delta.height * imgStep )
+ {
+ int x, i, j, k;
+ work_t k0 = 0;
+
+ /* do transfroms for each column. Calc only first obsSize.height DCT coefficients */
+ for( x = 0; x < roi.width; x++ )
+ {
+ float is = 0;
+ work_t *buf = buffer + x;
+ work_t *tab = tab_y + 2;
+
+ if( n1 & 1 )
+ {
+ is = img[x + m1 * imgStep];
+ k0 = ((work_t) is) * tab[-1];
+ }
+
+ /* first coefficient */
+ for( j = 0; j < m1; j++ )
+ {
+ float t0 = img[x + j * imgStep];
+ float t1 = img[x + (n1 - 1 - j) * imgStep];
+ float t2 = t0 + t1;
+
+ t0 -= t1;
+ temp0[j] = (work_t) t2;
+ is += t2;
+ temp1[j] = (work_t) t0;
+ }
+
+ buf[0] = DESCALE( is * tab[-2], PASS1_SHIFT );
+ if( (buf += roi.width) >= buf_limit )
+ continue;
+
+ /* other coefficients */
+ for( ;; )
+ {
+ s = 0;
+
+ for( k = 0; k < m1; k++ )
+ s += temp1[k] * tab[k];
+
+ buf[0] = DESCALE( s, PASS1_SHIFT );
+ if( (buf += roi.width) >= buf_limit )
+ break;
+
+ tab += m1;
+ s = 0;
+
+ if( n1 & 1 )
+ {
+ k0 = -k0;
+ s = k0;
+ }
+ for( k = 0; k < m1; k++ )
+ s += temp0[k] * tab[k];
+
+ buf[0] = DESCALE( s, PASS1_SHIFT );
+ tab += m1;
+
+ if( (buf += roi.width) >= buf_limit )
+ break;
+ }
+ }
+
+ k0 = 0;
+
+ /* do transforms for rows. */
+ for( x = 0; x + dctSize.width <= roi.width; x += delta.width )
+ {
+ for( i = 0; i < obsSize.height; i++ )
+ {
+ work_t *buf = buffer + x + roi.width * i;
+ work_t *tab = tab_x + 2;
+ float *obs_limit = obs + obsSize.width;
+
+ s = 0;
+
+ if( n2 & 1 )
+ {
+ s = buf[m2];
+ k0 = (work_t) (s * tab[-1]);
+ }
+
+ /* first coefficient */
+ for( j = 0; j < m2; j++ )
+ {
+ work_t t0 = buf[j];
+ work_t t1 = buf[n2 - 1 - j];
+ work_t t2 = t0 + t1;
+
+ t0 -= t1;
+ temp0[j] = (work_t) t2;
+ s += t2;
+ temp1[j] = (work_t) t0;
+ }
+
+ *obs++ = (float) DESCALE( s * tab[-2], PASS2_SHIFT );
+
+ if( obs == obs_limit )
+ continue;
+
+ /* other coefficients */
+ for( ;; )
+ {
+ s = 0;
+
+ for( k = 0; k < m2; k++ )
+ s += temp1[k] * tab[k];
+
+ obs[0] = (float) DESCALE( s, PASS2_SHIFT );
+ if( ++obs == obs_limit )
+ break;
+
+ tab += m2;
+
+ s = 0;
+
+ if( n2 & 1 )
+ {
+ k0 = -k0;
+ s = k0;
+ }
+ for( k = 0; k < m2; k++ )
+ s += temp0[k] * tab[k];
+ obs[0] = (float) DESCALE( s, PASS2_SHIFT );
+
+ tab += m2;
+ if( ++obs == obs_limit )
+ break;
+ }
+ }
+ }
+ }
+
+ cvFree( &buffer );
+ return CV_NO_ERR;
+}
+
+
+static void
+icvCalcDCTMatrix( work_t * cfs, int n )
+{
+ static const double sqrt2 = 1.4142135623730950488016887242097;
+ static const double pi = 3.1415926535897932384626433832795;
+
+ static const double sincos[16 * 2] = {
+ 1.00000000000000000, 0.00000000000000006,
+ 0.70710678118654746, 0.70710678118654757,
+ 0.49999999999999994, 0.86602540378443871,
+ 0.38268343236508978, 0.92387953251128674,
+ 0.30901699437494740, 0.95105651629515353,
+ 0.25881904510252074, 0.96592582628906831,
+ 0.22252093395631439, 0.97492791218182362,
+ 0.19509032201612825, 0.98078528040323043,
+ 0.17364817766693033, 0.98480775301220802,
+ 0.15643446504023087, 0.98768834059513777,
+ 0.14231483827328514, 0.98982144188093268,
+ 0.13052619222005157, 0.99144486137381038,
+ 0.12053668025532305, 0.99270887409805397,
+ 0.11196447610330786, 0.99371220989324260,
+ 0.10452846326765346, 0.99452189536827329,
+ 0.09801714032956060, 0.99518472667219693,
+ };
+
+#define ROTATE( c, s, dc, ds ) \
+ { \
+ t = c*dc - s*ds; \
+ s = c*ds + s*dc; \
+ c = t; \
+ }
+
+#define WRITE2( j, a, b ) \
+ { \
+ cfs[j] = SCALE(a); \
+ cfs2[j] = SCALE(b); \
+ }
+
+ double t, scale = 1. / sqrt( (double)n );
+ int i, j, m = n / 2;
+
+ cfs[0] = SCALE( scale );
+ scale *= sqrt2;
+ cfs[1] = SCALE( scale );
+ cfs += 2 - m;
+
+ if( n > 1 )
+ {
+ double a0, b0;
+ double da0, db0;
+ work_t *cfs2 = cfs + m * n;
+
+ if( n <= 16 )
+ {
+ da0 = a0 = sincos[2 * n - 1];
+ db0 = b0 = sincos[2 * n - 2];
+ }
+ else
+ {
+ t = pi / (2 * n);
+ da0 = a0 = cos( t );
+ db0 = b0 = sin( t );
+ }
+
+ /* other rows */
+ for( i = 1; i <= m; i++ )
+ {
+ double a = a0 * scale;
+ double b = b0 * scale;
+ double da = a0 * a0 - b0 * b0;
+ double db = a0 * b0 + a0 * b0;
+
+ cfs += m;
+ cfs2 -= m;
+
+ for( j = 0; j < m; j += 2 )
+ {
+ WRITE2( j, a, b );
+ ROTATE( a, b, da, db );
+ if( j + 1 < m )
+ {
+ WRITE2( j + 1, a, -b );
+ ROTATE( a, b, da, db );
+ }
+ }
+
+ ROTATE( a0, b0, da0, db0 );
+ }
+ }
+#undef ROTATE
+#undef WRITE2
+}
+
+
+CV_IMPL void
+cvImgToObs_DCT( const void* arr, float *obs, CvSize dctSize,
+ CvSize obsSize, CvSize delta )
+{
+ CV_FUNCNAME( "cvImgToObs_DCT" );
+
+ __BEGIN__;
+
+ CvMat stub, *mat = (CvMat*)arr;
+
+ CV_CALL( mat = cvGetMat( arr, &stub ));
+
+ switch( CV_MAT_TYPE( mat->type ))
+ {
+ case CV_8UC1:
+ IPPI_CALL( icvImgToObs_DCT_8u32f_C1R( mat->data.ptr, mat->step,
+ cvGetMatSize(mat), obs,
+ dctSize, obsSize, delta ));
+ break;
+ case CV_32FC1:
+ IPPI_CALL( icvImgToObs_DCT_32f_C1R( mat->data.fl, mat->step,
+ cvGetMatSize(mat), obs,
+ dctSize, obsSize, delta ));
+ break;
+ default:
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+ }
+
+ __END__;
+}
+
+
+/* End of file. */
diff --git a/cvaux/src/cvlcm.cpp b/cvaux/src/cvlcm.cpp
new file mode 100644
index 0000000..04059e7
--- /dev/null
+++ b/cvaux/src/cvlcm.cpp
@@ -0,0 +1,724 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/* Hybrid linear-contour model reconstruction */
+#include "_cvaux.h"
+
+#define CV_IMPL CV_EXTERN_C
+
+const float LCM_CONST_ZERO = 1e-6f;
+
+/****************************************************************************************\
+* Auxiliary struct definitions *
+\****************************************************************************************/
+typedef struct CvLCM
+{
+ CvGraph* Graph;
+ CvVoronoiDiagram2D* VoronoiDiagram;
+ CvMemStorage* ContourStorage;
+ CvMemStorage* EdgeStorage;
+ float maxWidth;
+} CvLCM;
+
+typedef struct CvLCMComplexNodeData
+{
+ CvVoronoiNode2D edge_node;
+ CvPoint2D32f site_first_pt;
+ CvPoint2D32f site_last_pt;
+ CvVoronoiSite2D* site_first;
+ CvVoronoiSite2D* site_last;
+ CvVoronoiEdge2D* edge;
+} CvLCMComplexNodeData;
+
+typedef struct CvLCMData
+{
+ CvVoronoiNode2D* pnode;
+ CvVoronoiSite2D* psite;
+ CvVoronoiEdge2D* pedge;
+} CvLCMData;
+
+
+/****************************************************************************************\
+* Function definitions *
+\****************************************************************************************/
+
+#define _CV_READ_SEQ_ELEM( elem, reader, type ) \
+{ \
+ assert( (reader).seq->elem_size == sizeof(*elem)); \
+ elem = (type)(reader).ptr; \
+ CV_NEXT_SEQ_ELEM( sizeof(*elem), reader ) \
+}
+
+#define _CV_IS_SITE_REFLEX( SITE ) ((SITE) ->node[0] == (SITE) ->node[1])
+#define _CV_IS_EDGE_REFLEX( EDGE ) (( (EDGE)->site[0]->node[0] == (EDGE)->site[0]->node[0] ) || \
+ ( (EDGE)->site[1]->node[0] == (EDGE)->site[1]->node[0] ) )
+
+#define _CV_INITIALIZE_CVLCMDATA(STRUCT,SITE,EDGE,NODE)\
+{ (STRUCT)->psite = SITE ; (STRUCT)->pedge = EDGE; (STRUCT)->pnode = NODE;}
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvConstructLCM
+// Purpose: Function constructs hybrid model
+// Context:
+// Parameters:
+// LCM : in&out.
+// Returns: 1, if hybrid model was succesfully constructed
+// 0, if some error occures
+//F*/
+CV_IMPL
+int _cvConstructLCM(CvLCM* LCM);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvConstructLCMComplexNode
+// Purpose: Function constructs Complex Node (node, which consists of
+// two points and more) of hybrid model
+// Context:
+// Parameters:
+// pLCM : in&out.
+// pLCMEdge: in, input edge of hybrid model
+// pLCMInputData: in, input parameters
+// Returns: pointer to constructed node
+//F*/
+CV_IMPL
+CvLCMNode* _cvConstructLCMComplexNode(CvLCM* pLCM,
+ CvLCMEdge* pLCMEdge,
+ CvLCMData* pLCMInputData);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvConstructLCMSimpleNode
+// Purpose: Function constructs Simple Node (node, which consists of
+// one point) of hybrid model
+// Context:
+// Parameters:
+// pLCM : in&out.
+// pLCMEdge: in, input edge of hybrid model
+// pLCMInputData: in, input parameters
+// Returns: pointer to constructed node
+//F*/
+CV_IMPL
+CvLCMNode* _cvConstructLCMSimpleNode(CvLCM* pLCM,
+ CvLCMEdge* pLCMEdge,
+ CvLCMData* pLCMInputData);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvConstructLCMSimpleNode
+// Purpose: Function constructs Edge of hybrid model
+// Context:
+// Parameters:
+// pLCM : in&out.
+// pLCMInputData: in, input parameters
+// Returns: pointer to constructed edge
+//F*/
+CV_IMPL
+CvLCMEdge* _cvConstructLCMEdge(CvLCM* pLCM,
+ CvLCMData* pLCMInputData);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvTreatExeptionalCase
+// Purpose: Function treats triangles and regular polygons
+// Context:
+// Parameters:
+// pLCM : in, information about graph
+// pLCMInputData: in, input parameters
+// Returns: pointer to graph node
+//F*/
+CV_IMPL
+CvLCMNode* _cvTreatExeptionalCase(CvLCM* pLCM,
+ CvLCMData* pLCMInputData);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvNodeMultyplicity
+// Purpose: Function seeks all non-boundary edges incident to
+// given node and correspondent incident sites
+// Context:
+// Parameters:
+// pEdge : in, original edge
+// pNode : in, given node
+// LinkedEdges : out, matrix of incident edges
+// LinkedSites : out, matrix of incident sites
+// pSite: in, original site (pNode must be the begin point of pEdge
+// for this pSite, this property hold out far all edges)
+// Returns: number of incident edges (must be less than 10)
+//F*/
+CV_IMPL
+int _cvNodeMultyplicity(CvVoronoiSite2D* pSite,
+ CvVoronoiEdge2D* pEdge,
+ CvVoronoiNode2D* pNode,
+ CvVoronoiEdge2D** LinkedEdges,
+ CvVoronoiSite2D** LinkedSites);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvCreateLCMNode
+// Purpose: Function create graph node
+// Context:
+// Parameters:
+// pLCM : in, information about graph
+// Returns: pointer to graph node
+//F*/
+CV_IMPL
+CvLCMNode* _cvCreateLCMNode(CvLCM* pLCM);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvCreateLCMEdge
+// Purpose: Function create graph edge
+// Context:
+// Parameters:
+// pLCM : in, information about graph
+// Returns: pointer to graph edge
+//F*/
+CV_IMPL
+CvLCMEdge* _cvCreateLCMEdge(CvLCM* pLCM);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvCreateLCMNode
+// Purpose: Function establishs the connection between node and ege
+// Context:
+// Parameters:
+// LCMNode : in, graph node
+// LCMEdge : in, graph edge
+// LCMEdge_prev : in&out, previous edge, connected with given node
+// index: in,
+// i : =0, if node is initial for edge
+// =1, if node is terminal for edge
+// Returns:
+//F*/
+CV_IMPL
+void _cvAttachLCMEdgeToLCMNode(CvLCMNode* LCMNode,
+ CvLCMEdge* LCMEdge,
+ CvLCMEdge* &LCMEdge_prev,
+ int index,
+ int i);
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvProjectionPointToSegment
+// Purpose: Function computes the ortogonal projection of PointO to
+// to segment[PointA, PointB]
+// Context:
+// Parameters:
+// PointO, PointA,PointB: in, given points
+// PrPoint : out, projection
+// dist : distance from PointO to PrPoint
+// Returns:
+//F*/
+CV_IMPL
+void _cvProjectionPointToSegment(CvPoint2D32f* PointO,
+ CvPoint2D32f* PointA,
+ CvPoint2D32f* PointB,
+ CvPoint2D32f* PrPoint,
+ float* dist);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvPrepareData
+// Purpose: Function fills up the struct CvLCMComplexNodeData
+// Context:
+// Parameters:
+// pLCMData : in
+// pLCMCCNData : out
+// Returns:
+//F*/
+CV_IMPL
+void _cvPrepareData(CvLCMComplexNodeData* pLCMCCNData,
+ CvLCMData* pLCMData);
+
+/****************************************************************************************\
+* Function realization *
+\****************************************************************************************/
+
+CV_IMPL CvGraph* cvLinearContorModelFromVoronoiDiagram(CvVoronoiDiagram2D* VoronoiDiagram,
+ float maxWidth)
+{
+ CvMemStorage* LCMstorage;
+ CvSet* SiteSet;
+ CvLCM LCM = {NULL, VoronoiDiagram,NULL,NULL,maxWidth};
+
+ CV_FUNCNAME( "cvLinearContorModelFromVoronoiDiagram" );
+ __BEGIN__;
+
+ if( !VoronoiDiagram )
+ CV_ERROR( CV_StsBadArg,"Voronoi Diagram is not defined" );
+ if( maxWidth < 0 )
+ CV_ERROR( CV_StsBadArg,"Treshold parameter must be non negative" );
+
+ for(SiteSet = VoronoiDiagram->sites;
+ SiteSet != NULL;
+ SiteSet = (CvSet*)SiteSet->h_next)
+ {
+ if(SiteSet->v_next)
+ CV_ERROR( CV_StsBadArg,"Can't operate with multiconnected domains" );
+ if(SiteSet->total > 70000)
+ CV_ERROR( CV_StsBadArg,"Can't operate with large domains" );
+ }
+
+
+ LCMstorage = cvCreateMemStorage(0);
+ LCM.EdgeStorage = cvCreateChildMemStorage(LCMstorage);
+ LCM.ContourStorage = cvCreateChildMemStorage(LCMstorage);
+ LCM.Graph = cvCreateGraph(CV_SEQ_KIND_GRAPH|CV_GRAPH_FLAG_ORIENTED,
+ sizeof(CvGraph),
+ sizeof(CvLCMNode),
+ sizeof(CvLCMEdge),
+ LCMstorage);
+ if(!_cvConstructLCM(&LCM))
+ cvReleaseLinearContorModelStorage(&LCM.Graph);
+
+
+ __END__;
+ return LCM.Graph;
+}//end of cvLinearContorModelFromVoronoiDiagram
+
+CV_IMPL int cvReleaseLinearContorModelStorage(CvGraph** Graph)
+{
+ CvSeq* LCMNodeSeq, *LCMEdgeSeq;
+ CvLCMNode* pLCMNode;
+ CvLCMEdge* pLCMEdge;
+
+ /*CV_FUNCNAME( "cvReleaseLinearContorModelStorage" );*/
+ __BEGIN__;
+
+ if(!Graph || !(*Graph))
+ return 0;
+
+ LCMNodeSeq = (CvSeq*)(*Graph);
+ LCMEdgeSeq = (CvSeq*)(*Graph)->edges;
+ if(LCMNodeSeq->total > 0)
+ {
+ pLCMNode = (CvLCMNode*)cvGetSeqElem(LCMNodeSeq,0);
+ if(pLCMNode->contour->storage)
+ cvReleaseMemStorage(&pLCMNode->contour->storage);
+ }
+ if(LCMEdgeSeq->total > 0)
+ {
+ pLCMEdge = (CvLCMEdge*)cvGetSeqElem(LCMEdgeSeq,0);
+ if(pLCMEdge->chain->storage)
+ cvReleaseMemStorage(&pLCMEdge->chain->storage);
+ }
+ if((*Graph)->storage)
+ cvReleaseMemStorage(&(*Graph)->storage);
+ *Graph = NULL;
+
+
+ __END__;
+ return 1;
+}//end of cvReleaseLinearContorModelStorage
+
+int _cvConstructLCM(CvLCM* LCM)
+{
+ CvVoronoiSite2D* pSite = 0;
+ CvVoronoiEdge2D* pEdge = 0, *pEdge1;
+ CvVoronoiNode2D* pNode, *pNode1;
+
+ CvVoronoiEdge2D* LinkedEdges[10];
+ CvVoronoiSite2D* LinkedSites[10];
+
+ CvSeqReader reader;
+ CvLCMData LCMdata;
+ int i;
+
+ for(CvSet* SiteSet = LCM->VoronoiDiagram->sites;
+ SiteSet != NULL;
+ SiteSet = (CvSet*)SiteSet->h_next)
+ {
+ cvStartReadSeq((CvSeq*)SiteSet, &reader);
+ for(i = 0; i < SiteSet->total; i++)
+ {
+ _CV_READ_SEQ_ELEM(pSite,reader,CvVoronoiSite2D*);
+ if(pSite->node[0] == pSite->node[1])
+ continue;
+ pEdge = CV_LAST_VORONOIEDGE2D(pSite);
+ pNode = CV_VORONOIEDGE2D_BEGINNODE(pEdge,pSite);
+ if(pNode->radius > LCM->maxWidth)
+ goto PREPARECOMPLEXNODE;
+
+ pEdge1 = CV_PREV_VORONOIEDGE2D(pEdge,pSite);
+ pNode1 = CV_VORONOIEDGE2D_BEGINNODE(pEdge1,pSite);
+ if(pNode1->radius > LCM->maxWidth)
+ goto PREPARECOMPLEXNODE;
+ if(pNode1->radius == 0)
+ continue;
+ if(_cvNodeMultyplicity(pSite, pEdge,pNode,LinkedEdges,LinkedSites) == 1)
+ goto PREPARESIMPLENODE;
+ }
+// treate triangle or regular polygon
+ _CV_INITIALIZE_CVLCMDATA(&LCMdata,pSite,pEdge,CV_VORONOIEDGE2D_ENDNODE(pEdge,pSite));
+ if(!_cvTreatExeptionalCase(LCM,&LCMdata))
+ return 0;
+ continue;
+
+PREPARECOMPLEXNODE:
+ _CV_INITIALIZE_CVLCMDATA(&LCMdata,pSite,pEdge,CV_VORONOIEDGE2D_ENDNODE(pEdge,pSite));
+ if(!_cvConstructLCMComplexNode(LCM,NULL,&LCMdata))
+ return 0;
+ continue;
+
+PREPARESIMPLENODE:
+ _CV_INITIALIZE_CVLCMDATA(&LCMdata,pSite,pEdge,CV_VORONOIEDGE2D_ENDNODE(pEdge,pSite));
+ if(!_cvConstructLCMSimpleNode(LCM,NULL,&LCMdata))
+ return 0;
+ continue;
+ }
+ return 1;
+}//end of _cvConstructLCM
+
+CvLCMNode* _cvConstructLCMComplexNode(CvLCM* pLCM,
+ CvLCMEdge* pLCMEdge,
+ CvLCMData* pLCMInputData)
+{
+ CvLCMNode* pLCMNode;
+ CvLCMEdge* pLCMEdge_prev = NULL;
+ CvSeqWriter writer;
+ CvVoronoiSite2D* pSite, *pSite_first, *pSite_last;
+ CvVoronoiEdge2D* pEdge, *pEdge_stop;
+ CvVoronoiNode2D* pNode0, *pNode1;
+ CvLCMData LCMOutputData;
+ CvLCMComplexNodeData LCMCCNData;
+ int index = 0;
+
+ _cvPrepareData(&LCMCCNData,pLCMInputData);
+
+ pLCMNode = _cvCreateLCMNode(pLCM);
+ _cvAttachLCMEdgeToLCMNode(pLCMNode,pLCMEdge,pLCMEdge_prev,1,1);
+ cvStartAppendToSeq((CvSeq*)pLCMNode->contour,&writer);
+ CV_WRITE_SEQ_ELEM(LCMCCNData.site_last_pt, writer);
+ index++;
+
+ if(pLCMEdge)
+ {
+ CV_WRITE_SEQ_ELEM(LCMCCNData.edge_node.pt, writer );
+ CV_WRITE_SEQ_ELEM(LCMCCNData.site_first_pt, writer );
+ index+=2;
+ }
+
+ pSite_first = LCMCCNData.site_first;
+ pSite_last = LCMCCNData.site_last;
+ pEdge = LCMCCNData.edge;
+
+ for(pSite = pSite_first;
+ pSite != pSite_last;
+ pSite = CV_NEXT_VORONOISITE2D(pSite),
+ pEdge = CV_PREV_VORONOIEDGE2D(CV_LAST_VORONOIEDGE2D(pSite),pSite))
+ {
+ pEdge_stop = CV_FIRST_VORONOIEDGE2D(pSite);
+ for(;pEdge && pEdge != pEdge_stop;
+ pEdge = CV_PREV_VORONOIEDGE2D(pEdge,pSite))
+ {
+ pNode0 = CV_VORONOIEDGE2D_BEGINNODE(pEdge,pSite);
+ pNode1 = CV_VORONOIEDGE2D_ENDNODE(pEdge,pSite);
+ if(pNode0->radius <= pLCM->maxWidth && pNode1->radius <= pLCM->maxWidth)
+ {
+ _CV_INITIALIZE_CVLCMDATA(&LCMOutputData,pSite,pEdge,pNode1);
+ _cvPrepareData(&LCMCCNData,&LCMOutputData);
+ CV_WRITE_SEQ_ELEM(LCMCCNData.site_first_pt, writer);
+ CV_WRITE_SEQ_ELEM(LCMCCNData.edge_node.pt, writer );
+ index+=2;
+ pLCMEdge = _cvConstructLCMEdge(pLCM,&LCMOutputData);
+ _cvAttachLCMEdgeToLCMNode(pLCMNode,pLCMEdge,pLCMEdge_prev,index - 1,0);
+ CV_WRITE_SEQ_ELEM(LCMCCNData.site_last_pt, writer);
+ index++;
+
+ pSite = CV_TWIN_VORONOISITE2D(pSite,pEdge);
+ pEdge_stop = CV_FIRST_VORONOIEDGE2D(pSite);
+ if(pSite == pSite_last)
+ break;
+ }
+ }
+ if(pSite == pSite_last)
+ break;
+
+ CV_WRITE_SEQ_ELEM(pSite->node[1]->pt, writer);
+ index++;
+ }
+
+ if(pLCMEdge_prev)
+ pLCMEdge_prev->next[(pLCMEdge_prev == (CvLCMEdge*)pLCMNode->first)] = pLCMNode->first;
+ cvEndWriteSeq(&writer);
+ return pLCMNode;
+}//end of _cvConstructLCMComplexNode
+
+CvLCMNode* _cvConstructLCMSimpleNode(CvLCM* pLCM,
+ CvLCMEdge* pLCMEdge,
+ CvLCMData* pLCMInputData)
+{
+ CvVoronoiEdge2D* pEdge = pLCMInputData->pedge;
+ CvVoronoiSite2D* pSite = pLCMInputData->psite;
+ CvVoronoiNode2D* pNode = CV_VORONOIEDGE2D_BEGINNODE(pEdge,pSite);
+
+ CvVoronoiEdge2D* LinkedEdges[10];
+ CvVoronoiSite2D* LinkedSites[10];
+ int multyplicity = _cvNodeMultyplicity(pSite,pEdge,pNode,LinkedEdges,LinkedSites);
+ if(multyplicity == 2)
+ {
+ pLCMInputData->pedge = LinkedEdges[1];
+ pLCMInputData->psite = CV_TWIN_VORONOISITE2D(LinkedSites[1],LinkedEdges[1]);
+ return NULL;
+ }
+
+ CvLCMEdge* pLCMEdge_prev = NULL;
+ CvLCMNode* pLCMNode;
+ CvLCMData LCMOutputData;
+
+ pLCMNode = _cvCreateLCMNode(pLCM);
+ cvSeqPush((CvSeq*)pLCMNode->contour,&pNode->pt);
+ _cvAttachLCMEdgeToLCMNode(pLCMNode,pLCMEdge,pLCMEdge_prev,0,1);
+
+ for(int i = (int)(pLCMEdge != NULL);i < multyplicity; i++)
+ {
+ pEdge = LinkedEdges[i];
+ pSite = LinkedSites[i];
+ _CV_INITIALIZE_CVLCMDATA(&LCMOutputData,CV_TWIN_VORONOISITE2D(pSite,pEdge),pEdge,pNode);
+ pLCMEdge = _cvConstructLCMEdge(pLCM,&LCMOutputData);
+ _cvAttachLCMEdgeToLCMNode(pLCMNode,pLCMEdge,pLCMEdge_prev,0,0);
+ }
+ pLCMEdge_prev->next[(pLCMEdge_prev == (CvLCMEdge*)pLCMNode->first)] = pLCMNode->first;
+ return pLCMNode;
+}//end of _cvConstructLCMSimpleNode
+
+CvLCMEdge* _cvConstructLCMEdge(CvLCM* pLCM,
+ CvLCMData* pLCMInputData)
+{
+ CvVoronoiEdge2D* pEdge = pLCMInputData->pedge;
+ CvVoronoiSite2D* pSite = pLCMInputData->psite;
+ float width = 0;
+
+ CvLCMData LCMData;
+ CvVoronoiNode2D* pNode0,*pNode1;
+
+ CvLCMEdge* pLCMEdge = _cvCreateLCMEdge(pLCM);
+
+ CvSeqWriter writer;
+ cvStartAppendToSeq(pLCMEdge->chain,&writer );
+
+ pNode0 = pNode1 = pLCMInputData->pnode;
+ CV_WRITE_SEQ_ELEM(pNode0->pt, writer);
+ width += pNode0->radius;
+
+ for(int counter = 0;
+ counter < pLCM->VoronoiDiagram->edges->total;
+ counter++)
+ {
+ pNode1 = CV_VORONOIEDGE2D_BEGINNODE(pEdge,pSite);
+ if(pNode1->radius >= pLCM->maxWidth)
+ goto CREATECOMPLEXNODE;
+
+ CV_WRITE_SEQ_ELEM(pNode1->pt,writer);
+ width += pNode1->radius;
+ _CV_INITIALIZE_CVLCMDATA(&LCMData,pSite,pEdge,pNode1);
+ if(_cvConstructLCMSimpleNode(pLCM,pLCMEdge,&LCMData))
+ goto LCMEDGEEXIT;
+
+ pEdge = LCMData.pedge; pSite = LCMData.psite;
+ pNode0 = pNode1;
+ }
+ return NULL;
+
+CREATECOMPLEXNODE:
+ _CV_INITIALIZE_CVLCMDATA(&LCMData,pSite,pEdge,pNode0);
+ CV_WRITE_SEQ_ELEM(LCMData.pnode->pt,writer);
+ width += LCMData.pnode->radius;
+ _cvConstructLCMComplexNode(pLCM,pLCMEdge,&LCMData);
+
+LCMEDGEEXIT:
+ cvEndWriteSeq(&writer);
+ pLCMEdge->width = width/pLCMEdge->chain->total;
+ return pLCMEdge;
+}//end of _cvConstructLCMEdge
+
+CvLCMNode* _cvTreatExeptionalCase(CvLCM* pLCM,
+ CvLCMData* pLCMInputData)
+{
+ CvVoronoiEdge2D* pEdge = pLCMInputData->pedge;
+ CvVoronoiSite2D* pSite = pLCMInputData->psite;
+ CvVoronoiNode2D* pNode = CV_VORONOIEDGE2D_BEGINNODE(pEdge,pSite);
+ CvLCMNode* pLCMNode = _cvCreateLCMNode(pLCM);
+ cvSeqPush((CvSeq*)pLCMNode->contour,&pNode->pt);
+ return pLCMNode;
+}//end of _cvConstructLCMEdge
+
+CV_INLINE
+CvLCMNode* _cvCreateLCMNode(CvLCM* pLCM)
+{
+ CvLCMNode* pLCMNode;
+ cvSetAdd((CvSet*)pLCM->Graph, NULL, (CvSetElem**)&pLCMNode );
+ pLCMNode->contour = (CvContour*)cvCreateSeq(0, sizeof(CvContour),
+ sizeof(CvPoint2D32f),pLCM->ContourStorage);
+ pLCMNode->first = NULL;
+ return pLCMNode;
+}//end of _cvCreateLCMNode
+
+CV_INLINE
+CvLCMEdge* _cvCreateLCMEdge(CvLCM* pLCM)
+{
+ CvLCMEdge* pLCMEdge;
+ cvSetAdd( (CvSet*)(pLCM->Graph->edges), 0, (CvSetElem**)&pLCMEdge );
+ pLCMEdge->chain = cvCreateSeq(0, sizeof(CvSeq),sizeof(CvPoint2D32f),pLCM->EdgeStorage);
+ pLCMEdge->next[0] = pLCMEdge->next[1] = NULL;
+ pLCMEdge->vtx[0] = pLCMEdge->vtx[1] = NULL;
+ pLCMEdge->index1 = pLCMEdge->index2 = -1;
+ return pLCMEdge;
+}//end of _cvCreateLCMEdge
+
+CV_INLINE
+void _cvAttachLCMEdgeToLCMNode(CvLCMNode* LCMNode,
+ CvLCMEdge* LCMEdge,
+ CvLCMEdge* &LCMEdge_prev,
+ int index,
+ int i)
+{
+ if(!LCMEdge)
+ return;
+ if(i==0)
+ LCMEdge->index1 = index;
+ else
+ LCMEdge->index2 = index;
+
+ LCMEdge->vtx[i] = (CvGraphVtx*)LCMNode;
+ if(!LCMEdge_prev)
+ LCMNode->first = (CvGraphEdge*)LCMEdge;
+ else
+// LCMEdge_prev->next[(LCMEdge_prev == (CvLCMEdge*)LCMNode->first)] = (CvGraphEdge*)LCMEdge;
+ LCMEdge_prev->next[(LCMEdge_prev->vtx[0] != (CvGraphVtx*)LCMNode)] = (CvGraphEdge*)LCMEdge;
+
+ LCMEdge->next[i] = LCMNode->first;
+ LCMEdge_prev = LCMEdge;
+}//end of _cvAttachLCMEdgeToLCMNode
+
+
+int _cvNodeMultyplicity(CvVoronoiSite2D* pSite,
+ CvVoronoiEdge2D* pEdge,
+ CvVoronoiNode2D* pNode,
+ CvVoronoiEdge2D** LinkedEdges,
+ CvVoronoiSite2D** LinkedSites)
+{
+ if(!pNode->radius)
+ return -1;
+ assert(pNode == CV_VORONOIEDGE2D_BEGINNODE(pEdge,pSite));
+
+ int multyplicity = 0;
+ CvVoronoiEdge2D* pEdge_cur = pEdge;
+ do
+ {
+ if(pEdge_cur->node[0]->radius && pEdge_cur->node[1]->radius)
+ {
+ LinkedEdges[multyplicity] = pEdge_cur;
+ LinkedSites[multyplicity] = pSite;
+ multyplicity++;
+ }
+ pEdge_cur = CV_PREV_VORONOIEDGE2D(pEdge_cur,pSite);
+ pSite = CV_TWIN_VORONOISITE2D(pSite,pEdge_cur);
+ }while(pEdge_cur != pEdge);
+ return multyplicity;
+}//end of _cvNodeMultyplicity
+
+
+CV_INLINE
+void _cvPrepareData(CvLCMComplexNodeData* pLCMCCNData,
+ CvLCMData* pLCMData)
+{
+ pLCMCCNData->site_first = pLCMData->psite;
+ pLCMCCNData->site_last = CV_TWIN_VORONOISITE2D(pLCMData->psite,pLCMData->pedge);
+ if(pLCMData->pedge == CV_LAST_VORONOIEDGE2D(pLCMData->psite))
+ {
+ pLCMCCNData->edge = CV_PREV_VORONOIEDGE2D(pLCMData->pedge,pLCMData->psite);
+ pLCMCCNData->edge_node = *pLCMData->pnode;
+ pLCMCCNData->site_first_pt = pLCMData->psite->node[0]->pt;
+ pLCMCCNData->site_last_pt = pLCMData->psite->node[0]->pt;
+ }
+ else
+ {
+ pLCMCCNData->edge = pLCMData->pedge;
+ pLCMCCNData->edge_node = *pLCMData->pnode;
+ _cvProjectionPointToSegment(&pLCMCCNData->edge_node.pt,
+ &pLCMCCNData->site_first->node[0]->pt,
+ &pLCMCCNData->site_first->node[1]->pt,
+ &pLCMCCNData->site_first_pt,
+ NULL);
+ _cvProjectionPointToSegment(&pLCMCCNData->edge_node.pt,
+ &pLCMCCNData->site_last->node[0]->pt,
+ &pLCMCCNData->site_last->node[1]->pt,
+ &pLCMCCNData->site_last_pt,
+ NULL);
+ }
+}//end of _cvPrepareData
+
+
+void _cvProjectionPointToSegment(CvPoint2D32f* PointO,
+ CvPoint2D32f* PointA,
+ CvPoint2D32f* PointB,
+ CvPoint2D32f* PrPoint,
+ float* dist)
+{
+ float scal_AO_AB, scal_AB_AB;
+ CvPoint2D32f VectorAB = {PointB->x - PointA->x, PointB->y - PointA->y};
+ scal_AB_AB = VectorAB.x*VectorAB.x + VectorAB.y*VectorAB.y;
+ if(scal_AB_AB < LCM_CONST_ZERO)
+ {
+ *PrPoint = *PointA;
+ if(dist)
+ *dist = (float)sqrt( (double)(PointO->x -PointA->x)*(PointO->x -PointA->x) + (PointO->y - PointA->y)*(PointO->y - PointA->y));
+ return;
+ }
+
+ CvPoint2D32f VectorAO = {PointO->x - PointA->x, PointO->y - PointA->y};
+ scal_AO_AB = VectorAO.x*VectorAB.x + VectorAO.y*VectorAB.y;
+
+ if(dist)
+ {
+ float vector_AO_AB = (float)fabs(VectorAO.x*VectorAB.y - VectorAO.y*VectorAB.x);
+ *dist = (float)(vector_AO_AB/sqrt((double)scal_AB_AB));
+ }
+
+ float alfa = scal_AO_AB/scal_AB_AB;
+ PrPoint->x = PointO->x - VectorAO.x + alfa*VectorAB.x;
+ PrPoint->y = PointO->y - VectorAO.y + alfa*VectorAB.y;
+ return;
+}//end of _cvProjectionPointToSegment
+
+
+
+
diff --git a/cvaux/src/cvlee.cpp b/cvaux/src/cvlee.cpp
new file mode 100644
index 0000000..58db0d0
--- /dev/null
+++ b/cvaux/src/cvlee.cpp
@@ -0,0 +1,4718 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/* Reconstruction of contour skeleton */
+#include "_cvaux.h"
+#include <time.h>
+
+#define NEXT_SEQ(seq,seq_first) ((seq) == (seq_first) ? seq->v_next : seq->h_next)
+#define SIGN(x) ( x<0 ? -1:( x>0 ? 1:0 ) )
+
+const float LEE_CONST_ZERO = 1e-6f;
+const float LEE_CONST_DIFF_POINTS = 1e-2f;
+const float LEE_CONST_ACCEPTABLE_ERROR = 1e-4f;
+
+/****************************************************************************************\
+* Auxiliary struct definitions *
+\****************************************************************************************/
+
+template<class T>
+struct CvLeePoint
+{
+ T x,y;
+};
+
+typedef CvLeePoint<float> CvPointFloat;
+typedef CvLeePoint<float> CvDirection;
+
+struct CvVoronoiSiteInt;
+struct CvVoronoiEdgeInt;
+struct CvVoronoiNodeInt;
+struct CvVoronoiParabolaInt;
+struct CvVoronoiChainInt;
+struct CvVoronoiHoleInt;
+
+struct CvVoronoiDiagramInt
+{
+ CvSeq* SiteSeq;
+ CvSeq* EdgeSeq;
+ CvSeq* NodeSeq;
+ CvSeq* ChainSeq;
+ CvSeq* ParabolaSeq;
+ CvSeq* DirectionSeq;
+ CvSeq* HoleSeq;
+ CvVoronoiSiteInt* reflex_site;
+ CvVoronoiHoleInt* top_hole;
+};
+
+struct CvVoronoiStorageInt
+{
+ CvMemStorage* SiteStorage;
+ CvMemStorage* EdgeStorage;
+ CvMemStorage* NodeStorage;
+ CvMemStorage* ChainStorage;
+ CvMemStorage* ParabolaStorage;
+ CvMemStorage* DirectionStorage;
+ CvMemStorage* HoleStorage;
+};
+
+struct CvVoronoiNodeInt
+{
+ CvPointFloat node;
+ float radius;
+};
+
+struct CvVoronoiSiteInt
+{
+ CvVoronoiNodeInt* node1;
+ CvVoronoiNodeInt* node2;
+ CvVoronoiEdgeInt* edge1;
+ CvVoronoiEdgeInt* edge2;
+ CvVoronoiSiteInt* next_site;
+ CvVoronoiSiteInt* prev_site;
+ CvDirection* direction;
+};
+
+struct CvVoronoiEdgeInt
+{
+ CvVoronoiNodeInt* node1;
+ CvVoronoiNodeInt* node2;
+ CvVoronoiSiteInt* site;
+ CvVoronoiEdgeInt* next_edge;
+ CvVoronoiEdgeInt* prev_edge;
+ CvVoronoiEdgeInt* twin_edge;
+ CvVoronoiParabolaInt* parabola;
+ CvDirection* direction;
+};
+
+struct CvVoronoiParabolaInt
+{
+ float map[6];
+ float a;
+ CvVoronoiNodeInt* focus;
+ CvVoronoiSiteInt* directrice;
+};
+
+struct CvVoronoiChainInt
+{
+ CvVoronoiSiteInt * first_site;
+ CvVoronoiSiteInt * last_site;
+ CvVoronoiChainInt* next_chain;
+};
+
+struct CvVoronoiHoleInt
+{
+ CvSeq* SiteSeq;
+ CvSeq* ChainSeq;
+ CvVoronoiSiteInt* site_top;
+ CvVoronoiSiteInt* site_nearest;
+ CvVoronoiSiteInt* site_opposite;
+ CvVoronoiNodeInt* node;
+ CvVoronoiHoleInt* next_hole;
+ bool error;
+ float x_coord;
+};
+
+typedef CvVoronoiSiteInt* pCvVoronoiSite;
+typedef CvVoronoiEdgeInt* pCvVoronoiEdge;
+typedef CvVoronoiNodeInt* pCvVoronoiNode;
+typedef CvVoronoiParabolaInt* pCvVoronoiParabola;
+typedef CvVoronoiChainInt* pCvVoronoiChain;
+typedef CvVoronoiHoleInt* pCvVoronoiHole;
+typedef CvPointFloat* pCvPointFloat;
+typedef CvDirection* pCvDirection;
+
+/****************************************************************************************\
+* Function definitions *
+\****************************************************************************************/
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvLee
+// Purpose: Compute Voronoi Diagram for one given polygon with holes
+// Context:
+// Parameters:
+// ContourSeq : in, vertices of polygon.
+// VoronoiDiagramInt : in&out, pointer to struct, which contains the
+// description of Voronoi Diagram.
+// VoronoiStorage: in, storage for Voronoi Diagram.
+// contour_type: in, type of vertices.
+// The possible values are CV_LEE_INT,CV_LEE_FLOAT,CV_LEE_DOUBLE.
+// contour_orientation: in, orientation of polygons.
+// = 1, if contour is left - oriented in left coordinat system
+// =-1, if contour is left - oriented in right coordinat system
+// attempt_number: in, number of unsuccessful attemts made by program to compute
+// the Voronoi Diagram befor return the error
+//
+// Returns: 1, if Voronoi Diagram was succesfully computed
+// 0, if some error occures
+//F*/
+static int _cvLee(CvSeq* ContourSeq,
+ CvVoronoiDiagramInt* pVoronoiDiagramInt,
+ CvMemStorage* VoronoiStorage,
+ CvLeeParameters contour_type,
+ int contour_orientation,
+ int attempt_number);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvConstuctSites
+// Purpose : Compute sites for given polygon with holes
+// (site is an edge of polygon or a reflex vertex).
+// Context:
+// Parameters:
+// ContourSeq : in, vertices of polygon
+// pVoronoiDiagram : in, pointer to struct, which contains the
+// description of Voronoi Diagram
+// contour_type: in, type of vertices. The possible values are
+// CV_LEE_INT,CV_LEE_FLOAT,CV_LEE_DOUBLE.
+// contour_orientation: in, orientation of polygons.
+// = 1, if contour is left - oriented in left coordinat system
+// =-1, if contour is left - oriented in right coordinat system
+// Return: 1, if sites were succesfully constructed
+// 0, if some error occures
+//F*/
+static int _cvConstuctSites(CvSeq* ContourSeq,
+ CvVoronoiDiagramInt* pVoronoiDiagram,
+ CvLeeParameters contour_type,
+ int contour_orientation);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvConstructChains
+// Purpose : Compute chains for given polygon with holes.
+// Context:
+// Parameters:
+// pVoronoiDiagram : in, pointer to struct, which contains the
+// description of Voronoi Diagram
+// Return: 1, if chains were succesfully constructed
+// 0, if some error occures
+//F*/
+static int _cvConstructChains(CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvConstructSkeleton
+// Purpose: Compute skeleton for given collection of sites, using Lee algorithm
+// Context:
+// Parameters:
+// VoronoiDiagram : in, pointer to struct, which contains the
+// description of Voronoi Diagram.
+// Returns: 1, if skeleton was succesfully computed
+// 0, if some error occures
+//F*/
+static int _cvConstructSkeleton(CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvConstructSiteTree
+// Purpose: Construct tree of sites (by analogy with contour tree).
+// Context:
+// Parameters:
+// VoronoiDiagram : in, pointer to struct, which contains the
+// description of Voronoi Diagram.
+// Returns:
+//F*/
+static void _cvConstructSiteTree(CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvReleaseVoronoiStorage
+// Purpose : Function realease storages.
+// The storages are divided into two groups:
+// SiteStorage, EdgeStorage, NodeStorage form the first group;
+// ChainStorage,ParabolaStorage,DirectionStorage,HoleStorage form the second group.
+// Context:
+// Parameters:
+// pVoronoiStorage: in,
+// group1,group2: in, if group1<>0 then storages from first group released
+// if group2<>0 then storages from second group released
+// Return :
+//F*/
+static void _cvReleaseVoronoiStorage(CvVoronoiStorageInt* pVoronoiStorage, int group1, int group2);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvConvert
+// Purpose : Function convert internal representation of VD (via
+// structs CvVoronoiSiteInt, CvVoronoiEdgeInt,CvVoronoiNodeInt) into
+// external representation of VD (via structs CvVoronoiSite2D, CvVoronoiEdge2D,
+// CvVoronoiNode2D)
+// Context:
+// Parameters:
+// VoronoiDiagram: in
+// VoronoiStorage: in
+// change_orientation: in, if = -1 then the convertion is accompanied with change
+// of orientation
+//
+// Return: 1, if convertion was succesfully completed
+// 0, if some error occures
+//F*/
+/*
+static int _cvConvert(CvVoronoiDiagram2D* VoronoiDiagram,
+ CvMemStorage* VoronoiStorage,
+ int change_orientation);
+*/
+static int _cvConvert(CvVoronoiDiagram2D* VoronoiDiagram,
+ CvVoronoiDiagramInt VoronoiDiagramInt,
+ CvSet* &NewSiteSeqPrev,
+ CvSeqWriter &NodeWriter,
+ CvSeqWriter &EdgeWriter,
+ CvMemStorage* VoronoiStorage,
+ int change_orientation);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvConvertSameOrientation
+// Purpose : Function convert internal representation of VD (via
+// structs CvVoronoiSiteInt, CvVoronoiEdgeInt,CvVoronoiNodeInt) into
+// external representation of VD (via structs CvVoronoiSite2D, CvVoronoiEdge2D,
+// CvVoronoiNode2D) without change of orientation
+// Context:
+// Parameters:
+// VoronoiDiagram: in
+// VoronoiStorage: in
+/
+// Return: 1, if convertion was succesfully completed
+// 0, if some error occures
+//F*/
+/*
+static int _cvConvertSameOrientation(CvVoronoiDiagram2D* VoronoiDiagram,
+ CvMemStorage* VoronoiStorage);
+*/
+static int _cvConvertSameOrientation(CvVoronoiDiagram2D* VoronoiDiagram,
+ CvVoronoiDiagramInt VoronoiDiagramInt,
+ CvSet* &NewSiteSeqPrev,
+ CvSeqWriter &NodeWriter,
+ CvSeqWriter &EdgeWriter,
+ CvMemStorage* VoronoiStorage);
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Author: Andrey Sobolev
+// Name: _cvConvertChangeOrientation
+// Purpose : Function convert internal representation of VD (via
+// structs CvVoronoiSiteInt, CvVoronoiEdgeInt,CvVoronoiNodeInt) into
+// external representation of VD (via structs CvVoronoiSite2D, CvVoronoiEdge2D,
+// CvVoronoiNode2D) with change of orientation
+// Context:
+// Parameters:
+// VoronoiDiagram: in
+// VoronoiStorage: in
+/
+// Return: 1, if convertion was succesfully completed
+// 0, if some error occures
+//F*/
+/*
+static int _cvConvertChangeOrientation(CvVoronoiDiagram2D* VoronoiDiagram,
+ CvMemStorage* VoronoiStorage);
+ */
+static int _cvConvertChangeOrientation(CvVoronoiDiagram2D* VoronoiDiagram,
+ CvVoronoiDiagramInt VoronoiDiagramInt,
+ CvSet* &NewSiteSeqPrev,
+ CvSeqWriter &NodeWriter,
+ CvSeqWriter &EdgeWriter,
+ CvMemStorage* VoronoiStorage);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Compute sites for external polygon.
+ Arguments
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ ContourSeq : in, vertices of polygon
+ pReflexSite: out, pointer to reflex site,if any exist,else NULL
+ orientation: in, orientation of contour ( = 1 or = -1)
+ type: in, type of vertices. The possible values are (int)1,
+ (float)1,(double)1.
+ Return: 1, if sites were succesfully constructed
+ 0, if some error occures :
+ --------------------------------------------------------------------------*/
+template<class T>
+int _cvConstructExtSites(CvVoronoiDiagramInt* pVoronoiDiagram,
+ CvSeq* ContourSeq,
+ int orientation,
+ T /*type*/);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Compute sites for internal polygon (for hole).
+ Arguments
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ CurrSiteSeq: in, the sequence for sites to be constructed
+ CurrContourSeq : in, vertices of polygon
+ pTopSite: out, pointer to the most left site of polygon (it is the most left
+ vertex of polygon)
+ orientation: in, orientation of contour ( = 1 or = -1)
+ type: in, type of vertices. The possible values are (int)1,
+ (float)1,(double)1.
+ Return: 1, if sites were succesfully constructed
+ 0, if some error occures :
+ --------------------------------------------------------------------------*/
+template<class T>
+int _cvConstructIntSites(CvVoronoiDiagramInt* pVoronoiDiagram,
+ CvSeq* CurrSiteSeq,
+ CvSeq* CurrContourSeq,
+ pCvVoronoiSite &pTopSite,
+ int orientation,
+ T /*type*/);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Compute the simple chains of sites for external polygon.
+ Arguments
+ pVoronoiDiagram : in&out, pointer to struct, which contains the
+ description of Voronoi Diagram
+
+ Return: 1, if chains were succesfully constructed
+ 0, if some error occures
+ --------------------------------------------------------------------------*/
+static int _cvConstructExtChains(CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Compute the simple chains of sites for internal polygon (= hole)
+ Arguments
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ CurrSiteSeq : in, the sequence of sites
+ CurrChainSeq : in,the sequence for chains to be constructed
+ pTopSite : in, the most left site of hole
+
+ Return :
+ --------------------------------------------------------------------------*/
+static void _cvConstructIntChains(CvVoronoiDiagramInt* pVoronoiDiagram,
+ CvSeq* CurrChainSeq,
+ CvSeq* CurrSiteSeq,
+ pCvVoronoiSite pTopSite);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Compute the initial Voronoi Diagram for single site
+ Arguments
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ pSite: in, pointer to site
+
+ Return :
+ --------------------------------------------------------------------------*/
+static void _cvConstructEdges(pCvVoronoiSite pSite,CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function moves each node on small random value. The nodes are taken
+ from pVoronoiDiagram->NodeSeq.
+ Arguments
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ begin,end: in, the first and the last nodes in pVoronoiDiagram->NodeSeq,
+ which moves
+ shift: in, the value of maximal shift.
+ Return :
+ --------------------------------------------------------------------------*/
+static void _cvRandomModification(CvVoronoiDiagramInt* pVoronoiDiagram, int begin, int end, float shift);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Compute the internal Voronoi Diagram for external polygon.
+ Arguments
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ Return : 1, if VD was constructed succesfully
+ 0, if some error occure
+ --------------------------------------------------------------------------*/
+static int _cvConstructExtVD(CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Compute the external Voronoi Diagram for each internal polygon (hole).
+ Arguments
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ Return :
+ --------------------------------------------------------------------------*/
+static void _cvConstructIntVD(CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function joins the Voronoi Diagrams of different
+ chains into one Voronoi Diagram
+ Arguments
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ pChain1,pChain1: in, given chains
+ Return : 1, if joining was succesful
+ 0, if some error occure
+ --------------------------------------------------------------------------*/
+static int _cvJoinChains(pCvVoronoiChain pChain1,
+ pCvVoronoiChain pChain2,
+ CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function finds the nearest site for top vertex
+ (= the most left vertex) of each hole
+ Arguments
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ Return :
+ --------------------------------------------------------------------------*/
+static void _cvFindNearestSite(CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function seeks for site, which has common bisector in
+ final VD with top vertex of given hole. It stores in pHole->opposite_site.
+ The search begins from Hole->nearest_site and realizes in clockwise
+ direction around the top vertex of given hole.
+ Arguments
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ pHole : in, given hole
+ Return : 1, if the search was succesful
+ 0, if some error occure
+ --------------------------------------------------------------------------*/
+static int _cvFindOppositSiteCW(pCvVoronoiHole pHole, CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function seeks for site, which has common bisector in
+ final VD with top vertex of given hole. It stores in pHole->opposite_site.
+ The search begins from Hole->nearest_site and realizes in counterclockwise
+ direction around the top vertex of given hole.
+ Arguments
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ pHole : in, given hole
+ Return : 1, if the search was succesful
+ 0, if some error occure
+ --------------------------------------------------------------------------*/
+static int _cvFindOppositSiteCCW(pCvVoronoiHole pHole,CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function merges external VD of hole and internal VD, which was
+ constructed ealier.
+ Arguments
+pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ pHole : in, given hole
+ Return : 1, if merging was succesful
+ 0, if some error occure
+ --------------------------------------------------------------------------*/
+static int _cvMergeVD(pCvVoronoiHole pHole,CvVoronoiDiagramInt* pVoronoiDiagram);
+
+
+/* ///////////////////////////////////////////////////////////////////////////////////////
+// Computation of bisectors //
+/////////////////////////////////////////////////////////////////////////////////////// */
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Compute the bisector of two sites
+ Arguments
+ pSite_left,pSite_right: in, given sites
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ pEdge : out, bisector
+ Return :
+ --------------------------------------------------------------------------*/
+void _cvCalcEdge(pCvVoronoiSite pSite_left,
+ pCvVoronoiSite pSite_right,
+ pCvVoronoiEdge pEdge,
+ CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Compute the bisector of point and site
+ Arguments
+ pSite : in, site
+ pNode : in, point
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ pEdge : out, bisector
+ Return :
+ --------------------------------------------------------------------------*/
+void _cvCalcEdge(pCvVoronoiSite pSite,
+ pCvVoronoiNode pNode,
+ pCvVoronoiEdge pEdge,
+ CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Compute the bisector of point and site
+ Arguments
+ pSite : in, site
+ pNode : in, point
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ pEdge : out, bisector
+ Return :
+ --------------------------------------------------------------------------*/
+void _cvCalcEdge(pCvVoronoiNode pNode,
+ pCvVoronoiSite pSite,
+ pCvVoronoiEdge pEdge,
+ CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Compute the direction of bisector of two segments
+ Arguments
+ pDirection1: in, direction of first segment
+ pDirection2: in, direction of second segment
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ pEdge : out, bisector
+ Return :
+ --------------------------------------------------------------------------*/
+CV_INLINE
+void _cvCalcEdgeLL(pCvDirection pDirection1,
+ pCvDirection pDirection2,
+ pCvVoronoiEdge pEdge,
+ CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Compute the bisector of two points
+ Arguments
+ pPoint1, pPoint2: in, given points
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ pEdge : out, bisector
+ Return :
+ --------------------------------------------------------------------------*/
+CV_INLINE
+void _cvCalcEdgePP(pCvPointFloat pPoint1,
+ pCvPointFloat pPoint2,
+ pCvVoronoiEdge pEdge,
+ CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Compute the bisector of segment and point. Since
+ it is parabola, it is defined by its focus (site - point)
+ and directrice(site-segment)
+ Arguments
+ pFocus : in, point, which defines the focus of parabola
+ pDirectrice: in, site - segment, which defines the directrice of parabola
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ pEdge : out, bisector
+ Return :
+ --------------------------------------------------------------------------*/
+CV_INLINE
+void _cvCalcEdgePL(pCvVoronoiNode pFocus,
+ pCvVoronoiSite pDirectrice,
+ pCvVoronoiEdge pEdge,
+ CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Compute the bisector of segment and point. Since
+ it is parabola, it is defined by its focus (site - point)
+ and directrice(site-segment)
+ Arguments
+ pFocus : in, point, which defines the focus of parabola
+ pDirectrice: in, site - segment, which defines the directrice of parabola
+ pVoronoiDiagram : in, pointer to struct, which contains the
+ description of Voronoi Diagram
+ pEdge : out, bisector
+ Return :
+ --------------------------------------------------------------------------*/
+CV_INLINE
+void _cvCalcEdgeLP(pCvVoronoiSite pDirectrice,
+ pCvVoronoiNode pFocus,
+ pCvVoronoiEdge pEdge,
+ CvVoronoiDiagramInt* pVoronoiDiagram);
+
+/* ///////////////////////////////////////////////////////////////////////////////////////
+// Computation of intersections of bisectors //
+/////////////////////////////////////////////////////////////////////////////////////// */
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes intersection of two edges. Intersection
+ must be the nearest to the marked point on pEdge1
+ (this marked point is pEdge1->node1->node).
+ Arguments
+ pEdge1,pEdge2: in, two edges
+ pPoint: out, intersection of pEdge1 and pEdge2
+ Radius: out, distance between pPoint and sites, assosiated
+ with pEdge1 and pEdge2 (pPoint is situated on the equal
+ distance from site, assosiated with pEdge1 and from
+ site,assosiated with pEdge2)
+ Return : distance between pPoint and marked point on pEdge1 or
+ : -1, if edges have no intersections
+ --------------------------------------------------------------------------*/
+static
+float _cvCalcEdgeIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ CvPointFloat* pPoint,
+ float &Radius);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes intersection of two edges. Intersection
+ must be the nearest to the marked point on pEdge1
+ (this marked point is pEdge1->node1->node).
+ Arguments
+ pEdge1 : in, straight ray
+ pEdge2: in, straight ray or segment
+ pPoint: out, intersection of pEdge1 and pEdge2
+ Radius: out, distance between pPoint and sites, assosiated
+ with pEdge1 and pEdge2 (pPoint is situated on the equal
+ distance from site, assosiated with pEdge1 and from
+ site,assosiated with pEdge2)
+ Return : distance between pPoint and marked point on pEdge1 or
+ : -1, if edges have no intersections
+ --------------------------------------------------------------------------*/
+static
+float _cvLine_LineIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes intersection of two edges. Intersection
+ must be the nearest to the marked point on pEdge1
+ (this marked point is pEdge1->node1->node).
+ Arguments
+ pEdge1 : in, straight ray
+ pEdge2: in, parabolic ray or segment
+ pPoint: out, intersection of pEdge1 and pEdge2
+ Radius: out, distance between pPoint and sites, assosiated
+ with pEdge1 and pEdge2 (pPoint is situated on the equal
+ distance from site, assosiated with pEdge1 and from
+ site,assosiated with pEdge2)
+ Return : distance between pPoint and marked point on pEdge1 or
+ : -1, if edges have no intersections
+ --------------------------------------------------------------------------*/
+static
+float _cvLine_ParIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes intersection of two edges. Intersection
+ must be the nearest to the marked point on pEdge1
+ (this marked point is pEdge1->node1->node).
+ Arguments
+ pEdge1 : in, straight ray
+ pEdge2: in, parabolic segment
+ pPoint: out, intersection of pEdge1 and pEdge2
+ Radius: out, distance between pPoint and sites, assosiated
+ with pEdge1 and pEdge2 (pPoint is situated on the equal
+ distance from site, assosiated with pEdge1 and from
+ site,assosiated with pEdge2)
+ Return : distance between pPoint and marked point on pEdge1 or
+ : -1, if edges have no intersections
+ --------------------------------------------------------------------------*/
+static
+float _cvLine_CloseParIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes intersection of two edges. Intersection
+ must be the nearest to the marked point on pEdge1
+ (this marked point is pEdge1->node1->node).
+ Arguments
+ pEdge1 : in, straight ray
+ pEdge2: in, parabolic ray
+ pPoint: out, intersection of pEdge1 and pEdge2
+ Radius: out, distance between pPoint and sites, assosiated
+ with pEdge1 and pEdge2 (pPoint is situated on the equal
+ distance from site, assosiated with pEdge1 and from
+ site,assosiated with pEdge2)
+ Return : distance between pPoint and marked point on pEdge1 or
+ : -1, if edges have no intersections
+ --------------------------------------------------------------------------*/
+static
+float _cvLine_OpenParIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes intersection of two edges. Intersection
+ must be the nearest to the marked point on pEdge1
+ (this marked point is pEdge1->node1->node).
+ Arguments
+ pEdge1 : in, parabolic ray
+ pEdge2: in, straight ray or segment
+ pPoint: out, intersection of pEdge1 and pEdge2
+ Radius: out, distance between pPoint and sites, assosiated
+ with pEdge1 and pEdge2 (pPoint is situated on the equal
+ distance from site, assosiated with pEdge1 and from
+ site,assosiated with pEdge2)
+ Return : distance between pPoint and marked point on pEdge1 or
+ : -1, if edges have no intersections
+ --------------------------------------------------------------------------*/
+static
+float _cvPar_LineIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius);
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes intersection of two edges. Intersection
+ must be the nearest to the marked point on pEdge1
+ (this marked point is pEdge1->node1->node).
+ Arguments
+ pEdge1 : in, parabolic ray
+ pEdge2: in, straight ray
+ pPoint: out, intersection of pEdge1 and pEdge2
+ Radius: out, distance between pPoint and sites, assosiated
+ with pEdge1 and pEdge2 (pPoint is situated on the equal
+ distance from site, assosiated with pEdge1 and from
+ site,assosiated with pEdge2)
+ Return : distance between pPoint and marked point on pEdge1 or
+ : -1, if edges have no intersections
+ --------------------------------------------------------------------------*/
+static
+float _cvPar_OpenLineIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes intersection of two edges. Intersection
+ must be the nearest to the marked point on pEdge1
+ (this marked point is pEdge1->node1->node).
+ Arguments
+ pEdge1 : in, parabolic ray
+ pEdge2: in, straight segment
+ pPoint: out, intersection of pEdge1 and pEdge2
+ Radius: out, distance between pPoint and sites, assosiated
+ with pEdge1 and pEdge2 (pPoint is situated on the equal
+ distance from site, assosiated with pEdge1 and from
+ site,assosiated with pEdge2)
+ Return : distance between pPoint and marked point on pEdge1 or
+ : -1, if edges have no intersections
+ --------------------------------------------------------------------------*/
+static
+float _cvPar_CloseLineIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes intersection of two edges. Intersection
+ must be the nearest to the marked point on pEdge1
+ (this marked point is pEdge1->node1->node).
+ Arguments
+ pEdge1 : in, parabolic ray
+ pEdge2: in, parabolic ray or segment
+ pPoint: out, intersection of pEdge1 and pEdge2
+ Radius: out, distance between pPoint and sites, assosiated
+ with pEdge1 and pEdge2 (pPoint is situated on the equal
+ distance from site, assosiated with pEdge1 and from
+ site,assosiated with pEdge2)
+ Return : distance between pPoint and marked point on pEdge1 or
+ : -1, if edges have no intersections
+ --------------------------------------------------------------------------*/
+static
+float _cvPar_ParIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius);
+
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes intersection of two edges. Intersection
+ must be the nearest to the marked point on pEdge1
+ (this marked point is pEdge1->node1->node).
+ Arguments
+ pEdge1 : in, parabolic ray
+ pEdge2: in, parabolic ray
+ pPoint: out, intersection of pEdge1 and pEdge2
+ Radius: out, distance between pPoint and sites, assosiated
+ with pEdge1 and pEdge2 (pPoint is situated on the equal
+ distance from site, assosiated with pEdge1 and from
+ site,assosiated with pEdge2)
+ Return : distance between pPoint and marked point on pEdge1 or
+ : -1, if edges have no intersections
+ --------------------------------------------------------------------------*/
+static
+float _cvPar_OpenParIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes intersection of two edges. Intersection
+ must be the nearest to the marked point on pEdge1
+ (this marked point is pEdge1->node1->node).
+ Arguments
+ pEdge1 : in, parabolic ray
+ pEdge2: in, parabolic segment
+ pPoint: out, intersection of pEdge1 and pEdge2
+ Radius: out, distance between pPoint and sites, assosiated
+ with pEdge1 and pEdge2 (pPoint is situated on the equal
+ distance from site, assosiated with pEdge1 and from
+ site,assosiated with pEdge2)
+ Return : distance between pPoint and marked point on pEdge1 or
+ : -1, if edges have no intersections
+ --------------------------------------------------------------------------*/
+static
+float _cvPar_CloseParIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius);
+
+/* ///////////////////////////////////////////////////////////////////////////////////////
+// Subsidiary functions //
+/////////////////////////////////////////////////////////////////////////////////////// */
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description :
+ Arguments
+ pEdge1 : in
+ pEdge2 : out
+ Return :
+ --------------------------------------------------------------------------*/
+CV_INLINE
+void _cvMakeTwinEdge(pCvVoronoiEdge pEdge2,
+ pCvVoronoiEdge pEdge1);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description :
+ Arguments
+ pEdge : in&out
+ pEdge_left_prev : in&out
+ pSite_left : in&out
+ Return :
+ --------------------------------------------------------------------------*/
+CV_INLINE
+void _cvStickEdgeLeftBegin(pCvVoronoiEdge pEdge,
+ pCvVoronoiEdge pEdge_left_prev,
+ pCvVoronoiSite pSite_left);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description :
+ Arguments
+ pEdge : in&out
+ pEdge_right_next : in&out
+ pSite_right : in&out
+ Return :
+ --------------------------------------------------------------------------*/
+CV_INLINE
+void _cvStickEdgeRightBegin(pCvVoronoiEdge pEdge,
+ pCvVoronoiEdge pEdge_right_next,
+ pCvVoronoiSite pSite_right);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description :
+ Arguments
+ pEdge : in&out
+ pEdge_left_next : in&out
+ pSite_left : in&out
+ Return :
+ --------------------------------------------------------------------------*/
+CV_INLINE
+void _cvStickEdgeLeftEnd(pCvVoronoiEdge pEdge,
+ pCvVoronoiEdge pEdge_left_next,
+ pCvVoronoiSite pSite_left);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description :
+ Arguments
+ pEdge : in&out
+ pEdge_right_prev : in&out
+ pSite_right : in&out
+ Return :
+ --------------------------------------------------------------------------*/
+CV_INLINE
+void _cvStickEdgeRightEnd(pCvVoronoiEdge pEdge,
+ pCvVoronoiEdge pEdge_right_prev,
+ pCvVoronoiSite pSite_right);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description :
+ Arguments
+ pEdge_left_cur : in
+ pEdge_left : in
+ Return :
+ --------------------------------------------------------------------------*/
+CV_INLINE
+void _cvTwinNULLLeft(pCvVoronoiEdge pEdge_left_cur,
+ pCvVoronoiEdge pEdge_left);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description :
+ Arguments
+ pEdge_right_cur : in
+ pEdge_right : in
+ Return :
+ --------------------------------------------------------------------------*/
+CV_INLINE
+void _cvTwinNULLRight(pCvVoronoiEdge pEdge_right_cur,
+ pCvVoronoiEdge pEdge_right);
+
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : function initializes the struct CvVoronoiNode
+ Arguments
+ pNode : out
+ pPoint : in,
+ radius : in
+ Return :
+ --------------------------------------------------------------------------*/
+template <class T> CV_INLINE
+void _cvInitVoronoiNode(pCvVoronoiNode pNode,
+ T pPoint, float radius = 0);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : function initializes the struct CvVoronoiSite
+ Arguments
+ pSite : out
+ pNode1,pNode2,pPrev_site : in
+ Return :
+ --------------------------------------------------------------------------*/
+CV_INLINE
+void _cvInitVoronoiSite(pCvVoronoiSite pSite,
+ pCvVoronoiNode pNode1,
+ pCvVoronoiNode pNode2,
+ pCvVoronoiSite pPrev_site);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : function pushs the element in the end of the sequence
+ end returns its adress
+ Arguments
+ Seq : in, pointer to the sequence
+ Elem : in, element
+ Return : pointer to the element in the sequence
+ --------------------------------------------------------------------------*/
+template <class T> CV_INLINE
+T _cvSeqPush(CvSeq* Seq, T pElem);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : function pushs the element in the begin of the sequence
+ end returns its adress
+ Arguments
+ Seq : in, pointer to the sequence
+ Elem : in, element
+ Return : pointer to the element in the sequence
+ --------------------------------------------------------------------------*/
+template <class T> CV_INLINE
+T _cvSeqPushFront(CvSeq* Seq, T pElem);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : function pushs the element pHole in pHoleHierarchy->HoleSeq
+ so as all elements in this sequence would be normalized
+ according to field .x_coord of element. pHoleHierarchy->TopHole
+ points to hole with smallest x_coord.
+ Arguments
+pHoleHierarchy : in, pointer to the structur
+ pHole : in, element
+ Return : pointer to the element in the sequence
+ --------------------------------------------------------------------------*/
+CV_INLINE
+void _cvSeqPushInOrder(CvVoronoiDiagramInt* pVoronoiDiagram, pCvVoronoiHole pHole);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : function intersects given edge pEdge (and his twin edge)
+ by point pNode on two parts
+ Arguments
+ pEdge : in, given edge
+ pNode : in, given point
+ EdgeSeq : in
+ Return : one of parts
+ --------------------------------------------------------------------------*/
+CV_INLINE
+pCvVoronoiEdge _cvDivideRightEdge(pCvVoronoiEdge pEdge,
+ pCvVoronoiNode pNode,
+ CvSeq* EdgeSeq);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : function intersects given edge pEdge (and his twin edge)
+ by point pNode on two parts
+ Arguments
+ pEdge : in, given edge
+ pNode : in, given point
+ EdgeSeq : in
+ Return : one of parts
+ --------------------------------------------------------------------------*/
+CV_INLINE
+pCvVoronoiEdge _cvDivideLeftEdge(pCvVoronoiEdge pEdge,
+ pCvVoronoiNode pNode,
+ CvSeq* EdgeSeq);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : function pushs the element in the end of the sequence
+ end returns its adress
+ Arguments
+ writer: in, writer associated with sequence
+ pElem : in, element
+ Return : pointer to the element in the sequence
+ --------------------------------------------------------------------------*/
+template<class T> CV_INLINE
+T _cvWriteSeqElem(T pElem, CvSeqWriter &writer);
+
+/* ///////////////////////////////////////////////////////////////////////////////////////
+// Mathematical functions //
+/////////////////////////////////////////////////////////////////////////////////////// */
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function changes x and y
+ Arguments
+ x,y : in&out
+ Return :
+ --------------------------------------------------------------------------*/
+template <class T> CV_INLINE
+void _cvSwap(T &x, T &y);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes the inverse map to the
+ given ortogonal affine map
+ Arguments
+ A : in, given ortogonal affine map
+ B : out, inverse map
+ Return : 1, if inverse map exist
+ 0, else
+ --------------------------------------------------------------------------*/
+template <class T> CV_INLINE
+int _cvCalcOrtogInverse(T* B, T* A);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes the composition of two affine maps
+ Arguments
+ A,B : in, given affine maps
+ Result: out, composition of A and B (Result = AB)
+ Return :
+ --------------------------------------------------------------------------*/
+template <class T> CV_INLINE
+void _cvCalcComposition(T* Result,T* A,T* B);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes the image of point under
+ given affin map
+ Arguments
+ A : in, affine maps
+ pPoint : in, pointer to point
+ pImgPoint:out, pointer to image of point
+ Return :
+ --------------------------------------------------------------------------*/
+template<class T> CV_INLINE
+void _cvCalcPointImage(pCvPointFloat pImgPoint,pCvPointFloat pPoint,T* A);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes the image of vector under
+ given affin map
+ Arguments
+ A : in, affine maps
+ pVector : in, pointer to vector
+ pImgVector:out, pointer to image of vector
+ Return :
+ --------------------------------------------------------------------------*/
+template<class T> CV_INLINE
+void _cvCalcVectorImage(pCvDirection pImgVector,pCvDirection pVector,T* A);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes the distance between the point
+ and site. Internal function.
+ Arguments
+ pPoint : in, point
+ pSite : in, site
+ Return : distance
+ --------------------------------------------------------------------------*/
+CV_INLINE
+float _cvCalcDist(pCvPointFloat pPoint, pCvVoronoiSite pSite);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes the distance between two points
+ Arguments
+ pPoint1,pPoint2 : in, two points
+ Return : distance
+ --------------------------------------------------------------------------*/
+CV_INLINE
+float _cvPPDist(pCvPointFloat pPoint1,pCvPointFloat pPoint2);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function computes the distance betwin point and
+ segment. Internal function.
+ Arguments
+ pPoint: in, point
+ pPoint1,pPoint2 : in, segment [pPoint1,pPoint2]
+ Return : distance
+ --------------------------------------------------------------------------*/
+CV_INLINE
+float _cvPLDist(pCvPointFloat pPoint,pCvPointFloat pPoint1,pCvDirection pDirection);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function solves the squar equation with real coefficients
+ T - float or double
+ Arguments
+ c2,c1,c0: in, real coefficients of polynom
+ X: out, array of roots
+ Return : number of roots
+ --------------------------------------------------------------------------*/
+template <class T>
+int _cvSolveEqu2thR(T c2, T c1, T c0, T* X);
+
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : Function solves the linear equation with real or complex coefficients
+ T - float or double or complex
+ Arguments
+ c1,c0: in, real or complex coefficients of polynom
+ X: out, array of roots
+ Return : number of roots
+ --------------------------------------------------------------------------*/
+template <class T> CV_INLINE
+int _cvSolveEqu1th(T c1, T c0, T* X);
+
+/****************************************************************************************\
+* Storage Block Increase *
+\****************************************************************************************/
+/*--------------------------------------------------------------------------
+ Author : Andrey Sobolev
+ Description : For each sequence function creates the memory block sufficient to store
+ all elements of sequnce
+ Arguments
+ pVoronoiDiagramInt: in, pointer to struct, which contains the
+ description of Voronoi Diagram.
+ vertices_number: in, number of vertices in polygon
+ Return :
+ --------------------------------------------------------------------------*/
+void _cvSetSeqBlockSize(CvVoronoiDiagramInt* pVoronoiDiagramInt,int vertices_number)
+{
+ int N = 2*vertices_number;
+ cvSetSeqBlockSize(pVoronoiDiagramInt->SiteSeq,N*pVoronoiDiagramInt->SiteSeq->elem_size);
+ cvSetSeqBlockSize(pVoronoiDiagramInt->EdgeSeq,3*N*pVoronoiDiagramInt->EdgeSeq->elem_size);
+ cvSetSeqBlockSize(pVoronoiDiagramInt->NodeSeq,5*N*pVoronoiDiagramInt->NodeSeq->elem_size);
+ cvSetSeqBlockSize(pVoronoiDiagramInt->ParabolaSeq,N*pVoronoiDiagramInt->ParabolaSeq->elem_size);
+ cvSetSeqBlockSize(pVoronoiDiagramInt->DirectionSeq,3*N*pVoronoiDiagramInt->DirectionSeq->elem_size);
+ cvSetSeqBlockSize(pVoronoiDiagramInt->ChainSeq,N*pVoronoiDiagramInt->DirectionSeq->elem_size);
+ cvSetSeqBlockSize(pVoronoiDiagramInt->HoleSeq,100*pVoronoiDiagramInt->HoleSeq->elem_size);
+}
+
+/****************************************************************************************\
+* Function realization *
+\****************************************************************************************/
+
+
+CV_IMPL int cvVoronoiDiagramFromContour(CvSeq* ContourSeq,
+ CvVoronoiDiagram2D** VoronoiDiagram,
+ CvMemStorage* VoronoiStorage,
+ CvLeeParameters contour_type,
+ int contour_orientation,
+ int attempt_number)
+{
+ CV_FUNCNAME( "cvVoronoiDiagramFromContour" );
+
+ __BEGIN__;
+
+ CvSet* SiteSeq = NULL;
+ CvSeq* CurContourSeq = NULL;
+ CvVoronoiDiagramInt VoronoiDiagramInt;
+ CvSeqWriter NodeWriter, EdgeWriter;
+ CvMemStorage* storage;
+
+ memset( &VoronoiDiagramInt, 0, sizeof(VoronoiDiagramInt) );
+
+ if( !ContourSeq )
+ CV_ERROR( CV_StsBadArg,"Contour sequence is empty" );
+
+ if(!VoronoiStorage)
+ CV_ERROR( CV_StsBadArg,"Storage is not initialized" );
+
+ if( contour_type < 0 || contour_type > 2)
+ CV_ERROR( CV_StsBadArg,"Unsupported parameter: type" );
+
+ if( contour_orientation != 1 && contour_orientation != -1)
+ CV_ERROR( CV_StsBadArg,"Unsupported parameter: orientation" );
+
+ storage = cvCreateChildMemStorage(VoronoiStorage);
+ (*VoronoiDiagram) = (CvVoronoiDiagram2D*)cvCreateSet(0,sizeof(CvVoronoiDiagram2D),sizeof(CvVoronoiNode2D), storage);
+ storage = cvCreateChildMemStorage(VoronoiStorage);
+ (*VoronoiDiagram)->edges = cvCreateSet(0,sizeof(CvSet),sizeof(CvVoronoiEdge2D), storage);
+ cvStartAppendToSeq((CvSeq*)(*VoronoiDiagram)->edges, &EdgeWriter);
+ cvStartAppendToSeq((CvSeq*)(*VoronoiDiagram), &NodeWriter);
+
+ for(CurContourSeq = ContourSeq;\
+ CurContourSeq != NULL;\
+ CurContourSeq = CurContourSeq->h_next)
+ {
+ if(_cvLee(CurContourSeq, &VoronoiDiagramInt,VoronoiStorage,contour_type,contour_orientation,attempt_number))
+
+ {
+ if(!_cvConvert(*VoronoiDiagram,VoronoiDiagramInt,SiteSeq,NodeWriter,EdgeWriter,VoronoiStorage,contour_orientation))
+ goto exit;
+ }
+ else if(CurContourSeq->total >= 3)
+ goto exit;
+ }
+
+ cvEndWriteSeq(&EdgeWriter);
+ cvEndWriteSeq(&NodeWriter);
+ if(SiteSeq != NULL)
+ return 1;
+
+
+ __END__;
+ return 0;
+}//end of cvVoronoiDiagramFromContour
+
+CV_IMPL int cvVoronoiDiagramFromImage(IplImage* pImage,
+ CvSeq** ContourSeq,
+ CvVoronoiDiagram2D** VoronoiDiagram,
+ CvMemStorage* VoronoiStorage,
+ CvLeeParameters regularization_method,
+ float approx_precision)
+{
+ CV_FUNCNAME( "cvVoronoiDiagramFromContour" );
+ int RESULT = 0;
+
+ __BEGIN__;
+
+ IplImage* pWorkImage = NULL;
+ CvSize image_size;
+ int i, multiplicator = 3;
+
+ int approx_method;
+ CvMemStorage* ApproxContourStorage = NULL;
+ CvSeq* ApproxContourSeq = NULL;
+
+ if( !ContourSeq )
+ CV_ERROR( CV_StsBadArg,"Contour sequence is not initialized" );
+
+ if( (*ContourSeq)->total != 0)
+ CV_ERROR( CV_StsBadArg,"Contour sequence is not empty" );
+
+ if(!VoronoiStorage)
+ CV_ERROR( CV_StsBadArg,"Storage is not initialized" );
+
+ if(!pImage)
+ CV_ERROR( CV_StsBadArg,"Image is not initialized" );
+
+ if(pImage->nChannels != 1 || pImage->depth != 8)
+ CV_ERROR( CV_StsBadArg,"Unsupported image format" );
+
+ if(approx_precision<0 && approx_precision != CV_LEE_AUTO)
+ CV_ERROR( CV_StsBadArg,"Unsupported presision value" );
+
+ switch(regularization_method)
+ {
+ case CV_LEE_ERODE: image_size.width = pImage->width;
+ image_size.height = pImage->height;
+ pWorkImage = cvCreateImage(image_size,8,1);
+ cvErode(pImage,pWorkImage,0,1);
+ approx_method = CV_CHAIN_APPROX_TC89_L1;
+ break;
+ case CV_LEE_ZOOM: image_size.width = multiplicator*pImage->width;
+ image_size.height = multiplicator*pImage->height;
+ pWorkImage = cvCreateImage(image_size,8,1);
+ cvResize(pImage, pWorkImage, CV_INTER_NN);
+ approx_method = CV_CHAIN_APPROX_TC89_L1;
+ break;
+ case CV_LEE_NON: pWorkImage = pImage;
+ approx_method = CV_CHAIN_APPROX_TC89_L1;
+ break;
+ default: CV_ERROR( CV_StsBadArg,"Unsupported regularisation method" );
+ break;
+
+ }
+
+ cvFindContours(pWorkImage, (*ContourSeq)->storage, ContourSeq, \
+ sizeof(CvContour), CV_RETR_CCOMP, approx_method );
+
+ if(pWorkImage && pWorkImage != pImage )
+ cvReleaseImage(&pWorkImage);
+
+ ApproxContourStorage = cvCreateMemStorage(0);
+ if(approx_precision > 0)
+ {
+ ApproxContourSeq = cvApproxPoly(*ContourSeq, sizeof(CvContour), ApproxContourStorage,\
+ CV_POLY_APPROX_DP,approx_precision,1);
+
+ RESULT = cvVoronoiDiagramFromContour(ApproxContourSeq,VoronoiDiagram,VoronoiStorage,CV_LEE_INT,-1,10);
+ }
+ else if(approx_precision == CV_LEE_AUTO)
+ {
+ ApproxContourSeq = *ContourSeq;
+ for(i = 1; i < 50; i++)
+ {
+ RESULT = cvVoronoiDiagramFromContour(ApproxContourSeq,VoronoiDiagram,VoronoiStorage,CV_LEE_INT,-1,1);
+ if(RESULT)
+ break;
+ ApproxContourSeq = cvApproxPoly(ApproxContourSeq, sizeof(CvContour),ApproxContourStorage,\
+ CV_POLY_APPROX_DP,(float)i,1);
+ }
+ }
+ else
+ RESULT = cvVoronoiDiagramFromContour(*ContourSeq,VoronoiDiagram,VoronoiStorage,CV_LEE_INT,-1,10);
+/*
+ if(ApproxContourSeq)
+ {
+ cvClearMemStorage( (*ContourSeq)->storage );
+ *ContourSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvPoint),(*ContourSeq)->storage);
+ CvSeqReader reader;
+ CvSeqWriter writer;
+ CvPoint Point;
+ cvStartAppendToSeq(*ContourSeq, &writer);
+ cvStartReadSeq(ApproxContourSeq, &reader);
+ for(int i = 0;i < ApproxContourSeq->total;i++)
+ {
+ CV_READ_SEQ_ELEM(Point,reader);
+ Point.y = 600 - Point.y;
+ CV_WRITE_SEQ_ELEM(Point,writer);
+ }
+ cvEndWriteSeq(&writer);
+ }
+ */
+
+ cvReleaseMemStorage(&ApproxContourStorage);
+
+
+ __END__;
+ return RESULT;
+}//end of cvVoronoiDiagramFromImage
+
+CV_IMPL void cvReleaseVoronoiStorage(CvVoronoiDiagram2D* VoronoiDiagram,
+ CvMemStorage** pVoronoiStorage)
+{
+ /*CV_FUNCNAME( "cvReleaseVoronoiStorage" );*/
+ __BEGIN__;
+
+ CvSeq* Seq;
+
+ if(VoronoiDiagram->storage)
+ cvReleaseMemStorage(&VoronoiDiagram->storage);
+ for(Seq = (CvSeq*)VoronoiDiagram->sites; Seq != NULL; Seq = Seq->h_next)
+ if(Seq->storage)
+ cvReleaseMemStorage(&Seq->storage);
+ for(Seq = (CvSeq*)VoronoiDiagram->edges; Seq != NULL; Seq = Seq->h_next)
+ if(Seq->storage)
+ cvReleaseMemStorage(&Seq->storage);
+
+ if(*pVoronoiStorage)
+ cvReleaseMemStorage(pVoronoiStorage);
+
+ __END__;
+}//end of cvReleaseVoronoiStorage
+
+static int _cvLee(CvSeq* ContourSeq,
+ CvVoronoiDiagramInt* pVoronoiDiagramInt,
+ CvMemStorage* VoronoiStorage,
+ CvLeeParameters contour_type,
+ int contour_orientation,
+ int attempt_number)
+{
+ //orientation = 1 for left coordinat system
+ //orientation = -1 for right coordinat system
+ if(ContourSeq->total<3)
+ return 0;
+
+ int attempt = 0;
+ CvVoronoiStorageInt VoronoiStorageInt;
+
+ srand((int)time(NULL));
+
+NEXTATTEMPT:
+ VoronoiStorageInt.SiteStorage = cvCreateChildMemStorage(VoronoiStorage);
+ VoronoiStorageInt.NodeStorage = cvCreateChildMemStorage(VoronoiStorage);
+ VoronoiStorageInt.EdgeStorage = cvCreateChildMemStorage(VoronoiStorage);
+ VoronoiStorageInt.ParabolaStorage = cvCreateMemStorage(0);
+ VoronoiStorageInt.ChainStorage = cvCreateMemStorage(0);
+ VoronoiStorageInt.DirectionStorage = cvCreateMemStorage(0);
+ VoronoiStorageInt.HoleStorage = cvCreateMemStorage(0);
+
+ pVoronoiDiagramInt->SiteSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvVoronoiSiteInt),VoronoiStorageInt.SiteStorage);
+ pVoronoiDiagramInt->NodeSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvVoronoiNodeInt),VoronoiStorageInt.NodeStorage);
+ pVoronoiDiagramInt->EdgeSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvVoronoiEdgeInt),VoronoiStorageInt.EdgeStorage);
+ pVoronoiDiagramInt->ChainSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvVoronoiChainInt),VoronoiStorageInt.ChainStorage);
+ pVoronoiDiagramInt->DirectionSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvDirection),VoronoiStorageInt.DirectionStorage);
+ pVoronoiDiagramInt->ParabolaSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvVoronoiParabolaInt),VoronoiStorageInt.ParabolaStorage);
+ pVoronoiDiagramInt->HoleSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvVoronoiHoleInt),VoronoiStorageInt.HoleStorage);
+
+ _cvSetSeqBlockSize(pVoronoiDiagramInt,ContourSeq->total);
+
+ if(!_cvConstuctSites(ContourSeq, pVoronoiDiagramInt, contour_type,contour_orientation))
+ {
+ attempt = attempt_number;
+ goto FAULT;
+ }
+ _cvRandomModification(pVoronoiDiagramInt, 0,pVoronoiDiagramInt->NodeSeq->total,0.2f);
+
+ if(!_cvConstructChains(pVoronoiDiagramInt))
+ {
+ attempt = attempt_number;
+ goto FAULT;
+ }
+
+ if(!_cvConstructSkeleton(pVoronoiDiagramInt))
+ goto FAULT;
+
+ _cvConstructSiteTree(pVoronoiDiagramInt);
+
+//SUCCESS:
+ _cvReleaseVoronoiStorage(&VoronoiStorageInt,0,1);
+ return 1;
+
+FAULT:
+ _cvReleaseVoronoiStorage(&VoronoiStorageInt,1,1);
+ if(++attempt < attempt_number)
+ goto NEXTATTEMPT;
+
+ return 0;
+}// end of _cvLee
+
+static int _cvConstuctSites(CvSeq* ContourSeq,
+ CvVoronoiDiagramInt* pVoronoiDiagram,
+ CvLeeParameters contour_type,
+ int contour_orientation)
+{
+ pVoronoiDiagram->reflex_site = NULL;
+ pVoronoiDiagram->top_hole = NULL;
+ int result = 0;
+
+ switch(contour_type)
+ {
+ case CV_LEE_INT : result = _cvConstructExtSites(pVoronoiDiagram,ContourSeq,contour_orientation,(int)1);
+ break;
+ case CV_LEE_FLOAT : result = _cvConstructExtSites(pVoronoiDiagram,ContourSeq,contour_orientation,(float)1);
+ break;
+ case CV_LEE_DOUBLE : result = _cvConstructExtSites(pVoronoiDiagram,ContourSeq,contour_orientation,(double)1);
+ break;
+ default: return 0;
+ }
+
+ if(!result)
+ return 0;
+
+ CvSeq* CurSiteSeq;
+ CvVoronoiHoleInt Hole = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,false,0};
+ pCvVoronoiSite pTopSite = 0;
+ for(CvSeq* CurContourSeq = ContourSeq->v_next;\
+ CurContourSeq != NULL;\
+ CurContourSeq = CurContourSeq->h_next)
+ {
+ if(CurContourSeq->total == 0)
+ continue;
+
+ CurSiteSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvVoronoiSiteInt),pVoronoiDiagram->SiteSeq->storage);
+ switch(contour_type)
+ {
+ case CV_LEE_INT : result = _cvConstructIntSites(pVoronoiDiagram,CurSiteSeq,CurContourSeq,pTopSite,contour_orientation,(int)1);
+ break;
+ case CV_LEE_FLOAT : result = _cvConstructIntSites(pVoronoiDiagram,CurSiteSeq,CurContourSeq,pTopSite,contour_orientation,(float)1);
+ break;
+ case CV_LEE_DOUBLE :result = _cvConstructIntSites(pVoronoiDiagram,CurSiteSeq,CurContourSeq,pTopSite,contour_orientation,(double)1);
+ break;
+ default: result = 0;
+ }
+ if(!result)
+ continue;
+
+ Hole.SiteSeq = CurSiteSeq;
+ Hole.site_top = pTopSite;
+ Hole.x_coord = pTopSite->node1->node.x;
+ Hole.error = false;
+ _cvSeqPushInOrder(pVoronoiDiagram, &Hole);
+ }
+ return 1;
+}//end of _cvConstuctSites
+
+static int _cvConstructChains(CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ if(!_cvConstructExtChains(pVoronoiDiagram))
+ return 0;
+
+ CvSeq* CurrChainSeq;
+ for(pCvVoronoiHole pHole = pVoronoiDiagram->top_hole;\
+ pHole != NULL; \
+ pHole = pHole->next_hole)
+ {
+ pHole->error = false;
+ CurrChainSeq = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvVoronoiChainInt),pVoronoiDiagram->ChainSeq->storage);
+ _cvConstructIntChains(pVoronoiDiagram,CurrChainSeq,pHole->SiteSeq,pHole->site_top);
+ pHole->ChainSeq = CurrChainSeq;
+ }
+ return 1;
+}//end of _cvConstructChains
+
+static int _cvConstructSkeleton(CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ if(!_cvConstructExtVD(pVoronoiDiagram))
+ return 0;
+ _cvConstructIntVD(pVoronoiDiagram);
+ _cvFindNearestSite(pVoronoiDiagram);
+
+ float dx,dy;
+ int result;
+ for(pCvVoronoiHole pHole = pVoronoiDiagram->top_hole;\
+ pHole != NULL; pHole = pHole->next_hole)
+ {
+ if(pHole->error)
+ continue;
+ dx = pHole->node->node.x - pHole->site_top->node1->node.x;
+ dy = pHole->node->node.y - pHole->site_top->node1->node.y;
+
+ if(fabs(dy) < 0.01 && dx < 0)
+ pHole->site_opposite = pHole->site_nearest;
+ else
+ {
+ if(dy > 0)
+ result = _cvFindOppositSiteCCW(pHole,pVoronoiDiagram);
+ else
+ result = _cvFindOppositSiteCW(pHole,pVoronoiDiagram);
+
+ if(!result)
+ {
+ pHole->error = true;
+ continue;
+ }
+ }
+
+ if(!_cvMergeVD(pHole,pVoronoiDiagram))
+ return 0;
+ }
+ return 1;
+}//end of _cvConstructSkeleton
+
+static void _cvConstructSiteTree(CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ CvSeq* CurSeq = pVoronoiDiagram->SiteSeq;
+ for(pCvVoronoiHole pHole = pVoronoiDiagram->top_hole;\
+ pHole != NULL; pHole = pHole->next_hole)
+ {
+ if(pHole->error)
+ continue;
+ if(CurSeq == pVoronoiDiagram->SiteSeq)
+ {
+ CurSeq->v_next = pHole->SiteSeq;
+ pHole->SiteSeq->v_prev = CurSeq;
+ }
+ else
+ {
+ CurSeq->h_next = pHole->SiteSeq;
+ pHole->SiteSeq->h_prev = CurSeq;
+ pHole->SiteSeq->v_prev = pVoronoiDiagram->SiteSeq;
+ }
+ CurSeq = pHole->SiteSeq;
+ }
+ CurSeq->h_next = NULL;
+}//end of _cvConstructSiteTree
+
+static void _cvRandomModification(CvVoronoiDiagramInt* pVoronoiDiagram, int begin, int end, float shift)
+{
+ CvSeqReader Reader;
+ pCvVoronoiNode pNode;
+ const float rnd_const = shift/RAND_MAX;
+ int i;
+
+ cvStartReadSeq(pVoronoiDiagram->NodeSeq, &Reader,0);
+ for( i = begin; i < end; i++)
+ {
+ pNode = (pCvVoronoiNode)Reader.ptr;
+ pNode->node.x = (float)cvFloor(pNode->node.x) + rand()*rnd_const;
+ pNode->node.y = (float)cvFloor(pNode->node.y) + rand()*rnd_const;
+ CV_NEXT_SEQ_ELEM( sizeof(CvVoronoiNodeInt), Reader );
+ }
+
+ for(pCvVoronoiHole pHole = pVoronoiDiagram->top_hole;\
+ pHole != NULL;\
+ pHole = pHole->next_hole)
+ {
+ pHole->site_top->node1->node.x = (float)cvFloor(pHole->site_top->node1->node.x);
+ }
+
+}//end of _cvRandomModification
+
+static void _cvReleaseVoronoiStorage(CvVoronoiStorageInt* pVoronoiStorage, int group1, int group2)
+{
+ //if group1 = 1 then SiteSeq, NodeSeq, EdgeSeq released
+ //if group2 = 1 then DirectionSeq, ParabolaSeq, ChainSeq, HoleSeq released
+ if(group1 == 1)
+ {
+ if(pVoronoiStorage->SiteStorage!=NULL)
+ cvReleaseMemStorage(&pVoronoiStorage->SiteStorage);
+ if(pVoronoiStorage->EdgeStorage!=NULL)
+ cvReleaseMemStorage(&pVoronoiStorage->EdgeStorage);
+ if(pVoronoiStorage->NodeStorage!=NULL)
+ cvReleaseMemStorage(&pVoronoiStorage->NodeStorage);
+ }
+ if(group2 == 1)
+ {
+ if(pVoronoiStorage->ParabolaStorage!=NULL)
+ cvReleaseMemStorage(&pVoronoiStorage->ParabolaStorage);
+ if(pVoronoiStorage->ChainStorage!=NULL)
+ cvReleaseMemStorage(&pVoronoiStorage->ChainStorage);
+ if(pVoronoiStorage->DirectionStorage!=NULL)
+ cvReleaseMemStorage(&pVoronoiStorage->DirectionStorage);
+ if(pVoronoiStorage->HoleStorage != NULL)
+ cvReleaseMemStorage(&pVoronoiStorage->HoleStorage);
+ }
+}// end of _cvReleaseVoronoiStorage
+
+static int _cvConvert(CvVoronoiDiagram2D* VoronoiDiagram,
+ CvVoronoiDiagramInt VoronoiDiagramInt,
+ CvSet* &SiteSeq,
+ CvSeqWriter &NodeWriter,
+ CvSeqWriter &EdgeWriter,
+ CvMemStorage* VoronoiStorage,
+ int contour_orientation)
+{
+ if(contour_orientation == 1)
+ return _cvConvertSameOrientation(VoronoiDiagram,VoronoiDiagramInt,SiteSeq,NodeWriter,
+ EdgeWriter,VoronoiStorage);
+ else
+ return _cvConvertChangeOrientation(VoronoiDiagram,VoronoiDiagramInt,SiteSeq,NodeWriter,
+ EdgeWriter,VoronoiStorage);
+}// end of _cvConvert
+
+static int _cvConvertSameOrientation(CvVoronoiDiagram2D* VoronoiDiagram,
+ CvVoronoiDiagramInt VoronoiDiagramInt,
+ CvSet* &NewSiteSeqPrev,
+ CvSeqWriter &NodeWriter,
+ CvSeqWriter &EdgeWriter,
+ CvMemStorage* VoronoiStorage)
+{
+ CvSeq* SiteSeq = VoronoiDiagramInt.SiteSeq;
+ CvSeq* EdgeSeq = VoronoiDiagramInt.EdgeSeq;
+ CvSeq* NodeSeq = VoronoiDiagramInt.NodeSeq;
+
+
+ CvMemStorage *NewSiteStorage = cvCreateChildMemStorage(VoronoiStorage);
+ CvSet *NewSiteSeq = NULL,*CurrNewSiteSeq = NULL, *PrevNewSiteSeq = NULL;;
+ CvSeqWriter SiteWriter;
+
+ CvVoronoiSite2D NewSite = {{0,0},{0,0},{0,0}},NewSite_prev;
+ CvVoronoiSite2D *pNewSite, *pNewSite_prev = &NewSite_prev;
+ pCvVoronoiSite pSite,pFirstSite;
+
+ CvVoronoiEdge2D NewEdge = {{0,0},{0,0},{0,0,0,0}};
+ CvVoronoiEdge2D *pNewEdge1, *pNewEdge2;
+ pCvVoronoiEdge pEdge;
+
+ CvVoronoiNode2D* pNode1, *pNode2;
+ CvVoronoiNode2D Node;
+ Node.next_free = NULL;
+
+ for(CvSeq* CurrSiteSeq = SiteSeq;\
+ CurrSiteSeq != NULL;\
+ CurrSiteSeq = NEXT_SEQ(CurrSiteSeq,SiteSeq))
+ {
+ CurrNewSiteSeq = cvCreateSet(0,sizeof(CvSet),sizeof(CvVoronoiSite2D), NewSiteStorage);
+ if(!NewSiteSeq)
+ NewSiteSeq = PrevNewSiteSeq = CurrNewSiteSeq;
+ else if(PrevNewSiteSeq->v_prev == NULL)
+ {
+ PrevNewSiteSeq->v_next = (CvSeq*)CurrNewSiteSeq;
+ CurrNewSiteSeq->v_prev = (CvSeq*)PrevNewSiteSeq;
+ }
+ else
+ {
+ PrevNewSiteSeq->h_next = (CvSeq*)CurrNewSiteSeq;
+ CurrNewSiteSeq->h_prev = (CvSeq*)PrevNewSiteSeq;
+ CurrNewSiteSeq->v_prev = (CvSeq*)PrevNewSiteSeq->v_prev;
+ }
+ PrevNewSiteSeq = CurrNewSiteSeq;
+
+ pSite = pFirstSite = (pCvVoronoiSite)cvGetSeqElem(CurrSiteSeq, 0);
+ while(pSite->prev_site->node1 == pSite->prev_site->node2)\
+ pSite = pSite->next_site;
+ pFirstSite = pSite;
+
+ pNewSite_prev = &NewSite_prev;
+ cvStartAppendToSeq((CvSeq*)CurrNewSiteSeq, &SiteWriter);
+ do
+ {
+ pNewSite = _cvWriteSeqElem(&NewSite,SiteWriter);
+ pNewSite->next[0] = pNewSite_prev;
+ pNewSite_prev->next[1] = pNewSite;
+ pEdge = pSite->edge1;
+ if(!pEdge || !pEdge->node1 || !pEdge->node2)
+ return 0;
+
+ if(pEdge->site == NULL)
+ {
+ pNewEdge1 = (CvVoronoiEdge2D*)pEdge->twin_edge;
+ pNewEdge1->site[1] = pNewSite;
+ pNewSite->node[0] = pNewEdge1->node[0];
+ }
+ else
+ {
+ pNewEdge1 = _cvWriteSeqElem(&NewEdge,EdgeWriter);
+ pNewEdge1->site[0] = pNewSite;
+
+ pNode1 = _cvWriteSeqElem(&Node,NodeWriter);
+ pNode2 = _cvWriteSeqElem(&Node,NodeWriter);
+ pNode1->pt.x = pEdge->node1->node.x;
+ pNode1->pt.y = pEdge->node1->node.y;
+ pNode1->radius = pEdge->node1->radius;
+ pNode2->pt.x = pEdge->node2->node.x;
+ pNode2->pt.y = pEdge->node2->node.y;
+ pNode2->radius = pEdge->node2->radius;
+ pNewEdge1->node[0] = pNode1;
+ pNewEdge1->node[1] = pNode2;
+
+ pNewSite->node[0] = pNewEdge1->node[1];
+
+ if(!pNewEdge1->node[0] || !pNewEdge1->node[1])
+ return 0;
+ pEdge->twin_edge->site = NULL;
+ pEdge->twin_edge->twin_edge = (pCvVoronoiEdge)pNewEdge1;
+ }
+ pNewSite->edge[1] = pNewEdge1;
+ pEdge = pEdge->prev_edge;
+ while((pEdge != NULL && CurrSiteSeq->total>1) ||
+ (pEdge != pSite->edge2 && CurrSiteSeq->total == 1))
+ {
+ if(pEdge->site == NULL)
+ {
+ pNewEdge2 = (CvVoronoiEdge2D*)pEdge->twin_edge;
+ pNewEdge2->site[1] = pNewSite;
+ if(CV_VORONOIEDGE2D_BEGINNODE(pNewEdge1,pNewSite) != pNewEdge2->node[0])
+ {
+ cvFlushSeqWriter(&NodeWriter);
+// cvSetRemove((CvSet*)VoronoiDiagram,VoronoiDiagram->total-1);
+ pNewEdge1->node[0] = pNewEdge2->node[0];
+ }
+ }
+ else
+ {
+ pNewEdge2 = _cvWriteSeqElem(&NewEdge,EdgeWriter);
+ pNewEdge2->site[0] = pNewSite;
+
+ pNode1 = _cvWriteSeqElem(&Node,NodeWriter);
+ pNode1->pt.x = pEdge->node1->node.x;
+ pNode1->pt.y = pEdge->node1->node.y;
+ pNode1->radius = pEdge->node1->radius;
+ pNewEdge2->node[0] = pNode1;
+
+ if(pNewEdge1->site[0] == pNewSite)
+ pNewEdge2->node[1] = pNewEdge1->node[0];
+ else
+ pNewEdge2->node[1] = pNewEdge1->node[1];
+
+ if(!pNewEdge1->node[0] || !pNewEdge1->node[1])
+ return 0;
+ pEdge->twin_edge->site = NULL;
+ pEdge->twin_edge->twin_edge = (pCvVoronoiEdge)pNewEdge2;
+ }
+ if(pNewEdge1->site[0] == pNewSite)
+ pNewEdge1->next[2] = pNewEdge2;
+ else
+ pNewEdge1->next[3] = pNewEdge2;
+
+ if(pNewEdge2->site[0] == pNewSite)
+ pNewEdge2->next[0] = pNewEdge1;
+ else
+ pNewEdge2->next[1] = pNewEdge1;
+
+ pEdge = pEdge->prev_edge;
+ pNewEdge1 = pNewEdge2;
+ }
+ pNewSite->edge[0] = pNewEdge1;
+ pNewSite->node[1] = pNewEdge1->node[0];
+
+ if(pSite->node1 == pSite->node2 && pSite != pSite->next_site && pNewEdge1->node[0] != pNewEdge1->node[1])
+ {
+ cvFlushSeqWriter(&NodeWriter);
+// cvSetRemove((CvSet*)VoronoiDiagram,VoronoiDiagram->total-1);
+ pNewSite->node[1] = pNewEdge1->node[0] = pNewSite->node[0];
+ }
+
+ pNewSite_prev = pNewSite;
+ pSite = pSite->next_site;
+ }while(pSite != pFirstSite);
+ pNewSite->node[1] = pNewEdge1->node[1];
+ if(pSite == pSite->next_site)
+ {
+ Node.pt.x = pSite->node1->node.x;
+ Node.pt.y = pSite->node1->node.y;
+ Node.radius = 0;
+ pNewSite->node[0] = pNewSite->node[1] = _cvWriteSeqElem(&Node,NodeWriter);
+ }
+
+ cvEndWriteSeq(&SiteWriter);
+ pNewSite = (CvVoronoiSite2D*)cvGetSetElem(CurrNewSiteSeq, 0);
+ pNewSite->next[0] = pNewSite_prev;
+ pNewSite_prev->next[1] = pNewSite;
+ }
+
+ cvReleaseMemStorage(&(SiteSeq->storage));
+ cvReleaseMemStorage(&(EdgeSeq->storage));
+ cvReleaseMemStorage(&(NodeSeq->storage));
+
+ if(NewSiteSeqPrev == NULL)
+ VoronoiDiagram->sites = NewSiteSeq;
+ else
+ {
+ NewSiteSeqPrev->h_next = (CvSeq*)NewSiteSeq;
+ NewSiteSeq->h_prev = (CvSeq*)NewSiteSeqPrev;
+ }
+
+ NewSiteSeqPrev = NewSiteSeq;
+ return 1;
+}//end of _cvConvertSameOrientation
+
+static int _cvConvertChangeOrientation(CvVoronoiDiagram2D* VoronoiDiagram,
+ CvVoronoiDiagramInt VoronoiDiagramInt,
+ CvSet* &NewSiteSeqPrev,
+ CvSeqWriter &NodeWriter,
+ CvSeqWriter &EdgeWriter,
+ CvMemStorage* VoronoiStorage)
+{
+ // pNewSite->edge[1] = pSite->edge2
+ // pNewSite->edge[0] = pSite->edge1
+
+ CvSeq* SiteSeq = VoronoiDiagramInt.SiteSeq;
+ CvSeq* EdgeSeq = VoronoiDiagramInt.EdgeSeq;
+ CvSeq* NodeSeq = VoronoiDiagramInt.NodeSeq;
+
+
+ CvMemStorage *NewSiteStorage = cvCreateChildMemStorage(VoronoiStorage);
+ CvSet *NewSiteSeq = NULL,*CurrNewSiteSeq = NULL, *PrevNewSiteSeq = NULL;;
+ CvSeqWriter SiteWriter;
+
+ CvVoronoiSite2D NewSite = {{0,0},{0,0},{0,0}},NewSite_prev;
+ CvVoronoiSite2D *pNewSite, *pNewSite_prev = &NewSite_prev;
+ pCvVoronoiSite pSite,pFirstSite;
+
+ CvVoronoiEdge2D NewEdge = {{0,0},{0,0},{0,0,0,0}};
+ CvVoronoiEdge2D *pNewEdge1, *pNewEdge2;
+ pCvVoronoiEdge pEdge;
+
+ CvVoronoiNode2D* pNode1, *pNode2;
+ CvVoronoiNode2D Node;
+ Node.next_free = NULL;
+
+ for(CvSeq* CurrSiteSeq = SiteSeq;\
+ CurrSiteSeq != NULL;\
+ CurrSiteSeq = NEXT_SEQ(CurrSiteSeq,SiteSeq))
+ {
+ CurrNewSiteSeq = cvCreateSet(0,sizeof(CvSet),sizeof(CvVoronoiSite2D), NewSiteStorage);
+ if(!NewSiteSeq)
+ NewSiteSeq = PrevNewSiteSeq = CurrNewSiteSeq;
+ else if(PrevNewSiteSeq->v_prev == NULL)
+ {
+ PrevNewSiteSeq->v_next = (CvSeq*)CurrNewSiteSeq;
+ CurrNewSiteSeq->v_prev = (CvSeq*)PrevNewSiteSeq;
+ }
+ else
+ {
+ PrevNewSiteSeq->h_next = (CvSeq*)CurrNewSiteSeq;
+ CurrNewSiteSeq->h_prev = (CvSeq*)PrevNewSiteSeq;
+ CurrNewSiteSeq->v_prev = (CvSeq*)PrevNewSiteSeq->v_prev;
+ }
+ PrevNewSiteSeq = CurrNewSiteSeq;
+
+ pSite = (pCvVoronoiSite)cvGetSeqElem(CurrSiteSeq, 0);
+ while(pSite->next_site->node1 == pSite->next_site->node2)\
+ pSite = pSite->next_site;
+ pFirstSite = pSite;
+
+ pNewSite_prev = &NewSite_prev;
+ cvStartAppendToSeq((CvSeq*)CurrNewSiteSeq, &SiteWriter);
+ do
+ {
+ pNewSite = _cvWriteSeqElem(&NewSite,SiteWriter);
+ pNewSite->next[0] = pNewSite_prev;
+ pNewSite_prev->next[1] = pNewSite;
+
+ pEdge = pSite->edge2;
+ if(!pEdge || !pEdge->node1 || !pEdge->node2)
+ return 0;
+
+ if(pEdge->site == NULL)
+ {
+ pNewEdge1 = (CvVoronoiEdge2D*)pEdge->twin_edge;
+ pNewEdge1->site[1] = pNewSite;
+ pNewSite->node[0] = pNewEdge1->node[0];
+ }
+ else
+ {
+ pNewEdge1 = _cvWriteSeqElem(&NewEdge,EdgeWriter);
+ pNewEdge1->site[0] = pNewSite;
+
+ pNode1 = _cvWriteSeqElem(&Node,NodeWriter);
+ pNode2 = _cvWriteSeqElem(&Node,NodeWriter);
+ pNode1->pt.x = pEdge->node1->node.x;
+ pNode1->pt.y = pEdge->node1->node.y;
+ pNode1->radius = pEdge->node1->radius;
+ pNode2->pt.x = pEdge->node2->node.x;
+ pNode2->pt.y = pEdge->node2->node.y;
+ pNode2->radius = pEdge->node2->radius;
+ pNewEdge1->node[0] = pNode2;
+ pNewEdge1->node[1] = pNode1;
+
+ pNewSite->node[0] = pNewEdge1->node[1];
+
+ if(!pNewEdge1->node[0] || !pNewEdge1->node[1])
+ return 0;
+ pEdge->twin_edge->site = NULL;
+ pEdge->twin_edge->twin_edge = (pCvVoronoiEdge)pNewEdge1;
+ }
+ pNewSite->edge[1] = pNewEdge1;
+
+
+ pEdge = pEdge->next_edge;
+ while((pEdge != NULL && CurrSiteSeq->total>1) ||
+ (pEdge != pSite->edge1 && CurrSiteSeq->total == 1))
+ {
+ if(pEdge->site == NULL)
+ {
+ pNewEdge2 = (CvVoronoiEdge2D*)pEdge->twin_edge;
+ pNewEdge2->site[1] = pNewSite;
+ if(CV_VORONOIEDGE2D_BEGINNODE(pNewEdge1,pNewSite) != pNewEdge2->node[0])
+ {
+ cvFlushSeqWriter(&NodeWriter);
+// cvSetRemove((CvSet*)VoronoiDiagram,VoronoiDiagram->total-1);
+ pNewEdge1->node[0] = pNewEdge2->node[0];
+ }
+ }
+ else
+ {
+ pNewEdge2 = _cvWriteSeqElem(&NewEdge,EdgeWriter);
+ pNewEdge2->site[0] = pNewSite;
+
+ pNode2 = _cvWriteSeqElem(&Node,NodeWriter);
+ pNode2->pt.x = pEdge->node2->node.x;
+ pNode2->pt.y = pEdge->node2->node.y;
+ pNode2->radius = pEdge->node2->radius;
+ pNewEdge2->node[0] = pNode2;
+
+ if(pNewEdge1->site[0] == pNewSite)
+ pNewEdge2->node[1] = pNewEdge1->node[0];
+ else
+ pNewEdge2->node[1] = pNewEdge1->node[1];
+
+ if(!pNewEdge1->node[0] || !pNewEdge1->node[1])
+ return 0;
+ pEdge->twin_edge->site = NULL;
+ pEdge->twin_edge->twin_edge = (pCvVoronoiEdge)pNewEdge2;
+ }
+ if(pNewEdge1->site[0] == pNewSite)
+ pNewEdge1->next[2] = pNewEdge2;
+ else
+ pNewEdge1->next[3] = pNewEdge2;
+
+ if(pNewEdge2->site[0] == pNewSite)
+ pNewEdge2->next[0] = pNewEdge1;
+ else
+ pNewEdge2->next[1] = pNewEdge1;
+
+ pEdge = pEdge->next_edge;
+ pNewEdge1 = pNewEdge2;
+ }
+ pNewSite->edge[0] = pNewEdge1;
+ pNewSite->node[1] = pNewEdge1->node[0];
+
+ if(pSite->node1 == pSite->node2 && pSite != pSite->next_site && pNewEdge1->node[0] != pNewEdge1->node[1])
+ {
+ cvFlushSeqWriter(&NodeWriter);
+// cvSetRemove((CvSet*)VoronoiDiagram,VoronoiDiagram->total-1);
+ pNewSite->node[1] = pNewEdge1->node[0] = pNewSite->node[0];
+ }
+
+ pNewSite_prev = pNewSite;
+ pSite = pSite->prev_site;
+ }while(pSite != pFirstSite);
+ pNewSite->node[1] = pNewEdge1->node[1];
+ if(pSite == pSite->next_site)
+ {
+ Node.pt.x = pSite->node1->node.x;
+ Node.pt.y = pSite->node1->node.y;
+ Node.radius = 0;
+ pNewSite->node[0] = pNewSite->node[1] = _cvWriteSeqElem(&Node,NodeWriter);
+ }
+
+ cvEndWriteSeq(&SiteWriter);
+ pNewSite = (CvVoronoiSite2D*)cvGetSetElem(CurrNewSiteSeq, 0);
+ pNewSite->next[0] = pNewSite_prev;
+ pNewSite_prev->next[1] = pNewSite;
+ }
+
+ cvReleaseMemStorage(&(SiteSeq->storage));
+ cvReleaseMemStorage(&(EdgeSeq->storage));
+ cvReleaseMemStorage(&(NodeSeq->storage));
+
+ if(NewSiteSeqPrev == NULL)
+ VoronoiDiagram->sites = NewSiteSeq;
+ else
+ {
+ NewSiteSeqPrev->h_next = (CvSeq*)NewSiteSeq;
+ NewSiteSeq->h_prev = (CvSeq*)NewSiteSeqPrev;
+ }
+ NewSiteSeqPrev = NewSiteSeq;
+ return 1;
+}//end of _cvConvert
+
+template<class T>
+int _cvConstructExtSites(CvVoronoiDiagramInt* pVoronoiDiagram,
+ CvSeq* ContourSeq,
+ int orientation,
+ T type)
+{
+ const double angl_eps = 0.03;
+ CvSeq* SiteSeq = pVoronoiDiagram->SiteSeq;
+ CvSeq* NodeSeq = pVoronoiDiagram->NodeSeq;
+ //CvSeq* DirectionSeq = pVoronoiDiagram->DirectionSeq;
+ CvPointFloat Vertex1,Vertex2,Vertex3;
+ CvLeePoint<T> VertexT1,VertexT2,VertexT3;
+
+ CvSeqReader ContourReader;
+ CvVoronoiSiteInt Site = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+ CvVoronoiSiteInt SiteTemp = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+ CvVoronoiNodeInt Node;
+ pCvVoronoiNode pNode1,pNode2;
+ pCvVoronoiSite pSite = &SiteTemp,pSite_prev = &SiteTemp;
+ pCvVoronoiSite pReflexSite = NULL;
+ int NReflexSite = 0;
+
+ float delta_x_rc, delta_x_cl, delta_y_rc, delta_y_cl;
+ float norm_cl,norm_rc, mult_cl_rc;
+ float _sin, _cos;
+ int i;
+
+ if(orientation == 1)
+ {
+ cvStartReadSeq(ContourSeq, &ContourReader,0);
+ CV_READ_SEQ_ELEM(VertexT1,ContourReader);
+ CV_READ_SEQ_ELEM(VertexT2,ContourReader);
+ }
+ else
+ {
+ cvStartReadSeq(ContourSeq, &ContourReader,1);
+ CV_REV_READ_SEQ_ELEM(VertexT1,ContourReader);
+ CV_REV_READ_SEQ_ELEM(VertexT2,ContourReader);
+ }
+
+ Vertex1.x = (float)VertexT1.x;
+ Vertex1.y = (float)VertexT1.y;
+ Vertex2.x = (float)VertexT2.x;
+ Vertex2.y = (float)VertexT2.y;
+
+ _cvInitVoronoiNode(&Node, &Vertex2);
+ pNode1 = _cvSeqPush(NodeSeq, &Node);
+
+ delta_x_cl = Vertex2.x - Vertex1.x;
+ delta_y_cl = Vertex2.y - Vertex1.y;
+ norm_cl = (float)sqrt((double)delta_x_cl*delta_x_cl + delta_y_cl*delta_y_cl);
+
+ for( i = 0;i<ContourSeq->total;i++)
+ {
+ if(orientation == 1)
+ {
+ CV_READ_SEQ_ELEM(VertexT3,ContourReader);
+ }
+ else
+ {
+ CV_REV_READ_SEQ_ELEM(VertexT3,ContourReader);
+ }
+
+ Vertex3.x = (float)VertexT3.x;
+ Vertex3.y = (float)VertexT3.y;
+
+ _cvInitVoronoiNode(&Node, &Vertex3);
+ pNode2 = _cvSeqPush(NodeSeq, &Node);
+
+ delta_x_rc = Vertex3.x - Vertex2.x;
+ delta_y_rc = Vertex3.y - Vertex2.y;
+ norm_rc = (float)sqrt((double)delta_x_rc*delta_x_rc + delta_y_rc*delta_y_rc);
+ if(norm_rc==0)
+ continue;
+
+ mult_cl_rc = norm_cl*norm_rc;
+ _sin = (delta_y_rc* delta_x_cl - delta_x_rc* delta_y_cl)/mult_cl_rc;
+ _cos = -(delta_x_cl*delta_x_rc + delta_y_cl*delta_y_rc)/mult_cl_rc;
+
+ if((_sin > angl_eps) || (_sin > 0 && _cos > 0))
+ {
+ pSite = _cvSeqPush(SiteSeq, &Site);
+ _cvInitVoronoiSite(pSite,pNode1,pNode2,pSite_prev);
+ pSite_prev->next_site = pSite;
+ }
+ else if((_sin < -angl_eps) || (_sin < 0 && _cos > 0))
+ {
+ pSite = _cvSeqPush(SiteSeq, &Site);
+ _cvInitVoronoiSite(pSite,pNode1,pNode1,pSite_prev);
+ pReflexSite = pSite;
+ NReflexSite++;
+ pSite_prev->next_site = pSite;
+
+ pSite_prev = pSite;
+ pSite = _cvSeqPush(SiteSeq, &Site);
+ _cvInitVoronoiSite(pSite,pNode1,pNode2,pSite_prev);
+ pSite_prev->next_site = pSite;
+ }
+ else
+ {
+ Vertex2 = Vertex3;
+ delta_y_rc = delta_y_cl + delta_y_rc;
+ delta_x_rc = delta_x_cl + delta_x_rc;
+ pSite->node2 = pNode2;
+
+ norm_rc = (float)sqrt((double)delta_y_rc*delta_y_rc + delta_x_rc*delta_x_rc);
+ }
+ Vertex2=Vertex3;
+ delta_y_cl= delta_y_rc;
+ delta_x_cl= delta_x_rc;
+ norm_cl = norm_rc;
+ pSite_prev = pSite;
+ pNode1 = pNode2;
+ }
+
+ if(SiteTemp.next_site==NULL)
+ return 0;
+
+ if(ContourSeq->total - NReflexSite<2)
+ return 0;
+
+ if(SiteSeq->total<3)
+ return 0;
+
+ pSite->node2 = SiteTemp.next_site->node1;
+ pSite->next_site = SiteTemp.next_site;
+ SiteTemp.next_site->prev_site = pSite;
+
+ i = 0;
+ if(pReflexSite!=NULL)
+ for(i=0; i<SiteSeq->total; i++)
+ {
+ if(pReflexSite->next_site->next_site->node1 !=
+ pReflexSite->next_site->next_site->node2)
+ break;
+ else
+ pReflexSite = pReflexSite->next_site->next_site;
+ }
+ pVoronoiDiagram->reflex_site = pReflexSite;
+ return (i<SiteSeq->total);
+}//end of _cvConstructExtSites
+
+template<class T>
+int _cvConstructIntSites(CvVoronoiDiagramInt* pVoronoiDiagram,
+ CvSeq* CurrSiteSeq,
+ CvSeq* CurrContourSeq,
+ pCvVoronoiSite &pTopSite,
+ int orientation,
+ T type)
+{
+ const double angl_eps = 0.03;
+ float min_x = (float)999999999;
+ CvSeq* SiteSeq = CurrSiteSeq;
+ CvSeq* NodeSeq = pVoronoiDiagram->NodeSeq;
+ //CvSeq* DirectionSeq = pVoronoiDiagram->DirectionSeq;
+ CvPointFloat Vertex1,Vertex2,Vertex3;
+ CvLeePoint<T> VertexT1,VertexT2,VertexT3;
+
+ CvSeqReader ContourReader;
+ CvVoronoiSiteInt Site = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+ CvVoronoiSiteInt SiteTemp = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+ CvVoronoiNodeInt Node;
+ pCvVoronoiNode pNode1,pNode2;
+ pCvVoronoiSite pSite = &SiteTemp,pSite_prev = &SiteTemp;
+ pTopSite = NULL;
+ int NReflexSite = 0;
+
+ if(CurrContourSeq->total == 1)
+ {
+ cvStartReadSeq(CurrContourSeq, &ContourReader,0);
+ CV_READ_SEQ_ELEM(VertexT1,ContourReader);
+ Vertex1.x = (float)VertexT1.x;
+ Vertex1.y = (float)VertexT1.y;
+
+ _cvInitVoronoiNode(&Node, &Vertex1);
+ pNode1 = _cvSeqPush(NodeSeq, &Node);
+ pTopSite = pSite = _cvSeqPush(SiteSeq, &Site);
+ _cvInitVoronoiSite(pSite,pNode1,pNode1,pSite);
+ pSite->next_site = pSite;
+ return 1;
+ }
+
+ float delta_x_rc, delta_x_cl, delta_y_rc, delta_y_cl;
+ float norm_cl,norm_rc, mult_cl_rc;
+ float _sin, _cos;
+ int i;
+
+ if(orientation == 1)
+ {
+ cvStartReadSeq(CurrContourSeq, &ContourReader,0);
+ CV_READ_SEQ_ELEM(VertexT1,ContourReader);
+ CV_READ_SEQ_ELEM(VertexT2,ContourReader);
+ }
+ else
+ {
+ cvStartReadSeq(CurrContourSeq, &ContourReader,1);
+ CV_REV_READ_SEQ_ELEM(VertexT1,ContourReader);
+ CV_REV_READ_SEQ_ELEM(VertexT2,ContourReader);
+ }
+
+ Vertex1.x = (float)VertexT1.x;
+ Vertex1.y = (float)VertexT1.y;
+ Vertex2.x = (float)VertexT2.x;
+ Vertex2.y = (float)VertexT2.y;
+
+ _cvInitVoronoiNode(&Node, &Vertex2);
+ pNode1 = _cvSeqPush(NodeSeq, &Node);
+
+ delta_x_cl = Vertex2.x - Vertex1.x;
+ delta_y_cl = Vertex2.y - Vertex1.y;
+ norm_cl = (float)sqrt((double)delta_x_cl*delta_x_cl + delta_y_cl*delta_y_cl);
+ for( i = 0;i<CurrContourSeq->total;i++)
+ {
+ if(orientation == 1)
+ {
+ CV_READ_SEQ_ELEM(VertexT3,ContourReader);
+ }
+ else
+ {
+ CV_REV_READ_SEQ_ELEM(VertexT3,ContourReader);
+ }
+ Vertex3.x = (float)VertexT3.x;
+ Vertex3.y = (float)VertexT3.y;
+
+ _cvInitVoronoiNode(&Node, &Vertex3);
+ pNode2 = _cvSeqPush(NodeSeq, &Node);
+
+ delta_x_rc = Vertex3.x - Vertex2.x;
+ delta_y_rc = Vertex3.y - Vertex2.y;
+ norm_rc = (float)sqrt((double)delta_x_rc*delta_x_rc + delta_y_rc*delta_y_rc);
+ if(norm_rc==0)
+ continue;
+
+ mult_cl_rc = norm_cl*norm_rc;
+ _sin = (delta_y_rc* delta_x_cl - delta_x_rc* delta_y_cl)/mult_cl_rc;
+ _cos = -(delta_x_cl*delta_x_rc + delta_y_cl*delta_y_rc)/mult_cl_rc;
+ if((_sin > angl_eps) || (_sin > 0 && _cos > 0))
+ {
+ pSite = _cvSeqPush(SiteSeq, &Site);
+ _cvInitVoronoiSite(pSite,pNode1,pNode2,pSite_prev);
+ pSite_prev->next_site = pSite;
+ }
+ else if((_sin < -angl_eps) || (_sin < 0 && _cos > 0) || (_sin == 0 && CurrContourSeq->total == 2))
+ {
+ pSite = _cvSeqPush(SiteSeq, &Site);
+ _cvInitVoronoiSite(pSite,pNode1,pNode1,pSite_prev);
+ if(pNode1->node.x < min_x)
+ {
+ min_x = pNode1->node.x;
+ pTopSite = pSite;
+ }
+ NReflexSite++;
+ pSite_prev->next_site = pSite;
+
+ pSite_prev = pSite;
+ pSite = _cvSeqPush(SiteSeq, &Site);
+ _cvInitVoronoiSite(pSite,pNode1,pNode2,pSite_prev);
+ pSite_prev->next_site = pSite;
+ }
+ else
+ {
+ Vertex2 = Vertex3;
+ delta_y_rc = delta_y_cl + delta_y_rc;
+ delta_x_rc = delta_x_cl + delta_x_rc;
+ norm_rc = (float)sqrt((double)delta_y_rc*delta_y_rc + delta_x_rc*delta_x_rc);
+ pSite->node2 = pNode2;
+ }
+
+ Vertex1=Vertex2;
+ Vertex2=Vertex3;
+ delta_y_cl= delta_y_rc;
+ delta_x_cl= delta_x_rc;
+ norm_cl = norm_rc;
+ pSite_prev = pSite;
+ pNode1 = pNode2;
+ }
+
+ if(SiteTemp.next_site==NULL)
+ return 0;
+
+ if(NReflexSite < 3 && CurrContourSeq->total > 2 || NReflexSite < 2)
+ return 0;
+
+ pSite->node2 = SiteTemp.next_site->node1;
+ pSite->next_site = SiteTemp.next_site;
+ SiteTemp.next_site->prev_site = pSite;
+
+ return 1;
+}//end of _cvConstructIntSites
+
+static int _cvConstructExtChains(CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ CvSeq* SiteSeq = pVoronoiDiagram->SiteSeq;
+ CvSeq* ChainSeq = pVoronoiDiagram->ChainSeq;
+
+ CvVoronoiChainInt Chain;
+ pCvVoronoiChain pChain,pChainFirst;
+ pCvVoronoiSite pSite, pSite_prev, pSiteFirst,pReflexSite = pVoronoiDiagram->reflex_site;
+
+ if(pReflexSite==NULL)
+ pSite = pSiteFirst = (pCvVoronoiSite)cvGetSeqElem(SiteSeq, 0);
+ else
+ {
+ while(pReflexSite->next_site->next_site->node1==
+ pReflexSite->next_site->next_site->node2)
+ pReflexSite = pReflexSite->next_site->next_site;
+
+ pSite = pSiteFirst = pReflexSite->next_site;
+ }
+
+ Chain.last_site = pSite;
+ _cvConstructEdges(pSite,pVoronoiDiagram);
+ pSite_prev = pSite;
+ pSite = pSite->prev_site;
+ do
+ {
+ if(pSite->node1!=pSite->node2)
+ {
+ Chain.first_site = pSite_prev;
+ pChain = _cvSeqPushFront(ChainSeq,&Chain);
+
+ _cvConstructEdges(pSite,pVoronoiDiagram);
+ Chain.last_site = pSite;
+ Chain.next_chain = pChain;
+ }
+ else
+ {
+ pSite=pSite->prev_site;
+ _cvConstructEdges(pSite,pVoronoiDiagram);
+ _cvConstructEdges(pSite->next_site,pVoronoiDiagram);
+ }
+ pSite_prev = pSite;
+ pSite = pSite->prev_site;
+ }while(pSite!=pSiteFirst);
+
+ Chain.first_site = pSite_prev;
+ pChain = _cvSeqPushFront(ChainSeq,&Chain);
+ pChainFirst = (pCvVoronoiChain)cvGetSeqElem(ChainSeq,ChainSeq->total - 1);
+ pChainFirst->next_chain = pChain;
+ if(ChainSeq->total < 3)
+ return 0;
+ else
+ return 1;
+}// end of _cvConstructExtChains
+
+static void _cvConstructIntChains(CvVoronoiDiagramInt* pVoronoiDiagram,
+ CvSeq* CurrChainSeq,
+ CvSeq* CurrSiteSeq,
+ pCvVoronoiSite pTopSite)
+{
+ CvSeq* ChainSeq = CurrChainSeq;
+
+ if(CurrSiteSeq->total == 1)
+ return;
+
+ CvVoronoiChainInt Chain = {NULL,NULL,NULL};
+ pCvVoronoiChain pChain,pChainFirst;;
+ pCvVoronoiSite pSite, pSite_prev, pSiteFirst;
+ pSite = pSiteFirst = pTopSite->next_site;
+
+ Chain.last_site = pSite;
+ _cvConstructEdges(pSite,pVoronoiDiagram);
+ pSite_prev = pSite;
+ pSite = pSite->prev_site;
+ do
+ {
+ if(pSite->node1!=pSite->node2)
+ {
+ Chain.first_site = pSite_prev;
+ pChain = _cvSeqPushFront(ChainSeq,&Chain);
+
+ _cvConstructEdges(pSite,pVoronoiDiagram);
+ Chain.last_site = pSite;
+ Chain.next_chain = pChain;
+ }
+ else
+ {
+ pSite=pSite->prev_site;
+ if(pSite != pSiteFirst)
+ _cvConstructEdges(pSite,pVoronoiDiagram);
+ _cvConstructEdges(pSite->next_site,pVoronoiDiagram);
+ }
+ pSite_prev = pSite;
+ pSite = pSite->prev_site;
+ }while(pSite!=pSiteFirst && pSite!= pSiteFirst->prev_site);
+
+ if(pSite == pSiteFirst->prev_site && ChainSeq->total == 0)
+ return;
+
+ Chain.first_site = pSite_prev;
+ if(pSite == pSiteFirst->prev_site)
+ {
+ pChainFirst = (pCvVoronoiChain)cvGetSeqElem(ChainSeq,ChainSeq->total - 1);
+ pChainFirst->last_site = Chain.last_site;
+ pChainFirst->next_chain = Chain.next_chain;
+ return;
+ }
+ else
+ {
+ pChain = _cvSeqPushFront(ChainSeq,&Chain);
+ pChainFirst = (pCvVoronoiChain)cvGetSeqElem(ChainSeq,ChainSeq->total - 1);
+ pChainFirst->next_chain = pChain;
+ return;
+ }
+}// end of _cvConstructIntChains
+
+CV_INLINE void _cvConstructEdges(pCvVoronoiSite pSite,CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ CvSeq* EdgeSeq = pVoronoiDiagram->EdgeSeq;
+ CvSeq* DirectionSeq = pVoronoiDiagram->DirectionSeq;
+ CvVoronoiEdgeInt Edge = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+ pCvVoronoiEdge pEdge1,pEdge2;
+ CvDirection EdgeDirection,SiteDirection;
+ float site_lengh;
+
+ Edge.site = pSite;
+ if(pSite->node1!=pSite->node2)
+ {
+ SiteDirection.x = pSite->node2->node.x - pSite->node1->node.x;
+ SiteDirection.y = pSite->node2->node.y - pSite->node1->node.y;
+ site_lengh = (float)sqrt((double)SiteDirection.x*SiteDirection.x + SiteDirection.y * SiteDirection.y);
+ SiteDirection.x /= site_lengh;
+ SiteDirection.y /= site_lengh;
+ EdgeDirection.x = -SiteDirection.y;
+ EdgeDirection.y = SiteDirection.x;
+ Edge.direction = _cvSeqPush(DirectionSeq,&EdgeDirection);
+ pSite->direction = _cvSeqPush(DirectionSeq,&SiteDirection);
+
+ pEdge1 = _cvSeqPush(EdgeSeq,&Edge);
+ pEdge2 = _cvSeqPush(EdgeSeq,&Edge);
+ }
+ else
+ {
+ pCvVoronoiSite pSite_prev = pSite->prev_site;
+ pCvVoronoiSite pSite_next = pSite->next_site;
+
+ pEdge1 = _cvSeqPush(EdgeSeq,&Edge);
+ pEdge2 = _cvSeqPush(EdgeSeq,&Edge);
+
+ pEdge2->direction = pSite_next->edge1->direction;
+ pEdge2->twin_edge = pSite_next->edge1;
+ pSite_next->edge1->twin_edge = pEdge2;
+
+ pEdge1->direction = pSite_prev->edge2->direction;
+ pEdge1->twin_edge = pSite_prev->edge2;
+ pSite_prev->edge2->twin_edge = pEdge1;
+ }
+
+ pEdge2->node1 = pSite->node2;
+ pEdge1->node2 = pSite->node1;
+ pSite->edge1 = pEdge1;
+ pSite->edge2 = pEdge2;
+ pEdge2->next_edge = pEdge1;
+ pEdge1->prev_edge = pEdge2;
+}// end of _cvConstructEdges
+
+static int _cvConstructExtVD(CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ pCvVoronoiSite pSite_right = 0,pSite_left = 0;
+ pCvVoronoiEdge pEdge_left,pEdge_right;
+ pCvVoronoiChain pChain1, pChain2;
+
+ pChain1 = (pCvVoronoiChain)cvGetSeqElem(pVoronoiDiagram->ChainSeq,0);
+ do
+ {
+ pChain2 = pChain1->next_chain;
+ if(pChain2->next_chain==pChain1)
+ {
+ pSite_right = pChain1->first_site;
+ pSite_left = pChain2->last_site;
+ pEdge_left = pSite_left->edge2->next_edge;
+ pEdge_right = pSite_right->edge1->prev_edge;
+ pEdge_left->prev_edge = NULL;
+ pEdge_right->next_edge = NULL;
+ pSite_right->edge1 = NULL;
+ pSite_left->edge2 = NULL;
+ }
+
+ if(!_cvJoinChains(pChain1,pChain2,pVoronoiDiagram))
+ return 0;
+
+ pChain1->last_site = pChain2->last_site;
+ pChain1->next_chain = pChain2->next_chain;
+ pChain1 = pChain1->next_chain;
+ }while(pChain1->next_chain != pChain1);
+
+ pCvVoronoiNode pEndNode = pSite_left->node2;
+ if(pSite_right->edge1==NULL)
+ return 0;
+ else
+ pSite_right->edge1->node2 = pEndNode;
+
+ if(pSite_left->edge2==NULL)
+ return 0;
+ else
+ pSite_left->edge2->node1 = pEndNode;
+
+ return 1;
+}//end of _cvConstructExtVD
+
+static int _cvJoinChains(pCvVoronoiChain pChain1,
+ pCvVoronoiChain pChain2,
+ CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ const double dist_eps = 0.05;
+ if(pChain1->first_site == NULL || pChain1->last_site == NULL ||
+ pChain2->first_site == NULL || pChain2->last_site == NULL)
+ return 0;
+
+ CvVoronoiEdgeInt EdgeNULL = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+
+ CvSeq* NodeSeq = pVoronoiDiagram->NodeSeq;
+ CvSeq* EdgeSeq = pVoronoiDiagram->EdgeSeq;
+
+ pCvVoronoiSite pSite_left = pChain1->last_site;
+ pCvVoronoiSite pSite_right = pChain2->first_site;
+
+ pCvVoronoiEdge pEdge_left = pSite_left->edge2->next_edge;
+ pCvVoronoiEdge pEdge_right = pSite_right->edge1->prev_edge;
+
+ pCvVoronoiEdge pEdge_left_cur = pEdge_left;
+ pCvVoronoiEdge pEdge_right_cur = pEdge_right;
+
+ pCvVoronoiEdge pEdge_left_prev = NULL;
+ pCvVoronoiEdge pEdge_right_next = NULL;
+
+ pCvVoronoiNode pNode_siteleft = pChain1->first_site->node1;
+ pCvVoronoiNode pNode_siteright = pChain2->last_site->node2;
+ /*CvVoronoiSiteInt Site_left_chain = {pNode_siteleft,pNode_siteleft,NULL,NULL,NULL,NULL};
+ CvVoronoiSiteInt Site_right_chain = {pNode_siteright,pNode_siteright,NULL,NULL,NULL,NULL};*/
+
+ pCvVoronoiEdge pEdge1,pEdge2;
+ CvPointFloat Point1 = {0,0}, Point2 = {0,0};
+
+ float radius1,radius2,dist1,dist2;
+ bool left = true,right = true;
+
+ CvVoronoiNodeInt Node;
+ pCvVoronoiNode pNode_begin = pSite_left->node2;
+
+ pEdge1 = pSite_left->edge2;
+ pEdge1->node2 = NULL;
+ pEdge2 = pSite_right->edge1;
+ pEdge2->node1 = NULL;
+
+ for(;;)
+ {
+
+ if(left)
+ pEdge1->node1 = pNode_begin;
+ if(right)
+ pEdge2->node2 = pNode_begin;
+
+ pEdge_left = pEdge_left_cur;
+ pEdge_right = pEdge_right_cur;
+
+ if(left&&right)
+ {
+ _cvCalcEdge(pSite_left,pSite_right,pEdge1,pVoronoiDiagram);
+ _cvMakeTwinEdge(pEdge2,pEdge1);
+ _cvStickEdgeLeftBegin(pEdge1,pEdge_left_prev,pSite_left);
+ _cvStickEdgeRightBegin(pEdge2,pEdge_right_next,pSite_right);
+ }
+ else if(!left)
+ {
+ _cvCalcEdge(pNode_siteleft,pSite_right,pEdge2,pVoronoiDiagram);
+ _cvStickEdgeRightBegin(pEdge2,pEdge_right_next,pSite_right);
+ }
+ else if(!right)
+ {
+ _cvCalcEdge(pSite_left,pNode_siteright,pEdge1,pVoronoiDiagram);
+ _cvStickEdgeLeftBegin(pEdge1,pEdge_left_prev,pSite_left);
+ }
+
+ dist1=dist2=-1;
+ radius1 = -1; radius2 = -2;
+
+ while(pEdge_left!=NULL)
+ {
+ if(pEdge_left->node2 == NULL)
+ {
+ pEdge_left_cur = pEdge_left = pEdge_left->next_edge;
+ if(pEdge_left == NULL)
+ break;
+ }
+
+ if(left)
+ dist1 = _cvCalcEdgeIntersection(pEdge1, pEdge_left, &Point1,radius1);
+ else
+ dist1 = _cvCalcEdgeIntersection(pEdge2, pEdge_left, &Point1,radius1);
+
+ if(dist1>=0)
+ break;
+
+ pEdge_left = pEdge_left->next_edge;
+ }
+
+ while(pEdge_right!=NULL)
+ {
+ if(pEdge_right->node1 == NULL)
+ {
+ pEdge_right_cur = pEdge_right = pEdge_right->prev_edge;
+ if(pEdge_right == NULL)
+ break;
+ }
+
+ if(left)
+ dist2 = _cvCalcEdgeIntersection(pEdge1, pEdge_right, &Point2, radius2);
+ else
+ dist2 = _cvCalcEdgeIntersection(pEdge2, pEdge_right, &Point2, radius2);
+
+ if(dist2>=0)
+ break;
+
+ pEdge_right = pEdge_right->prev_edge;
+ }
+
+ if(dist1<0&&dist2<0)
+ {
+ if(left)
+ {
+ pEdge_left = pSite_left->edge1;
+ if(pEdge_left==NULL)
+ _cvStickEdgeLeftEnd(pEdge1,NULL,pSite_left);
+ else
+ {
+ while(pEdge_left->node1!=NULL
+ &&pEdge_left->node1==pEdge_left->prev_edge->node2)
+ {
+ pEdge_left = pEdge_left->prev_edge;
+ if(pEdge_left==NULL || pEdge_left->prev_edge == NULL)
+ return 0;
+ }
+ _cvStickEdgeLeftEnd(pEdge1,pEdge_left,pSite_left);
+ }
+ }
+ if(right)
+ {
+ pEdge_right = pSite_right->edge2;
+ if(pEdge_right==NULL)
+ _cvStickEdgeRightEnd(pEdge2,NULL,pSite_right);
+ else
+ {
+ while(pEdge_right->node2!=NULL
+ && pEdge_right->node2==pEdge_right->next_edge->node1)
+ {
+ pEdge_right = pEdge_right->next_edge;
+ if(pEdge_right==NULL || pEdge_right->next_edge == NULL )
+ return 0;
+ }
+ _cvStickEdgeRightEnd(pEdge2,pEdge_right,pSite_right);
+ }
+ }
+ return 1;
+ }
+
+ if(fabs(dist1 - dist2)<dist_eps)
+ {
+ pNode_begin = _cvSeqPush(NodeSeq,&Node);
+ _cvInitVoronoiNode(pNode_begin, &Point2,radius2);
+
+ pEdge1->node2 = pNode_begin;
+ pEdge2->node1 = pNode_begin;
+
+ _cvStickEdgeLeftEnd(pEdge1,pEdge_left,pSite_left);
+ _cvTwinNULLLeft(pEdge_left_cur,pEdge_left);
+
+ _cvStickEdgeRightEnd(pEdge2,pEdge_right,pSite_right);
+ _cvTwinNULLRight(pEdge_right_cur,pEdge_right);
+
+ if(pEdge_left->twin_edge!=NULL&&pEdge_right->twin_edge!=NULL)
+ {
+ pEdge_left_prev = pEdge_left->twin_edge;
+ if(!pEdge_left_prev)
+ return 0;
+ pEdge_left_cur = pEdge_left_prev->next_edge;
+ pEdge_right_next = pEdge_right->twin_edge;
+ if(!pEdge_right_next)
+ return 0;
+ pEdge_right_cur = pEdge_right_next->prev_edge;
+ pSite_right = pEdge_right_next->site;
+ pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL);
+ pSite_left = pEdge_left_prev->site;
+ pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL);
+ continue;
+ }
+
+ if(pEdge_left->twin_edge==NULL&&pEdge_right->twin_edge!=NULL)
+ {
+ pEdge_right_next = pEdge_right->twin_edge;
+ if(!pEdge_right_next)
+ return 0;
+ pEdge_right_cur = pEdge_right_next->prev_edge;
+ pSite_right = pEdge_right_next->site;
+ pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL);
+ pEdge_left_cur = NULL;
+ left = false;
+ continue;
+ }
+
+ if(pEdge_left->twin_edge!=NULL&&pEdge_right->twin_edge==NULL)
+ {
+ pEdge_left_prev = pEdge_left->twin_edge;
+ if(!pEdge_left_prev)
+ return 0;
+ pEdge_left_cur = pEdge_left_prev->next_edge;
+ pSite_left = pEdge_left_prev->site;
+ pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL);
+ pEdge_right_cur = NULL;
+ right = false;
+ continue;
+ }
+ if(pEdge_left->twin_edge==NULL&&pEdge_right->twin_edge==NULL)
+ return 1;
+ }
+
+ if((dist1<dist2&&dist1>=0)||(dist1>=0&&dist2<0))
+ {
+
+ pNode_begin = _cvSeqPush(NodeSeq,&Node);
+ _cvInitVoronoiNode(pNode_begin, &Point1,radius1);
+ pEdge1->node2 = pNode_begin;
+ _cvTwinNULLLeft(pEdge_left_cur,pEdge_left);
+ _cvStickEdgeLeftEnd(pEdge1,pEdge_left,pSite_left);
+ if(right)
+ {
+ pEdge2->node1 = pNode_begin;
+ pEdge_right_next = pEdge2;
+ pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL);
+ if(pEdge_left->twin_edge!=NULL)
+ {
+ pEdge_left_prev = pEdge_left->twin_edge;
+ if(!pEdge_left_prev)
+ return 0;
+ pEdge_left_cur = pEdge_left_prev->next_edge;
+ pSite_left = pEdge_left_prev->site;
+ pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL);
+ continue;
+ }
+ else
+ {
+ pEdge_left_cur = NULL;
+ left = false;
+ continue;
+ }
+ }
+ else
+ {
+ if(pEdge_left->twin_edge!=NULL)
+ {
+ pEdge_left_prev = pEdge_left->twin_edge;
+ if(!pEdge_left_prev)
+ return 0;
+ pEdge_left_cur = pEdge_left_prev->next_edge;
+ pSite_left = pEdge_left_prev->site;
+ pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL);
+ continue;
+ }
+ else
+ return 1;
+
+ }
+
+ }
+
+ if((dist1>dist2&&dist2>=0)||(dist1<0&&dist2>=0))
+ {
+ pNode_begin = _cvSeqPush(NodeSeq,&Node);
+ _cvInitVoronoiNode(pNode_begin, &Point2,radius2);
+ pEdge2->node1 = pNode_begin;
+ _cvTwinNULLRight(pEdge_right_cur,pEdge_right);
+ _cvStickEdgeRightEnd(pEdge2,pEdge_right,pSite_right);
+ if(left)
+ {
+ pEdge1->node2 = pNode_begin;
+ pEdge_left_prev = pEdge1;
+ pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL);
+ if(pEdge_right->twin_edge!=NULL)
+ {
+ pEdge_right_next = pEdge_right->twin_edge;
+ if(!pEdge_right_next)
+ return 0;
+ pEdge_right_cur = pEdge_right_next->prev_edge;
+ pSite_right = pEdge_right_next->site;
+ pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL);
+ continue;
+ }
+ else
+ {
+ pEdge_right_cur = NULL;
+ right = false;
+ continue;
+ }
+ }
+ else
+ {
+ if(pEdge_right->twin_edge!=NULL)
+ {
+ pEdge_right_next = pEdge_right->twin_edge;
+ if(!pEdge_right_next)
+ return 0;
+ pEdge_right_cur = pEdge_right_next->prev_edge;
+ pSite_right = pEdge_right_next->site;
+ pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL);
+ continue;
+ }
+ else
+ return 1;
+ }
+
+ }
+ }
+
+}// end of _cvJoinChains
+
+static void _cvFindNearestSite(CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ pCvVoronoiHole pCurrHole, pHole = pVoronoiDiagram->top_hole;
+ pCvPointFloat pTopPoint,pPoint1,pPoint2;
+ CvPointFloat Direction;
+ pCvVoronoiSite pSite;
+ CvVoronoiNodeInt Node;
+ CvSeq* CurrSeq;
+ float min_distance,distance;
+ int i;
+ for(;pHole != NULL; pHole = pHole->next_hole)
+ {
+ if(pHole->error)
+ continue;
+ pTopPoint = &pHole->site_top->node1->node;
+ pCurrHole = NULL;
+ CurrSeq = pVoronoiDiagram->SiteSeq;
+ min_distance = (float)3e+34;
+ while(pCurrHole != pHole)
+ {
+ if(pCurrHole && pCurrHole->error)
+ continue;
+ pSite = (pCvVoronoiSite)cvGetSeqElem(CurrSeq,0);
+ if(CurrSeq->total == 1)
+ {
+ distance = _cvCalcDist(pTopPoint, pSite);
+ if(distance < min_distance)
+ {
+ min_distance = distance;
+ pHole->site_nearest = pSite;
+ }
+ }
+ else
+ {
+ for(i = 0; i < CurrSeq->total;i++, pSite = pSite->next_site)
+ {
+ if(pSite->node1 != pSite->node2)
+ {
+ pPoint1 = &pSite->node1->node;
+ pPoint2 = &pSite->node2->node;
+
+ Direction.x = -pSite->direction->y;
+ Direction.y = pSite->direction->x;
+
+ if(
+ (pTopPoint->x - pPoint2->x)*Direction.y -
+ (pTopPoint->y - pPoint2->y)*Direction.x > 0
+ ||
+ (pTopPoint->x - pPoint1->x)*Direction.y -
+ (pTopPoint->y - pPoint1->y)*Direction.x < 0
+ ||
+ (pTopPoint->x - pPoint1->x)*pSite->direction->y -
+ (pTopPoint->y - pPoint1->y)*pSite->direction->x > 0
+ )
+ continue;
+
+ distance = _cvCalcDist(pTopPoint, pSite);
+ }
+ else
+ {
+ pPoint1 = &pSite->node1->node;
+ if(
+ (pTopPoint->x - pPoint1->x)*pSite->edge2->direction->y -
+ (pTopPoint->y - pPoint1->y)*pSite->edge2->direction->x > 0
+ ||
+ (pTopPoint->x - pPoint1->x)*pSite->edge1->direction->y -
+ (pTopPoint->y - pPoint1->y)*pSite->edge1->direction->x < 0
+ )
+ continue;
+
+ distance = _cvCalcDist(pTopPoint, pSite);
+ }
+
+
+ if(distance < min_distance)
+ {
+ min_distance = distance;
+ pHole->site_nearest = pSite;
+ }
+ }
+ }
+
+ if(pCurrHole == NULL)
+ pCurrHole = pVoronoiDiagram->top_hole;
+ else
+ pCurrHole = pCurrHole->next_hole;
+
+ CurrSeq = pCurrHole->SiteSeq;
+ }
+ pHole->x_coord = min_distance;
+
+ if(pHole->site_nearest->node1 == pHole->site_nearest->node2)
+ {
+ Direction.x = (pHole->site_nearest->node1->node.x - pHole->site_top->node1->node.x)/2;
+ Direction.y = (pHole->site_nearest->node1->node.y - pHole->site_top->node1->node.y)/2;
+ }
+ else
+ {
+
+ Direction.x = pHole->site_nearest->direction->y * min_distance / 2;
+ Direction.y = - pHole->site_nearest->direction->x * min_distance / 2;
+ }
+
+ Node.node.x = pHole->site_top->node1->node.x + Direction.x;
+ Node.node.y = pHole->site_top->node1->node.y + Direction.y;
+ pHole->node = _cvSeqPush(pVoronoiDiagram->NodeSeq, &Node);
+ }
+}//end of _cvFindNearestSite
+
+static void _cvConstructIntVD(CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ pCvVoronoiChain pChain1, pChain2;
+ pCvVoronoiHole pHole;
+ int i;
+
+ pHole = pVoronoiDiagram->top_hole;
+
+ for(;pHole != NULL; pHole = pHole->next_hole)
+ {
+ if(pHole->ChainSeq->total == 0)
+ continue;
+ pChain1 = (pCvVoronoiChain)cvGetSeqElem(pHole->ChainSeq,0);
+ for(i = pHole->ChainSeq->total; i > 0;i--)
+ {
+ pChain2 = pChain1->next_chain;
+ if(!_cvJoinChains(pChain1,pChain2,pVoronoiDiagram))
+ {
+ pHole->error = true;
+ break;
+ }
+
+ pChain1->last_site = pChain2->last_site;
+ pChain1->next_chain = pChain2->next_chain;
+ pChain1 = pChain1->next_chain;
+ }
+ }
+}// end of _cvConstructIntVD
+
+static int _cvFindOppositSiteCW(pCvVoronoiHole pHole, CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ pCvVoronoiSite pSite_left = pHole->site_nearest;
+ pCvVoronoiSite pSite_right = pHole->site_top;
+ pCvVoronoiNode pNode = pHole->node;
+
+ CvDirection Direction = {-1,0};
+ CvVoronoiEdgeInt Edge_right = {NULL,pSite_right->node1,pSite_right,NULL,NULL,NULL,NULL,&Direction};
+
+ pCvVoronoiEdge pEdge_left = pSite_left->edge2->next_edge;
+ pCvVoronoiEdge pEdge_right = &Edge_right;
+
+ CvVoronoiEdgeInt Edge = {NULL,pNode,pSite_right,NULL,NULL,NULL,NULL,NULL};
+ CvVoronoiEdgeInt Edge_cur = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+ pCvVoronoiEdge pEdge = &Edge;
+
+ float radius1, radius2,dist1, dist2;
+ CvPointFloat Point1 = {0,0}, Point2 = {0,0};
+
+ for(;;)
+ {
+ pEdge->direction = NULL;
+ pEdge->parabola = NULL;
+ _cvCalcEdge(pSite_left,pSite_right,pEdge,pVoronoiDiagram);
+
+ dist1=dist2=-1;
+ radius1 = -1; radius2 = -2;
+ while(pEdge_left!=NULL)
+ {
+ dist1 = _cvCalcEdgeIntersection(pEdge, pEdge_left, &Point1,radius1);
+ if(dist1>=0)
+ break;
+ pEdge_left = pEdge_left->next_edge;
+ }
+
+ dist2 = _cvCalcEdgeIntersection(pEdge, pEdge_right, &Point2, radius2);
+ if(dist2>=0 && dist1 >= dist2)
+ {
+ pHole->site_opposite = pSite_left;
+ pNode->node = Point2;
+ return 1;
+ }
+
+ if(dist1<0)
+ return 0;
+
+ Edge_cur = *pEdge_left->twin_edge;
+ Edge_cur.node1 = pNode;
+ pEdge_left = &Edge_cur;
+
+ pSite_left = pEdge_left->site;
+ pNode->node = Point1;
+ }
+}//end of _cvFindOppositSiteCW
+
+static int _cvFindOppositSiteCCW(pCvVoronoiHole pHole,CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ pCvVoronoiSite pSite_right = pHole->site_nearest;
+ pCvVoronoiSite pSite_left = pHole->site_top;
+ pCvVoronoiNode pNode = pHole->node;
+
+ CvDirection Direction = {-1,0};
+ CvVoronoiEdgeInt Edge_left = {pSite_left->node1,NULL,pSite_left,NULL,NULL,NULL, NULL, &Direction};
+
+ pCvVoronoiEdge pEdge_left = &Edge_left;
+ pCvVoronoiEdge pEdge_right = pSite_right->edge1->prev_edge;
+
+ CvVoronoiEdgeInt Edge = {NULL,pNode,pSite_left,NULL,NULL,NULL,NULL};
+ CvVoronoiEdgeInt Edge_cur = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+ pCvVoronoiEdge pEdge = &Edge;
+
+ double dist1, dist2;
+ float radius1, radius2;
+ CvPointFloat Point1 = {0,0}, Point2 = {0,0};
+
+ for(;;)
+ {
+ pEdge->direction = NULL;
+ pEdge->parabola = NULL;
+ _cvCalcEdge(pSite_left,pSite_right,pEdge,pVoronoiDiagram);
+
+ dist1=dist2=-1;
+ radius1 = -1; radius2 = -2;
+ while(pEdge_right!=NULL)
+ {
+ dist1 = _cvCalcEdgeIntersection(pEdge, pEdge_right, &Point1,radius2);
+ if(dist1>=0)
+ break;
+ pEdge_right = pEdge_right->prev_edge;
+ }
+
+ dist2 = _cvCalcEdgeIntersection(pEdge, pEdge_left, &Point2, radius1);
+ if(dist2>=0 && dist1 > dist2)
+ {
+ pHole->site_opposite = pSite_right;
+ pNode->node = Point2;
+ return 1;
+ }
+
+ if(dist1<0)
+ return 0;
+
+ Edge_cur = *pEdge_right->twin_edge;
+ Edge_cur.node2 = pNode;
+ pEdge_right = &Edge_cur;
+
+ pSite_right = pEdge_right->site;
+ pNode->node = Point1;
+ }
+}//end of _cvFindOppositSiteCCW
+
+static int _cvMergeVD(pCvVoronoiHole pHole,CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ pCvVoronoiSite pSite_left_first = pHole->site_top;
+ pCvVoronoiSite pSite_right_first = pHole->site_opposite;
+ pCvVoronoiNode pNode_begin = pHole->node;
+ if(pSite_left_first == NULL || pSite_right_first == NULL || pNode_begin == NULL)
+ return 0;
+
+ pCvVoronoiSite pSite_left = pSite_left_first;
+ pCvVoronoiSite pSite_right = pSite_right_first;
+
+ const double dist_eps = 0.05;
+ CvVoronoiEdgeInt EdgeNULL = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+
+ CvSeq* NodeSeq = pVoronoiDiagram->NodeSeq;
+ CvSeq* EdgeSeq = pVoronoiDiagram->EdgeSeq;
+
+ pCvVoronoiEdge pEdge_left = NULL;
+ if(pSite_left->edge2 != NULL)
+ pEdge_left = pSite_left->edge2->next_edge;
+
+ pCvVoronoiEdge pEdge_right = pSite_right->edge1;
+ pCvVoronoiEdge pEdge_left_cur = pEdge_left;
+ pCvVoronoiEdge pEdge_right_cur = pEdge_right;
+
+ pCvVoronoiEdge pEdge_left_prev = NULL;
+ pCvVoronoiEdge pEdge_right_next = NULL;
+
+ pCvVoronoiEdge pEdge1,pEdge2,pEdge1_first, pEdge2_first;
+ CvPointFloat Point1 = {0,0}, Point2 = {0,0};
+
+ float radius1,radius2,dist1,dist2;
+
+ CvVoronoiNodeInt Node;
+
+ pEdge1_first = pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL);;
+ pEdge2_first = pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL);;
+ pEdge1->site = pSite_left_first;
+ pEdge2->site = pSite_right_first;
+
+ do
+ {
+ pEdge1->node1 = pEdge2->node2 = pNode_begin;
+
+ pEdge_left = pEdge_left_cur;
+ pEdge_right = pEdge_right_cur->prev_edge;
+
+ _cvCalcEdge(pSite_left,pSite_right,pEdge1,pVoronoiDiagram);
+ _cvMakeTwinEdge(pEdge2,pEdge1);
+
+ if(pEdge_left_prev != NULL)
+ _cvStickEdgeLeftBegin(pEdge1,pEdge_left_prev,pSite_left);
+ if(pEdge_right_next != NULL)
+ _cvStickEdgeRightBegin(pEdge2,pEdge_right_next,pSite_right);
+
+ dist1=dist2=-1;
+ radius1 = -1; radius2 = -2;
+
+//LEFT:
+ while(pEdge_left!=NULL)
+ {
+ if(pEdge_left->node2 == NULL)
+ pEdge_left_cur = pEdge_left = pEdge_left->next_edge;
+
+ dist1 = _cvCalcEdgeIntersection(pEdge1, pEdge_left, &Point1,radius1);
+ if(dist1>=0)
+ goto RIGHT;
+ pEdge_left = pEdge_left->next_edge;
+ }
+
+RIGHT:
+ while(pEdge_right!=NULL)
+ {
+ dist2 = _cvCalcEdgeIntersection(pEdge1, pEdge_right, &Point2,radius2);
+ if(dist2>=0)
+ goto RESULTHANDLING;
+
+ pEdge_right = pEdge_right->prev_edge;
+ }
+ pEdge_right = pEdge_right_cur;
+ dist2 = _cvCalcEdgeIntersection(pEdge1, pEdge_right, &Point2, radius2);
+
+RESULTHANDLING:
+ if(dist1<0&&dist2<0)
+ return 0;
+
+ if(fabs(dist1 - dist2)<dist_eps)
+ {
+ pNode_begin = _cvSeqPush(NodeSeq,&Node);
+ _cvInitVoronoiNode(pNode_begin, &Point2,radius2);
+
+ pEdge1->node2 = pNode_begin;
+ pEdge2->node1 = pNode_begin;
+
+ pEdge_right_cur = _cvDivideRightEdge(pEdge_right,pNode_begin,EdgeSeq);
+
+ _cvStickEdgeLeftEnd(pEdge1,pEdge_left,pSite_left);
+ _cvStickEdgeRightEnd(pEdge2,pEdge_right,pSite_right);
+
+ pEdge_left_prev = pEdge_left->twin_edge;
+ if(!pEdge_left_prev)
+ return 0;
+ pEdge_left_cur = pEdge_left_prev->next_edge;
+ pSite_left = pEdge_left_prev->site;
+ pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL);
+
+ pEdge_right_next = pEdge_right->twin_edge;
+ if(!pEdge_right_next)
+ return 0;
+ pSite_right = pEdge_right_next->site;
+ pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL);
+
+ continue;
+ }
+
+ if((dist1<dist2&&dist1>=0)||(dist1>=0&&dist2<0))
+ {
+ pNode_begin = _cvSeqPush(NodeSeq,&Node);
+ _cvInitVoronoiNode(pNode_begin, &Point1,radius1);
+
+ pEdge1->node2 = pNode_begin;
+ _cvStickEdgeLeftEnd(pEdge1,pEdge_left,pSite_left);
+
+ pEdge2->node1 = pNode_begin;
+ pEdge_right_next = pEdge2;
+ pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL);
+
+ pEdge_left_prev = pEdge_left->twin_edge;
+ if(!pEdge_left_prev)
+ return 0;
+ pEdge_left_cur = pEdge_left_prev->next_edge;
+ pSite_left = pEdge_left_prev->site;
+ pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL);
+
+ continue;
+ }
+
+ if((dist1>dist2&&dist2>=0)||(dist1<0&&dist2>=0))
+ {
+ pNode_begin = _cvSeqPush(NodeSeq,&Node);
+ _cvInitVoronoiNode(pNode_begin, &Point2,radius2);
+
+ pEdge_right_cur = _cvDivideRightEdge(pEdge_right,pNode_begin,EdgeSeq);
+
+ pEdge2->node1 = pNode_begin;
+ _cvStickEdgeRightEnd(pEdge2,pEdge_right,pSite_right);
+
+ pEdge1->node2 = pNode_begin;
+ pEdge_left_prev = pEdge1;
+ pEdge1 = _cvSeqPush(EdgeSeq, &EdgeNULL);
+
+ pEdge_right_next = pEdge_right->twin_edge;
+ if(!pEdge_right_next)
+ return 0;
+ pSite_right = pEdge_right_next->site;
+ pEdge2 = _cvSeqPush(EdgeSeq, &EdgeNULL);
+
+ continue;
+ }
+
+ }while(!(pSite_left == pSite_left_first && pSite_right == pSite_right_first));
+
+ pEdge1_first->node1 = pNode_begin;
+ pEdge2_first->node2 = pNode_begin;
+ _cvStickEdgeLeftBegin(pEdge1_first,pEdge_left_prev,pSite_left_first);
+ _cvStickEdgeRightBegin(pEdge2_first,pEdge_right_next,pSite_right_first);
+
+ if(pSite_left_first->edge2 == NULL)
+ pSite_left_first->edge2 = pSite_left_first->edge1 = pEdge1_first;
+ return 1;
+}// end of _cvMergeVD
+
+
+/* ///////////////////////////////////////////////////////////////////////////////////////
+// Computation of bisectors //
+/////////////////////////////////////////////////////////////////////////////////////// */
+
+void _cvCalcEdge(pCvVoronoiSite pSite_left,
+ pCvVoronoiSite pSite_right,
+ pCvVoronoiEdge pEdge,
+ CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ if((pSite_left->node1!=pSite_left->node2)&&
+ (pSite_right->node1!=pSite_right->node2))
+ _cvCalcEdgeLL(pSite_left->direction,
+ pSite_right->direction,
+ pEdge,pVoronoiDiagram);
+
+ else if((pSite_left->node1!=pSite_left->node2)&&
+ (pSite_right->node1 == pSite_right->node2))
+ _cvCalcEdgeLP(pSite_left,pSite_right->node1,pEdge,pVoronoiDiagram);
+
+ else if((pSite_left->node1==pSite_left->node2)&&
+ (pSite_right->node1!=pSite_right->node2))
+ _cvCalcEdgePL(pSite_left->node1,pSite_right,pEdge,pVoronoiDiagram);
+
+ else
+ _cvCalcEdgePP(&(pSite_left->node1->node),
+ &(pSite_right->node1->node),
+ pEdge,pVoronoiDiagram);
+}//end of _cvCalcEdge
+
+void _cvCalcEdge(pCvVoronoiSite pSite,
+ pCvVoronoiNode pNode,
+ pCvVoronoiEdge pEdge,
+ CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ if(pSite->node1!=pSite->node2)
+ _cvCalcEdgeLP(pSite, pNode, pEdge,pVoronoiDiagram);
+ else
+ _cvCalcEdgePP(&(pSite->node1->node),
+ &pNode->node,
+ pEdge,pVoronoiDiagram);
+}//end of _cvCalcEdge
+
+void _cvCalcEdge(pCvVoronoiNode pNode,
+ pCvVoronoiSite pSite,
+ pCvVoronoiEdge pEdge,
+ CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ if(pSite->node1!=pSite->node2)
+ _cvCalcEdgePL(pNode,pSite,pEdge,pVoronoiDiagram);
+ else
+ _cvCalcEdgePP(&pNode->node,&pSite->node1->node,pEdge,pVoronoiDiagram);
+}//end of _cvCalcEdge
+
+CV_INLINE
+void _cvCalcEdgeLL(pCvDirection pDirection1,
+ pCvDirection pDirection2,
+ pCvVoronoiEdge pEdge,
+ CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ CvDirection Direction = {pDirection2->x - pDirection1->x, pDirection2->y - pDirection1->y};
+ if((fabs(Direction.x)<LEE_CONST_ZERO)&&(fabs(Direction.y)<LEE_CONST_ZERO))
+ Direction = *pDirection2;
+ pEdge->direction = _cvSeqPush(pVoronoiDiagram->DirectionSeq,&Direction);;
+}//end of _cvCalcEdgeLL
+
+CV_INLINE
+void _cvCalcEdgePP(pCvPointFloat pPoint1,
+ pCvPointFloat pPoint2,
+ pCvVoronoiEdge pEdge,
+ CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ CvDirection Direction = {pPoint1->y - pPoint2->y,pPoint2->x - pPoint1->x};
+ pEdge->direction = _cvSeqPush(pVoronoiDiagram->DirectionSeq,&Direction);
+}//end of _cvCalcEdgePP
+
+CV_INLINE
+void _cvCalcEdgePL(pCvVoronoiNode pFocus,
+ pCvVoronoiSite pDirectrice,
+ pCvVoronoiEdge pEdge,
+ CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ pCvPointFloat pPoint0 = &pFocus->node;
+ pCvPointFloat pPoint1 = &pDirectrice->node1->node;
+
+ CvDirection Vector01 = {pPoint0->x - pPoint1->x,pPoint0->y - pPoint1->y};
+ float half_h = (Vector01.y*pDirectrice->direction->x - Vector01.x*pDirectrice->direction->y)/2;
+ CvDirection Normal = {-pDirectrice->direction->y,pDirectrice->direction->x};
+ if(half_h < LEE_CONST_ZERO)
+ {
+ pEdge->direction = _cvSeqPush(pVoronoiDiagram->DirectionSeq,&Normal);
+ return;
+ }
+ CvVoronoiParabolaInt Parabola;
+ pCvVoronoiParabola pParabola = _cvSeqPush(pVoronoiDiagram->ParabolaSeq,&Parabola);
+ float* map = pParabola->map;
+
+ map[1] = Normal.x;
+ map[4] = Normal.y;
+ map[0] = Normal.y;
+ map[3] = -Normal.x;
+ map[2] = pPoint0->x - Normal.x*half_h;
+ map[5] = pPoint0->y - Normal.y*half_h;
+
+ pParabola->a = 1/(4*half_h);
+ pParabola->focus = pFocus;
+ pParabola->directrice = pDirectrice;
+ pEdge->parabola = pParabola;
+}//end of _cvCalcEdgePL
+
+CV_INLINE
+void _cvCalcEdgeLP(pCvVoronoiSite pDirectrice,
+ pCvVoronoiNode pFocus,
+ pCvVoronoiEdge pEdge,
+ CvVoronoiDiagramInt* pVoronoiDiagram)
+{
+ pCvPointFloat pPoint0 = &pFocus->node;
+ pCvPointFloat pPoint1 = &pDirectrice->node1->node;
+
+ CvDirection Vector01 = {pPoint0->x - pPoint1->x,pPoint0->y - pPoint1->y};
+ float half_h = (Vector01.y*pDirectrice->direction->x - Vector01.x*pDirectrice->direction->y)/2;
+ CvDirection Normal = {-pDirectrice->direction->y,pDirectrice->direction->x};
+ if(half_h < LEE_CONST_ZERO)
+ {
+ pEdge->direction = _cvSeqPush(pVoronoiDiagram->DirectionSeq,&Normal);
+ return;
+ }
+ CvVoronoiParabolaInt Parabola;
+ pCvVoronoiParabola pParabola = _cvSeqPush(pVoronoiDiagram->ParabolaSeq,&Parabola);
+ float* map = pParabola->map;
+
+ map[1] = Normal.x;
+ map[4] = Normal.y;
+ map[0] = -Normal.y;
+ map[3] = Normal.x;
+ map[2] = pPoint0->x - Normal.x*half_h;
+ map[5] = pPoint0->y - Normal.y*half_h;
+
+ pParabola->a = 1/(4*half_h);
+ pParabola->focus = pFocus;
+ pParabola->directrice = pDirectrice;
+ pEdge->parabola = pParabola;
+}//end of _cvCalcEdgeLP
+
+/* ///////////////////////////////////////////////////////////////////////////////////////
+// Computation of intersections of bisectors //
+/////////////////////////////////////////////////////////////////////////////////////// */
+
+static
+float _cvCalcEdgeIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ CvPointFloat* pPoint,
+ float &Radius)
+{
+ if((pEdge1->parabola==NULL)&&(pEdge2->parabola==NULL))
+ return _cvLine_LineIntersection(pEdge1,pEdge2,pPoint,Radius);
+ if((pEdge1->parabola==NULL)&&(pEdge2->parabola!=NULL))
+ return _cvLine_ParIntersection(pEdge1,pEdge2,pPoint,Radius);
+ if((pEdge1->parabola!=NULL)&&(pEdge2->parabola==NULL))
+ return _cvPar_LineIntersection(pEdge1,pEdge2,pPoint,Radius);
+ if((pEdge1->parabola!=NULL)&&(pEdge2->parabola!=NULL))
+ return _cvPar_ParIntersection(pEdge1,pEdge2,pPoint,Radius);
+ return -1;
+}//end of _cvCalcEdgeIntersection
+
+static
+float _cvLine_LineIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius)
+{
+ if(((pEdge1->node1 == pEdge2->node1 ||
+ pEdge1->node1 == pEdge2->node2) &&
+ pEdge1->node1 != NULL)||
+ ((pEdge1->node2 == pEdge2->node1 ||
+ pEdge1->node2 == pEdge2->node2) &&
+ pEdge1->node2 != NULL))
+ return -1;
+
+ CvPointFloat Point1,Point3;
+ float det;
+ float k,m;
+ float x21,x43,y43,y21,x31,y31;
+
+ if(pEdge1->node1!=NULL)
+ {
+ Point1.x = pEdge1->node1->node.x;
+ Point1.y = pEdge1->node1->node.y;
+ }
+ else
+ {
+ Point1.x = pEdge1->node2->node.x;
+ Point1.y = pEdge1->node2->node.y;
+ }
+ x21 = pEdge1->direction->x;
+ y21 = pEdge1->direction->y;
+
+ if(pEdge2->node2==NULL)
+ {
+ Point3.x = pEdge2->node1->node.x;
+ Point3.y = pEdge2->node1->node.y;
+ x43 = pEdge2->direction->x;
+ y43 = pEdge2->direction->y;
+
+ }
+ else if(pEdge2->node1==NULL)
+ {
+ Point3.x = pEdge2->node2->node.x;
+ Point3.y = pEdge2->node2->node.y;
+ x43 = pEdge2->direction->x;
+ y43 = pEdge2->direction->y;
+ }
+ else
+ {
+ Point3.x = pEdge2->node1->node.x;
+ Point3.y = pEdge2->node1->node.y;
+ x43 = pEdge2->node2->node.x - Point3.x;
+ y43 = pEdge2->node2->node.y - Point3.y;
+ }
+
+ x31 = Point3.x - Point1.x;
+ y31 = Point3.y - Point1.y;
+
+ det = y21*x43 - x21*y43;
+ if(fabs(det) < LEE_CONST_ZERO)
+ return -1;
+
+ k = (x43*y31 - y43*x31)/det;
+ m = (x21*y31 - y21*x31)/det;
+
+ if(k<-LEE_CONST_ACCEPTABLE_ERROR||m<-LEE_CONST_ACCEPTABLE_ERROR)
+ return -1;
+ if(((pEdge1->node2!=NULL)&&(pEdge1->node1!=NULL))&&(k>1.f+LEE_CONST_ACCEPTABLE_ERROR))
+ return -1;
+ if(((pEdge2->node2!=NULL)&&(pEdge2->node1!=NULL))&&(m>1.f+LEE_CONST_ACCEPTABLE_ERROR))
+ return -1;
+
+ pPoint->x = (float)(k*x21) + Point1.x;
+ pPoint->y = (float)(k*y21) + Point1.y;
+
+ Radius = _cvCalcDist(pPoint,pEdge1->site);
+ return _cvPPDist(pPoint,&Point1);;
+}//end of _cvLine_LineIntersection
+
+static
+float _cvLine_ParIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius)
+{
+ if(pEdge2->node1==NULL||pEdge2->node2==NULL)
+ return _cvLine_OpenParIntersection(pEdge1,pEdge2,pPoint,Radius);
+ else
+ return _cvLine_CloseParIntersection(pEdge1,pEdge2,pPoint,Radius);
+}//end of _cvLine_ParIntersection
+
+static
+float _cvLine_OpenParIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius)
+{
+ int IntersectionNumber = 1;
+ if(((pEdge1->node1 == pEdge2->node1 ||
+ pEdge1->node1 == pEdge2->node2) &&
+ pEdge1->node1 != NULL)||
+ ((pEdge1->node2 == pEdge2->node1 ||
+ pEdge1->node2 == pEdge2->node2) &&
+ pEdge1->node2 != NULL))
+ IntersectionNumber = 2;
+
+ pCvPointFloat pRayPoint1;
+ if(pEdge1->node1!=NULL)
+ pRayPoint1 = &(pEdge1->node1->node);
+ else
+ pRayPoint1 = &(pEdge1->node2->node);
+
+ pCvDirection pDirection = pEdge1->direction;
+ float* Parabola = pEdge2->parabola->map;
+
+ pCvPointFloat pParPoint1;
+ if(pEdge2->node1==NULL)
+ pParPoint1 = &(pEdge2->node2->node);
+ else
+ pParPoint1 = &(pEdge2->node1->node);
+
+ float InversParabola[6];
+ _cvCalcOrtogInverse(InversParabola, Parabola);
+
+ CvPointFloat Point,ParPoint1_img,RayPoint1_img;
+ CvDirection Direction_img;
+ _cvCalcPointImage(&RayPoint1_img, pRayPoint1, InversParabola);
+ _cvCalcVectorImage(&Direction_img,pDirection, InversParabola);
+
+ float c2 = pEdge2->parabola->a*Direction_img.x;
+ float c1 = -Direction_img.y;
+ float c0 = Direction_img.y* RayPoint1_img.x - Direction_img.x*RayPoint1_img.y;
+ float X[2];
+ int N = _cvSolveEqu2thR(c2,c1,c0,X);
+ if(N==0)
+ return -1;
+
+ _cvCalcPointImage(&ParPoint1_img, pParPoint1, InversParabola);
+ int sign_x = SIGN(Direction_img.x);
+ int sign_y = SIGN(Direction_img.y);
+ if(N==1)
+ {
+ if(X[0]<ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR)
+ return -1;
+ float pr0 = (X[0]-RayPoint1_img.x)*sign_x + \
+ (pEdge2->parabola->a*X[0]*X[0]-RayPoint1_img.y)*sign_y;
+ if(pr0 <= -LEE_CONST_ACCEPTABLE_ERROR)
+ return -1;
+ }
+ else
+ {
+ if(X[1]<ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR)
+ return -1;
+ float pr0 = (X[0]-RayPoint1_img.x)*sign_x + \
+ (pEdge2->parabola->a*X[0]*X[0]-RayPoint1_img.y)*sign_y;
+ float pr1 = (X[1]-RayPoint1_img.x)*sign_x + \
+ (pEdge2->parabola->a*X[1]*X[1]-RayPoint1_img.y)*sign_y;
+
+ if(pr0 <= -LEE_CONST_ACCEPTABLE_ERROR &&pr1 <= -LEE_CONST_ACCEPTABLE_ERROR)
+ return -1;
+
+ if(pr0 >- LEE_CONST_ACCEPTABLE_ERROR && pr1 >- LEE_CONST_ACCEPTABLE_ERROR)
+ {
+ if(X[0] >= ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR)
+ {
+ if(pr0>pr1)
+ _cvSwap(X[0],X[1]);
+ }
+ else
+ {
+ N=1;
+ X[0] = X[1];
+ }
+ }
+ else if(pr0 >- LEE_CONST_ACCEPTABLE_ERROR)
+ {
+ N = 1;
+ if(X[0] < ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR)
+ return -1;
+ }
+ else if(pr1 >- LEE_CONST_ACCEPTABLE_ERROR)
+ {
+ N=1;
+ X[0] = X[1];
+ }
+ else
+ return -1;
+ }
+
+ Point.x = X[(N-1)*(IntersectionNumber - 1)];
+ Point.y = pEdge2->parabola->a*Point.x*Point.x;
+
+ Radius = Point.y + 1.f/(4*pEdge2->parabola->a);
+ _cvCalcPointImage(pPoint,&Point,Parabola);
+ float dist = _cvPPDist(pPoint, pRayPoint1);
+ if(IntersectionNumber == 2 && dist < LEE_CONST_DIFF_POINTS)
+ return -1;
+ else
+ return dist;
+}// end of _cvLine_OpenParIntersection
+
+static
+float _cvLine_CloseParIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius)
+{
+ int IntersectionNumber = 1;
+ if(((pEdge1->node1 == pEdge2->node1 ||
+ pEdge1->node1 == pEdge2->node2) &&
+ pEdge1->node1 != NULL)||
+ ((pEdge1->node2 == pEdge2->node1 ||
+ pEdge1->node2 == pEdge2->node2) &&
+ pEdge1->node2 != NULL))
+ IntersectionNumber = 2;
+
+ pCvPointFloat pRayPoint1;
+ if(pEdge1->node1!=NULL)
+ pRayPoint1 = &(pEdge1->node1->node);
+ else
+ pRayPoint1 = &(pEdge1->node2->node);
+
+ pCvDirection pDirection = pEdge1->direction;
+ float* Parabola = pEdge2->parabola->map;
+
+ pCvPointFloat pParPoint1,pParPoint2;
+ pParPoint2 = &(pEdge2->node1->node);
+ pParPoint1 = &(pEdge2->node2->node);
+
+
+ float InversParabola[6];
+ _cvCalcOrtogInverse(InversParabola, Parabola);
+
+ CvPointFloat Point,ParPoint1_img,ParPoint2_img,RayPoint1_img;
+ CvDirection Direction_img;
+ _cvCalcPointImage(&RayPoint1_img, pRayPoint1, InversParabola);
+ _cvCalcVectorImage(&Direction_img,pDirection, InversParabola);
+
+ float c2 = pEdge2->parabola->a*Direction_img.x;
+ float c1 = -Direction_img.y;
+ float c0 = Direction_img.y* RayPoint1_img.x - Direction_img.x*RayPoint1_img.y;
+ float X[2];
+ int N = _cvSolveEqu2thR(c2,c1,c0,X);
+ if(N==0)
+ return -1;
+
+ _cvCalcPointImage(&ParPoint1_img, pParPoint1, InversParabola);
+ _cvCalcPointImage(&ParPoint2_img, pParPoint2, InversParabola);
+ if(ParPoint1_img.x>ParPoint2_img.x)
+ _cvSwap(ParPoint1_img,ParPoint2_img);
+ int sign_x = SIGN(Direction_img.x);
+ int sign_y = SIGN(Direction_img.y);
+ if(N==1)
+ {
+ if((X[0]<ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR) ||
+ (X[0]>ParPoint2_img.x + LEE_CONST_ACCEPTABLE_ERROR))
+ return -1;
+ float pr0 = (X[0]-RayPoint1_img.x)*sign_x + \
+ (pEdge2->parabola->a*X[0]*X[0]-RayPoint1_img.y)*sign_y;
+ if(pr0 <= -LEE_CONST_ACCEPTABLE_ERROR)
+ return -1;
+ }
+ else
+ {
+ if((X[1]<ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR) ||
+ (X[0]>ParPoint2_img.x + LEE_CONST_ACCEPTABLE_ERROR))
+ return -1;
+
+ if((X[0]<ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR) &&
+ (X[1]>ParPoint2_img.x + LEE_CONST_ACCEPTABLE_ERROR))
+ return -1;
+
+ float pr0 = (X[0]-RayPoint1_img.x)*sign_x + \
+ (pEdge2->parabola->a*X[0]*X[0]-RayPoint1_img.y)*sign_y;
+ float pr1 = (X[1]-RayPoint1_img.x)*sign_x + \
+ (pEdge2->parabola->a*X[1]*X[1]-RayPoint1_img.y)*sign_y;
+
+ if(pr0 <= -LEE_CONST_ACCEPTABLE_ERROR && pr1 <= -LEE_CONST_ACCEPTABLE_ERROR)
+ return -1;
+
+ if(pr0 > -LEE_CONST_ACCEPTABLE_ERROR && pr1 > -LEE_CONST_ACCEPTABLE_ERROR)
+ {
+ if(X[0] >= ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR)
+ {
+ if(X[1] <= ParPoint2_img.x + LEE_CONST_ACCEPTABLE_ERROR)
+ {
+ if(pr0>pr1)
+ _cvSwap(X[0], X[1]);
+ }
+ else
+ N=1;
+ }
+ else
+ {
+ N=1;
+ X[0] = X[1];
+ }
+ }
+ else if(pr0 > -LEE_CONST_ACCEPTABLE_ERROR)
+ {
+
+ if(X[0] >= ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR)
+ N=1;
+ else
+ return -1;
+ }
+ else if(pr1 > -LEE_CONST_ACCEPTABLE_ERROR)
+ {
+ if(X[1] <= ParPoint2_img.x + LEE_CONST_ACCEPTABLE_ERROR)
+ {
+ N=1;
+ X[0] = X[1];
+ }
+ else
+ return -1;
+ }
+ else
+ return -1;
+ }
+
+ Point.x = X[(N-1)*(IntersectionNumber - 1)];
+ Point.y = pEdge2->parabola->a*Point.x*Point.x;
+ Radius = Point.y + 1.f/(4*pEdge2->parabola->a);
+ _cvCalcPointImage(pPoint,&Point,Parabola);
+ float dist = _cvPPDist(pPoint, pRayPoint1);
+ if(IntersectionNumber == 2 && dist < LEE_CONST_DIFF_POINTS)
+ return -1;
+ else
+ return dist;
+}// end of _cvLine_CloseParIntersection
+
+static
+float _cvPar_LineIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius)
+{
+ if(pEdge2->node1==NULL||pEdge2->node2==NULL)
+ return _cvPar_OpenLineIntersection(pEdge1,pEdge2,pPoint,Radius);
+ else
+ return _cvPar_CloseLineIntersection(pEdge1,pEdge2,pPoint,Radius);
+}//end _cvPar_LineIntersection
+
+static
+float _cvPar_OpenLineIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius)
+{
+ int i, IntersectionNumber = 1;
+ if(((pEdge1->node1 == pEdge2->node1 ||
+ pEdge1->node1 == pEdge2->node2) &&
+ pEdge1->node1 != NULL)||
+ ((pEdge1->node2 == pEdge2->node1 ||
+ pEdge1->node2 == pEdge2->node2) &&
+ pEdge1->node2 != NULL))
+ IntersectionNumber = 2;
+
+ float* Parabola = pEdge1->parabola->map;
+ pCvPointFloat pParPoint1;
+ if(pEdge1->node1!=NULL)
+ pParPoint1 = &(pEdge1->node1->node);
+ else
+ pParPoint1 = &(pEdge1->node2->node);
+
+ pCvPointFloat pRayPoint1;
+ if(pEdge2->node1==NULL)
+ pRayPoint1 = &(pEdge2->node2->node);
+ else
+ pRayPoint1 = &(pEdge2->node1->node);
+ pCvDirection pDirection = pEdge2->direction;
+
+
+ float InversParabola[6];
+ _cvCalcOrtogInverse(InversParabola, Parabola);
+
+ CvPointFloat Point = {0,0},ParPoint1_img,RayPoint1_img;
+ CvDirection Direction_img;
+ _cvCalcVectorImage(&Direction_img,pDirection, InversParabola);
+ _cvCalcPointImage(&RayPoint1_img, pRayPoint1, InversParabola);
+
+
+ float q = RayPoint1_img.y - pEdge1->parabola->a*RayPoint1_img.x*RayPoint1_img.x;
+ if(pEdge2->site->node1 == pEdge2->site->node2 && q < 0 ||
+ pEdge2->site->node1 != pEdge2->site->node2 && q > 0)
+ return -1;
+
+ float c2 = pEdge1->parabola->a*Direction_img.x;
+ float c1 = -Direction_img.y;
+ float c0 = Direction_img.y* RayPoint1_img.x - Direction_img.x*RayPoint1_img.y;
+ float X[2];
+ int N = _cvSolveEqu2thR(c2,c1,c0,X);
+ if(N==0)
+ return -1;
+
+ _cvCalcPointImage(&ParPoint1_img, pParPoint1, InversParabola);
+ int sign_x = SIGN(Direction_img.x);
+ int sign_y = SIGN(Direction_img.y);
+ float pr;
+
+ if(N==2 && IntersectionNumber == 2)
+ _cvSwap(X[0], X[1]);
+
+ for( i=0;i<N;i++)
+ {
+ if(X[i]<=ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR)
+ continue;
+ pr = (X[i]-RayPoint1_img.x)*sign_x +
+ (pEdge1->parabola->a*X[i]*X[i]-RayPoint1_img.y)*sign_y;
+ if(pr <= -LEE_CONST_ACCEPTABLE_ERROR)
+ continue;
+ else
+ {
+ Point.x = X[i];
+ break;
+ }
+ }
+
+ if(i==N)
+ return -1;
+
+ Point.y = pEdge1->parabola->a*Point.x*Point.x;
+ Radius = Point.y + 1.f/(4*pEdge1->parabola->a);
+ _cvCalcPointImage(pPoint,&Point,Parabola);
+ float dist = Point.x - ParPoint1_img.x;
+ if(IntersectionNumber == 2 && dist < LEE_CONST_DIFF_POINTS)
+ return -1;
+ else
+ return dist;
+}// end of _cvPar_OpenLineIntersection
+
+static
+float _cvPar_CloseLineIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius)
+{
+ int i, IntersectionNumber = 1;
+ if(((pEdge1->node1 == pEdge2->node1 ||
+ pEdge1->node1 == pEdge2->node2) &&
+ pEdge1->node1 != NULL)||
+ ((pEdge1->node2 == pEdge2->node1 ||
+ pEdge1->node2 == pEdge2->node2) &&
+ pEdge1->node2 != NULL))
+ IntersectionNumber = 2;
+
+ float* Parabola = pEdge1->parabola->map;
+ pCvPointFloat pParPoint1;
+ if(pEdge1->node1!=NULL)
+ pParPoint1 = &(pEdge1->node1->node);
+ else
+ pParPoint1 = &(pEdge1->node2->node);
+
+ pCvPointFloat pRayPoint1,pRayPoint2;
+ pRayPoint2 = &(pEdge2->node1->node);
+ pRayPoint1 = &(pEdge2->node2->node);
+
+ pCvDirection pDirection = pEdge2->direction;
+ float InversParabola[6];
+ _cvCalcOrtogInverse(InversParabola, Parabola);
+
+ CvPointFloat Point={0,0},ParPoint1_img,RayPoint1_img,RayPoint2_img;
+ CvDirection Direction_img;
+ _cvCalcPointImage(&RayPoint1_img, pRayPoint1, InversParabola);
+ _cvCalcPointImage(&RayPoint2_img, pRayPoint2, InversParabola);
+
+ float q;
+ if(Radius == -1)
+ {
+ q = RayPoint1_img.y - pEdge1->parabola->a*RayPoint1_img.x*RayPoint1_img.x;
+ if(pEdge2->site->node1 == pEdge2->site->node2 && q < 0 ||
+ pEdge2->site->node1 != pEdge2->site->node2 && q > 0)
+ return -1;
+ }
+ if(Radius == -2)
+ {
+ q = RayPoint2_img.y - pEdge1->parabola->a*RayPoint2_img.x*RayPoint2_img.x;
+ if(pEdge2->site->node1 == pEdge2->site->node2 && q < 0 ||
+ pEdge2->site->node1 != pEdge2->site->node2 && q > 0)
+ return -1;
+ }
+
+ _cvCalcPointImage(&ParPoint1_img, pParPoint1, InversParabola);
+ _cvCalcVectorImage(&Direction_img,pDirection, InversParabola);
+
+ float c2 = pEdge1->parabola->a*Direction_img.x;
+ float c1 = -Direction_img.y;
+ float c0 = Direction_img.y* RayPoint1_img.x - Direction_img.x*RayPoint1_img.y;
+ float X[2];
+ int N = _cvSolveEqu2thR(c2,c1,c0,X);
+ if(N==0)
+ return -1;
+ int sign_x = SIGN(RayPoint2_img.x - RayPoint1_img.x);
+ int sign_y = SIGN(RayPoint2_img.y - RayPoint1_img.y);
+ float pr_dir = (RayPoint2_img.x - RayPoint1_img.x)*sign_x +
+ (RayPoint2_img.y - RayPoint1_img.y)*sign_y;
+ float pr;
+
+ if(N==2 && IntersectionNumber == 2)
+ _cvSwap(X[0], X[1]);
+
+ for( i =0;i<N;i++)
+ {
+ if(X[i] <= ParPoint1_img.x - LEE_CONST_ACCEPTABLE_ERROR)
+ continue;
+ pr = (X[i]-RayPoint1_img.x)*sign_x + \
+ (pEdge1->parabola->a*X[i]*X[i]-RayPoint1_img.y)*sign_y;
+ if(pr <= -LEE_CONST_ACCEPTABLE_ERROR || pr>=pr_dir + LEE_CONST_ACCEPTABLE_ERROR)
+ continue;
+ else
+ {
+ Point.x = X[i];
+ break;
+ }
+ }
+
+ if(i==N)
+ return -1;
+
+ Point.y = pEdge1->parabola->a*Point.x*Point.x;
+ Radius = Point.y + 1.f/(4*pEdge1->parabola->a);
+ _cvCalcPointImage(pPoint,&Point,Parabola);
+ float dist = Point.x - ParPoint1_img.x;
+ if(IntersectionNumber == 2 && dist < LEE_CONST_DIFF_POINTS)
+ return -1;
+ else
+ return dist;
+}// end of _cvPar_CloseLineIntersection
+
+static
+float _cvPar_ParIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius)
+{
+ if(pEdge2->node1==NULL||pEdge2->node2==NULL)
+ return _cvPar_OpenParIntersection(pEdge1,pEdge2,pPoint,Radius);
+ else
+ return _cvPar_CloseParIntersection(pEdge1,pEdge2,pPoint,Radius);
+}// end of _cvPar_ParIntersection
+
+static
+float _cvPar_OpenParIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius)
+{
+ int i, IntersectionNumber = 1;
+ if(((pEdge1->node1 == pEdge2->node1 ||
+ pEdge1->node1 == pEdge2->node2) &&
+ pEdge1->node1 != NULL)||
+ ((pEdge1->node2 == pEdge2->node1 ||
+ pEdge1->node2 == pEdge2->node2) &&
+ pEdge1->node2 != NULL))
+ IntersectionNumber = 2;
+
+ float* Parabola1 = pEdge1->parabola->map;
+ pCvPointFloat pPar1Point1;
+ if(pEdge1->node1!=NULL)
+ pPar1Point1 = &(pEdge1->node1->node);
+ else
+ pPar1Point1 = &(pEdge1->node2->node);
+
+ float* Parabola2 = pEdge2->parabola->map;
+ pCvPointFloat pPar2Point1;
+ if(pEdge2->node1!=NULL)
+ pPar2Point1 = &(pEdge2->node1->node);
+ else
+ pPar2Point1 = &(pEdge2->node2->node);
+
+ CvPointFloat Point;
+ CvDirection Direction;
+ if(pEdge1->parabola->directrice==pEdge2->parabola->directrice) //common site is segment -> different focuses
+ {
+ pCvPointFloat pFocus1 = &(pEdge1->parabola->focus->node);
+ pCvPointFloat pFocus2 = &(pEdge2->parabola->focus->node);
+
+ Point.x = (pFocus1->x + pFocus2->x)/2;
+ Point.y = (pFocus1->y + pFocus2->y)/2;
+ Direction.x = pFocus1->y - pFocus2->y;
+ Direction.y = pFocus2->x - pFocus1->x;
+ }
+ else//common site is focus -> different directrices
+ {
+ pCvVoronoiSite pDirectrice1 = pEdge1->parabola->directrice;
+ pCvPointFloat pPoint1 = &(pDirectrice1->node1->node);
+ pCvDirection pVector21 = pDirectrice1->direction;
+
+ pCvVoronoiSite pDirectrice2 = pEdge2->parabola->directrice;
+ pCvPointFloat pPoint3 = &(pDirectrice2->node1->node);
+ pCvDirection pVector43 = pDirectrice2->direction;
+
+ Direction.x = pVector43->x - pVector21->x;
+ Direction.y = pVector43->y - pVector21->y;
+
+ if((fabs(Direction.x) < LEE_CONST_ZERO) &&
+ (fabs(Direction.y) < LEE_CONST_ZERO))
+ Direction = *pVector43;
+
+ float det = pVector21->y * pVector43->x - pVector21->x * pVector43->y;
+ if(fabs(det) < LEE_CONST_ZERO)
+ {
+ Point.x = (pPoint1->x + pPoint3->x)/2;
+ Point.y = (pPoint1->y + pPoint3->y)/2;
+ }
+ else
+ {
+ float d1 = pVector21->y*pPoint1->x - pVector21->x*pPoint1->y;
+ float d2 = pVector43->y*pPoint3->x - pVector43->x*pPoint3->y;
+ Point.x = (float)((pVector43->x*d1 - pVector21->x*d2)/det);
+ Point.y = (float)((pVector43->y*d1 - pVector21->y*d2)/det);
+ }
+ }
+
+ float InversParabola2[6];
+ _cvCalcOrtogInverse(InversParabola2, Parabola2);
+
+ CvPointFloat Par2Point1_img,Point_img;
+ CvDirection Direction_img;
+ _cvCalcVectorImage(&Direction_img,&Direction, InversParabola2);
+ _cvCalcPointImage(&Point_img, &Point, InversParabola2);
+
+ float a1 = pEdge1->parabola->a;
+ float a2 = pEdge2->parabola->a;
+ float c2 = a2*Direction_img.x;
+ float c1 = -Direction_img.y;
+ float c0 = Direction_img.y* Point_img.x - Direction_img.x*Point_img.y;
+ float X[2];
+ int N = _cvSolveEqu2thR(c2,c1,c0,X);
+
+ if(N==0)
+ return -1;
+
+ _cvCalcPointImage(&Par2Point1_img, pPar2Point1, InversParabola2);
+
+ if(X[N-1]<Par2Point1_img.x)
+ return -1;
+
+ if(X[0]<Par2Point1_img.x)
+ {
+ X[0] = X[1];
+ N=1;
+ }
+
+ float InversParabola1[6];
+ CvPointFloat Par1Point1_img;
+ _cvCalcOrtogInverse(InversParabola1, Parabola1);
+ _cvCalcPointImage(&Par1Point1_img, pPar1Point1, InversParabola1);
+ float InvPar1_Par2[6];
+ _cvCalcComposition(InvPar1_Par2,InversParabola1,Parabola2);
+ for(i=0;i<N;i++)
+ X[i] = (InvPar1_Par2[1]*a2*X[i] + InvPar1_Par2[0])*X[i] + InvPar1_Par2[2];
+
+ if(N!=1)
+ {
+ if((X[0]>X[1] && IntersectionNumber == 1)||
+ (X[0]<X[1] && IntersectionNumber == 2))
+ _cvSwap(X[0], X[1]);
+ }
+
+ for(i = 0;i<N;i++)
+ {
+ Point.x = X[i];
+ Point.y = a1*Point.x*Point.x;
+ if(Point.x < Par1Point1_img.x - LEE_CONST_ACCEPTABLE_ERROR)
+ continue;
+ else
+ break;
+ }
+
+ if(i==N)
+ return -1;
+
+ Radius = Point.y + 1.f/(4*pEdge1->parabola->a);
+ _cvCalcPointImage(pPoint,&Point,Parabola1);
+ float dist = Point.x - Par1Point1_img.x;
+ if(IntersectionNumber == 2 && dist < LEE_CONST_DIFF_POINTS)
+ return -1;
+ else
+ return dist;
+}// end of _cvPar_OpenParIntersection
+
+static
+float _cvPar_CloseParIntersection(pCvVoronoiEdge pEdge1,
+ pCvVoronoiEdge pEdge2,
+ pCvPointFloat pPoint,
+ float &Radius)
+{
+ int i, IntersectionNumber = 1;
+ if(((pEdge1->node1 == pEdge2->node1 ||
+ pEdge1->node1 == pEdge2->node2) &&
+ pEdge1->node1 != NULL)||
+ ((pEdge1->node2 == pEdge2->node1 ||
+ pEdge1->node2 == pEdge2->node2) &&
+ pEdge1->node2 != NULL))
+ IntersectionNumber = 2;
+
+ float* Parabola1 = pEdge1->parabola->map;
+ float* Parabola2 = pEdge2->parabola->map;
+ pCvPointFloat pPar1Point1;
+ if(pEdge1->node1!=NULL)
+ pPar1Point1 = &(pEdge1->node1->node);
+ else
+ pPar1Point1 = &(pEdge1->node2->node);
+
+ pCvPointFloat pPar2Point1 = &(pEdge2->node1->node);
+ pCvPointFloat pPar2Point2 = &(pEdge2->node2->node);
+
+ CvPointFloat Point;
+ CvDirection Direction;
+ if(pEdge1->parabola->directrice==pEdge2->parabola->directrice) //common site is segment -> different focuses
+ {
+ pCvPointFloat pFocus1 = &(pEdge1->parabola->focus->node);
+ pCvPointFloat pFocus2 = &(pEdge2->parabola->focus->node);
+
+ Point.x = (pFocus1->x + pFocus2->x)/2;
+ Point.y = (pFocus1->y + pFocus2->y)/2;
+ Direction.x = pFocus1->y - pFocus2->y;
+ Direction.y = pFocus2->x - pFocus1->x;
+ }
+ else//common site is focus -> different directrices
+ {
+ pCvVoronoiSite pDirectrice1 = pEdge1->parabola->directrice;
+ pCvPointFloat pPoint1 = &(pDirectrice1->node1->node);
+ pCvDirection pVector21 = pDirectrice1->direction;
+
+ pCvVoronoiSite pDirectrice2 = pEdge2->parabola->directrice;
+ pCvPointFloat pPoint3 = &(pDirectrice2->node1->node);
+ pCvDirection pVector43 = pDirectrice2->direction;
+
+ Direction.x = pVector43->x - pVector21->x;
+ Direction.y = pVector43->y - pVector21->y;
+
+ if((fabs(Direction.x) < LEE_CONST_ZERO) &&
+ (fabs(Direction.y) < LEE_CONST_ZERO))
+ Direction = *pVector43;
+
+ float det = pVector21->y * pVector43->x - pVector21->x * pVector43->y;
+ if(fabs(det) < LEE_CONST_ZERO)
+ {
+ Point.x = (pPoint1->x + pPoint3->x)/2;
+ Point.y = (pPoint1->y + pPoint3->y)/2;
+ }
+ else
+ {
+ float d1 = pVector21->y*pPoint1->x - pVector21->x*pPoint1->y;
+ float d2 = pVector43->y*pPoint3->x - pVector43->x*pPoint3->y;
+ Point.x = (float)((pVector43->x*d1 - pVector21->x*d2)/det);
+ Point.y = (float)((pVector43->y*d1 - pVector21->y*d2)/det);
+ }
+ }
+
+
+
+ float InversParabola2[6];
+ _cvCalcOrtogInverse(InversParabola2, Parabola2);
+
+ CvPointFloat Par2Point1_img,Par2Point2_img,Point_img;
+ CvDirection Direction_img;
+ _cvCalcVectorImage(&Direction_img,&Direction, InversParabola2);
+ _cvCalcPointImage(&Point_img, &Point, InversParabola2);
+
+ float a1 = pEdge1->parabola->a;
+ float a2 = pEdge2->parabola->a;
+ float c2 = a2*Direction_img.x;
+ float c1 = -Direction_img.y;
+ float c0 = Direction_img.y* Point_img.x - Direction_img.x*Point_img.y;
+ float X[2];
+ int N = _cvSolveEqu2thR(c2,c1,c0,X);
+
+ if(N==0)
+ return -1;
+
+ _cvCalcPointImage(&Par2Point1_img, pPar2Point1, InversParabola2);
+ _cvCalcPointImage(&Par2Point2_img, pPar2Point2, InversParabola2);
+ if(Par2Point1_img.x>Par2Point2_img.x)
+ _cvSwap(Par2Point1_img,Par2Point2_img);
+
+ if(X[0]>Par2Point2_img.x||X[N-1]<Par2Point1_img.x)
+ return -1;
+
+ if(X[0]<Par2Point1_img.x)
+ {
+ if(X[1]<Par2Point2_img.x)
+ {
+ X[0] = X[1];
+ N=1;
+ }
+ else
+ return -1;
+ }
+ else if(X[N-1]>Par2Point2_img.x)
+ N=1;
+
+ float InversParabola1[6];
+ CvPointFloat Par1Point1_img;
+ _cvCalcOrtogInverse(InversParabola1, Parabola1);
+ _cvCalcPointImage(&Par1Point1_img, pPar1Point1, InversParabola1);
+ float InvPar1_Par2[6];
+ _cvCalcComposition(InvPar1_Par2,InversParabola1,Parabola2);
+ for(i=0;i<N;i++)
+ X[i] = (InvPar1_Par2[1]*a2*X[i] + InvPar1_Par2[0])*X[i] + InvPar1_Par2[2];
+
+ if(N!=1)
+ {
+ if((X[0]>X[1] && IntersectionNumber == 1)||
+ (X[0]<X[1] && IntersectionNumber == 2))
+ _cvSwap(X[0], X[1]);
+ }
+
+
+ for(i = 0;i<N;i++)
+ {
+ Point.x = (float)X[i];
+ Point.y = (float)a1*Point.x*Point.x;
+ if(Point.x < Par1Point1_img.x - LEE_CONST_ACCEPTABLE_ERROR)
+ continue;
+ else
+ break;
+ }
+
+ if(i==N)
+ return -1;
+
+ Radius = Point.y + 1.f/(4*a1);
+ _cvCalcPointImage(pPoint,&Point,Parabola1);
+ float dist = Point.x - Par1Point1_img.x;
+ if(IntersectionNumber == 2 && dist < LEE_CONST_DIFF_POINTS)
+ return -1;
+ else
+ return dist;
+}// end of _cvPar_CloseParIntersection
+
+/* ///////////////////////////////////////////////////////////////////////////////////////
+// Subsidiary functions //
+/////////////////////////////////////////////////////////////////////////////////////// */
+
+CV_INLINE
+void _cvMakeTwinEdge(pCvVoronoiEdge pEdge2,
+ pCvVoronoiEdge pEdge1)
+{
+ pEdge2->direction = pEdge1->direction;
+ pEdge2->parabola = pEdge1->parabola;
+ pEdge2->node1 = pEdge1->node2;
+ pEdge2->twin_edge = pEdge1;
+ pEdge1->twin_edge = pEdge2;
+}//end of _cvMakeTwinEdge
+
+CV_INLINE
+void _cvStickEdgeLeftBegin(pCvVoronoiEdge pEdge,
+ pCvVoronoiEdge pEdge_left_prev,
+ pCvVoronoiSite pSite_left)
+{
+ pEdge->prev_edge = pEdge_left_prev;
+ pEdge->site = pSite_left;
+ if(pEdge_left_prev == NULL)
+ pSite_left->edge2 = pEdge;
+ else
+ {
+ pEdge_left_prev->node2 = pEdge->node1;
+ pEdge_left_prev->next_edge = pEdge;
+ }
+}//end of _cvStickEdgeLeftBegin
+
+CV_INLINE
+void _cvStickEdgeRightBegin(pCvVoronoiEdge pEdge,
+ pCvVoronoiEdge pEdge_right_next,
+ pCvVoronoiSite pSite_right)
+{
+ pEdge->next_edge = pEdge_right_next;
+ pEdge->site = pSite_right;
+ if(pEdge_right_next == NULL)
+ pSite_right->edge1 = pEdge;
+ else
+ {
+ pEdge_right_next->node1 = pEdge->node2;
+ pEdge_right_next->prev_edge = pEdge;
+ }
+}// end of _cvStickEdgeRightBegin
+
+CV_INLINE
+void _cvStickEdgeLeftEnd(pCvVoronoiEdge pEdge,
+ pCvVoronoiEdge pEdge_left_next,
+ pCvVoronoiSite pSite_left)
+{
+ pEdge->next_edge = pEdge_left_next;
+ if(pEdge_left_next == NULL)
+ pSite_left->edge1 = pEdge;
+ else
+ {
+ pEdge_left_next->node1 = pEdge->node2;
+ pEdge_left_next->prev_edge = pEdge;
+ }
+}//end of _cvStickEdgeLeftEnd
+
+CV_INLINE
+void _cvStickEdgeRightEnd(pCvVoronoiEdge pEdge,
+ pCvVoronoiEdge pEdge_right_prev,
+ pCvVoronoiSite pSite_right)
+{
+ pEdge->prev_edge = pEdge_right_prev;
+ if(pEdge_right_prev == NULL)
+ pSite_right->edge2 = pEdge;
+ else
+ {
+ pEdge_right_prev->node2 = pEdge->node1;
+ pEdge_right_prev->next_edge = pEdge;
+ }
+}//end of _cvStickEdgeRightEnd
+
+template <class T> CV_INLINE
+void _cvInitVoronoiNode(pCvVoronoiNode pNode,
+ T pPoint,
+ float radius)
+{
+ pNode->node.x = (float)pPoint->x;
+ pNode->node.y = (float)pPoint->y;
+ pNode->radius = radius;
+}//end of _cvInitVoronoiNode
+
+CV_INLINE
+void _cvInitVoronoiSite(pCvVoronoiSite pSite,
+ pCvVoronoiNode pNode1,
+ pCvVoronoiNode pNode2,
+ pCvVoronoiSite pPrev_site)
+{
+ pSite->node1 = pNode1;
+ pSite->node2 = pNode2;
+ pSite->prev_site = pPrev_site;
+}//end of _cvInitVoronoiSite
+
+template <class T> CV_INLINE
+T _cvSeqPush(CvSeq* Seq, T pElem)
+{
+ cvSeqPush(Seq, pElem);
+ return (T)(Seq->ptr - Seq->elem_size);
+// return (T)cvGetSeqElem(Seq, Seq->total - 1,NULL);
+}//end of _cvSeqPush
+
+template <class T> CV_INLINE
+T _cvSeqPushFront(CvSeq* Seq, T pElem)
+{
+ cvSeqPushFront(Seq,pElem);
+ return (T)Seq->first->data;
+// return (T)cvGetSeqElem(Seq,0,NULL);
+}//end of _cvSeqPushFront
+
+CV_INLINE
+void _cvTwinNULLLeft(pCvVoronoiEdge pEdge_left_cur,
+ pCvVoronoiEdge pEdge_left)
+{
+ while(pEdge_left_cur!=pEdge_left)
+ {
+ if(pEdge_left_cur->twin_edge!=NULL)
+ pEdge_left_cur->twin_edge->twin_edge = NULL;
+ pEdge_left_cur = pEdge_left_cur->next_edge;
+ }
+}//end of _cvTwinNULLLeft
+
+CV_INLINE
+void _cvTwinNULLRight(pCvVoronoiEdge pEdge_right_cur,
+ pCvVoronoiEdge pEdge_right)
+{
+ while(pEdge_right_cur!=pEdge_right)
+ {
+ if(pEdge_right_cur->twin_edge!=NULL)
+ pEdge_right_cur->twin_edge->twin_edge = NULL;
+ pEdge_right_cur = pEdge_right_cur->prev_edge;
+ }
+}//end of _cvTwinNULLRight
+
+CV_INLINE
+void _cvSeqPushInOrder(CvVoronoiDiagramInt* pVoronoiDiagram, pCvVoronoiHole pHole)
+{
+ pHole = _cvSeqPush(pVoronoiDiagram->HoleSeq, pHole);
+ if(pVoronoiDiagram->HoleSeq->total == 1)
+ {
+ pVoronoiDiagram->top_hole = pHole;
+ return;
+ }
+
+ pCvVoronoiHole pTopHole = pVoronoiDiagram->top_hole;
+ pCvVoronoiHole pCurrHole;
+ if(pTopHole->x_coord >= pHole->x_coord)
+ {
+ pHole->next_hole = pTopHole;
+ pVoronoiDiagram->top_hole = pHole;
+ return;
+ }
+
+ for(pCurrHole = pTopHole; \
+ pCurrHole->next_hole != NULL; \
+ pCurrHole = pCurrHole->next_hole)
+ if(pCurrHole->next_hole->x_coord >= pHole->x_coord)
+ break;
+ pHole->next_hole = pCurrHole->next_hole;
+ pCurrHole->next_hole = pHole;
+}//end of _cvSeqPushInOrder
+
+CV_INLINE
+pCvVoronoiEdge _cvDivideRightEdge(pCvVoronoiEdge pEdge,pCvVoronoiNode pNode, CvSeq* EdgeSeq)
+{
+ CvVoronoiEdgeInt Edge1 = *pEdge;
+ CvVoronoiEdgeInt Edge2 = *pEdge->twin_edge;
+ pCvVoronoiEdge pEdge1, pEdge2;
+
+ pEdge1 = _cvSeqPush(EdgeSeq, &Edge1);
+ pEdge2 = _cvSeqPush(EdgeSeq, &Edge2);
+
+ if(pEdge1->next_edge != NULL)
+ pEdge1->next_edge->prev_edge = pEdge1;
+ pEdge1->prev_edge = NULL;
+
+ if(pEdge2->prev_edge != NULL)
+ pEdge2->prev_edge->next_edge = pEdge2;
+ pEdge2->next_edge = NULL;
+
+ pEdge1->node1 = pEdge2->node2= pNode;
+ pEdge1->twin_edge = pEdge2;
+ pEdge2->twin_edge = pEdge1;
+ return pEdge2;
+}//end of _cvDivideRightEdge
+
+CV_INLINE
+pCvVoronoiEdge _cvDivideLeftEdge(pCvVoronoiEdge pEdge,pCvVoronoiNode pNode, CvSeq* EdgeSeq)
+{
+ CvVoronoiEdgeInt Edge1 = *pEdge;
+ CvVoronoiEdgeInt Edge2 = *pEdge->twin_edge;
+ pCvVoronoiEdge pEdge1, pEdge2;
+
+ pEdge1 = _cvSeqPush(EdgeSeq, &Edge1);
+ pEdge2 = _cvSeqPush(EdgeSeq, &Edge2);
+
+ if(pEdge2->next_edge != NULL)
+ pEdge2->next_edge->prev_edge = pEdge2;
+ pEdge2->prev_edge = NULL;
+
+ if(pEdge1->prev_edge != NULL)
+ pEdge1->prev_edge->next_edge = pEdge1;
+ pEdge1->next_edge = NULL;
+
+ pEdge1->node2 = pEdge2->node1= pNode;
+ pEdge1->twin_edge = pEdge2;
+ pEdge2->twin_edge = pEdge1;
+ return pEdge2;
+}//end of _cvDivideLeftEdge
+
+template<class T> CV_INLINE
+T _cvWriteSeqElem(T pElem, CvSeqWriter &writer)
+{
+ if( writer.ptr >= writer.block_max )
+ cvCreateSeqBlock( &writer);
+
+ T ptr = (T)writer.ptr;
+ memcpy(writer.ptr, pElem, sizeof(*pElem));
+ writer.ptr += sizeof(*pElem);
+ return ptr;
+}//end of _cvWriteSeqElem
+
+/* ///////////////////////////////////////////////////////////////////////////////////////
+// Mathematical functions //
+/////////////////////////////////////////////////////////////////////////////////////// */
+
+template<class T> CV_INLINE
+void _cvCalcPointImage(pCvPointFloat pImgPoint,pCvPointFloat pPoint,T* A)
+{
+ pImgPoint->x = (float)(A[0]*pPoint->x + A[1]*pPoint->y + A[2]);
+ pImgPoint->y = (float)(A[3]*pPoint->x + A[4]*pPoint->y + A[5]);
+}//end of _cvCalcPointImage
+
+template <class T> CV_INLINE
+void _cvSwap(T &x, T &y)
+{
+ T z; z=x; x=y; y=z;
+}//end of _cvSwap
+
+template <class T> CV_INLINE
+int _cvCalcOrtogInverse(T* B, T* A)
+{
+ int sign_det = SIGN(A[0]*A[4] - A[1]*A[3]);
+
+ if(sign_det)
+ {
+ B[0] = A[4]*sign_det;
+ B[1] = -A[1]*sign_det;
+ B[3] = -A[3]*sign_det;
+ B[4] = A[0]*sign_det;
+ B[2] = - (B[0]*A[2]+B[1]*A[5]);
+ B[5] = - (B[3]*A[2]+B[4]*A[5]);
+ return 1;
+ }
+ else
+ return 0;
+}//end of _cvCalcOrtogInverse
+
+template<class T> CV_INLINE
+void _cvCalcVectorImage(pCvDirection pImgVector,pCvDirection pVector,T* A)
+{
+ pImgVector->x = A[0]*pVector->x + A[1]*pVector->y;
+ pImgVector->y = A[3]*pVector->x + A[4]*pVector->y;
+}//end of _cvCalcVectorImage
+
+template <class T> CV_INLINE
+void _cvCalcComposition(T* Result,T* A,T* B)
+{
+ Result[0] = A[0]*B[0] + A[1]*B[3];
+ Result[1] = A[0]*B[1] + A[1]*B[4];
+ Result[3] = A[3]*B[0] + A[4]*B[3];
+ Result[4] = A[3]*B[1] + A[4]*B[4];
+ Result[2] = A[0]*B[2] + A[1]*B[5] + A[2];
+ Result[5] = A[3]*B[2] + A[4]*B[5] + A[5];
+}//end of _cvCalcComposition
+
+CV_INLINE
+float _cvCalcDist(pCvPointFloat pPoint, pCvVoronoiSite pSite)
+{
+ if(pSite->node1==pSite->node2)
+ return _cvPPDist(pPoint,&(pSite->node1->node));
+ else
+ return _cvPLDist(pPoint,&(pSite->node1->node),pSite->direction);
+}//end of _cvCalcComposition
+
+CV_INLINE
+float _cvPPDist(pCvPointFloat pPoint1,pCvPointFloat pPoint2)
+{
+ float delta_x = pPoint1->x - pPoint2->x;
+ float delta_y = pPoint1->y - pPoint2->y;
+ return (float)sqrt((double)delta_x*delta_x + delta_y*delta_y);
+}//end of _cvPPDist
+
+
+CV_INLINE
+float _cvPLDist(pCvPointFloat pPoint,pCvPointFloat pPoint1,pCvDirection pDirection)
+{
+ return (float)fabs(pDirection->x*(pPoint->y - pPoint1->y) -
+ pDirection->y*(pPoint->x - pPoint1->x));
+}//end of _cvPLDist
+
+template <class T>
+int _cvSolveEqu2thR(T c2, T c1, T c0, T* X)
+{
+ const T eps = (T)1e-6;
+ if(fabs(c2)<eps)
+ return _cvSolveEqu1th(c1,c0,X);
+
+ T Discr = c1*c1 - c2*c0*4;
+ if(Discr<-eps)
+ return 0;
+ Discr = (T)sqrt((double)fabs(Discr));
+
+ if(fabs(Discr)<eps)
+ {
+ X[0] = -c1/(c2*2);
+ if(fabs(X[0])<eps)
+ X[0]=0;
+ return 1;
+ }
+ else
+ {
+ if(c1 >=0)
+ {
+ if(c2>0)
+ {
+ X[0] = (-c1 - Discr)/(2*c2);
+ X[1] = -2*c0/(c1+Discr);
+ return 2;
+ }
+ else
+ {
+ X[1] = (-c1 - Discr)/(2*c2);
+ X[0] = -2*c0/(c1+Discr);
+ return 2;
+ }
+ }
+ else
+ {
+ if(c2>0)
+ {
+ X[1] = (-c1 + Discr)/(2*c2);
+ X[0] = -2*c0/(c1-Discr);
+ return 2;
+ }
+ else
+ {
+ X[0] = (-c1 + Discr)/(2*c2);
+ X[1] = -2*c0/(c1-Discr);
+ return 2;
+ }
+ }
+ }
+}//end of _cvSolveEqu2thR
+
+template <class T> CV_INLINE
+int _cvSolveEqu1th(T c1, T c0, T* X)
+{
+ const T eps = (T)1e-6;
+ if(fabs(c1)<eps)
+ return 0;
+
+ X[0] = -c0/c1;
+ return 1;
+}//end of _cvSolveEqu1th
diff --git a/cvaux/src/cvlevmar.cpp b/cvaux/src/cvlevmar.cpp
new file mode 100644
index 0000000..d8a8529
--- /dev/null
+++ b/cvaux/src/cvlevmar.cpp
@@ -0,0 +1,320 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+#include "cvtypes.h"
+#include <float.h>
+#include <limits.h>
+#include "cv.h"
+
+/* Valery Mosyagin */
+
+//#define TRACKLEVMAR
+
+typedef void (*pointer_LMJac)( const CvMat* src, CvMat* dst );
+typedef void (*pointer_LMFunc)( const CvMat* src, CvMat* dst );
+
+/* Optimization using Levenberg-Marquardt */
+void cvLevenbergMarquardtOptimization(pointer_LMJac JacobianFunction,
+ pointer_LMFunc function,
+ /*pointer_Err error_function,*/
+ CvMat *X0,CvMat *observRes,CvMat *resultX,
+ int maxIter,double epsilon)
+{
+ /* This is not sparce method */
+ /* Make optimization using */
+ /* func - function to compute */
+ /* uses function to compute jacobian */
+
+ /* Allocate memory */
+ CvMat *vectX = 0;
+ CvMat *vectNewX = 0;
+ CvMat *resFunc = 0;
+ CvMat *resNewFunc = 0;
+ CvMat *error = 0;
+ CvMat *errorNew = 0;
+ CvMat *Jac = 0;
+ CvMat *delta = 0;
+ CvMat *matrJtJ = 0;
+ CvMat *matrJtJN = 0;
+ CvMat *matrJt = 0;
+ CvMat *vectB = 0;
+
+ CV_FUNCNAME( "cvLevenbegrMarquardtOptimization" );
+ __BEGIN__;
+
+
+ if( JacobianFunction == 0 || function == 0 || X0 == 0 || observRes == 0 || resultX == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(X0) || !CV_IS_MAT(observRes) || !CV_IS_MAT(resultX) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Some of input parameters must be a matrices" );
+ }
+
+
+ int numVal;
+ int numFunc;
+ double valError;
+ double valNewError;
+
+ numVal = X0->rows;
+ numFunc = observRes->rows;
+
+ /* test input data */
+ if( X0->cols != 1 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of colomn of vector X0 must be 1" );
+ }
+
+ if( observRes->cols != 1 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of colomn of vector observed rusult must be 1" );
+ }
+
+ if( resultX->cols != 1 || resultX->rows != numVal )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of result vector X must be equals to X0" );
+ }
+
+ if( maxIter <= 0 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of maximum iteration must be > 0" );
+ }
+
+ if( epsilon < 0 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Epsilon must be >= 0" );
+ }
+
+ /* copy x0 to current value of x */
+ CV_CALL( vectX = cvCreateMat(numVal, 1, CV_64F) );
+ CV_CALL( vectNewX = cvCreateMat(numVal, 1, CV_64F) );
+ CV_CALL( resFunc = cvCreateMat(numFunc,1, CV_64F) );
+ CV_CALL( resNewFunc = cvCreateMat(numFunc,1, CV_64F) );
+ CV_CALL( error = cvCreateMat(numFunc,1, CV_64F) );
+ CV_CALL( errorNew = cvCreateMat(numFunc,1, CV_64F) );
+ CV_CALL( Jac = cvCreateMat(numFunc,numVal, CV_64F) );
+ CV_CALL( delta = cvCreateMat(numVal, 1, CV_64F) );
+ CV_CALL( matrJtJ = cvCreateMat(numVal, numVal, CV_64F) );
+ CV_CALL( matrJtJN = cvCreateMat(numVal, numVal, CV_64F) );
+ CV_CALL( matrJt = cvCreateMat(numVal, numFunc,CV_64F) );
+ CV_CALL( vectB = cvCreateMat(numVal, 1, CV_64F) );
+
+ cvCopy(X0,vectX);
+
+ /* ========== Main optimization loop ============ */
+ double change;
+ int currIter;
+ double alpha;
+
+ change = 1;
+ currIter = 0;
+ alpha = 0.001;
+
+ do {
+
+ /* Compute value of function */
+ function(vectX,resFunc);
+ /* Print result of function to file */
+
+ /* Compute error */
+ cvSub(observRes,resFunc,error);
+
+ //valError = error_function(observRes,resFunc);
+ /* Need to use new version of computing error (norm) */
+ valError = cvNorm(observRes,resFunc);
+
+ /* Compute Jacobian for given point vectX */
+ JacobianFunction(vectX,Jac);
+
+ /* Define optimal delta for J'*J*delta=J'*error */
+ /* compute J'J */
+ cvMulTransposed(Jac,matrJtJ,1);
+
+ cvCopy(matrJtJ,matrJtJN);
+
+ /* compute J'*error */
+ cvTranspose(Jac,matrJt);
+ cvmMul(matrJt,error,vectB);
+
+
+ /* Solve normal equation for given alpha and Jacobian */
+ do
+ {
+ /* Increase diagonal elements by alpha */
+ for( int i = 0; i < numVal; i++ )
+ {
+ double val;
+ val = cvmGet(matrJtJ,i,i);
+ cvmSet(matrJtJN,i,i,(1+alpha)*val);
+ }
+
+ /* Solve system to define delta */
+ cvSolve(matrJtJN,vectB,delta,CV_SVD);
+
+ /* We know delta and we can define new value of vector X */
+ cvAdd(vectX,delta,vectNewX);
+
+ /* Compute result of function for new vector X */
+ function(vectNewX,resNewFunc);
+ cvSub(observRes,resNewFunc,errorNew);
+
+ valNewError = cvNorm(observRes,resNewFunc);
+
+ currIter++;
+
+ if( valNewError < valError )
+ {/* accept new value */
+ valError = valNewError;
+
+ /* Compute relative change of required parameter vectorX. change = norm(curr-prev) / norm(curr) ) */
+ change = cvNorm(vectX, vectNewX, CV_RELATIVE_L2);
+
+ alpha /= 10;
+ cvCopy(vectNewX,vectX);
+ break;
+ }
+ else
+ {
+ alpha *= 10;
+ }
+
+ } while ( currIter < maxIter );
+ /* new value of X and alpha were accepted */
+
+ } while ( change > epsilon && currIter < maxIter );
+
+
+ /* result was computed */
+ cvCopy(vectX,resultX);
+
+ __END__;
+
+ cvReleaseMat(&vectX);
+ cvReleaseMat(&vectNewX);
+ cvReleaseMat(&resFunc);
+ cvReleaseMat(&resNewFunc);
+ cvReleaseMat(&error);
+ cvReleaseMat(&errorNew);
+ cvReleaseMat(&Jac);
+ cvReleaseMat(&delta);
+ cvReleaseMat(&matrJtJ);
+ cvReleaseMat(&matrJtJN);
+ cvReleaseMat(&matrJt);
+ cvReleaseMat(&vectB);
+
+ return;
+}
+
+/*------------------------------------------------------------------------------*/
+#if 0
+//tests
+void Jac_Func2(CvMat *vectX,CvMat *Jac)
+{
+ double x = cvmGet(vectX,0,0);
+ double y = cvmGet(vectX,1,0);
+ cvmSet(Jac,0,0,2*(x-2));
+ cvmSet(Jac,0,1,2*(y+3));
+
+ cvmSet(Jac,1,0,1);
+ cvmSet(Jac,1,1,1);
+ return;
+}
+
+void Res_Func2(CvMat *vectX,CvMat *res)
+{
+ double x = cvmGet(vectX,0,0);
+ double y = cvmGet(vectX,1,0);
+ cvmSet(res,0,0,(x-2)*(x-2)+(y+3)*(y+3));
+ cvmSet(res,1,0,x+y);
+
+ return;
+}
+
+
+double Err_Func2(CvMat *obs,CvMat *res)
+{
+ CvMat *tmp;
+ tmp = cvCreateMat(obs->rows,1,CV_64F);
+ cvSub(obs,res,tmp);
+
+ double e;
+ e = cvNorm(tmp);
+
+ return e;
+}
+
+
+void TestOptimX2Y2()
+{
+ CvMat vectX0;
+ double vectX0_dat[2];
+ vectX0 = cvMat(2,1,CV_64F,vectX0_dat);
+ vectX0_dat[0] = 5;
+ vectX0_dat[1] = -7;
+
+ CvMat observRes;
+ double observRes_dat[2];
+ observRes = cvMat(2,1,CV_64F,observRes_dat);
+ observRes_dat[0] = 0;
+ observRes_dat[1] = -1;
+ observRes_dat[0] = 0;
+ observRes_dat[1] = -1.2;
+
+ CvMat optimX;
+ double optimX_dat[2];
+ optimX = cvMat(2,1,CV_64F,optimX_dat);
+
+
+ LevenbegrMarquardtOptimization( Jac_Func2, Res_Func2, Err_Func2,
+ &vectX0,&observRes,&optimX,100,0.000001);
+
+ return;
+
+}
+
+#endif
+
+
+
diff --git a/cvaux/src/cvlevmarprojbandle.cpp b/cvaux/src/cvlevmarprojbandle.cpp
new file mode 100644
index 0000000..54c8dea
--- /dev/null
+++ b/cvaux/src/cvlevmarprojbandle.cpp
@@ -0,0 +1,1783 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+
+#include "_cvaux.h"
+//#include "cvtypes.h"
+#include <float.h>
+#include <limits.h>
+//#include "cv.h"
+
+#include <stdio.h>
+
+void icvReconstructPoints4DStatus(CvMat** projPoints, CvMat **projMatrs, CvMat** presPoints, CvMat *points4D,int numImages,CvMat **projError=0);
+
+/* Valery Mosyagin */
+
+/* If you want to save internal debug info to files uncomment next lines and set paths to files if need */
+/* Note these file may be very large */
+/*
+#define TRACK_BUNDLE
+#define TRACK_BUNDLE_FILE "d:\\test\\bundle.txt"
+#define TRACK_BUNDLE_FILE_JAC "d:\\test\\bundle.txt"
+#define TRACK_BUNDLE_FILE_JACERRPROJ "d:\\test\\JacErrProj.txt"
+#define TRACK_BUNDLE_FILE_JACERRPNT "d:\\test\\JacErrPoint.txt"
+#define TRACK_BUNDLE_FILE_MATRW "d:\\test\\matrWt.txt"
+#define TRACK_BUNDLE_FILE_DELTAP "d:\\test\\deltaP.txt"
+*/
+#define TRACK_BUNDLE_FILE "d:\\test\\bundle.txt"
+
+
+/* ============== Bundle adjustment optimization ================= */
+void icvComputeDerivateProj(CvMat *points4D,CvMat *projMatr, CvMat *status, CvMat *derivProj)
+{
+ /* Compute derivate for given projection matrix points and status of points */
+
+ CV_FUNCNAME( "icvComputeDerivateProj" );
+ __BEGIN__;
+
+
+ /* ----- Test input params for errors ----- */
+ if( points4D == 0 || projMatr == 0 || status == 0 || derivProj == 0)
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(points4D) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "points4D must be a matrix 4xN" );
+ }
+
+ /* Compute number of points */
+ int numPoints;
+ numPoints = points4D->cols;
+
+ if( numPoints < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of points4D must be more than zero" );
+ }
+
+ if( points4D->rows != 4 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of coordinates of points4D must be 4" );
+ }
+
+ if( !CV_IS_MAT(projMatr) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "projMatr must be a matrix 3x4" );
+ }
+
+ if( projMatr->rows != 3 || projMatr->cols != 4 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Size of projection matrix (projMatr) must be 3x4" );
+ }
+
+ if( !CV_IS_MAT(status) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Status must be a matrix 1xN" );
+ }
+
+ if( status->rows != 1 || status->cols != numPoints )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Size of status of points must be 1xN" );
+ }
+
+ if( !CV_IS_MAT(derivProj) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "derivProj must be a matrix VisN x 12" );
+ }
+
+ if( derivProj->cols != 12 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "derivProj must be a matrix VisN x 12" );
+ }
+ /* ----- End test ----- */
+
+ int i;
+
+ /* Allocate memory for derivates */
+
+ double p[12];
+ /* Copy projection matrix */
+ for( i = 0; i < 12; i++ )
+ {
+ p[i] = cvmGet(projMatr,i/4,i%4);
+ }
+
+ /* Fill deriv matrix */
+ int currVisPoint;
+ int currPoint;
+
+ currVisPoint = 0;
+ for( currPoint = 0; currPoint < numPoints; currPoint++ )
+ {
+ if( cvmGet(status,0,currPoint) > 0 )
+ {
+ double X[4];
+ X[0] = cvmGet(points4D,0,currVisPoint);
+ X[1] = cvmGet(points4D,1,currVisPoint);
+ X[2] = cvmGet(points4D,2,currVisPoint);
+ X[3] = cvmGet(points4D,3,currVisPoint);
+
+ /* Compute derivate for this point */
+
+ double piX[3];
+ piX[0] = X[0]*p[0] + X[1]*p[1] + X[2]*p[2] + X[3]*p[3];
+ piX[1] = X[0]*p[4] + X[1]*p[5] + X[2]*p[6] + X[3]*p[7];
+ piX[2] = X[0]*p[8] + X[1]*p[9] + X[2]*p[10] + X[3]*p[11];
+
+ int i;
+ /* fill derivate by point */
+
+ double tmp3 = 1/(piX[2]*piX[2]);
+
+ double tmp1 = -piX[0]*tmp3;
+ double tmp2 = -piX[1]*tmp3;
+
+ /* fill derivate by projection matrix */
+ for( i = 0; i < 4; i++ )
+ {
+ /* derivate for x */
+ cvmSet(derivProj,currVisPoint*2,i,X[i]/piX[2]);//x' p1i
+ cvmSet(derivProj,currVisPoint*2,4+i,0);//x' p1i
+ cvmSet(derivProj,currVisPoint*2,8+i,X[i]*tmp1);//x' p3i
+
+ /* derivate for y */
+ cvmSet(derivProj,currVisPoint*2+1,i,0);//y' p2i
+ cvmSet(derivProj,currVisPoint*2+1,4+i,X[i]/piX[2]);//y' p2i
+ cvmSet(derivProj,currVisPoint*2+1,8+i,X[i]*tmp2);//y' p3i
+ }
+
+ currVisPoint++;
+ }
+ }
+
+ if( derivProj->rows != currVisPoint * 2 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "derivProj must be a matrix 2VisN x 12" );
+ }
+
+
+ __END__;
+ return;
+}
+/*======================================================================================*/
+
+void icvComputeDerivateProjAll(CvMat *points4D, CvMat **projMatrs, CvMat **pointPres, int numImages,CvMat **projDerives)
+{
+ CV_FUNCNAME( "icvComputeDerivateProjAll" );
+ __BEGIN__;
+
+ /* ----- Test input params for errors ----- */
+ if( numImages < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of images must more than zero" );
+ }
+ if( projMatrs == 0 || pointPres == 0 || projDerives == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+ /* ----- End test ----- */
+
+ int currImage;
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ icvComputeDerivateProj(points4D,projMatrs[currImage], pointPres[currImage], projDerives[currImage]);
+ }
+
+ __END__;
+ return;
+}
+/*======================================================================================*/
+
+void icvComputeDerivatePoints(CvMat *points4D,CvMat *projMatr, CvMat *presPoints, CvMat *derivPoint)
+{
+
+ CV_FUNCNAME( "icvComputeDerivatePoints" );
+ __BEGIN__;
+
+ /* ----- Test input params for errors ----- */
+ if( points4D == 0 || projMatr == 0 || presPoints == 0 || derivPoint == 0)
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(points4D) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "points4D must be a matrix N x 4" );
+ }
+
+ int numPoints;
+ numPoints = presPoints->cols;
+
+ if( numPoints < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of points must be more than zero" );
+ }
+
+ if( points4D->rows != 4 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "points4D must be a matrix N x 4" );
+ }
+
+ if( !CV_IS_MAT(projMatr) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "projMatr must be a matrix 3x4" );
+ }
+
+ if( projMatr->rows != 3 || projMatr->cols != 4 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Size of projection matrix (projMatr) must be 3x4" );
+ }
+
+ if( !CV_IS_MAT(presPoints) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Status must be a matrix 1xN" );
+ }
+
+ if( presPoints->rows != 1 || presPoints->cols != numPoints )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Size of presPoints status must be 1xN" );
+ }
+
+ if( !CV_IS_MAT(derivPoint) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "derivPoint must be a matrix 2 x 4VisNum" );
+ }
+ /* ----- End test ----- */
+
+ /* Compute derivates by points */
+
+ double p[12];
+ int i;
+ for( i = 0; i < 12; i++ )
+ {
+ p[i] = cvmGet(projMatr,i/4,i%4);
+ }
+
+ int currVisPoint;
+ int currProjPoint;
+
+ currVisPoint = 0;
+ for( currProjPoint = 0; currProjPoint < numPoints; currProjPoint++ )
+ {
+ if( cvmGet(presPoints,0,currProjPoint) > 0 )
+ {
+ double X[4];
+ X[0] = cvmGet(points4D,0,currProjPoint);
+ X[1] = cvmGet(points4D,1,currProjPoint);
+ X[2] = cvmGet(points4D,2,currProjPoint);
+ X[3] = cvmGet(points4D,3,currProjPoint);
+
+ double piX[3];
+ piX[0] = X[0]*p[0] + X[1]*p[1] + X[2]*p[2] + X[3]*p[3];
+ piX[1] = X[0]*p[4] + X[1]*p[5] + X[2]*p[6] + X[3]*p[7];
+ piX[2] = X[0]*p[8] + X[1]*p[9] + X[2]*p[10] + X[3]*p[11];
+
+ int i,j;
+
+ double tmp3 = 1/(piX[2]*piX[2]);
+
+ for( j = 0; j < 2; j++ )//for x and y
+ {
+ for( i = 0; i < 4; i++ )// for X,Y,Z,W
+ {
+ cvmSet( derivPoint,
+ j, currVisPoint*4+i,
+ (p[j*4+i]*piX[2]-p[8+i]*piX[j]) * tmp3 );
+ }
+ }
+ currVisPoint++;
+ }
+ }
+
+ if( derivPoint->rows != 2 || derivPoint->cols != currVisPoint*4 )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "derivPoint must be a matrix 2 x 4VisNum" );
+ }
+
+ __END__;
+ return;
+}
+/*======================================================================================*/
+void icvComputeDerivatePointsAll(CvMat *points4D, CvMat **projMatrs, CvMat **pointPres, int numImages,CvMat **pointDerives)
+{
+ CV_FUNCNAME( "icvComputeDerivatePointsAll" );
+ __BEGIN__;
+
+ /* ----- Test input params for errors ----- */
+ if( numImages < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of images must more than zero" );
+ }
+ if( projMatrs == 0 || pointPres == 0 || pointDerives == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+ /* ----- End test ----- */
+
+ int currImage;
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ icvComputeDerivatePoints(points4D, projMatrs[currImage], pointPres[currImage], pointDerives[currImage]);
+ }
+
+ __END__;
+ return;
+}
+/*======================================================================================*/
+void icvComputeMatrixVAll(int numImages,CvMat **pointDeriv,CvMat **presPoints, CvMat **matrV)
+{
+ int *shifts = 0;
+
+ CV_FUNCNAME( "icvComputeMatrixVAll" );
+ __BEGIN__;
+
+ /* ----- Test input params for errors ----- */
+ if( numImages < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of images must more than zero" );
+ }
+ if( pointDeriv == 0 || presPoints == 0 || matrV == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+ /* !!! not tested all parameters */
+ /* ----- End test ----- */
+
+ /* Compute all matrices U */
+ int currImage;
+ int currPoint;
+ int numPoints;
+ numPoints = presPoints[0]->cols;
+ CV_CALL(shifts = (int*)cvAlloc(sizeof(int)*numImages));
+ memset(shifts,0,sizeof(int)*numImages);
+
+ for( currPoint = 0; currPoint < numPoints; currPoint++ )//For each point (matrix V)
+ {
+ int i,j;
+
+ for( i = 0; i < 4; i++ )
+ {
+ for( j = 0; j < 4; j++ )
+ {
+ double sum = 0;
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ if( cvmGet(presPoints[currImage],0,currPoint) > 0 )
+ {
+ sum += cvmGet(pointDeriv[currImage],0,shifts[currImage]*4+i) *
+ cvmGet(pointDeriv[currImage],0,shifts[currImage]*4+j);
+
+ sum += cvmGet(pointDeriv[currImage],1,shifts[currImage]*4+i) *
+ cvmGet(pointDeriv[currImage],1,shifts[currImage]*4+j);
+ }
+ }
+
+ cvmSet(matrV[currPoint],i,j,sum);
+ }
+ }
+
+
+ /* shift position of visible points */
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ if( cvmGet(presPoints[currImage],0,currPoint) > 0 )
+ {
+ shifts[currImage]++;
+ }
+ }
+ }
+
+ __END__;
+ cvFree( &shifts);
+
+ return;
+}
+/*======================================================================================*/
+void icvComputeMatrixUAll(int numImages,CvMat **projDeriv,CvMat** matrU)
+{
+ CV_FUNCNAME( "icvComputeMatrixVAll" );
+ __BEGIN__;
+ /* ----- Test input params for errors ----- */
+ if( numImages < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of images must more than zero" );
+ }
+ if( projDeriv == 0 || matrU == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+ /* !!! Not tested all input parameters */
+ /* ----- End test ----- */
+
+ /* Compute matrices V */
+ int currImage;
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ cvMulTransposed(projDeriv[currImage],matrU[currImage],1);
+ }
+
+ __END__;
+ return;
+}
+/*======================================================================================*/
+void icvComputeMatrixW(int numImages, CvMat **projDeriv, CvMat **pointDeriv, CvMat **presPoints, CvMat *matrW)
+{
+ CV_FUNCNAME( "icvComputeMatrixW" );
+ __BEGIN__;
+
+ /* ----- Test input params for errors ----- */
+ if( numImages < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of images must more than zero" );
+ }
+ if( projDeriv == 0 || pointDeriv == 0 || presPoints == 0 || matrW == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+ int numPoints;
+ numPoints = presPoints[0]->cols;
+ if( numPoints < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of points must more than zero" );
+ }
+ if( !CV_IS_MAT(matrW) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "matrW must be a matrix 12NumIm x 4NumPnt" );
+ }
+ if( matrW->rows != numImages*12 || matrW->cols != numPoints*4 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "matrW must be a matrix 12NumIm x 4NumPnt" );
+ }
+ /* !!! Not tested all input parameters */
+ /* ----- End test ----- */
+
+ /* Compute number of points */
+ /* Compute matrix W using derivate proj and points */
+
+ int currImage;
+
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ for( int currLine = 0; currLine < 12; currLine++ )
+ {
+ int currVis = 0;
+ for( int currPoint = 0; currPoint < numPoints; currPoint++ )
+ {
+ if( cvmGet(presPoints[currImage],0,currPoint) > 0 )
+ {
+
+ for( int currCol = 0; currCol < 4; currCol++ )
+ {
+ double sum;
+ sum = cvmGet(projDeriv[currImage],currVis*2+0,currLine) *
+ cvmGet(pointDeriv[currImage],0,currVis*4+currCol);
+
+ sum += cvmGet(projDeriv[currImage],currVis*2+1,currLine) *
+ cvmGet(pointDeriv[currImage],1,currVis*4+currCol);
+
+ cvmSet(matrW,currImage*12+currLine,currPoint*4+currCol,sum);
+ }
+ currVis++;
+ }
+ else
+ {/* set all sub elements to zero */
+ for( int currCol = 0; currCol < 4; currCol++ )
+ {
+ cvmSet(matrW,currImage*12+currLine,currPoint*4+currCol,0);
+ }
+ }
+ }
+ }
+ }
+
+#ifdef TRACK_BUNDLE
+ {
+ FILE *file;
+ file = fopen( TRACK_BUNDLE_FILE_MATRW ,"w");
+ int currPoint,currImage;
+ for( currPoint = 0; currPoint < numPoints; currPoint++ )
+ {
+ fprintf(file,"\nPoint=%d\n",currPoint);
+ int currRow;
+ for( currRow = 0; currRow < 4; currRow++ )
+ {
+ for( currImage = 0; currImage< numImages; currImage++ )
+ {
+ int i;
+ for( i = 0; i < 12; i++ )
+ {
+ double val = cvmGet(matrW, currImage * 12 + i, currPoint * 4 + currRow);
+ fprintf(file,"%lf ",val);
+ }
+ }
+ fprintf(file,"\n");
+ }
+ }
+ fclose(file);
+ }
+#endif
+
+ __END__;
+ return;
+}
+/*======================================================================================*/
+/* Compute jacobian mult projection matrices error */
+void icvComputeJacErrorProj(int numImages,CvMat **projDeriv,CvMat **projErrors,CvMat *jacProjErr )
+{
+ CV_FUNCNAME( "icvComputeJacErrorProj" );
+ __BEGIN__;
+
+ /* ----- Test input params for errors ----- */
+ if( numImages < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of images must more than zero" );
+ }
+ if( projDeriv == 0 || projErrors == 0 || jacProjErr == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+ if( !CV_IS_MAT(jacProjErr) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "jacProjErr must be a matrix 12NumIm x 1" );
+ }
+ if( jacProjErr->rows != numImages*12 || jacProjErr->cols != 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "jacProjErr must be a matrix 12NumIm x 1" );
+ }
+ /* !!! Not tested all input parameters */
+ /* ----- End test ----- */
+
+ int currImage;
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ for( int currCol = 0; currCol < 12; currCol++ )
+ {
+ int num = projDeriv[currImage]->rows;
+ double sum = 0;
+ for( int i = 0; i < num; i++ )
+ {
+ sum += cvmGet(projDeriv[currImage],i,currCol) *
+ cvmGet(projErrors[currImage],i%2,i/2);
+ }
+ cvmSet(jacProjErr,currImage*12+currCol,0,sum);
+ }
+ }
+
+#ifdef TRACK_BUNDLE
+ {
+ FILE *file;
+ file = fopen( TRACK_BUNDLE_FILE_JACERRPROJ ,"w");
+ int currImage;
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ fprintf(file,"\nImage=%d\n",currImage);
+ int currRow;
+ for( currRow = 0; currRow < 12; currRow++ )
+ {
+ double val = cvmGet(jacProjErr, currImage * 12 + currRow, 0);
+ fprintf(file,"%lf\n",val);
+ }
+ fprintf(file,"\n");
+ }
+ fclose(file);
+ }
+#endif
+
+
+ __END__;
+ return;
+}
+/*======================================================================================*/
+/* Compute jacobian mult points error */
+void icvComputeJacErrorPoint(int numImages,CvMat **pointDeriv,CvMat **projErrors, CvMat **presPoints,CvMat *jacPointErr )
+{
+ int *shifts = 0;
+
+ CV_FUNCNAME( "icvComputeJacErrorPoint" );
+ __BEGIN__;
+
+ /* ----- Test input params for errors ----- */
+ if( numImages < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of images must more than zero" );
+ }
+
+ if( pointDeriv == 0 || projErrors == 0 || presPoints == 0 || jacPointErr == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ int numPoints;
+ numPoints = presPoints[0]->cols;
+ if( numPoints < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of points must more than zero" );
+ }
+
+ if( !CV_IS_MAT(jacPointErr) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "jacPointErr must be a matrix 4NumPnt x 1" );
+ }
+
+ if( jacPointErr->rows != numPoints*4 || jacPointErr->cols != 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "jacPointErr must be a matrix 4NumPnt x 1" );
+ }
+ /* !!! Not tested all input parameters */
+ /* ----- End test ----- */
+
+ int currImage;
+ int currPoint;
+ CV_CALL(shifts = (int*)cvAlloc(sizeof(int)*numImages));
+ memset(shifts,0,sizeof(int)*numImages);
+ for( currPoint = 0; currPoint < numPoints; currPoint++ )
+ {
+ for( int currCoord = 0; currCoord < 4; currCoord++ )
+ {
+ double sum = 0;
+ {
+ int currVis = 0;
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ if( cvmGet(presPoints[currImage],0,currPoint) > 0 )
+ {
+ sum += cvmGet(pointDeriv[currImage],0,shifts[currImage]*4+currCoord) *
+ cvmGet(projErrors[currImage],0,shifts[currImage]);//currVis);
+
+ sum += cvmGet(pointDeriv[currImage],1,shifts[currImage]*4+currCoord) *
+ cvmGet(projErrors[currImage],1,shifts[currImage]);//currVis);
+
+ currVis++;
+ }
+ }
+ }
+
+ cvmSet(jacPointErr,currPoint*4+currCoord,0,sum);
+ }
+
+ /* Increase shifts */
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ if( cvmGet(presPoints[currImage],0,currPoint) > 0 )
+ {
+ shifts[currImage]++;
+ }
+ }
+ }
+
+
+#ifdef TRACK_BUNDLE
+ {
+ FILE *file;
+ file = fopen(TRACK_BUNDLE_FILE_JACERRPNT,"w");
+ int currPoint;
+ for( currPoint = 0; currPoint < numPoints; currPoint++ )
+ {
+ fprintf(file,"\nPoint=%d\n",currPoint);
+ int currRow;
+ for( currRow = 0; currRow < 4; currRow++ )
+ {
+ double val = cvmGet(jacPointErr, currPoint * 4 + currRow, 0);
+ fprintf(file,"%lf\n",val);
+ }
+ fprintf(file,"\n");
+ }
+ fclose(file);
+ }
+#endif
+
+
+
+ __END__;
+ cvFree( &shifts);
+
+}
+/*======================================================================================*/
+
+/* Reconstruct 4D points using status */
+void icvReconstructPoints4DStatus(CvMat** projPoints, CvMat **projMatrs, CvMat** presPoints,
+ CvMat *points4D,int numImages,CvMat **projError)
+{
+
+ double* matrA_dat = 0;
+ double* matrW_dat = 0;
+
+ CV_FUNCNAME( "icvReconstructPoints4DStatus" );
+ __BEGIN__;
+
+ /* ----- Test input params for errors ----- */
+ if( numImages < 2 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of images must be more than one" );
+ }
+
+ if( projPoints == 0 || projMatrs == 0 || presPoints == 0 || points4D == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ int numPoints;
+ numPoints = points4D->cols;
+ if( numPoints < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of points4D must be more than zero" );
+ }
+
+ if( points4D->rows != 4 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Points must have 4 cordinates" );
+ }
+
+ /* !!! Not tested all input parameters */
+ /* ----- End test ----- */
+
+ int currImage;
+ int currPoint;
+
+ /* Allocate maximum data */
+
+
+ CvMat matrV;
+ double matrV_dat[4*4];
+ matrV = cvMat(4,4,CV_64F,matrV_dat);
+
+ CV_CALL(matrA_dat = (double*)cvAlloc(3*numImages * 4 * sizeof(double)));
+ CV_CALL(matrW_dat = (double*)cvAlloc(3*numImages * 4 * sizeof(double)));
+
+ /* reconstruct each point */
+ for( currPoint = 0; currPoint < numPoints; currPoint++ )
+ {
+ /* Reconstruct current point */
+ /* Define number of visible projections */
+ int numVisProj = 0;
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ if( cvmGet(presPoints[currImage],0,currPoint) > 0 )
+ {
+ numVisProj++;
+ }
+ }
+
+ if( numVisProj < 2 )
+ {
+ /* This point can't be reconstructed */
+ continue;
+ }
+
+ /* Allocate memory and create matrices */
+ CvMat matrA;
+ matrA = cvMat(3*numVisProj,4,CV_64F,matrA_dat);
+
+ CvMat matrW;
+ matrW = cvMat(3*numVisProj,4,CV_64F,matrW_dat);
+
+ int currVisProj = 0;
+ for( currImage = 0; currImage < numImages; currImage++ )/* For each view */
+ {
+ if( cvmGet(presPoints[currImage],0,currPoint) > 0 )
+ {
+ double x,y;
+ x = cvmGet(projPoints[currImage],0,currPoint);
+ y = cvmGet(projPoints[currImage],1,currPoint);
+ for( int k = 0; k < 4; k++ )
+ {
+ matrA_dat[currVisProj*12 + k] =
+ x * cvmGet(projMatrs[currImage],2,k) - cvmGet(projMatrs[currImage],0,k);
+
+ matrA_dat[currVisProj*12+4 + k] =
+ y * cvmGet(projMatrs[currImage],2,k) - cvmGet(projMatrs[currImage],1,k);
+
+ matrA_dat[currVisProj*12+8 + k] =
+ x * cvmGet(projMatrs[currImage],1,k) - y * cvmGet(projMatrs[currImage],0,k);
+ }
+ currVisProj++;
+ }
+ }
+
+ /* Solve system for current point */
+ {
+ cvSVD(&matrA,&matrW,0,&matrV,CV_SVD_V_T);
+
+ /* Copy computed point */
+ cvmSet(points4D,0,currPoint,cvmGet(&matrV,3,0));//X
+ cvmSet(points4D,1,currPoint,cvmGet(&matrV,3,1));//Y
+ cvmSet(points4D,2,currPoint,cvmGet(&matrV,3,2));//Z
+ cvmSet(points4D,3,currPoint,cvmGet(&matrV,3,3));//W
+ }
+
+ }
+
+ {/* Compute projection error */
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ CvMat point4D;
+ CvMat point3D;
+ double point3D_dat[3];
+ point3D = cvMat(3,1,CV_64F,point3D_dat);
+
+ int currPoint;
+ int numVis = 0;
+ double totalError = 0;
+ for( currPoint = 0; currPoint < numPoints; currPoint++ )
+ {
+ if( cvmGet(presPoints[currImage],0,currPoint) > 0)
+ {
+ double dx,dy;
+ cvGetCol(points4D,&point4D,currPoint);
+ cvmMul(projMatrs[currImage],&point4D,&point3D);
+ double w = point3D_dat[2];
+ double x = point3D_dat[0] / w;
+ double y = point3D_dat[1] / w;
+
+ dx = cvmGet(projPoints[currImage],0,currPoint) - x;
+ dy = cvmGet(projPoints[currImage],1,currPoint) - y;
+ if( projError )
+ {
+ cvmSet(projError[currImage],0,currPoint,dx);
+ cvmSet(projError[currImage],1,currPoint,dy);
+ }
+ totalError += sqrt(dx*dx+dy*dy);
+ numVis++;
+ }
+ }
+
+ //double meanError = totalError / (double)numVis;
+
+ }
+
+ }
+
+ __END__;
+
+ cvFree( &matrA_dat);
+ cvFree( &matrW_dat);
+
+ return;
+}
+
+/*======================================================================================*/
+
+void icvProjPointsStatusFunc( int numImages, CvMat *points4D, CvMat **projMatrs, CvMat **pointsPres, CvMat **projPoints)
+{
+ CV_FUNCNAME( "icvProjPointsStatusFunc" );
+ __BEGIN__;
+
+ /* ----- Test input params for errors ----- */
+ if( numImages < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of images must be more than zero" );
+ }
+
+ if( points4D == 0 || projMatrs == 0 || pointsPres == 0 || projPoints == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ int numPoints;
+ numPoints = points4D->cols;
+ if( numPoints < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of points4D must be more than zero" );
+ }
+
+ if( points4D->rows != 4 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Points must have 4 cordinates" );
+ }
+
+ /* !!! Not tested all input parameters */
+ /* ----- End test ----- */
+
+ CvMat point4D;
+ CvMat point3D;
+ double point4D_dat[4];
+ double point3D_dat[3];
+ point4D = cvMat(4,1,CV_64F,point4D_dat);
+ point3D = cvMat(3,1,CV_64F,point3D_dat);
+
+#ifdef TRACK_BUNDLE
+ {
+ FILE *file;
+ file = fopen( TRACK_BUNDLE_FILE ,"a");
+ fprintf(file,"\n----- test 14.01 icvProjPointsStatusFunc -----\n");
+ fclose(file);
+ }
+#endif
+
+ int currImage;
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ /* Get project matrix */
+ /* project visible points using current projection matrix */
+ int currVisPoint = 0;
+ for( int currPoint = 0; currPoint < numPoints; currPoint++ )
+ {
+ if( cvmGet(pointsPres[currImage],0,currPoint) > 0 )
+ {
+ /* project current point */
+ cvGetSubRect(points4D,&point4D,cvRect(currPoint,0,1,4));
+
+#ifdef TRACK_BUNDLE
+ {
+ FILE *file;
+ file = fopen( TRACK_BUNDLE_FILE ,"a");
+ fprintf(file,"\n----- test 14.02 point4D (%lf, %lf, %lf, %lf) -----\n",
+ cvmGet(&point4D,0,0),
+ cvmGet(&point4D,1,0),
+ cvmGet(&point4D,2,0),
+ cvmGet(&point4D,3,0));
+ fclose(file);
+ }
+#endif
+
+ cvmMul(projMatrs[currImage],&point4D,&point3D);
+ double w = point3D_dat[2];
+ cvmSet(projPoints[currImage],0,currVisPoint,point3D_dat[0]/w);
+ cvmSet(projPoints[currImage],1,currVisPoint,point3D_dat[1]/w);
+
+#ifdef TRACK_BUNDLE
+ {
+ FILE *file;
+ file = fopen( TRACK_BUNDLE_FILE ,"a");
+ fprintf(file,"\n----- test 14.03 (%lf, %lf, %lf) -> (%lf, %lf)-----\n",
+ point3D_dat[0],
+ point3D_dat[1],
+ point3D_dat[2],
+ point3D_dat[0]/w,
+ point3D_dat[1]/w
+ );
+ fclose(file);
+ }
+#endif
+ currVisPoint++;
+ }
+ }
+ }
+
+ __END__;
+}
+
+/*======================================================================================*/
+void icvFreeMatrixArray(CvMat ***matrArray,int numMatr)
+{
+ /* Free each matrix */
+ int currMatr;
+
+ if( *matrArray != 0 )
+ {/* Need delete */
+ for( currMatr = 0; currMatr < numMatr; currMatr++ )
+ {
+ cvReleaseMat((*matrArray)+currMatr);
+ }
+ cvFree( matrArray);
+ }
+ return;
+}
+
+/*======================================================================================*/
+void *icvClearAlloc(int size)
+{
+ void *ptr = 0;
+
+ CV_FUNCNAME( "icvClearAlloc" );
+ __BEGIN__;
+
+ if( size > 0 )
+ {
+ CV_CALL(ptr = cvAlloc(size));
+ memset(ptr,0,size);
+ }
+
+ __END__;
+ return ptr;
+}
+
+/*======================================================================================*/
+#if 0
+void cvOptimizeLevenbergMarquardtBundleWraper( CvMat** projMatrs, CvMat** observProjPoints,
+ CvMat** pointsPres, int numImages,
+ CvMat** resultProjMatrs, CvMat* resultPoints4D,int maxIter,double epsilon )
+{
+ /* Delete al sparse points */
+
+int icvDeleteSparsInPoints( int numImages,
+ CvMat **points,
+ CvMat **status,
+ CvMat *wasStatus)/* status of previous configuration */
+
+}
+#endif
+/*======================================================================================*/
+/* !!! may be useful to return norm of error */
+/* !!! may be does not work correct with not all visible 4D points */
+void cvOptimizeLevenbergMarquardtBundle( CvMat** projMatrs, CvMat** observProjPoints,
+ CvMat** pointsPres, int numImages,
+ CvMat** resultProjMatrs, CvMat* resultPoints4D,int maxIter,double epsilon )
+{
+
+ CvMat *vectorX_points4D = 0;
+ CvMat **vectorX_projMatrs = 0;
+
+ CvMat *newVectorX_points4D = 0;
+ CvMat **newVectorX_projMatrs = 0;
+
+ CvMat *changeVectorX_points4D = 0;
+ CvMat *changeVectorX_projMatrs = 0;
+
+ CvMat **observVisPoints = 0;
+ CvMat **projVisPoints = 0;
+ CvMat **errorProjPoints = 0;
+ CvMat **DerivProj = 0;
+ CvMat **DerivPoint = 0;
+ CvMat *matrW = 0;
+ CvMat **matrsUk = 0;
+ CvMat **workMatrsUk = 0;
+ CvMat **matrsVi = 0;
+ CvMat *workMatrVi = 0;
+ CvMat **workMatrsInvVi = 0;
+ CvMat *jacProjErr = 0;
+ CvMat *jacPointErr = 0;
+
+ CvMat *matrTmpSys1 = 0;
+ CvMat *matrSysDeltaP = 0;
+ CvMat *vectTmpSys3 = 0;
+ CvMat *vectSysDeltaP = 0;
+ CvMat *deltaP = 0;
+ CvMat *deltaM = 0;
+ CvMat *vectTmpSysM = 0;
+
+ int numPoints = 0;
+
+
+ CV_FUNCNAME( "cvOptimizeLevenbergMarquardtBundle" );
+ __BEGIN__;
+
+ /* ----- Test input params for errors ----- */
+ if( numImages < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of images must be more than zero" );
+ }
+
+ if( maxIter < 1 || maxIter > 2000 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Maximum number of iteration must be in [1..1000]" );
+ }
+
+ if( epsilon < 0 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Epsilon parameter must be >= 0" );
+ }
+
+ if( !CV_IS_MAT(resultPoints4D) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "resultPoints4D must be a matrix 4 x NumPnt" );
+ }
+
+ numPoints = resultPoints4D->cols;
+ if( numPoints < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of points must be more than zero" );//!!!
+ }
+
+ if( resultPoints4D->rows != 4 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "resultPoints4D must have 4 cordinates" );
+ }
+
+ /* ----- End test ----- */
+
+ /* Optimization using bundle adjustment */
+ /* work with non visible points */
+
+ CV_CALL( vectorX_points4D = cvCreateMat(4,numPoints,CV_64F));
+ CV_CALL( vectorX_projMatrs = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages));
+
+ CV_CALL( newVectorX_points4D = cvCreateMat(4,numPoints,CV_64F));
+ CV_CALL( newVectorX_projMatrs = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages));
+
+ CV_CALL( changeVectorX_points4D = cvCreateMat(4,numPoints,CV_64F));
+ CV_CALL( changeVectorX_projMatrs = cvCreateMat(3,4,CV_64F));
+
+ int currImage;
+
+ /* ----- Test input params ----- */
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ /* Test size of input initial and result projection matrices */
+ if( !CV_IS_MAT(projMatrs[currImage]) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "each of initial projMatrs must be a matrix 3 x 4" );
+ }
+ if( projMatrs[currImage]->rows != 3 || projMatrs[currImage]->cols != 4 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "each of initial projMatrs must be a matrix 3 x 4" );
+ }
+
+
+ if( !CV_IS_MAT(observProjPoints[currImage]) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "each of observProjPoints must be a matrix 2 x NumPnts" );
+ }
+ if( observProjPoints[currImage]->rows != 2 || observProjPoints[currImage]->cols != numPoints )
+ {
+ CV_ERROR( CV_StsOutOfRange, "each of observProjPoints must be a matrix 2 x NumPnts" );
+ }
+
+ if( !CV_IS_MAT(pointsPres[currImage]) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "each of pointsPres must be a matrix 1 x NumPnt" );
+ }
+ if( pointsPres[currImage]->rows != 1 || pointsPres[currImage]->cols != numPoints )
+ {
+ CV_ERROR( CV_StsOutOfRange, "each of pointsPres must be a matrix 1 x NumPnt" );
+ }
+
+ if( !CV_IS_MAT(resultProjMatrs[currImage]) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "each of resultProjMatrs must be a matrix 3 x 4" );
+ }
+ if( resultProjMatrs[currImage]->rows != 3 || resultProjMatrs[currImage]->cols != 4 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "each of resultProjMatrs must be a matrix 3 x 4" );
+ }
+
+ }
+ /* ----- End test ----- */
+
+ /* Copy projection matrices to vectorX0 */
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ CV_CALL( vectorX_projMatrs[currImage] = cvCreateMat(3,4,CV_64F));
+ CV_CALL( newVectorX_projMatrs[currImage] = cvCreateMat(3,4,CV_64F));
+ cvCopy(projMatrs[currImage],vectorX_projMatrs[currImage]);
+ }
+
+ /* Reconstruct points4D using projection matrices and status information */
+ icvReconstructPoints4DStatus(observProjPoints, projMatrs, pointsPres, vectorX_points4D, numImages);
+
+ /* ----- Allocate memory for work matrices ----- */
+ /* Compute number of good points on each images */
+
+ CV_CALL( observVisPoints = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages) );
+ CV_CALL( projVisPoints = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages) );
+ CV_CALL( errorProjPoints = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages) );
+ CV_CALL( DerivProj = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages) );
+ CV_CALL( DerivPoint = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages) );
+ CV_CALL( matrW = cvCreateMat(12*numImages,4*numPoints,CV_64F) );
+ CV_CALL( matrsUk = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages) );
+ CV_CALL( workMatrsUk = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numImages) );
+ CV_CALL( matrsVi = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numPoints) );
+ CV_CALL( workMatrVi = cvCreateMat(4,4,CV_64F) );
+ CV_CALL( workMatrsInvVi = (CvMat**)icvClearAlloc(sizeof(CvMat*)*numPoints) );
+
+ CV_CALL( jacProjErr = cvCreateMat(12*numImages,1,CV_64F) );
+ CV_CALL( jacPointErr = cvCreateMat(4*numPoints,1,CV_64F) );
+
+
+ int i;
+ for( i = 0; i < numPoints; i++ )
+ {
+ CV_CALL( matrsVi[i] = cvCreateMat(4,4,CV_64F) );
+ CV_CALL( workMatrsInvVi[i] = cvCreateMat(4,4,CV_64F) );
+ }
+
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ CV_CALL( matrsUk[currImage] = cvCreateMat(12,12,CV_64F) );
+ CV_CALL( workMatrsUk[currImage] = cvCreateMat(12,12,CV_64F) );
+
+ int currVisPoint = 0, currPoint, numVisPoint;
+ for( currPoint = 0; currPoint < numPoints; currPoint++ )
+ {
+ if( cvmGet(pointsPres[currImage],0,currPoint) > 0 )
+ {
+ currVisPoint++;
+ }
+ }
+
+ numVisPoint = currVisPoint;
+
+ /* Allocate memory for current image data */
+ CV_CALL( observVisPoints[currImage] = cvCreateMat(2,numVisPoint,CV_64F) );
+ CV_CALL( projVisPoints[currImage] = cvCreateMat(2,numVisPoint,CV_64F) );
+
+ /* create error matrix */
+ CV_CALL( errorProjPoints[currImage] = cvCreateMat(2,numVisPoint,CV_64F) );
+
+ /* Create derivate matrices */
+ CV_CALL( DerivProj[currImage] = cvCreateMat(2*numVisPoint,12,CV_64F) );
+ CV_CALL( DerivPoint[currImage] = cvCreateMat(2,numVisPoint*4,CV_64F) );
+
+ /* Copy observed projected visible points */
+ currVisPoint = 0;
+ for( currPoint = 0; currPoint < numPoints; currPoint++ )
+ {
+ if( cvmGet(pointsPres[currImage],0,currPoint) > 0 )
+ {
+ cvmSet(observVisPoints[currImage],0,currVisPoint,cvmGet(observProjPoints[currImage],0,currPoint));
+ cvmSet(observVisPoints[currImage],1,currVisPoint,cvmGet(observProjPoints[currImage],1,currPoint));
+ currVisPoint++;
+ }
+ }
+ }
+ /*---------------------------------------------------*/
+
+ CV_CALL( matrTmpSys1 = cvCreateMat(numPoints*4, numImages*12, CV_64F) );
+ CV_CALL( matrSysDeltaP = cvCreateMat(numImages*12, numImages*12, CV_64F) );
+ CV_CALL( vectTmpSys3 = cvCreateMat(numPoints*4,1,CV_64F) );
+ CV_CALL( vectSysDeltaP = cvCreateMat(numImages*12,1,CV_64F) );
+ CV_CALL( deltaP = cvCreateMat(numImages*12,1,CV_64F) );
+ CV_CALL( deltaM = cvCreateMat(numPoints*4,1,CV_64F) );
+ CV_CALL( vectTmpSysM = cvCreateMat(numPoints*4,1,CV_64F) );
+
+
+//#ifdef TRACK_BUNDLE
+#if 1
+ {
+ /* Create file to track */
+ FILE* file;
+ file = fopen( TRACK_BUNDLE_FILE ,"w");
+ fprintf(file,"begin\n");
+ fclose(file);
+ }
+#endif
+
+ /* ============= main optimization loop ============== */
+
+ /* project all points using current vector X */
+ icvProjPointsStatusFunc(numImages, vectorX_points4D, vectorX_projMatrs, pointsPres, projVisPoints);
+
+ /* Compute error with observed value and computed projection */
+ double prevError;
+ prevError = 0;
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ cvSub(observVisPoints[currImage],projVisPoints[currImage],errorProjPoints[currImage]);
+ double currNorm = cvNorm(errorProjPoints[currImage]);
+ prevError += currNorm * currNorm;
+ }
+ prevError = sqrt(prevError);
+
+ int currIter;
+ double change;
+ double alpha;
+
+//#ifdef TRACK_BUNDLE
+#if 1
+ {
+ /* Create file to track */
+ FILE* file;
+ file = fopen( TRACK_BUNDLE_FILE ,"a");
+ fprintf(file,"\n========================================\n");;
+ fprintf(file,"Iter=0\n");
+ fprintf(file,"Error = %20.15lf\n",prevError);
+ fprintf(file,"Change = %20.15lf\n",1.0);
+
+ fprintf(file,"projection errors\n");
+
+ /* Print all proejction errors */
+ int currImage;
+ for( currImage = 0; currImage < numImages; currImage++)
+ {
+ fprintf(file,"\nImage=%d\n",currImage);
+ int numPn = errorProjPoints[currImage]->cols;
+ for( int currPoint = 0; currPoint < numPn; currPoint++ )
+ {
+ double ex,ey;
+ ex = cvmGet(errorProjPoints[currImage],0,currPoint);
+ ey = cvmGet(errorProjPoints[currImage],1,currPoint);
+ fprintf(file,"%40.35lf, %40.35lf\n",ex,ey);
+ }
+ }
+ fclose(file);
+ }
+#endif
+
+ currIter = 0;
+ change = 1;
+ alpha = 0.001;
+
+
+ do
+ {
+
+#ifdef TRACK_BUNDLE
+ {
+ FILE *file;
+ file = fopen( TRACK_BUNDLE_FILE ,"a");
+ fprintf(file,"\n----- test 6 do main -----\n");
+
+ double norm = cvNorm(vectorX_points4D);
+ fprintf(file," test 6.01 prev normPnts=%lf\n",norm);
+
+ for( int i=0;i<numImages;i++ )
+ {
+ double norm = cvNorm(vectorX_projMatrs[i]);
+ fprintf(file," test 6.01 prev normProj=%lf\n",norm);
+ }
+
+ fclose(file);
+ }
+#endif
+
+ /* Compute derivates by projectinon matrices */
+ icvComputeDerivateProjAll(vectorX_points4D,vectorX_projMatrs,pointsPres,numImages,DerivProj);
+
+ /* Compute derivates by 4D points */
+ icvComputeDerivatePointsAll(vectorX_points4D,vectorX_projMatrs,pointsPres,numImages,DerivPoint);
+
+ /* Compute matrces Uk */
+ icvComputeMatrixUAll(numImages,DerivProj,matrsUk);
+ icvComputeMatrixVAll(numImages,DerivPoint,pointsPres,matrsVi);
+ icvComputeMatrixW(numImages,DerivProj,DerivPoint,pointsPres,matrW);
+
+
+#ifdef TRACK_BUNDLE
+ {
+ FILE *file;
+ file = fopen( TRACK_BUNDLE_FILE ,"a");
+ fprintf(file,"\n----- test 6.03 do matrs U V -----\n");
+
+ int i;
+ for( i = 0; i < numImages; i++ )
+ {
+ double norm = cvNorm(matrsUk[i]);
+ fprintf(file," test 6.01 prev matrsUk=%lf\n",norm);
+ }
+
+ for( i = 0; i < numPoints; i++ )
+ {
+ double norm = cvNorm(matrsVi[i]);
+ fprintf(file," test 6.01 prev matrsVi=%lf\n",norm);
+ }
+
+ fclose(file);
+ }
+#endif
+
+ /* Compute jac errors */
+ icvComputeJacErrorProj(numImages, DerivProj, errorProjPoints, jacProjErr);
+ icvComputeJacErrorPoint(numImages, DerivPoint, errorProjPoints, pointsPres, jacPointErr);
+
+#ifdef TRACK_BUNDLE
+ {
+ FILE *file;
+ file = fopen( TRACK_BUNDLE_FILE ,"a");
+ fprintf(file,"\n----- test 6 do main -----\n");
+ double norm1 = cvNorm(vectorX_points4D);
+ fprintf(file," test 6.02 post normPnts=%lf\n",norm1);
+ fclose(file);
+ }
+#endif
+ /* Copy matrices Uk to work matrices Uk */
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ cvCopy(matrsUk[currImage],workMatrsUk[currImage]);
+ }
+
+#ifdef TRACK_BUNDLE
+ {
+ FILE *file;
+ file = fopen( TRACK_BUNDLE_FILE ,"a");
+ fprintf(file,"\n----- test 60.3 do matrs U V -----\n");
+
+ int i;
+ for( i = 0; i < numImages; i++ )
+ {
+ double norm = cvNorm(matrsUk[i]);
+ fprintf(file," test 6.01 post1 matrsUk=%lf\n",norm);
+ }
+
+ for( i = 0; i < numPoints; i++ )
+ {
+ double norm = cvNorm(matrsVi[i]);
+ fprintf(file," test 6.01 post1 matrsVi=%lf\n",norm);
+ }
+
+ fclose(file);
+ }
+#endif
+
+ /* ========== Solve normal equation for given alpha and Jacobian ============ */
+
+ do
+ {
+ /* ---- Add alpha to matrices --- */
+ /* Add alpha to matrInvVi and make workMatrsInvVi */
+
+ int currV;
+ for( currV = 0; currV < numPoints; currV++ )
+ {
+ cvCopy(matrsVi[currV],workMatrVi);
+
+ for( int i = 0; i < 4; i++ )
+ {
+ cvmSet(workMatrVi,i,i,cvmGet(matrsVi[currV],i,i)*(1+alpha) );
+ }
+
+ cvInvert(workMatrVi,workMatrsInvVi[currV],CV_LU/*,&currV*/);
+ }
+
+ /* Add alpha to matrUk and make matrix workMatrsUk */
+ for( currImage = 0; currImage< numImages; currImage++ )
+ {
+
+ for( i = 0; i < 12; i++ )
+ {
+ cvmSet(workMatrsUk[currImage],i,i,cvmGet(matrsUk[currImage],i,i)*(1+alpha));
+ }
+
+
+ }
+
+ /* Fill matrix to make system for computing delta P (matrTmpSys1 = inv(V)*tr(W) )*/
+ for( currV = 0; currV < numPoints; currV++ )
+ {
+ int currRowV;
+ for( currRowV = 0; currRowV < 4; currRowV++ )
+ {
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ for( int currCol = 0; currCol < 12; currCol++ )/* For each column of transposed matrix W */
+ {
+ double sum = 0;
+ for( i = 0; i < 4; i++ )
+ {
+ sum += cvmGet(workMatrsInvVi[currV],currRowV,i) *
+ cvmGet(matrW,currImage*12+currCol,currV*4+i);
+ }
+ cvmSet(matrTmpSys1,currV*4+currRowV,currImage*12+currCol,sum);
+ }
+ }
+ }
+ }
+
+
+ /* Fill matrix to make system for computing delta P (matrTmpSys2 = W * matrTmpSys ) */
+ cvmMul(matrW,matrTmpSys1,matrSysDeltaP);
+
+ /* need to compute U-matrTmpSys2. But we compute matTmpSys2-U */
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ CvMat subMatr;
+ cvGetSubRect(matrSysDeltaP,&subMatr,cvRect(currImage*12,currImage*12,12,12));
+ cvSub(&subMatr,workMatrsUk[currImage],&subMatr);
+ }
+
+ /* Compute right side of normal equation */
+ for( currV = 0; currV < numPoints; currV++ )
+ {
+ CvMat subMatrErPnts;
+ CvMat subMatr;
+ cvGetSubRect(jacPointErr,&subMatrErPnts,cvRect(0,currV*4,1,4));
+ cvGetSubRect(vectTmpSys3,&subMatr,cvRect(0,currV*4,1,4));
+ cvmMul(workMatrsInvVi[currV],&subMatrErPnts,&subMatr);
+ }
+
+ cvmMul(matrW,vectTmpSys3,vectSysDeltaP);
+ cvSub(vectSysDeltaP,jacProjErr,vectSysDeltaP);
+
+ /* Now we can compute part of normal system - deltaP */
+ cvSolve(matrSysDeltaP ,vectSysDeltaP, deltaP, CV_SVD);
+
+ /* Print deltaP to file */
+
+#ifdef TRACK_BUNDLE
+ {
+ FILE* file;
+ file = fopen( TRACK_BUNDLE_FILE_DELTAP ,"w");
+
+ int currImage;
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ fprintf(file,"\nImage=%d\n",currImage);
+ int i;
+ for( i = 0; i < 12; i++ )
+ {
+ double val;
+ val = cvmGet(deltaP,currImage*12+i,0);
+ fprintf(file,"%lf\n",val);
+ }
+ fprintf(file,"\n");
+ }
+ fclose(file);
+ }
+#endif
+ /* We know deltaP and now we can compute system for deltaM */
+ for( i = 0; i < numPoints * 4; i++ )
+ {
+ double sum = 0;
+ for( int j = 0; j < numImages * 12; j++ )
+ {
+ sum += cvmGet(matrW,j,i) * cvmGet(deltaP,j,0);
+ }
+ cvmSet(vectTmpSysM,i,0,cvmGet(jacPointErr,i,0)-sum);
+ }
+
+ /* Compute deltaM */
+ for( currV = 0; currV < numPoints; currV++ )
+ {
+ CvMat subMatr;
+ CvMat subMatrM;
+ cvGetSubRect(vectTmpSysM,&subMatr,cvRect(0,currV*4,1,4));
+ cvGetSubRect(deltaM,&subMatrM,cvRect(0,currV*4,1,4));
+ cvmMul(workMatrsInvVi[currV],&subMatr,&subMatrM);
+ }
+
+ /* We know delta and compute new value of vector X: nextVectX = vectX + deltas */
+
+ /* Compute new P */
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ for( i = 0; i < 3; i++ )
+ {
+ for( int j = 0; j < 4; j++ )
+ {
+ cvmSet(newVectorX_projMatrs[currImage],i,j,
+ cvmGet(vectorX_projMatrs[currImage],i,j) + cvmGet(deltaP,currImage*12+i*4+j,0));
+ }
+ }
+ }
+
+ /* Compute new M */
+ int currPoint;
+ for( currPoint = 0; currPoint < numPoints; currPoint++ )
+ {
+ for( i = 0; i < 4; i++ )
+ {
+ cvmSet(newVectorX_points4D,i,currPoint,
+ cvmGet(vectorX_points4D,i,currPoint) + cvmGet(deltaM,currPoint*4+i,0));
+ }
+ }
+
+ /* ----- Compute errors for new vectorX ----- */
+ /* Project points using new vectorX and status of each point */
+ icvProjPointsStatusFunc(numImages, newVectorX_points4D, newVectorX_projMatrs, pointsPres, projVisPoints);
+ /* Compute error with observed value and computed projection */
+ double newError = 0;
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ cvSub(observVisPoints[currImage],projVisPoints[currImage],errorProjPoints[currImage]);
+ double currNorm = cvNorm(errorProjPoints[currImage]);
+
+//#ifdef TRACK_BUNDLE
+#if 1
+ {
+ FILE *file;
+ file = fopen( TRACK_BUNDLE_FILE ,"a");
+ fprintf(file,"\n----- test 13,01 currImage=%d currNorm=%lf -----\n",currImage,currNorm);
+ fclose(file);
+ }
+#endif
+ newError += currNorm * currNorm;
+ }
+ newError = sqrt(newError);
+
+ currIter++;
+
+
+
+
+//#ifdef TRACK_BUNDLE
+#if 1
+ {
+ /* Create file to track */
+ FILE* file;
+ file = fopen( TRACK_BUNDLE_FILE ,"a");
+ fprintf(file,"\n========================================\n");
+ fprintf(file,"numPoints=%d\n",numPoints);
+ fprintf(file,"Iter=%d\n",currIter);
+ fprintf(file,"Error = %20.15lf\n",newError);
+ fprintf(file,"Change = %20.15lf\n",change);
+
+
+ /* Print all projection errors */
+#if 0
+ fprintf(file,"projection errors\n");
+ int currImage;
+ for( currImage = 0; currImage < numImages; currImage++)
+ {
+ fprintf(file,"\nImage=%d\n",currImage);
+ int numPn = errorProjPoints[currImage]->cols;
+ for( int currPoint = 0; currPoint < numPn; currPoint++ )
+ {
+ double ex,ey;
+ ex = cvmGet(errorProjPoints[currImage],0,currPoint);
+ ey = cvmGet(errorProjPoints[currImage],1,currPoint);
+ fprintf(file,"%lf,%lf\n",ex,ey);
+ }
+ }
+ fprintf(file,"\n---- test 0 -----\n");
+#endif
+
+ fclose(file);
+ }
+#endif
+
+
+
+ /* Compare new error and last error */
+ if( newError < prevError )
+ {/* accept new value */
+ prevError = newError;
+ /* Compute relative change of required parameter vectorX. change = norm(curr-prev) / norm(curr) ) */
+ {
+ double normAll1 = 0;
+ double normAll2 = 0;
+ double currNorm1 = 0;
+ double currNorm2 = 0;
+ /* compute norm for projection matrices */
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ currNorm1 = cvNorm(newVectorX_projMatrs[currImage],vectorX_projMatrs[currImage]);
+ currNorm2 = cvNorm(newVectorX_projMatrs[currImage]);
+
+ normAll1 += currNorm1 * currNorm1;
+ normAll2 += currNorm2 * currNorm2;
+ }
+
+ /* compute norm for points */
+ currNorm1 = cvNorm(newVectorX_points4D,vectorX_points4D);
+ currNorm2 = cvNorm(newVectorX_points4D);
+
+ normAll1 += currNorm1 * currNorm1;
+ normAll2 += currNorm2 * currNorm2;
+
+ /* compute change */
+ change = sqrt(normAll1) / sqrt(normAll2);
+
+
+//#ifdef TRACK_BUNDLE
+#if 1
+ {
+ /* Create file to track */
+ FILE* file;
+ file = fopen( TRACK_BUNDLE_FILE ,"a");
+ fprintf(file,"\nChange inside newVal change = %20.15lf\n",change);
+ fprintf(file," normAll1= %20.15lf\n",sqrt(normAll1));
+ fprintf(file," normAll2= %20.15lf\n",sqrt(normAll2));
+
+ fclose(file);
+ }
+#endif
+
+ }
+
+ alpha /= 10;
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ cvCopy(newVectorX_projMatrs[currImage],vectorX_projMatrs[currImage]);
+ }
+ cvCopy(newVectorX_points4D,vectorX_points4D);
+
+ break;
+ }
+ else
+ {
+ alpha *= 10;
+ }
+
+ } while( change > epsilon && currIter < maxIter );/* solve normal equation using current alpha */
+
+//#ifdef TRACK_BUNDLE
+#if 1
+ {
+ FILE* file;
+ file = fopen( TRACK_BUNDLE_FILE ,"a");
+ fprintf(file,"\nBest error = %40.35lf\n",prevError);
+ fclose(file);
+ }
+
+#endif
+
+
+ } while( change > epsilon && currIter < maxIter );
+
+ /*--------------------------------------------*/
+ /* Optimization complete copy computed params */
+ /* Copy projection matrices */
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ cvCopy(newVectorX_projMatrs[currImage],resultProjMatrs[currImage]);
+ }
+ /* Copy 4D points */
+ cvCopy(newVectorX_points4D,resultPoints4D);
+
+// free(memory);
+
+ __END__;
+
+ /* Free allocated memory */
+
+ /* Free simple matrices */
+ cvFree(&vectorX_points4D);
+ cvFree(&newVectorX_points4D);
+ cvFree(&changeVectorX_points4D);
+ cvFree(&changeVectorX_projMatrs);
+ cvFree(&matrW);
+ cvFree(&workMatrVi);
+ cvFree(&jacProjErr);
+ cvFree(&jacPointErr);
+ cvFree(&matrTmpSys1);
+ cvFree(&matrSysDeltaP);
+ cvFree(&vectTmpSys3);
+ cvFree(&vectSysDeltaP);
+ cvFree(&deltaP);
+ cvFree(&deltaM);
+ cvFree(&vectTmpSysM);
+
+ /* Free arrays of matrices */
+ icvFreeMatrixArray(&vectorX_projMatrs,numImages);
+ icvFreeMatrixArray(&newVectorX_projMatrs,numImages);
+ icvFreeMatrixArray(&observVisPoints,numImages);
+ icvFreeMatrixArray(&projVisPoints,numImages);
+ icvFreeMatrixArray(&errorProjPoints,numImages);
+ icvFreeMatrixArray(&DerivProj,numImages);
+ icvFreeMatrixArray(&DerivPoint,numImages);
+ icvFreeMatrixArray(&matrsUk,numImages);
+ icvFreeMatrixArray(&workMatrsUk,numImages);
+ icvFreeMatrixArray(&matrsVi,numPoints);
+ icvFreeMatrixArray(&workMatrsInvVi,numPoints);
+
+ return;
+}
diff --git a/cvaux/src/cvlevmartrif.cpp b/cvaux/src/cvlevmartrif.cpp
new file mode 100644
index 0000000..1d0b13d
--- /dev/null
+++ b/cvaux/src/cvlevmartrif.cpp
@@ -0,0 +1,497 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+#include "cvtypes.h"
+#include <float.h>
+#include <limits.h>
+#include "cv.h"
+
+/* Valery Mosyagin */
+
+typedef void (*pointer_LMJac)( const CvMat* src, CvMat* dst );
+typedef void (*pointer_LMFunc)( const CvMat* src, CvMat* dst );
+
+void cvLevenbergMarquardtOptimization(pointer_LMJac JacobianFunction,
+ pointer_LMFunc function,
+ /*pointer_Err error_function,*/
+ CvMat *X0,CvMat *observRes,CvMat *resultX,
+ int maxIter,double epsilon);
+
+void icvReconstructPointsFor3View( CvMat* projMatr1,CvMat* projMatr2,CvMat* projMatr3,
+ CvMat* projPoints1,CvMat* projPoints2,CvMat* projPoints3,
+ CvMat* points4D);
+
+
+/* Jacobian computation for trifocal case */
+void icvJacobianFunction_ProjTrifocal(const CvMat *vectX,CvMat *Jacobian)
+{
+ CV_FUNCNAME( "icvJacobianFunction_ProjTrifocal" );
+ __BEGIN__;
+
+ /* Test data for errors */
+ if( vectX == 0 || Jacobian == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(vectX) || !CV_IS_MAT(Jacobian) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters must be a matrices" );
+ }
+
+ int numPoints;
+ numPoints = (vectX->rows - 36)/4;
+
+ if( numPoints < 1 )//!!! Need to correct this minimal number of points
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "number of points must be more than 0" );
+ }
+
+ if( Jacobian->rows == numPoints*6 || Jacobian->cols != 36+numPoints*4 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of Jacobian is not correct it must be 6*numPoints x (36+numPoints*4)" );
+ }
+
+ /* Computed Jacobian in a given point */
+ /* This is for function with 3 projection matrices */
+ /* vector X consists of projection matrices and points3D */
+ /* each 3D points has X,Y,Z,W */
+ /* each projection matrices has 3x4 coeffs */
+ /* For N points 4D we have Jacobian 2N x (12*3+4N) */
+
+ /* Will store derivates as */
+ /* Fill Jacobian matrix */
+ int currProjPoint;
+ int currMatr;
+
+ cvZero(Jacobian);
+ for( currMatr = 0; currMatr < 3; currMatr++ )
+ {
+ double p[12];
+ for( int i=0;i<12;i++ )
+ {
+ p[i] = cvmGet(vectX,currMatr*12+i,0);
+ }
+
+ int currVal = 36;
+ for( currProjPoint = 0; currProjPoint < numPoints; currProjPoint++ )
+ {
+ /* Compute */
+ double X[4];
+ X[0] = cvmGet(vectX,currVal++,0);
+ X[1] = cvmGet(vectX,currVal++,0);
+ X[2] = cvmGet(vectX,currVal++,0);
+ X[3] = cvmGet(vectX,currVal++,0);
+
+ double piX[3];
+ piX[0] = X[0]*p[0] + X[1]*p[1] + X[2]*p[2] + X[3]*p[3];
+ piX[1] = X[0]*p[4] + X[1]*p[5] + X[2]*p[6] + X[3]*p[7];
+ piX[2] = X[0]*p[8] + X[1]*p[9] + X[2]*p[10] + X[3]*p[11];
+
+ int i,j;
+ /* fill derivate by point */
+
+ double tmp3 = 1/(piX[2]*piX[2]);
+
+ double tmp1 = -piX[0]*tmp3;
+ double tmp2 = -piX[1]*tmp3;
+ for( j = 0; j < 2; j++ )//for x and y
+ {
+ for( i = 0; i < 4; i++ )// for X,Y,Z,W
+ {
+ cvmSet( Jacobian,
+ currMatr*numPoints*2+currProjPoint*2+j, 36+currProjPoint*4+i,
+ (p[j*4+i]*piX[2]-p[8+i]*piX[j]) * tmp3 );
+ }
+ }
+ /* fill derivate by projection matrix */
+ for( i = 0; i < 4; i++ )
+ {
+ /* derivate for x */
+ cvmSet(Jacobian,currMatr*numPoints*2+currProjPoint*2,currMatr*12+i,X[i]/piX[2]);//x' p1i
+ cvmSet(Jacobian,currMatr*numPoints*2+currProjPoint*2,currMatr*12+8+i,X[i]*tmp1);//x' p3i
+
+ /* derivate for y */
+ cvmSet(Jacobian,currMatr*numPoints*2+currProjPoint*2+1,currMatr*12+4+i,X[i]/piX[2]);//y' p2i
+ cvmSet(Jacobian,currMatr*numPoints*2+currProjPoint*2+1,currMatr*12+8+i,X[i]*tmp2);//y' p3i
+ }
+
+ }
+ }
+
+ __END__;
+ return;
+}
+
+void icvFunc_ProjTrifocal(const CvMat *vectX, CvMat *resFunc)
+{
+ /* Computes function in a given point */
+ /* Computers project points using 3 projection matrices and points 3D */
+
+ /* vector X consists of projection matrices and points3D */
+ /* each projection matrices has 3x4 coeffs */
+ /* each 3D points has X,Y,Z,W(?) */
+
+ /* result of function is projection of N 3D points using 3 projection matrices */
+ /* projected points store as (projection by matrix P1),(projection by matrix P2),(projection by matrix P3) */
+ /* each projection is x1,y1,x2,y2,x3,y3,x4,y4 */
+
+ /* Compute projection of points */
+
+ /* Fill projection matrices */
+
+ CV_FUNCNAME( "icvFunc_ProjTrifocal" );
+ __BEGIN__;
+
+ /* Test data for errors */
+ if( vectX == 0 || resFunc == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(vectX) || !CV_IS_MAT(resFunc) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters must be a matrices" );
+ }
+
+ int numPoints;
+ numPoints = (vectX->rows - 36)/4;
+
+ if( numPoints < 1 )//!!! Need to correct this minimal number of points
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "number of points must be more than 0" );
+ }
+
+ if( resFunc->rows == 2*numPoints*3 || resFunc->cols != 1 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of resFunc is not correct it must be 2*numPoints*3 x 1");
+ }
+
+
+ CvMat projMatrs[3];
+ double projMatrs_dat[36];
+ projMatrs[0] = cvMat(3,4,CV_64F,projMatrs_dat);
+ projMatrs[1] = cvMat(3,4,CV_64F,projMatrs_dat+12);
+ projMatrs[2] = cvMat(3,4,CV_64F,projMatrs_dat+24);
+
+ CvMat point3D;
+ double point3D_dat[3];
+ point3D = cvMat(3,1,CV_64F,point3D_dat);
+
+ int currMatr;
+ int currV;
+ int i,j;
+
+ currV=0;
+ for( currMatr = 0; currMatr < 3; currMatr++ )
+ {
+ for( i = 0; i < 3; i++ )
+ {
+ for( j = 0;j < 4; j++ )
+ {
+ double val = cvmGet(vectX,currV,0);
+ cvmSet(&projMatrs[currMatr],i,j,val);
+ currV++;
+ }
+ }
+ }
+
+ /* Project points */
+ int currPoint;
+ CvMat point4D;
+ double point4D_dat[4];
+ point4D = cvMat(4,1,CV_64F,point4D_dat);
+ for( currPoint = 0; currPoint < numPoints; currPoint++ )
+ {
+ /* get curr point */
+ point4D_dat[0] = cvmGet(vectX,currV++,0);
+ point4D_dat[1] = cvmGet(vectX,currV++,0);
+ point4D_dat[2] = cvmGet(vectX,currV++,0);
+ point4D_dat[3] = cvmGet(vectX,currV++,0);
+
+ for( currMatr = 0; currMatr < 3; currMatr++ )
+ {
+ /* Compute projection for current point */
+ cvmMul(&projMatrs[currMatr],&point4D,&point3D);
+ double z = point3D_dat[2];
+ cvmSet(resFunc,currMatr*numPoints*2 + currPoint*2, 0,point3D_dat[0]/z);
+ cvmSet(resFunc,currMatr*numPoints*2 + currPoint*2+1,0,point3D_dat[1]/z);
+ }
+ }
+
+ __END__;
+ return;
+}
+
+
+/*----------------------------------------------------------------------------------------*/
+
+void icvOptimizeProjectionTrifocal(CvMat **projMatrs,CvMat **projPoints,
+ CvMat **resultProjMatrs, CvMat *resultPoints4D)
+{
+
+ CvMat *optimX = 0;
+ CvMat *points4D = 0;
+ CvMat *vectorX0 = 0;
+ CvMat *observRes = 0;
+ //CvMat *error = 0;
+
+ CV_FUNCNAME( "icvOptimizeProjectionTrifocal" );
+ __BEGIN__;
+
+ /* Test data for errors */
+ if( projMatrs == 0 || projPoints == 0 || resultProjMatrs == 0 || resultPoints4D == 0)
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(resultPoints4D) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "resultPoints4D must be a matrix" );
+ }
+
+ int numPoints;
+ numPoints = resultPoints4D->cols;
+ if( numPoints < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number points of resultPoints4D must be more than 0" );
+ }
+
+ if( resultPoints4D->rows != 4 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of coordinates of points4D must be 4" );
+ }
+
+ int i;
+ for( i = 0; i < 3; i++ )
+ {
+ if( projMatrs[i] == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of projMatrs is a NULL pointer" );
+ }
+
+ if( projPoints[i] == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of projPoints is a NULL pointer" );
+ }
+
+ if( resultProjMatrs[i] == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of resultProjMatrs is a NULL pointer" );
+ }
+
+ /* ----------- test for matrix ------------- */
+ if( !CV_IS_MAT(projMatrs[i]) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Each of projMatrs must be a matrix" );
+ }
+
+ if( !CV_IS_MAT(projPoints[i]) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Each of projPoints must be a matrix" );
+ }
+
+ if( !CV_IS_MAT(resultProjMatrs[i]) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Each of resultProjMatrs must be a matrix" );
+ }
+
+ /* ------------- Test sizes --------------- */
+ if( projMatrs[i]->rows != 3 || projMatrs[i]->cols != 4 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of projMatr must be 3x4" );
+ }
+
+ if( projPoints[i]->rows != 2 || projPoints[i]->cols != numPoints )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of resultProjMatrs must be 3x4" );
+ }
+
+ if( resultProjMatrs[i]->rows != 3 || resultProjMatrs[i]->cols != 4 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of resultProjMatrs must be 3x4" );
+ }
+ }
+
+
+ /* Allocate memory for points 4D */
+ CV_CALL( points4D = cvCreateMat(4,numPoints,CV_64F) );
+ CV_CALL( vectorX0 = cvCreateMat(36 + numPoints*4,1,CV_64F) );
+ CV_CALL( observRes = cvCreateMat(2*numPoints*3,1,CV_64F) );
+ CV_CALL( optimX = cvCreateMat(36+numPoints*4,1,CV_64F) );
+ //CV_CALL( error = cvCreateMat(numPoints*2*3,1,CV_64F) );
+
+
+ /* Reconstruct points 4D using projected points and projection matrices */
+ icvReconstructPointsFor3View( projMatrs[0],projMatrs[1],projMatrs[2],
+ projPoints[0],projPoints[1],projPoints[2],
+ points4D);
+
+
+
+ /* Fill observed points on images */
+ /* result of function is projection of N 3D points using 3 projection matrices */
+ /* projected points store as (projection by matrix P1),(projection by matrix P2),(projection by matrix P3) */
+ /* each projection is x1,y1,x2,y2,x3,y3,x4,y4 */
+ int currMatr;
+ for( currMatr = 0; currMatr < 3; currMatr++ )
+ {
+ for( i = 0; i < numPoints; i++ )
+ {
+ cvmSet(observRes,currMatr*numPoints*2+i*2 ,0,cvmGet(projPoints[currMatr],0,i) );/* x */
+ cvmSet(observRes,currMatr*numPoints*2+i*2+1,0,cvmGet(projPoints[currMatr],1,i) );/* y */
+ }
+ }
+
+ /* Fill with projection matrices */
+ for( currMatr = 0; currMatr < 3; currMatr++ )
+ {
+ int i;
+ for( i = 0; i < 12; i++ )
+ {
+ cvmSet(vectorX0,currMatr*12+i,0,cvmGet(projMatrs[currMatr],i/4,i%4));
+ }
+ }
+
+ /* Fill with 4D points */
+
+ int currPoint;
+ for( currPoint = 0; currPoint < numPoints; currPoint++ )
+ {
+ cvmSet(vectorX0,36 + currPoint*4 + 0,0,cvmGet(points4D,0,currPoint));
+ cvmSet(vectorX0,36 + currPoint*4 + 1,0,cvmGet(points4D,1,currPoint));
+ cvmSet(vectorX0,36 + currPoint*4 + 2,0,cvmGet(points4D,2,currPoint));
+ cvmSet(vectorX0,36 + currPoint*4 + 3,0,cvmGet(points4D,3,currPoint));
+ }
+
+
+ /* Allocate memory for result */
+ cvLevenbergMarquardtOptimization( icvJacobianFunction_ProjTrifocal, icvFunc_ProjTrifocal,
+ vectorX0,observRes,optimX,100,1e-6);
+
+ /* Copy results */
+ for( currMatr = 0; currMatr < 3; currMatr++ )
+ {
+ /* Copy projection matrices */
+ for(int i=0;i<12;i++)
+ {
+ cvmSet(resultProjMatrs[currMatr],i/4,i%4,cvmGet(optimX,currMatr*12+i,0));
+ }
+ }
+
+ /* Copy 4D points */
+ for( currPoint = 0; currPoint < numPoints; currPoint++ )
+ {
+ cvmSet(resultPoints4D,0,currPoint,cvmGet(optimX,36 + currPoint*4,0));
+ cvmSet(resultPoints4D,1,currPoint,cvmGet(optimX,36 + currPoint*4+1,0));
+ cvmSet(resultPoints4D,2,currPoint,cvmGet(optimX,36 + currPoint*4+2,0));
+ cvmSet(resultPoints4D,3,currPoint,cvmGet(optimX,36 + currPoint*4+3,0));
+ }
+
+ __END__;
+
+ /* Free allocated memory */
+ cvReleaseMat(&optimX);
+ cvReleaseMat(&points4D);
+ cvReleaseMat(&vectorX0);
+ cvReleaseMat(&observRes);
+
+ return;
+
+
+}
+
+/*------------------------------------------------------------------------------*/
+/* Create good points using status information */
+void icvCreateGoodPoints(CvMat *points,CvMat **goodPoints, CvMat *status)
+{
+ *goodPoints = 0;
+
+ CV_FUNCNAME( "icvCreateGoodPoints" );
+ __BEGIN__;
+
+ int numPoints;
+ numPoints = points->cols;
+
+ if( numPoints < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of points must be more than 0" );
+ }
+
+ int numCoord;
+ numCoord = points->rows;
+ if( numCoord < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of points coordinates must be more than 0" );
+ }
+
+ /* Define number of good points */
+ int goodNum;
+ int i,j;
+
+ goodNum = 0;
+ for( i = 0; i < numPoints; i++)
+ {
+ if( cvmGet(status,0,i) > 0 )
+ goodNum++;
+ }
+
+ /* Allocate memory for good points */
+ CV_CALL( *goodPoints = cvCreateMat(numCoord,goodNum,CV_64F) );
+
+ for( i = 0; i < numCoord; i++ )
+ {
+ int currPoint = 0;
+ for( j = 0; j < numPoints; j++)
+ {
+ if( cvmGet(status,0,j) > 0 )
+ {
+ cvmSet(*goodPoints,i,currPoint,cvmGet(points,i,j));
+ currPoint++;
+ }
+ }
+ }
+ __END__;
+ return;
+}
+
diff --git a/cvaux/src/cvlines.cpp b/cvaux/src/cvlines.cpp
new file mode 100644
index 0000000..4fece72
--- /dev/null
+++ b/cvaux/src/cvlines.cpp
@@ -0,0 +1,483 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cvaux.h"
+
+#if 0
+CvStatus
+icvFetchLine8uC3R( uchar * src, int src_step,
+ uchar * dst, int *dst_num, CvSize src_size, CvPoint start, CvPoint end )
+{
+ int i;
+ int dx = end.x - start.x, dy = end.y - start.y;
+ int err;
+
+ if( !src || !dst || (src_size.width | src_size.height) < 0 ||
+ src_step < src_size.width * 3 ||
+ (unsigned) start.x >= (unsigned) src_size.width ||
+ (unsigned) start.y >= (unsigned) src_size.height ||
+ (unsigned) end.x >= (unsigned) src_size.width ||
+ (unsigned) end.y >= (unsigned) src_size.height )
+ return CV_BADFACTOR_ERR;
+
+ if( dx < 0 )
+ {
+ dx = -dx;
+ dy = -dy;
+ start.x = end.x;
+ start.y = end.y;
+ }
+
+ src += start.y * src_step + start.x * 3;
+
+ i = dy >> 31;
+ dy = (dy ^ i) - i;
+ src_step = (src_step ^ i) - i;
+
+ if( dx > dy )
+ {
+ if( dst_num )
+ {
+ if( *dst_num <= dx )
+ return CV_BADSIZE_ERR;
+ *dst_num = dx + 1;
+ }
+ err = dx;
+ dx += dx;
+ dy += dy;
+ for( i = dx; i >= 0; i -= 2, dst += 3 )
+ {
+ int mask = (err -= dy) < 0 ? -1 : 0;
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+
+ err += dx & mask;
+ src += (src_step & mask) + 3;
+ }
+ }
+ else
+ {
+ if( dst_num )
+ {
+ if( *dst_num <= dy )
+ return CV_BADSIZE_ERR;
+ *dst_num = dy + 1;
+ }
+ err = dy;
+ dx += dx;
+ dy += dy;
+ for( i = dy; i >= 0; i -= 2, dst += 3 )
+ {
+ int mask = (err -= dx) < 0 ? -1 : 0;
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+
+ err += dy & mask;
+ src += src_step + (mask & 3);
+ }
+ }
+ return CV_NO_ERR;
+}
+
+CvStatus
+icvDrawLine8uC3R( uchar * src, int src_num,
+ uchar * dst, int dst_step, CvSize dst_size, CvPoint start, CvPoint end )
+{
+ int i;
+ int dx = end.x - start.x, dy = end.y - start.y;
+ int err;
+
+ if( !src || !dst || (dst_size.width | dst_size.height) < 0 ||
+ dst_step < dst_size.width * 3 ||
+ (unsigned) start.x >= (unsigned) dst_size.width ||
+ (unsigned) start.y >= (unsigned) dst_size.height ||
+ (unsigned) end.x >= (unsigned) dst_size.width ||
+ (unsigned) end.y >= (unsigned) dst_size.height )
+ return CV_BADFACTOR_ERR;
+
+ if( dx < 0 )
+ {
+ dx = -dx;
+ dy = -dy;
+ start.x = end.x;
+ start.y = end.y;
+ }
+
+ dst += start.y * dst_step + start.x * 3;
+
+ i = dy >> 31;
+ dy = (dy ^ i) - i;
+ dst_step = (dst_step ^ i) - i;
+
+ if( dx > dy )
+ {
+ if( (unsigned) (src_num - 1) < (unsigned) dx )
+ return CV_BADSIZE_ERR;
+ err = dx;
+ dx += dx;
+ dy += dy;
+ for( i = dx; i >= 0; i -= 2, src += 3 )
+ {
+ int mask = (err -= dy) < 0 ? -1 : 0;
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ err += dx & mask;
+ dst += (dst_step & mask) + 3;
+ }
+ }
+ else
+ {
+ if( (unsigned) (src_num - 1) < (unsigned) dy )
+ return CV_BADSIZE_ERR;
+ err = dy;
+ dx += dx;
+ dy += dy;
+ for( i = dy; i >= 0; i -= 2, src += 3 )
+ {
+ int mask = (err -= dx) < 0 ? -1 : 0;
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ err += dy & mask;
+ dst += dst_step + (mask & 3);
+ }
+ }
+ return CV_NO_ERR;
+}
+#endif
+
+/*======================================================================================*/
+
+static CvStatus
+icvPreWarpImage8uC3R( int numLines, /* number of scanlines */
+ uchar * src, /* source image */
+ int src_step, /* line step */
+ uchar * dst, /* dest buffers */
+ int *dst_nums, /* lens of buffer */
+ CvSize src_size, /* image size in pixels */
+ int *scanlines ) /* scanlines array */
+{
+ int k;
+ CvPoint start;
+ CvPoint end;
+ int curr;
+ int curr_dst;
+ CvMat mat;
+
+ curr = 0;
+ curr_dst = 0;
+
+ cvInitMatHeader( &mat, src_size.height, src_size.width, CV_8UC3, src, src_step );
+
+ for( k = 0; k < numLines; k++ )
+ {
+ start.x = scanlines[curr++];
+ start.y = scanlines[curr++];
+
+ end.x = scanlines[curr++];
+ end.y = scanlines[curr++];
+
+#ifdef _DEBUG
+ {
+ CvLineIterator iterator;
+ assert( cvInitLineIterator( &mat, start, end, &iterator, 8 ) == dst_nums[k] );
+ }
+#endif
+ cvSampleLine( &mat, start, end, dst + curr_dst, 8 );
+ curr_dst += dst_nums[k] * 3;
+
+ }
+
+ return CV_NO_ERR;
+}
+
+
+/*======================================================================================*/
+
+static CvStatus
+icvPostWarpImage8uC3R( int numLines, /* number of scanlines */
+ uchar * src, /* source buffers */
+ int *src_nums, /* lens of buffers */
+ uchar * dst, /* dest image */
+ int dst_step, /* dest image step */
+ CvSize dst_size, /* dest image size */
+ int *scanlines ) /* scanline */
+{
+ int i, k;
+ CvPoint start;
+ CvPoint end;
+ int curr;
+ int src_num;
+ int curr_src;
+ CvMat mat;
+ CvLineIterator iterator;
+
+ curr = 0;
+ curr_src = 0;
+
+ cvInitMatHeader( &mat, dst_size.height, dst_size.width, CV_8UC3, dst, dst_step );
+
+ for( k = 0; k < numLines; k++ )
+ {
+ start.x = scanlines[curr++];
+ start.y = scanlines[curr++];
+
+ end.x = scanlines[curr++];
+ end.y = scanlines[curr++];
+
+ src_num = src_nums[k];
+
+ if( cvInitLineIterator( &mat, start, end, &iterator, 8 ) != src_num )
+ {
+ assert(0);
+ return CV_NOTDEFINED_ERR;
+ }
+
+ for( i = 0; i < src_num; i++ )
+ {
+ memcpy( iterator.ptr, src + curr_src, 3 );
+ CV_NEXT_LINE_POINT( iterator );
+ curr_src += 3;
+ }
+
+#if 0
+ err = icvDrawLine8uC3R( src + curr_src, /* sourse buffer */
+ src_num, /* len of buffer */
+ dst, /* dest image */
+ dst_step, /* dest image step */
+ dst_size, /* dest image size */
+ start, /* start point */
+ end ); /* end point */
+ curr_src += src_num * 3;
+#endif
+ }
+
+ return CV_NO_ERR;
+
+}
+
+
+/*======================================================================================*/
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvDeleteMoire8uC3R
+// Purpose:
+// Function deletes moire - replaces black uncovered pixels with their neighboors.
+// Context:
+// Parameters:
+// img - image data
+// img_step - distance between lines in bytes
+// img_size - width and height of the image in pixels
+// Returns:
+// CV_NO_ERR if all Ok or error code
+// Notes:
+//F*/
+static CvStatus
+icvDeleteMoire8u( uchar * img, int img_step, CvSize img_size, int cn )
+{
+ int x, y;
+ uchar *src = img, *dst = img + img_step;
+
+ if( !img || img_size.width <= 0 || img_size.height <= 0 || img_step < img_size.width * 3 )
+ return CV_BADFACTOR_ERR;
+
+ img_size.width *= cn;
+
+ for( y = 1; y < img_size.height; y++, src = dst, dst += img_step )
+ {
+ switch( cn )
+ {
+ case 1:
+ for( x = 0; x < img_size.width; x++ )
+ {
+ if( dst[x] == 0 )
+ dst[x] = src[x];
+ }
+ break;
+ case 3:
+ for( x = 0; x < img_size.width; x += 3 )
+ {
+ if( dst[x] == 0 && dst[x + 1] == 0 && dst[x + 2] == 0 )
+ {
+ dst[x] = src[x];
+ dst[x + 1] = src[x + 1];
+ dst[x + 2] = src[x + 2];
+ }
+ }
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+
+ return CV_NO_ERR;
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvDeleteMoire
+// Purpose: The functions delete moire on the image after ViewMorphing
+// Context:
+// Parameters: img - image on which will delete moire
+//
+// Notes:
+//F*/
+CV_IMPL void
+cvDeleteMoire( IplImage * img )
+{
+ uchar *img_data = 0;
+ int img_step = 0;
+ CvSize img_size;
+
+ CV_FUNCNAME( "cvDeleteMoire" );
+
+ __BEGIN__;
+
+ cvGetImageRawData( img, &img_data, &img_step, &img_size );
+
+ if( img->nChannels != 1 && img->nChannels != 3 )
+ CV_ERROR( CV_BadNumChannels, "Source image must have 3 channel." );
+ if( img->depth != IPL_DEPTH_8U )
+ CV_ERROR( CV_BadDepth, "Channel depth of source image must be 8." );
+
+ CV_CALL( icvDeleteMoire8u( img_data, img_step, img_size, img->nChannels ));
+
+ __CLEANUP__;
+ __END__;
+
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvPreWarpImage
+// Purpose: The functions warp image for next stage of ViewMorphing
+// Context:
+// Parameters: img - initial image (in the beginning)
+//
+// Notes:
+//F*/
+CV_IMPL void
+cvPreWarpImage( int numLines, /* number of scanlines */
+ IplImage * img, /* Source Image */
+ uchar * dst, /* dest buffers */
+ int *dst_nums, /* lens of buffer */
+ int *scanlines /* scanlines array */ )
+{
+ uchar *img_data = 0;
+ int img_step = 0;
+ CvSize img_size;
+
+ CV_FUNCNAME( "cvPreWarpImage" );
+
+ __BEGIN__;
+
+ cvGetImageRawData( img, &img_data, &img_step, &img_size );
+
+ if( img->nChannels != 3 )
+ CV_ERROR( CV_BadNumChannels, "Source image must have 3 channel." );
+ if( img->depth != IPL_DEPTH_8U )
+ CV_ERROR( CV_BadDepth, "Channel depth of image must be 8." );
+
+ CV_CALL( icvPreWarpImage8uC3R( numLines, /* number of scanlines */
+ img_data, /* source image */
+ img_step, /* line step */
+ dst, /* dest buffers */
+ dst_nums, /* lens of buffer */
+ img_size, /* image size in pixels */
+ scanlines /* scanlines array */ ));
+
+ __CLEANUP__;
+ __END__;
+
+}
+
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvPostWarpImage
+// Purpose: The functions postwarp the image after morphing
+// Context:
+// Parameters: img - initial image (in the beginning)
+//
+// Notes:
+//F*/
+CV_IMPL void
+cvPostWarpImage( int numLines, /* number of scanlines */
+ uchar * src, /* source buffers */
+ int *src_nums, /* lens of buffers */
+ IplImage * img, /* dest image */
+ int *scanlines /* scanline */ )
+{
+ uchar *img_data = 0;
+ int img_step = 0;
+ CvSize img_size;
+
+ CV_FUNCNAME( "cvPostWarpImage" );
+
+ __BEGIN__;
+
+ cvGetImageRawData( img, &img_data, &img_step, &img_size );
+
+ if( img->nChannels != 3 )
+ CV_ERROR( CV_BadNumChannels, "Source image must have 3 channel." );
+ if( img->depth != IPL_DEPTH_8U )
+ CV_ERROR( CV_BadDepth, "Channel depth of image must be 8." );
+
+ CV_CALL( icvPostWarpImage8uC3R( numLines, /* number of scanlines */
+ src, /* source buffers */
+ src_nums, /* lens of buffers */
+ img_data, /* dest image */
+ img_step, /* dest image step */
+ img_size, /* dest image size */
+ scanlines /* scanline */ ));
+
+ __CLEANUP__;
+ __END__;
+}
+
+/* End of file */
+
diff --git a/cvaux/src/cvlmeds.cpp b/cvaux/src/cvlmeds.cpp
new file mode 100644
index 0000000..53d7882
--- /dev/null
+++ b/cvaux/src/cvlmeds.cpp
@@ -0,0 +1,1766 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cvaux.h"
+#include "_cvvm.h"
+#include <stdlib.h>
+
+#define Sgn(x) ( (x)<0 ? -1:1 ) /* Sgn(0) = 1 ! */
+/*===========================================================================*/
+CvStatus
+icvLMedS( int *points1, int *points2, int numPoints, CvMatrix3 * fundamentalMatrix )
+{
+ int sample, j, amount_samples, done;
+ int amount_solutions;
+ int ml7[21], mr7[21];
+
+ double F_try[9 * 3];
+ double F[9];
+ double Mj, Mj_new;
+
+ int i, num;
+
+ int *ml;
+ int *mr;
+ int *new_ml;
+ int *new_mr;
+ int new_num;
+ CvStatus error;
+
+ error = CV_NO_ERR;
+
+ if( fundamentalMatrix == 0 )
+ return CV_BADFACTOR_ERR;
+
+ num = numPoints;
+
+ if( num < 6 )
+ {
+ return CV_BADFACTOR_ERR;
+ } /* if */
+
+ ml = (int *) cvAlloc( sizeof( int ) * num * 3 );
+ mr = (int *) cvAlloc( sizeof( int ) * num * 3 );
+
+ for( i = 0; i < num; i++ )
+ {
+
+ ml[i * 3] = points1[i * 2];
+ ml[i * 3 + 1] = points1[i * 2 + 1];
+
+ ml[i * 3 + 2] = 1;
+
+ mr[i * 3] = points2[i * 2];
+ mr[i * 3 + 1] = points2[i * 2 + 1];
+
+ mr[i * 3 + 2] = 1;
+ } /* for */
+
+ if( num > 7 )
+ {
+
+ Mj = -1;
+ amount_samples = 1000; /* ------- Must be changed ! --------- */
+
+ for( sample = 0; sample < amount_samples; sample++ )
+ {
+
+ icvChoose7( ml, mr, num, ml7, mr7 );
+ icvPoint7( ml7, mr7, F_try, &amount_solutions );
+
+ for( i = 0; i < amount_solutions / 9; i++ )
+ {
+
+ Mj_new = icvMedian( ml, mr, num, F_try + i * 9 );
+
+ if( Mj_new >= 0 && (Mj == -1 || Mj_new < Mj) )
+ {
+
+ for( j = 0; j < 9; j++ )
+ {
+
+ F[j] = F_try[i * 9 + j];
+ } /* for */
+
+ Mj = Mj_new;
+ } /* if */
+ } /* for */
+ } /* for */
+
+ if( Mj == -1 )
+ return CV_BADFACTOR_ERR;
+
+ done = icvBoltingPoints( ml, mr, num, F, Mj, &new_ml, &new_mr, &new_num );
+
+ if( done == -1 )
+ {
+
+ cvFree( &mr );
+ cvFree( &ml );
+ return CV_OUTOFMEM_ERR;
+ } /* if */
+
+ if( done > 7 )
+ error = icvPoints8( new_ml, new_mr, new_num, F );
+
+ cvFree( &new_mr );
+ cvFree( &new_ml );
+
+ }
+ else
+ {
+ error = icvPoint7( ml, mr, F, &i );
+ } /* if */
+
+ if( error == CV_NO_ERR )
+ error = icvRank2Constraint( F );
+
+ for( i = 0; i < 3; i++ )
+ for( j = 0; j < 3; j++ )
+ fundamentalMatrix->m[i][j] = (float) F[i * 3 + j];
+
+ return error;
+
+} /* icvLMedS */
+
+/*===========================================================================*/
+/*===========================================================================*/
+void
+icvChoose7( int *ml, int *mr, int num, int *ml7, int *mr7 )
+{
+ int indexes[7], i, j;
+
+ if( !ml || !mr || num < 7 || !ml7 || !mr7 )
+ return;
+
+ for( i = 0; i < 7; i++ )
+ {
+
+ indexes[i] = (int) ((double) rand() / RAND_MAX * num);
+
+ for( j = 0; j < i; j++ )
+ {
+
+ if( indexes[i] == indexes[j] )
+ i--;
+ } /* for */
+ } /* for */
+
+ for( i = 0; i < 21; i++ )
+ {
+
+ ml7[i] = ml[3 * indexes[i / 3] + i % 3];
+ mr7[i] = mr[3 * indexes[i / 3] + i % 3];
+ } /* for */
+} /* cs_Choose7 */
+
+/*===========================================================================*/
+/*===========================================================================*/
+CvStatus
+icvCubic( double a2, double a1, double a0, double *squares )
+{
+ double p, q, D, c1, c2, b1, b2, ro1, ro2, fi1, fi2, tt;
+ double x[6][3];
+ int i, j, t;
+
+ if( !squares )
+ return CV_BADFACTOR_ERR;
+
+ p = a1 - a2 * a2 / 3;
+ q = (9 * a1 * a2 - 27 * a0 - 2 * a2 * a2 * a2) / 27;
+ D = q * q / 4 + p * p * p / 27;
+
+ if( D < 0 )
+ {
+
+ c1 = q / 2;
+ c2 = c1;
+ b1 = sqrt( -D );
+ b2 = -b1;
+
+ ro1 = sqrt( c1 * c1 - D );
+ ro2 = ro1;
+
+ fi1 = atan2( b1, c1 );
+ fi2 = -fi1;
+ }
+ else
+ {
+
+ c1 = q / 2 + sqrt( D );
+ c2 = q / 2 - sqrt( D );
+ b1 = 0;
+ b2 = 0;
+
+ ro1 = fabs( c1 );
+ ro2 = fabs( c2 );
+ fi1 = CV_PI * (1 - SIGN( c1 )) / 2;
+ fi2 = CV_PI * (1 - SIGN( c2 )) / 2;
+ } /* if */
+
+ for( i = 0; i < 6; i++ )
+ {
+
+ x[i][0] = -a2 / 3;
+ x[i][1] = 0;
+ x[i][2] = 0;
+
+ squares[i] = x[i][i % 2];
+ } /* for */
+
+ if( !REAL_ZERO( ro1 ))
+ {
+ tt = SIGN( ro1 ) * pow( fabs( ro1 ), 0.333333333333 );
+ c1 = tt - p / (3. * tt);
+ c2 = tt + p / (3. * tt);
+ } /* if */
+
+ if( !REAL_ZERO( ro2 ))
+ {
+ tt = SIGN( ro2 ) * pow( fabs( ro2 ), 0.333333333333 );
+ b1 = tt - p / (3. * tt);
+ b2 = tt + p / (3. * tt);
+ } /* if */
+
+ for( i = 0; i < 6; i++ )
+ {
+
+ if( i < 3 )
+ {
+
+ if( !REAL_ZERO( ro1 ))
+ {
+
+ x[i][0] = cos( fi1 / 3. + 2 * CV_PI * (i % 3) / 3. ) * c1 - a2 / 3;
+ x[i][1] = sin( fi1 / 3. + 2 * CV_PI * (i % 3) / 3. ) * c2;
+ }
+ else
+ {
+
+ x[i][2] = 1;
+ } /* if */
+ }
+ else
+ {
+
+ if( !REAL_ZERO( ro2 ))
+ {
+
+ x[i][0] = cos( fi2 / 3. + 2 * CV_PI * (i % 3) / 3. ) * b1 - a2 / 3;
+ x[i][1] = sin( fi2 / 3. + 2 * CV_PI * (i % 3) / 3. ) * b2;
+ }
+ else
+ {
+
+ x[i][2] = 1;
+ } /* if */
+ } /* if */
+ } /* for */
+
+ t = 0;
+
+ for( i = 0; i < 6; i++ )
+ {
+
+ if( !x[i][2] )
+ {
+
+ squares[t++] = x[i][0];
+ squares[t++] = x[i][1];
+ x[i][2] = 1;
+
+ for( j = i + 1; j < 6; j++ )
+ {
+
+ if( !x[j][2] && REAL_ZERO( x[i][0] - x[j][0] )
+ && REAL_ZERO( x[i][1] - x[j][1] ))
+ {
+
+ x[j][2] = 1;
+ break;
+ } /* if */
+ } /* for */
+ } /* if */
+ } /* for */
+ return CV_NO_ERR;
+} /* icvCubic */
+
+/*======================================================================================*/
+double
+icvDet( double *M )
+{
+ double value;
+
+ if( !M )
+ return 0;
+
+ value = M[0] * M[4] * M[8] + M[2] * M[3] * M[7] + M[1] * M[5] * M[6] -
+ M[2] * M[4] * M[6] - M[0] * M[5] * M[7] - M[1] * M[3] * M[8];
+
+ return value;
+
+} /* icvDet */
+
+/*===============================================================================*/
+double
+icvMinor( double *M, int x, int y )
+{
+ int row1, row2, col1, col2;
+ double value;
+
+ if( !M || x < 0 || x > 2 || y < 0 || y > 2 )
+ return 0;
+
+ row1 = (y == 0 ? 1 : 0);
+ row2 = (y == 2 ? 1 : 2);
+ col1 = (x == 0 ? 1 : 0);
+ col2 = (x == 2 ? 1 : 2);
+
+ value = M[row1 * 3 + col1] * M[row2 * 3 + col2] - M[row2 * 3 + col1] * M[row1 * 3 + col2];
+
+ value *= 1 - (x + y) % 2 * 2;
+
+ return value;
+
+} /* icvMinor */
+
+/*======================================================================================*/
+CvStatus
+icvGetCoef( double *f1, double *f2, double *a2, double *a1, double *a0 )
+{
+ double G[9], a3;
+ int i;
+
+ if( !f1 || !f2 || !a0 || !a1 || !a2 )
+ return CV_BADFACTOR_ERR;
+
+ for( i = 0; i < 9; i++ )
+ {
+
+ G[i] = f1[i] - f2[i];
+ } /* for */
+
+ a3 = icvDet( G );
+
+ if( REAL_ZERO( a3 ))
+ return CV_BADFACTOR_ERR;
+
+ *a2 = 0;
+ *a1 = 0;
+ *a0 = icvDet( f2 );
+
+ for( i = 0; i < 9; i++ )
+ {
+
+ *a2 += f2[i] * icvMinor( G, (int) (i % 3), (int) (i / 3) );
+ *a1 += G[i] * icvMinor( f2, (int) (i % 3), (int) (i / 3) );
+ } /* for */
+
+ *a0 /= a3;
+ *a1 /= a3;
+ *a2 /= a3;
+
+ return CV_NO_ERR;
+
+} /* icvGetCoef */
+
+/*===========================================================================*/
+double
+icvMedian( int *ml, int *mr, int num, double *F )
+{
+ double l1, l2, l3, d1, d2, value;
+ double *deviation;
+ int i, i3;
+
+ if( !ml || !mr || !F )
+ return -1;
+
+ deviation = (double *) cvAlloc( (num) * sizeof( double ));
+
+ if( !deviation )
+ return -1;
+
+ for( i = 0, i3 = 0; i < num; i++, i3 += 3 )
+ {
+
+ l1 = F[0] * mr[i3] + F[1] * mr[i3 + 1] + F[2];
+ l2 = F[3] * mr[i3] + F[4] * mr[i3 + 1] + F[5];
+ l3 = F[6] * mr[i3] + F[7] * mr[i3 + 1] + F[8];
+
+ d1 = (l1 * ml[i3] + l2 * ml[i3 + 1] + l3) / sqrt( l1 * l1 + l2 * l2 );
+
+ l1 = F[0] * ml[i3] + F[3] * ml[i3 + 1] + F[6];
+ l2 = F[1] * ml[i3] + F[4] * ml[i3 + 1] + F[7];
+ l3 = F[2] * ml[i3] + F[5] * ml[i3 + 1] + F[8];
+
+ d2 = (l1 * mr[i3] + l2 * mr[i3 + 1] + l3) / sqrt( l1 * l1 + l2 * l2 );
+
+ deviation[i] = (double) (d1 * d1 + d2 * d2);
+ } /* for */
+
+ if( icvSort( deviation, num ) != CV_NO_ERR )
+ {
+
+ cvFree( &deviation );
+ return -1;
+ } /* if */
+
+ value = deviation[num / 2];
+ cvFree( &deviation );
+ return value;
+
+} /* cs_Median */
+
+/*===========================================================================*/
+CvStatus
+icvSort( double *array, int length )
+{
+ int i, j, index;
+ double swapd;
+
+ if( !array || length < 1 )
+ return CV_BADFACTOR_ERR;
+
+ for( i = 0; i < length - 1; i++ )
+ {
+
+ index = i;
+
+ for( j = i + 1; j < length; j++ )
+ {
+
+ if( array[j] < array[index] )
+ index = j;
+ } /* for */
+
+ if( index - i )
+ {
+
+ swapd = array[i];
+ array[i] = array[index];
+ array[index] = swapd;
+ } /* if */
+ } /* for */
+
+ return CV_NO_ERR;
+
+} /* cs_Sort */
+
+/*===========================================================================*/
+int
+icvBoltingPoints( int *ml, int *mr,
+ int num, double *F, double Mj, int **new_ml, int **new_mr, int *new_num )
+{
+ double l1, l2, l3, d1, d2, sigma;
+ int i, j, length;
+ int *index;
+
+ if( !ml || !mr || num < 1 || !F || Mj < 0 )
+ return -1;
+
+ index = (int *) cvAlloc( (num) * sizeof( int ));
+
+ if( !index )
+ return -1;
+
+ length = 0;
+ sigma = (double) (2.5 * 1.4826 * (1 + 5. / (num - 7)) * sqrt( Mj ));
+
+ for( i = 0; i < num * 3; i += 3 )
+ {
+
+ l1 = F[0] * mr[i] + F[1] * mr[i + 1] + F[2];
+ l2 = F[3] * mr[i] + F[4] * mr[i + 1] + F[5];
+ l3 = F[6] * mr[i] + F[7] * mr[i + 1] + F[8];
+
+ d1 = (l1 * ml[i] + l2 * ml[i + 1] + l3) / sqrt( l1 * l1 + l2 * l2 );
+
+ l1 = F[0] * ml[i] + F[3] * ml[i + 1] + F[6];
+ l2 = F[1] * ml[i] + F[4] * ml[i + 1] + F[7];
+ l3 = F[2] * ml[i] + F[5] * ml[i + 1] + F[8];
+
+ d2 = (l1 * mr[i] + l2 * mr[i + 1] + l3) / sqrt( l1 * l1 + l2 * l2 );
+
+ if( d1 * d1 + d2 * d2 <= sigma * sigma )
+ {
+
+ index[i / 3] = 1;
+ length++;
+ }
+ else
+ {
+
+ index[i / 3] = 0;
+ } /* if */
+ } /* for */
+
+ *new_num = length;
+
+ *new_ml = (int *) cvAlloc( (length * 3) * sizeof( int ));
+
+ if( !new_ml )
+ {
+
+ cvFree( &index );
+ return -1;
+ } /* if */
+
+ *new_mr = (int *) cvAlloc( (length * 3) * sizeof( int ));
+
+ if( !new_mr )
+ {
+
+ cvFree( &new_ml );
+ cvFree( &index );
+ return -1;
+ } /* if */
+
+ j = 0;
+
+ for( i = 0; i < num * 3; )
+ {
+
+ if( index[i / 3] )
+ {
+
+ (*new_ml)[j] = ml[i];
+ (*new_mr)[j++] = mr[i++];
+ (*new_ml)[j] = ml[i];
+ (*new_mr)[j++] = mr[i++];
+ (*new_ml)[j] = ml[i];
+ (*new_mr)[j++] = mr[i++];
+ }
+ else
+ i += 3;
+ } /* for */
+
+ cvFree( &index );
+ return length;
+
+} /* cs_BoltingPoints */
+
+/*===========================================================================*/
+CvStatus
+icvPoints8( int *ml, int *mr, int num, double *F )
+{
+ double *U;
+ double l1, l2, w, old_norm = -1, new_norm = -2, summ;
+ int i3, i9, j, num3, its = 0, a, t;
+
+ if( !ml || !mr || num < 8 || !F )
+ return CV_BADFACTOR_ERR;
+
+ U = (double *) cvAlloc( (num * 9) * sizeof( double ));
+
+ if( !U )
+ return CV_OUTOFMEM_ERR;
+
+ num3 = num * 3;
+
+ while( !REAL_ZERO( new_norm - old_norm ))
+ {
+
+ if( its++ > 1e+2 )
+ {
+
+ cvFree( &U );
+ return CV_BADFACTOR_ERR;
+ } /* if */
+
+ old_norm = new_norm;
+
+ for( i3 = 0, i9 = 0; i3 < num3; i3 += 3, i9 += 9 )
+ {
+
+ l1 = F[0] * mr[i3] + F[1] * mr[i3 + 1] + F[2];
+ l2 = F[3] * mr[i3] + F[4] * mr[i3 + 1] + F[5];
+
+ if( REAL_ZERO( l1 ) && REAL_ZERO( l2 ))
+ {
+
+ cvFree( &U );
+ return CV_BADFACTOR_ERR;
+ } /* if */
+
+ w = 1 / (l1 * l1 + l2 * l2);
+
+ l1 = F[0] * ml[i3] + F[3] * ml[i3 + 1] + F[6];
+ l2 = F[1] * ml[i3] + F[4] * ml[i3 + 1] + F[7];
+
+ if( REAL_ZERO( l1 ) && REAL_ZERO( l2 ))
+ {
+
+ cvFree( &U );
+ return CV_BADFACTOR_ERR;
+ } /* if */
+
+ w += 1 / (l1 * l1 + l2 * l2);
+ w = sqrt( w );
+
+ for( j = 0; j < 9; j++ )
+ {
+
+ U[i9 + j] = w * (double) ml[i3 + j / 3] * (double) mr[i3 + j % 3];
+ } /* for */
+ } /* for */
+
+ new_norm = 0;
+
+ for( a = 0; a < num; a++ )
+ { /* row */
+
+ summ = 0;
+
+ for( t = 0; t < 9; t++ )
+ {
+
+ summ += U[a * 9 + t] * F[t];
+ } /* for */
+
+ new_norm += summ * summ;
+ } /* for */
+
+ new_norm = sqrt( new_norm );
+
+ icvAnalyticPoints8( U, num, F );
+ } /* while */
+
+ cvFree( &U );
+ return CV_NO_ERR;
+
+} /* cs_Points8 */
+
+/*===========================================================================*/
+double
+icvAnalyticPoints8( double *A, int num, double *F )
+{
+ double *U;
+ double V[8 * 8];
+ double W[8];
+ double *f;
+ double solution[9];
+ double temp1[8 * 8];
+ double *temp2;
+ double *A_short;
+ double norm, summ, best_norm;
+ int num8 = num * 8, num9 = num * 9;
+ int i, j, j8, j9, value, a, a8, a9, a_num, b, b8, t;
+
+ /* --------- Initialization data ------------------ */
+
+ if( !A || num < 8 || !F )
+ return -1;
+
+ best_norm = -1;
+ U = (double *) cvAlloc( (num8) * sizeof( double ));
+
+ if( !U )
+ return -1;
+
+ f = (double *) cvAlloc( (num) * sizeof( double ));
+
+ if( !f )
+ {
+ cvFree( &U );
+ return -1;
+ } /* if */
+
+ temp2 = (double *) cvAlloc( (num8) * sizeof( double ));
+
+ if( !temp2 )
+ {
+ cvFree( &f );
+ cvFree( &U );
+ return -1;
+ } /* if */
+
+ A_short = (double *) cvAlloc( (num8) * sizeof( double ));
+
+ if( !A_short )
+ {
+ cvFree( &temp2 );
+ cvFree( &f );
+ cvFree( &U );
+ return -1;
+ } /* if */
+
+ for( i = 0; i < 8; i++ )
+ {
+ for( j8 = 0, j9 = 0; j9 < num9; j8 += 8, j9 += 9 )
+ {
+ A_short[j8 + i] = A[j9 + i + 1];
+ } /* for */
+ } /* for */
+
+ for( i = 0; i < 9; i++ )
+ {
+
+ for( j = 0, j8 = 0, j9 = 0; j < num; j++, j8 += 8, j9 += 9 )
+ {
+
+ f[j] = -A[j9 + i];
+
+ if( i )
+ A_short[j8 + i - 1] = A[j9 + i - 1];
+ } /* for */
+
+ value = icvSingularValueDecomposition( num, 8, A_short, W, 1, U, 1, V );
+
+ if( !value )
+ { /* ----------- computing the solution ----------- */
+
+ /* ----------- W = W(-1) ----------- */
+ for( j = 0; j < 8; j++ )
+ {
+ if( !REAL_ZERO( W[j] ))
+ W[j] = 1 / W[j];
+ } /* for */
+
+ /* ----------- temp1 = V * W(-1) ----------- */
+ for( a8 = 0; a8 < 64; a8 += 8 )
+ { /* row */
+ for( b = 0; b < 8; b++ )
+ { /* column */
+ temp1[a8 + b] = V[a8 + b] * W[b];
+ } /* for */
+ } /* for */
+
+ /* ----------- temp2 = V * W(-1) * U(T) ----------- */
+ for( a8 = 0, a_num = 0; a8 < 64; a8 += 8, a_num += num )
+ { /* row */
+ for( b = 0, b8 = 0; b < num; b++, b8 += 8 )
+ { /* column */
+
+ temp2[a_num + b] = 0;
+
+ for( t = 0; t < 8; t++ )
+ {
+
+ temp2[a_num + b] += temp1[a8 + t] * U[b8 + t];
+ } /* for */
+ } /* for */
+ } /* for */
+
+ /* ----------- solution = V * W(-1) * U(T) * f ----------- */
+ for( a = 0, a_num = 0; a < 8; a++, a_num += num )
+ { /* row */
+ for( b = 0; b < num; b++ )
+ { /* column */
+
+ solution[a] = 0;
+
+ for( t = 0; t < num && W[a]; t++ )
+ {
+ solution[a] += temp2[a_num + t] * f[t];
+ } /* for */
+ } /* for */
+ } /* for */
+
+ for( a = 8; a > 0; a-- )
+ {
+
+ if( a == i )
+ break;
+ solution[a] = solution[a - 1];
+ } /* for */
+
+ solution[a] = 1;
+
+ norm = 0;
+
+ for( a9 = 0; a9 < num9; a9 += 9 )
+ { /* row */
+
+ summ = 0;
+
+ for( t = 0; t < 9; t++ )
+ {
+
+ summ += A[a9 + t] * solution[t];
+ } /* for */
+
+ norm += summ * summ;
+ } /* for */
+
+ norm = sqrt( norm );
+
+ if( best_norm == -1 || norm < best_norm )
+ {
+
+ for( j = 0; j < 9; j++ )
+ F[j] = solution[j];
+
+ best_norm = norm;
+ } /* if */
+ } /* if */
+ } /* for */
+
+ cvFree( &A_short );
+ cvFree( &temp2 );
+ cvFree( &f );
+ cvFree( &U );
+
+ return best_norm;
+
+} /* cs_AnalyticPoints8 */
+
+/*===========================================================================*/
+CvStatus
+icvRank2Constraint( double *F )
+{
+ double U[9], V[9], W[3];
+ double aW[3];
+ int i, i3, j, j3, t;
+
+ if( F == 0 )
+ return CV_BADFACTOR_ERR;
+
+ if( icvSingularValueDecomposition( 3, 3, F, W, 1, U, 1, V ))
+ return CV_BADFACTOR_ERR;
+
+ aW[0] = fabs(W[0]);
+ aW[1] = fabs(W[1]);
+ aW[2] = fabs(W[2]);
+
+ if( aW[0] < aW[1] )
+ {
+ if( aW[0] < aW[2] )
+ {
+
+ if( REAL_ZERO( W[0] ))
+ return CV_NO_ERR;
+ else
+ W[0] = 0;
+ }
+ else
+ {
+
+ if( REAL_ZERO( W[2] ))
+ return CV_NO_ERR;
+ else
+ W[2] = 0;
+ } /* if */
+ }
+ else
+ {
+
+ if( aW[1] < aW[2] )
+ {
+
+ if( REAL_ZERO( W[1] ))
+ return CV_NO_ERR;
+ else
+ W[1] = 0;
+ }
+ else
+ {
+ if( REAL_ZERO( W[2] ))
+ return CV_NO_ERR;
+ else
+ W[2] = 0;
+ } /* if */
+ } /* if */
+
+ for( i = 0; i < 3; i++ )
+ {
+ for( j3 = 0; j3 < 9; j3 += 3 )
+ {
+ U[j3 + i] *= W[i];
+ } /* for */
+ } /* for */
+
+ for( i = 0, i3 = 0; i < 3; i++, i3 += 3 )
+ {
+ for( j = 0, j3 = 0; j < 3; j++, j3 += 3 )
+ {
+
+ F[i3 + j] = 0;
+
+ for( t = 0; t < 3; t++ )
+ {
+ F[i3 + j] += U[i3 + t] * V[j3 + t];
+ } /* for */
+ } /* for */
+ } /* for */
+
+ return CV_NO_ERR;
+} /* cs_Rank2Constraint */
+
+
+/*===========================================================================*/
+
+int
+icvSingularValueDecomposition( int M,
+ int N,
+ double *A,
+ double *W, int get_U, double *U, int get_V, double *V )
+{
+ int i = 0, j, k, l = 0, i1, k1, l1 = 0;
+ int iterations, error = 0, jN, iN, kN, lN = 0;
+ double *rv1;
+ double c, f, g, h, s, x, y, z, scale, anorm;
+ double af, ag, ah, t;
+ int MN = M * N;
+ int NN = N * N;
+
+ /* max_iterations - maximum number QR-iterations
+ cc - reduces requirements to number stitch (cc>1)
+ */
+
+ int max_iterations = 100;
+ double cc = 100;
+
+ if( M < N )
+ return N;
+
+ rv1 = (double *) cvAlloc( N * sizeof( double ));
+
+ if( rv1 == 0 )
+ return N;
+
+ for( iN = 0; iN < MN; iN += N )
+ {
+ for( j = 0; j < N; j++ )
+ U[iN + j] = A[iN + j];
+ } /* for */
+
+ /* Adduction to bidiagonal type (transformations of reflection).
+ Bidiagonal matrix is located in W (diagonal elements)
+ and in rv1 (upperdiagonal elements)
+ */
+
+ g = 0;
+ scale = 0;
+ anorm = 0;
+
+ for( i = 0, iN = 0; i < N; i++, iN += N )
+ {
+
+ l = i + 1;
+ lN = iN + N;
+ rv1[i] = scale * g;
+
+ /* Multiplyings on the left */
+
+ g = 0;
+ s = 0;
+ scale = 0;
+
+ for( kN = iN; kN < MN; kN += N )
+ scale += fabs( U[kN + i] );
+
+ if( !REAL_ZERO( scale ))
+ {
+
+ for( kN = iN; kN < MN; kN += N )
+ {
+
+ U[kN + i] /= scale;
+ s += U[kN + i] * U[kN + i];
+ } /* for */
+
+ f = U[iN + i];
+ g = -sqrt( s ) * Sgn( f );
+ h = f * g - s;
+ U[iN + i] = f - g;
+
+ for( j = l; j < N; j++ )
+ {
+
+ s = 0;
+
+ for( kN = iN; kN < MN; kN += N )
+ {
+
+ s += U[kN + i] * U[kN + j];
+ } /* for */
+
+ f = s / h;
+
+ for( kN = iN; kN < MN; kN += N )
+ {
+
+ U[kN + j] += f * U[kN + i];
+ } /* for */
+ } /* for */
+
+ for( kN = iN; kN < MN; kN += N )
+ U[kN + i] *= scale;
+ } /* if */
+
+ W[i] = scale * g;
+
+ /* Multiplyings on the right */
+
+ g = 0;
+ s = 0;
+ scale = 0;
+
+ for( k = l; k < N; k++ )
+ scale += fabs( U[iN + k] );
+
+ if( !REAL_ZERO( scale ))
+ {
+
+ for( k = l; k < N; k++ )
+ {
+
+ U[iN + k] /= scale;
+ s += (U[iN + k]) * (U[iN + k]);
+ } /* for */
+
+ f = U[iN + l];
+ g = -sqrt( s ) * Sgn( f );
+ h = f * g - s;
+ U[i * N + l] = f - g;
+
+ for( k = l; k < N; k++ )
+ rv1[k] = U[iN + k] / h;
+
+ for( jN = lN; jN < MN; jN += N )
+ {
+
+ s = 0;
+
+ for( k = l; k < N; k++ )
+ s += U[jN + k] * U[iN + k];
+
+ for( k = l; k < N; k++ )
+ U[jN + k] += s * rv1[k];
+
+ } /* for */
+
+ for( k = l; k < N; k++ )
+ U[iN + k] *= scale;
+ } /* if */
+
+ t = fabs( W[i] );
+ t += fabs( rv1[i] );
+ anorm = MAX( anorm, t );
+ } /* for */
+
+ anorm *= cc;
+
+ /* accumulation of right transformations, if needed */
+
+ if( get_V )
+ {
+
+ for( i = N - 1, iN = NN - N; i >= 0; i--, iN -= N )
+ {
+
+ if( i < N - 1 )
+ {
+
+ /* pass-by small g */
+ if( !REAL_ZERO( g ))
+ {
+
+ for( j = l, jN = lN; j < N; j++, jN += N )
+ V[jN + i] = U[iN + j] / U[iN + l] / g;
+
+ for( j = l; j < N; j++ )
+ {
+
+ s = 0;
+
+ for( k = l, kN = lN; k < N; k++, kN += N )
+ s += U[iN + k] * V[kN + j];
+
+ for( kN = lN; kN < NN; kN += N )
+ V[kN + j] += s * V[kN + i];
+ } /* for */
+ } /* if */
+
+ for( j = l, jN = lN; j < N; j++, jN += N )
+ {
+ V[iN + j] = 0;
+ V[jN + i] = 0;
+ } /* for */
+ } /* if */
+
+ V[iN + i] = 1;
+ g = rv1[i];
+ l = i;
+ lN = iN;
+ } /* for */
+ } /* if */
+
+ /* accumulation of left transformations, if needed */
+
+ if( get_U )
+ {
+
+ for( i = N - 1, iN = NN - N; i >= 0; i--, iN -= N )
+ {
+
+ l = i + 1;
+ lN = iN + N;
+ g = W[i];
+
+ for( j = l; j < N; j++ )
+ U[iN + j] = 0;
+
+ /* pass-by small g */
+ if( !REAL_ZERO( g ))
+ {
+
+ for( j = l; j < N; j++ )
+ {
+
+ s = 0;
+
+ for( kN = lN; kN < MN; kN += N )
+ s += U[kN + i] * U[kN + j];
+
+ f = s / U[iN + i] / g;
+
+ for( kN = iN; kN < MN; kN += N )
+ U[kN + j] += f * U[kN + i];
+ } /* for */
+
+ for( jN = iN; jN < MN; jN += N )
+ U[jN + i] /= g;
+ }
+ else
+ {
+
+ for( jN = iN; jN < MN; jN += N )
+ U[jN + i] = 0;
+ } /* if */
+
+ U[iN + i] += 1;
+ } /* for */
+ } /* if */
+
+ /* Iterations QR-algorithm for bidiagonal matrixes
+ W[i] - is the main diagonal
+ rv1[i] - is the top diagonal, rv1[0]=0.
+ */
+
+ for( k = N - 1; k >= 0; k-- )
+ {
+
+ k1 = k - 1;
+ iterations = 0;
+
+ for( ;; )
+ {
+
+ /* Cycle: checking a possibility of fission matrix */
+ for( l = k; l >= 0; l-- )
+ {
+
+ l1 = l - 1;
+
+ if( REAL_ZERO( rv1[l] ) || REAL_ZERO( W[l1] ))
+ break;
+ } /* for */
+
+ if( !REAL_ZERO( rv1[l] ))
+ {
+
+ /* W[l1] = 0, matrix possible to fission
+ by clearing out rv1[l] */
+
+ c = 0;
+ s = 1;
+
+ for( i = l; i <= k; i++ )
+ {
+
+ f = s * rv1[i];
+ rv1[i] = c * rv1[i];
+
+ /* Rotations are done before the end of the block,
+ or when element in the line is finagle.
+ */
+
+ if( REAL_ZERO( f ))
+ break;
+
+ g = W[i];
+
+ /* Scaling prevents finagling H ( F!=0!) */
+
+ af = fabs( f );
+ ag = fabs( g );
+
+ if( af < ag )
+ h = ag * sqrt( 1 + (f / g) * (f / g) );
+ else
+ h = af * sqrt( 1 + (f / g) * (f / g) );
+
+ W[i] = h;
+ c = g / h;
+ s = -f / h;
+
+ if( get_U )
+ {
+
+ for( jN = 0; jN < MN; jN += N )
+ {
+
+ y = U[jN + l1];
+ z = U[jN + i];
+ U[jN + l1] = y * c + z * s;
+ U[jN + i] = -y * s + z * c;
+ } /* for */
+ } /* if */
+ } /* for */
+ } /* if */
+
+
+ /* Output in this place of program means,
+ that rv1[L] = 0, matrix fissioned
+ Iterations of the process of the persecution
+ will be executed always for
+ the bottom block ( from l before k ),
+ with increase l possible.
+ */
+
+ z = W[k];
+
+ if( l == k )
+ break;
+
+ /* Completion iterations: lower block
+ became trivial ( rv1[K]=0) */
+
+ if( iterations++ == max_iterations )
+ return k;
+
+ /* Shift is computed on the lowest order 2 minor. */
+
+ x = W[l];
+ y = W[k1];
+ g = rv1[k1];
+ h = rv1[k];
+
+ /* consequent fission prevents forming a machine zero */
+ f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2 * h) / y;
+
+ /* prevented overflow */
+ if( fabs( f ) > 1 )
+ {
+ g = fabs( f );
+ g *= sqrt( 1 + (1 / f) * (1 / f) );
+ }
+ else
+ g = sqrt( f * f + 1 );
+
+ f = ((x - z) * (x + z) + h * (y / (f + fabs( g ) * Sgn( f )) - h)) / x;
+ c = 1;
+ s = 1;
+
+ for( i1 = l; i1 <= k1; i1++ )
+ {
+
+ i = i1 + 1;
+ g = rv1[i];
+ y = W[i];
+ h = s * g;
+ g *= c;
+
+ /* Scaling at calculation Z prevents its clearing,
+ however if F and H both are zero - pass-by of fission on Z.
+ */
+
+ af = fabs( f );
+ ah = fabs( h );
+
+ if( af < ah )
+ z = ah * sqrt( 1 + (f / h) * (f / h) );
+
+ else
+ {
+
+ z = 0;
+ if( !REAL_ZERO( af ))
+ z = af * sqrt( 1 + (h / f) * (h / f) );
+ } /* if */
+
+ rv1[i1] = z;
+
+ /* if Z=0, the rotation is free. */
+ if( !REAL_ZERO( z ))
+ {
+
+ c = f / z;
+ s = h / z;
+ } /* if */
+
+ f = x * c + g * s;
+ g = -x * s + g * c;
+ h = y * s;
+ y *= c;
+
+ if( get_V )
+ {
+
+ for( jN = 0; jN < NN; jN += N )
+ {
+
+ x = V[jN + i1];
+ z = V[jN + i];
+ V[jN + i1] = x * c + z * s;
+ V[jN + i] = -x * s + z * c;
+ } /* for */
+ } /* if */
+
+ af = fabs( f );
+ ah = fabs( h );
+
+ if( af < ah )
+ z = ah * sqrt( 1 + (f / h) * (f / h) );
+ else
+ {
+
+ z = 0;
+ if( !REAL_ZERO( af ))
+ z = af * sqrt( 1 + (h / f) * (h / f) );
+ } /* if */
+
+ W[i1] = z;
+
+ if( !REAL_ZERO( z ))
+ {
+
+ c = f / z;
+ s = h / z;
+ } /* if */
+
+ f = c * g + s * y;
+ x = -s * g + c * y;
+
+ if( get_U )
+ {
+
+ for( jN = 0; jN < MN; jN += N )
+ {
+
+ y = U[jN + i1];
+ z = U[jN + i];
+ U[jN + i1] = y * c + z * s;
+ U[jN + i] = -y * s + z * c;
+ } /* for */
+ } /* if */
+ } /* for */
+
+ rv1[l] = 0;
+ rv1[k] = f;
+ W[k] = x;
+ } /* for */
+
+ if( z < 0 )
+ {
+
+ W[k] = -z;
+
+ if( get_V )
+ {
+
+ for( jN = 0; jN < NN; jN += N )
+ V[jN + k] *= -1;
+ } /* if */
+ } /* if */
+ } /* for */
+
+ cvFree( &rv1 );
+
+ return error;
+
+} /* vm_SingularValueDecomposition */
+
+/*========================================================================*/
+
+/* Obsolete functions. Just for ViewMorping */
+/*=====================================================================================*/
+
+int
+icvGaussMxN( double *A, double *B, int M, int N, double **solutions )
+{
+ int *variables;
+ int row, swapi, i, i_best = 0, j, j_best = 0, t;
+ double swapd, ratio, bigest;
+
+ if( !A || !B || !M || !N )
+ return -1;
+
+ variables = (int *) cvAlloc( (size_t) N * sizeof( int ));
+
+ if( variables == 0 )
+ return -1;
+
+ for( i = 0; i < N; i++ )
+ {
+ variables[i] = i;
+ } /* for */
+
+ /* ----- Direct way ----- */
+
+ for( row = 0; row < M; row++ )
+ {
+
+ bigest = 0;
+
+ for( j = row; j < M; j++ )
+ { /* search non null element */
+ for( i = row; i < N; i++ )
+ {
+ double a = fabs( A[j * N + i] ), b = fabs( bigest );
+ if( a > b )
+ {
+ bigest = A[j * N + i];
+ i_best = i;
+ j_best = j;
+ } /* if */
+ } /* for */
+ } /* for */
+
+ if( REAL_ZERO( bigest ))
+ break; /* if all shank elements are null */
+
+ if( j_best - row )
+ {
+
+ for( t = 0; t < N; t++ )
+ { /* swap a rows */
+
+ swapd = A[row * N + t];
+ A[row * N + t] = A[j_best * N + t];
+ A[j_best * N + t] = swapd;
+ } /* for */
+
+ swapd = B[row];
+ B[row] = B[j_best];
+ B[j_best] = swapd;
+ } /* if */
+
+ if( i_best - row )
+ {
+
+ for( t = 0; t < M; t++ )
+ { /* swap a columns */
+
+ swapd = A[t * N + i_best];
+ A[t * N + i_best] = A[t * N + row];
+ A[t * N + row] = swapd;
+ } /* for */
+
+ swapi = variables[row];
+ variables[row] = variables[i_best];
+ variables[i_best] = swapi;
+ } /* if */
+
+ for( i = row + 1; i < M; i++ )
+ { /* recounting A and B */
+
+ ratio = -A[i * N + row] / A[row * N + row];
+ B[i] += B[row] * ratio;
+
+ for( j = N - 1; j >= row; j-- )
+ {
+
+ A[i * N + j] += A[row * N + j] * ratio;
+ } /* for */
+ } /* for */
+ } /* for */
+
+ if( row < M )
+ { /* if rank(A)<M */
+
+ for( j = row; j < M; j++ )
+ {
+ if( !REAL_ZERO( B[j] ))
+ {
+
+ cvFree( &variables );
+ return -1; /* if system is antithetic */
+ } /* if */
+ } /* for */
+
+ M = row; /* decreasing size of the task */
+ } /* if */
+
+ /* ----- Reverse way ----- */
+
+ if( M < N )
+ { /* if solution are not exclusive */
+
+ *solutions = (double *) cvAlloc( ((N - M + 1) * N) * sizeof( double ));
+
+ if( *solutions == 0 )
+ {
+ cvFree( &variables );
+ return -1;
+ }
+
+
+ for( t = M; t <= N; t++ )
+ {
+ for( j = M; j < N; j++ )
+ {
+
+ (*solutions)[(t - M) * N + variables[j]] = (double) (t == j);
+ } /* for */
+
+ for( i = M - 1; i >= 0; i-- )
+ { /* finding component of solution */
+
+ if( t < N )
+ {
+ (*solutions)[(t - M) * N + variables[i]] = 0;
+ }
+ else
+ {
+ (*solutions)[(t - M) * N + variables[i]] = B[i] / A[i * N + i];
+ } /* if */
+
+ for( j = i + 1; j < N; j++ )
+ {
+
+ (*solutions)[(t - M) * N + variables[i]] -=
+ (*solutions)[(t - M) * N + variables[j]] * A[i * N + j] / A[i * N + i];
+ } /* for */
+ } /* for */
+ } /* for */
+
+ cvFree( &variables );
+ return N - M;
+ } /* if */
+
+ *solutions = (double *) cvAlloc( (N) * sizeof( double ));
+
+ if( solutions == 0 )
+ return -1;
+
+ for( i = N - 1; i >= 0; i-- )
+ { /* finding exclusive solution */
+
+ (*solutions)[variables[i]] = B[i] / A[i * N + i];
+
+ for( j = i + 1; j < N; j++ )
+ {
+
+ (*solutions)[variables[i]] -=
+ (*solutions)[variables[j]] * A[i * N + j] / A[i * N + i];
+ } /* for */
+ } /* for */
+
+ cvFree( &variables );
+ return 0;
+
+} /* icvGaussMxN */
+
+/*=====================================================================================*/
+/*
+static CvStatus
+icvGetCoof( double *f1, double *f2, double *a2, double *a1, double *a0 )
+{
+ double G[9], a3;
+ int i;
+
+ if( !f1 || !f2 || !a0 || !a1 || !a2 )
+ return CV_BADFACTOR_ERR;
+
+ for( i = 0; i < 9; i++ )
+ {
+
+ G[i] = f1[i] - f2[i];
+ }
+
+ a3 = icvDet( G );
+
+ if( REAL_ZERO( a3 ))
+ return CV_BADFACTOR_ERR;
+
+ *a2 = 0;
+ *a1 = 0;
+ *a0 = icvDet( f2 );
+
+ for( i = 0; i < 9; i++ )
+ {
+
+ *a2 += f2[i] * icvMinor( G, (int) (i % 3), (int) (i / 3) );
+ *a1 += G[i] * icvMinor( f2, (int) (i % 3), (int) (i / 3) );
+ }
+
+ *a0 /= a3;
+ *a1 /= a3;
+ *a2 /= a3;
+
+ return CV_NO_ERR;
+
+}*/ /* icvGetCoof */
+
+
+
+/*======================================================================================*/
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvLMedS7
+// Purpose:
+//
+//
+// Context:
+// Parameters:
+//
+//
+//
+//
+//
+//
+//
+// Returns:
+// CV_NO_ERR if all Ok or error code
+// Notes:
+//F*/
+
+CvStatus
+icvLMedS7( int *points1, int *points2, CvMatrix3 * matrix )
+{ /* Incorrect realization */
+ CvStatus error = CV_NO_ERR;
+
+/* int amount; */
+ matrix = matrix;
+ points1 = points1;
+ points2 = points2;
+
+/* error = cs_Point7( points1, points2, matrix ); */
+/* error = icvPoint7 ( points1, points2, matrix,&amount ); */
+ return error;
+
+} /* icvLMedS7 */
+
+
+/*======================================================================================*/
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: icvPoint7
+// Purpose:
+//
+//
+// Context:
+// Parameters:
+//
+//
+//
+//
+//
+//
+//
+// Returns:
+// CV_NO_ERR if all Ok or error code
+// Notes:
+//F*/
+
+CvStatus
+icvPoint7( int *ml, int *mr, double *F, int *amount )
+{
+ double A[63], B[7];
+ double *solutions;
+ double a2, a1, a0;
+ double squares[6];
+ int i, j;
+
+/* int amount; */
+/* float* F; */
+
+ CvStatus error = CV_BADFACTOR_ERR;
+
+/* F = (float*)matrix->m; */
+
+ if( !ml || !mr || !F )
+ return CV_BADFACTOR_ERR;
+
+ for( i = 0; i < 7; i++ )
+ {
+ for( j = 0; j < 9; j++ )
+ {
+
+ A[i * 9 + j] = (double) ml[i * 3 + j / 3] * (double) mr[i * 3 + j % 3];
+ } /* for */
+ B[i] = 0;
+ } /* for */
+
+ *amount = 0;
+
+ if( icvGaussMxN( A, B, 7, 9, &solutions ) == 2 )
+ {
+ if( icvGetCoef( solutions, solutions + 9, &a2, &a1, &a0 ) == CV_NO_ERR )
+ {
+ icvCubic( a2, a1, a0, squares );
+
+ for( i = 0; i < 1; i++ )
+ {
+
+ if( REAL_ZERO( squares[i * 2 + 1] ))
+ {
+
+ for( j = 0; j < 9; j++ )
+ {
+
+ F[*amount + j] = (float) (squares[i] * solutions[j] +
+ (1 - squares[i]) * solutions[j + 9]);
+ } /* for */
+
+ *amount += 9;
+
+ error = CV_NO_ERR;
+ } /* if */
+ } /* for */
+
+ cvFree( &solutions );
+ return error;
+ }
+ else
+ {
+ cvFree( &solutions );
+ } /* if */
+
+ }
+ else
+ {
+ cvFree( &solutions );
+ } /* if */
+
+ return error;
+} /* icvPoint7 */
+
diff --git a/cvaux/src/cvmat.cpp b/cvaux/src/cvmat.cpp
new file mode 100644
index 0000000..6ad2ba4
--- /dev/null
+++ b/cvaux/src/cvmat.cpp
@@ -0,0 +1,879 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+// temporarily remove it from build
+#if 0 && ((_MSC_VER>=1200) || defined __BORLANDC__)
+
+double CvMAT::get( const uchar* ptr, int type, int coi )
+{
+ double t = 0;
+ assert( (unsigned)coi < (unsigned)CV_MAT_CN(type) );
+
+ switch( CV_MAT_DEPTH(type) )
+ {
+ case CV_8U:
+ t = ((uchar*)ptr)[coi];
+ break;
+ case CV_8S:
+ t = ((char*)ptr)[coi];
+ break;
+ case CV_16S:
+ t = ((short*)ptr)[coi];
+ break;
+ case CV_32S:
+ t = ((int*)ptr)[coi];
+ break;
+ case CV_32F:
+ t = ((float*)ptr)[coi];
+ break;
+ case CV_64F:
+ t = ((double*)ptr)[coi];
+ break;
+ }
+
+ return t;
+}
+
+void CvMAT::set( uchar* ptr, int type, int coi, double d )
+{
+ int i;
+ assert( (unsigned)coi < (unsigned)CV_MAT_CN(type) );
+
+ switch( CV_MAT_DEPTH(type))
+ {
+ case CV_8U:
+ i = cvRound(d);
+ ((uchar*)ptr)[coi] = CV_CAST_8U(i);
+ break;
+ case CV_8S:
+ i = cvRound(d);
+ ((char*)ptr)[coi] = CV_CAST_8S(i);
+ break;
+ case CV_16S:
+ i = cvRound(d);
+ ((short*)ptr)[coi] = CV_CAST_16S(i);
+ break;
+ case CV_32S:
+ i = cvRound(d);
+ ((int*)ptr)[coi] = CV_CAST_32S(i);
+ break;
+ case CV_32F:
+ ((float*)ptr)[coi] = (float)d;
+ break;
+ case CV_64F:
+ ((double*)ptr)[coi] = d;
+ break;
+ }
+}
+
+
+void CvMAT::set( uchar* ptr, int type, int coi, int i )
+{
+ assert( (unsigned)coi < (unsigned)CV_MAT_CN(type) );
+
+ switch( CV_MAT_DEPTH(type))
+ {
+ case CV_8U:
+ ((uchar*)ptr)[coi] = CV_CAST_8U(i);
+ break;
+ case CV_8S:
+ ((char*)ptr)[coi] = CV_CAST_8S(i);
+ break;
+ case CV_16S:
+ ((short*)ptr)[coi] = CV_CAST_16S(i);
+ break;
+ case CV_32S:
+ ((int*)ptr)[coi] = i;
+ break;
+ case CV_32F:
+ ((float*)ptr)[coi] = (float)i;
+ break;
+ case CV_64F:
+ ((double*)ptr)[coi] = (double)i;
+ break;
+ }
+}
+
+
+void CvMAT::set( uchar* ptr, int type, double d )
+{
+ int i, cn = CV_MAT_CN(type);
+
+ switch( CV_MAT_DEPTH(type))
+ {
+ case CV_8U:
+ i = cvRound(d);
+ ((uchar*)ptr)[0] = CV_CAST_8U(i);
+ i = cn;
+ while( --i ) ((uchar*)ptr)[i] = 0;
+ break;
+ case CV_8S:
+ i = cvRound(d);
+ ((char*)ptr)[0] = CV_CAST_8S(i);
+ i = cn;
+ while( --i ) ((char*)ptr)[i] = 0;
+ break;
+ case CV_16S:
+ i = cvRound(d);
+ ((short*)ptr)[0] = CV_CAST_16S(i);
+ i = cn;
+ while( --i ) ((short*)ptr)[i] = 0;
+ break;
+ case CV_32S:
+ i = cvRound(d);
+ ((int*)ptr)[0] = i;
+ i = cn;
+ while( --i ) ((int*)ptr)[i] = 0;
+ break;
+ case CV_32F:
+ ((float*)ptr)[0] = (float)d;
+ i = cn;
+ while( --i ) ((float*)ptr)[i] = 0;
+ break;
+ case CV_64F:
+ ((double*)ptr)[0] = d;
+ i = cn;
+ while( --i ) ((double*)ptr)[i] = 0;
+ break;
+ }
+}
+
+
+void CvMAT::set( uchar* ptr, int type, int i )
+{
+ int cn = CV_MAT_CN(type);
+
+ switch( CV_MAT_DEPTH(type))
+ {
+ case CV_8U:
+ ((uchar*)ptr)[0] = CV_CAST_8U(i);
+ i = cn;
+ while( --i ) ((uchar*)ptr)[i] = 0;
+ break;
+ case CV_8S:
+ ((char*)ptr)[0] = CV_CAST_8S(i);
+ i = cn;
+ while( --i ) ((char*)ptr)[i] = 0;
+ break;
+ case CV_16S:
+ ((short*)ptr)[0] = CV_CAST_16S(i);
+ i = cn;
+ while( --i ) ((short*)ptr)[i] = 0;
+ break;
+ case CV_32S:
+ ((int*)ptr)[0] = i;
+ i = cn;
+ while( --i ) ((int*)ptr)[i] = 0;
+ break;
+ case CV_32F:
+ ((float*)ptr)[0] = (float)i;
+ i = cn;
+ while( --i ) ((float*)ptr)[i] = 0;
+ break;
+ case CV_64F:
+ ((double*)ptr)[0] = (double)i;
+ i = cn;
+ while( --i ) ((double*)ptr)[i] = 0;
+ break;
+ }
+}
+
+
+CvMAT::CvMAT( const _CvMAT_T_& mat_t )
+{
+ data.ptr = 0;
+ type = 0;
+ refcount = 0;
+ *this = mat_t;
+}
+
+
+CvMAT::CvMAT( const _CvMAT_ADD_& mat_add )
+{
+ data.ptr = 0;
+ type = 0;
+ refcount = 0;
+ *this = mat_add;
+}
+
+
+CvMAT::CvMAT( const _CvMAT_ADD_EX_& mat_add )
+{
+ data.ptr = 0;
+ type = 0;
+ refcount = 0;
+ *this = mat_add;
+}
+
+
+CvMAT::CvMAT( const _CvMAT_SCALE_& scale_mat )
+{
+ data.ptr = 0;
+ type = 0;
+ refcount = 0;
+ *this = scale_mat;
+}
+
+
+CvMAT::CvMAT( const _CvMAT_SCALE_SHIFT_& scale_shift_mat )
+{
+ data.ptr = 0;
+ type = 0;
+ refcount = 0;
+ *this = scale_shift_mat;
+}
+
+
+CvMAT::CvMAT( const _CvMAT_MUL_& mmul )
+{
+ data.ptr = 0;
+ type = 0;
+ refcount = 0;
+ *this = mmul;
+}
+
+
+CvMAT::CvMAT( const _CvMAT_MUL_ADD_& mmuladd )
+{
+ data.ptr = 0;
+ type = 0;
+ refcount = 0;
+ *this = mmuladd;
+}
+
+
+CvMAT::CvMAT( const _CvMAT_INV_& inv_mat )
+{
+ data.ptr = 0;
+ type = 0;
+ refcount = 0;
+ *this = inv_mat;
+}
+
+
+CvMAT::CvMAT( const _CvMAT_NOT_& not_mat )
+{
+ type = 0;
+ data.ptr = 0;
+ refcount = 0;
+ *this = not_mat;
+}
+
+
+CvMAT::CvMAT( const _CvMAT_UN_LOGIC_& mat_logic )
+{
+ type = 0;
+ data.ptr = 0;
+ refcount = 0;
+ *this = mat_logic;
+}
+
+
+CvMAT::CvMAT( const _CvMAT_LOGIC_& mat_logic )
+{
+ type = 0;
+ data.ptr = 0;
+ refcount = 0;
+ *this = mat_logic;
+}
+
+
+CvMAT::CvMAT( const _CvMAT_COPY_& mat_copy )
+{
+ CvMAT* src = (CvMAT*)mat_copy.a;
+ create( src->height, src->width, src->type );
+ cvCopy( src, this );
+}
+
+
+CvMAT::CvMAT( const _CvMAT_CVT_& mat_cvt )
+{
+ type = 0;
+ data.ptr = 0;
+ refcount = 0;
+ *this = mat_cvt;
+}
+
+
+CvMAT::CvMAT( const _CvMAT_DOT_OP_& dot_op )
+{
+ data.ptr = 0;
+ type = 0;
+ refcount = 0;
+ *this = dot_op;
+}
+
+
+CvMAT::CvMAT( const _CvMAT_SOLVE_& solve_mat )
+{
+ type = 0;
+ data.ptr = 0;
+ refcount = 0;
+ *this = solve_mat;
+}
+
+
+CvMAT::CvMAT( const _CvMAT_CMP_& cmp_mat )
+{
+ type = 0;
+ data.ptr = 0;
+ refcount = 0;
+ *this = cmp_mat;
+}
+
+
+/****************************************************************************************\
+* CvMAT::operator = *
+\****************************************************************************************/
+
+CvMAT& CvMAT::operator = ( const _CvMAT_T_& mat_t )
+{
+ CvMAT* src = (CvMAT*)&mat_t.a;
+ if( !data.ptr )
+ {
+ create( src->width, src->height, src->type );
+ }
+
+ cvTranspose( src, this );
+ return *this;
+}
+
+
+CvMAT& CvMAT::operator = ( const _CvMAT_ADD_& mat_add )
+{
+ CvMAT* a = mat_add.a;
+ CvMAT* b = mat_add.b;
+
+ if( !data.ptr )
+ {
+ create( a->height, a->width, a->type );
+ }
+
+ if( mat_add.beta == 1 )
+ {
+ cvAdd( a, b, this );
+ return *this;
+ }
+
+ if( mat_add.beta == -1 )
+ {
+ cvSub( a, b, this );
+ return *this;
+ }
+
+ if( CV_MAT_DEPTH(a->type) >= CV_32F && CV_MAT_CN(a->type) <= 2 )
+ cvScaleAdd( b, cvScalar(mat_add.beta), a, this );
+ else
+ cvAddWeighted( a, 1, b, mat_add.beta, 0, this );
+ return *this;
+}
+
+
+CvMAT& CvMAT::operator = ( const _CvMAT_ADD_EX_& mat_add )
+{
+ CvMAT* a = mat_add.a;
+ CvMAT* b = mat_add.b;
+
+ if( !data.ptr )
+ {
+ create( a->height, a->width, a->type );
+ }
+
+ cvAddWeighted( a, mat_add.alpha, b, mat_add.beta, mat_add.gamma, this );
+ return *this;
+}
+
+
+CvMAT& CvMAT::operator = ( const _CvMAT_SCALE_& scale_mat )
+{
+ CvMAT* src = scale_mat.a;
+
+ if( !data.ptr )
+ {
+ create( src->height, src->width, src->type );
+ }
+
+ cvConvertScale( src, this, scale_mat.alpha, 0 );
+ return *this;
+}
+
+
+CvMAT& CvMAT::operator = ( const _CvMAT_SCALE_SHIFT_& scale_shift_mat )
+{
+ CvMAT* src = scale_shift_mat.a;
+
+ if( !data.ptr )
+ {
+ create( src->height, src->width, src->type );
+ }
+
+ cvConvertScale( src, this, scale_shift_mat.alpha, scale_shift_mat.beta );
+ return *this;
+}
+
+
+CvMAT& CvMAT::operator = ( const _CvMAT_MUL_& mmul )
+{
+ CvMAT* a = mmul.a;
+ CvMAT* b = mmul.b;
+ int t_a = mmul.t_ab & 1;
+ int t_b = (mmul.t_ab & 2) != 0;
+ int m = (&(a->rows))[t_a];
+ int n = (&(b->rows))[t_b ^ 1];
+ /* this(m x n) = (a^o1(t))(m x l) * (b^o2(t))(l x n) */
+
+ if( !data.ptr )
+ {
+ create( m, n, a->type );
+ }
+
+ if( mmul.alpha == 1 )
+ {
+ if( mmul.t_ab == 0 )
+ {
+ cvMatMulAdd( a, b, 0, this );
+ return *this;
+ }
+
+ if( a->data.ptr == b->data.ptr && mmul.t_ab < 3 &&
+ a->rows == b->rows && a->cols == b->cols &&
+ a->data.ptr != data.ptr )
+ {
+ cvMulTransposed( a, this, mmul.t_ab & 1 );
+ return *this;
+ }
+ }
+
+ cvGEMM( a, b, mmul.alpha, 0, 0, this, mmul.t_ab );
+ return *this;
+}
+
+
+CvMAT& CvMAT::operator = ( const _CvMAT_MUL_ADD_& mmuladd )
+{
+ CvMAT* a = mmuladd.a;
+ CvMAT* b = mmuladd.b;
+ CvMAT* c = mmuladd.c;
+ int t_a = mmuladd.t_abc & 1;
+ int t_b = (mmuladd.t_abc & 2) != 0;
+ int m = (&(a->rows))[t_a];
+ int n = (&(b->rows))[t_b ^ 1];
+ /* this(m x n) = (a^o1(t))(m x l) * (b^o2(t))(l x n) */
+
+ if( !data.ptr )
+ {
+ create( m, n, a->type );
+ }
+
+ if( mmuladd.t_abc == 0 && mmuladd.alpha == 1 && mmuladd.beta == 1 )
+ cvMatMulAdd( a, b, c, this );
+ else
+ cvGEMM( a, b, mmuladd.alpha, c, mmuladd.beta, this, mmuladd.t_abc );
+ return *this;
+}
+
+
+CvMAT& CvMAT::operator = ( const _CvMAT_INV_& inv_mat )
+{
+ CvMAT* src = (CvMAT*)&inv_mat.a;
+
+ if( !data.ptr )
+ {
+ create( src->height, src->width, src->type );
+ }
+
+ if( inv_mat.method == 0 )
+ cvInvert( src, this );
+ else
+ cvPseudoInv( src, this );
+ return *this;
+}
+
+
+CvMAT& CvMAT::operator = ( const _CvMAT_NOT_& not_mat )
+{
+ CvMAT* src = not_mat.a;
+
+ if( !data.ptr )
+ {
+ create( src->height, src->width, src->type );
+ }
+
+ cvNot( src, this );
+ return *this;
+}
+
+
+CvMAT& CvMAT::operator = ( const _CvMAT_LOGIC_& mat_logic )
+{
+ CvMAT* a = mat_logic.a;
+ CvMAT* b = mat_logic.b;
+ int flags = mat_logic.flags;
+ _CvMAT_LOGIC_::Op op = mat_logic.op;
+
+ if( !data.ptr )
+ {
+ create( a->height, a->width, a->type );
+ }
+
+ switch( op )
+ {
+ case _CvMAT_LOGIC_::AND:
+
+ if( flags == 0 )
+ cvAnd( a, b, this );
+ else if( flags == 3 )
+ {
+ cvOr( a, b, this );
+ cvNot( this, this );
+ }
+ else if( flags == 1 )
+ {
+ if( data.ptr == b->data.ptr )
+ {
+ cvNot( b, this );
+ cvOr( this, a, this );
+ cvNot( this, this );
+ }
+ else
+ {
+ cvNot( a, this );
+ cvAnd( this, b, this );
+ }
+ }
+ else
+ {
+ if( data.ptr == a->data.ptr )
+ {
+ cvNot( a, this );
+ cvOr( this, b, this );
+ cvNot( this, this );
+ }
+ else
+ {
+ cvNot( b, this );
+ cvAnd( this, a, this );
+ }
+ }
+ break;
+
+ case _CvMAT_LOGIC_::OR:
+
+ if( flags == 0 )
+ cvOr( a, b, this );
+ else if( flags == 3 )
+ {
+ cvAnd( a, b, this );
+ cvNot( this, this );
+ }
+ else if( flags == 1 )
+ {
+ if( data.ptr == b->data.ptr )
+ {
+ cvNot( b, this );
+ cvAnd( this, a, this );
+ cvNot( this, this );
+ }
+ else
+ {
+ cvNot( a, this );
+ cvOr( this, b, this );
+ }
+ }
+ else
+ {
+ if( data.ptr == a->data.ptr )
+ {
+ cvNot( a, this );
+ cvAnd( this, b, this );
+ cvNot( this, this );
+ }
+ else
+ {
+ cvNot( b, this );
+ cvOr( this, a, this );
+ }
+ }
+ break;
+
+ case _CvMAT_LOGIC_::XOR:
+
+ cvXor( a, b, this );
+ if( flags == 1 || flags == 2 )
+ cvNot( this, this );
+ break;
+ }
+
+ return *this;
+}
+
+
+CvMAT& CvMAT::operator = ( const _CvMAT_UN_LOGIC_& mat_logic )
+{
+ CvMAT* a = mat_logic.a;
+ CvScalar scalar = cvScalarAll( mat_logic.alpha );
+ int flags = mat_logic.flags;
+ _CvMAT_LOGIC_::Op op = mat_logic.op;
+
+ if( !data.ptr )
+ {
+ create( a->height, a->width, a->type );
+ }
+
+ switch( op )
+ {
+ case _CvMAT_LOGIC_::AND:
+
+ if( flags == 0 )
+ cvAndS( a, scalar, this );
+ else
+ {
+ cvNot( a, this );
+ cvAndS( this, scalar, this );
+ }
+ break;
+
+ case _CvMAT_LOGIC_::OR:
+
+ if( flags == 0 )
+ cvOrS( a, scalar, this );
+ else
+ {
+ cvNot( a, this );
+ cvOrS( this, scalar, this );
+ }
+ break;
+
+ case _CvMAT_LOGIC_::XOR:
+
+ if( flags == 0 )
+ cvXorS( a, scalar, this );
+ else
+ cvXorS( a, ~scalar, this );
+ break;
+ }
+
+ return *this;
+}
+
+
+CvMAT& CvMAT::operator = ( const _CvMAT_COPY_& mat_copy )
+{
+ CvMAT* src = (CvMAT*)mat_copy.a;
+
+ if( !data.ptr )
+ {
+ create( src->height, src->width, src->type );
+ }
+
+ if( src != this )
+ cvCopy( src, this );
+
+ return *this;
+}
+
+
+CvMAT& CvMAT::operator = ( const _CvMAT_CVT_& mat_cvt )
+{
+ CvMAT* src = (CvMAT*)&mat_cvt.a;
+
+ if( !data.ptr )
+ {
+ int depth = mat_cvt.newdepth;
+ create( src->height, src->width, depth < 0 ? src->type :
+ CV_MAT_CN(src->type)|CV_MAT_DEPTH(depth));
+ }
+
+ cvCvtScale( src, this, mat_cvt.scale, mat_cvt.shift );
+ return *this;
+}
+
+
+CvMAT& CvMAT::operator = ( const _CvMAT_DOT_OP_& dot_op )
+{
+ CvMAT* a = (CvMAT*)&(dot_op.a);
+ CvMAT* b = dot_op.b;
+
+ if( !data.ptr )
+ {
+ create( a->height, a->width, a->type );
+ }
+
+ switch( dot_op.op )
+ {
+ case '*':
+ cvMul( a, b, this, dot_op.alpha );
+ break;
+ case '/':
+ if( b != 0 )
+ cvDiv( a, b, this, dot_op.alpha );
+ else
+ cvDiv( 0, a, this, dot_op.alpha );
+ break;
+ case 'm':
+ if( b != 0 )
+ cvMin( a, b, this );
+ else
+ cvMinS( a, dot_op.alpha, this );
+ break;
+ case 'M':
+ if( b != 0 )
+ cvMax( a, b, this );
+ else
+ cvMaxS( a, dot_op.alpha, this );
+ break;
+ case 'a':
+ if( b != 0 )
+ cvAbsDiff( a, b, this );
+ else
+ cvAbsDiffS( a, this, cvScalar(dot_op.alpha) );
+ break;
+ default:
+ assert(0);
+ }
+
+ return *this;
+}
+
+
+CvMAT& CvMAT::operator = ( const _CvMAT_SOLVE_& solve_mat )
+{
+ CvMAT* a = (CvMAT*)(solve_mat.a);
+ CvMAT* b = (CvMAT*)(solve_mat.b);
+
+ if( !data.ptr )
+ {
+ create( a->height, b->width, a->type );
+ }
+
+ if( solve_mat.method == 0 )
+ cvSolve( a, b, this );
+ else
+ {
+ CvMAT temp;
+ cvInitMatHeader( &temp, a->cols, a->rows, a->type );
+ cvCreateData( &temp );
+
+ cvPseudoInv( a, &temp );
+ cvMatMul( &temp, b, this );
+ }
+
+ return *this;
+}
+
+
+CvMAT& CvMAT::operator = ( const _CvMAT_CMP_& mat_cmp )
+{
+ CvMAT* a = mat_cmp.a;
+ CvMAT* b = mat_cmp.b;
+
+ if( !data.ptr )
+ {
+ create( a->height, a->width, CV_8UC1 );
+ }
+
+ if( b )
+ cvCmp( a, b, this, mat_cmp.cmp_op );
+ else
+ cvCmpS( a, mat_cmp.alpha, this, mat_cmp.cmp_op );
+ return *this;
+}
+
+
+/****************************************************************************************\
+* CvMAT I/O operations *
+\****************************************************************************************/
+
+void CvMAT::write( const char* name, FILE* f, const char* fmt )
+{
+ int i, j, w = width * CV_MAT_CN(type);
+ FILE* out = f ? f : stdout;
+
+ if( name )
+ fprintf( stdout, "%s(%d x %d) =\n\t", name, rows, cols );
+
+ for( i = 0; i < rows; i++ )
+ {
+ switch( CV_MAT_DEPTH(type))
+ {
+ case CV_8U: if( !fmt )
+ fmt = "%4d";
+ for( j = 0; j < w; j++ )
+ fprintf( out, fmt, ((uchar*)(data.ptr + i*step))[j] );
+ break;
+ case CV_8S: if( !fmt )
+ fmt = "%5d";
+ for( j = 0; j < w; j++ )
+ fprintf( out, fmt, ((char*)(data.ptr + i*step))[j] );
+ break;
+ case CV_16S: if( !fmt )
+ fmt = "%7d";
+ for( j = 0; j < w; j++ )
+ fprintf( out, fmt, ((short*)(data.ptr + i*step))[j] );
+ break;
+ case CV_32S: if( !fmt )
+ fmt = " %08x";
+ for( j = 0; j < w; j++ )
+ fprintf( out, fmt, ((int*)(data.ptr + i*step))[j] );
+ break;
+ case CV_32F: if( !fmt )
+ fmt = "%15g";
+ for( j = 0; j < w; j++ )
+ fprintf( out, fmt, ((float*)(data.ptr + i*step))[j] );
+ break;
+ case CV_64F: if( !fmt )
+ fmt = "%15g";
+ for( j = 0; j < w; j++ )
+ fprintf( out, fmt, ((double*)(data.ptr + i*step))[j] );
+ break;
+ }
+ fprintf( out, "\n%s", i < rows - 1 ? "\t" : "" );
+ }
+ fprintf( out, "\n" );
+}
+
+#endif /* _MSC_VER || __BORLANDC__ */
+
+/* End of file. */
+
+
diff --git a/cvaux/src/cvmorphcontours.cpp b/cvaux/src/cvmorphcontours.cpp
new file mode 100644
index 0000000..9d34291
--- /dev/null
+++ b/cvaux/src/cvmorphcontours.cpp
@@ -0,0 +1,855 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+#define PATH_TO_E 1
+#define PATH_TO_SE 2
+#define PATH_TO_S 3
+
+#define K_S 2
+#define E_S 2
+#define C_S .01
+#define K_Z 5000
+#define K_NM 50000
+#define K_B 40
+#define NULL_EDGE 0.001f
+#define inf DBL_MAX
+
+typedef struct __CvWork
+{
+ double w_east;
+ double w_southeast;
+ double w_south;
+ char path_e;
+ char path_se;
+ char path_s;
+}_CvWork;
+
+
+double _cvBendingWork( CvPoint2D32f* B0,
+ CvPoint2D32f* F0,
+ CvPoint2D32f* B1,
+ CvPoint2D32f* F1/*,
+ CvPoint* K */);
+
+double _cvStretchingWork(CvPoint2D32f* P1,
+ CvPoint2D32f* P2);
+
+void _cvWorkEast (int i, int j, _CvWork** W, CvPoint2D32f* edges1, CvPoint2D32f* edges2);
+void _cvWorkSouthEast(int i, int j, _CvWork** W, CvPoint2D32f* edges1, CvPoint2D32f* edges2);
+void _cvWorkSouth (int i, int j, _CvWork** W, CvPoint2D32f* edges1, CvPoint2D32f* edges2);
+
+static CvPoint2D32f null_edge = {0,0};
+
+double _cvStretchingWork(CvPoint2D32f* P1,
+ CvPoint2D32f* P2)
+{
+ double L1,L2, L_min, dL;
+
+ L1 = sqrt( (double)P1->x*P1->x + P1->y*P1->y);
+ L2 = sqrt( (double)P2->x*P2->x + P2->y*P2->y);
+
+ L_min = MIN(L1, L2);
+ dL = fabs( L1 - L2 );
+
+ return K_S * pow( dL, E_S ) / ( L_min + C_S*dL );
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////
+double _cvBendingWork( CvPoint2D32f* B0,
+ CvPoint2D32f* F0,
+ CvPoint2D32f* B1,
+ CvPoint2D32f* F1/*,
+ CvPoint* K*/)
+{
+ CvPoint2D32f Q( CvPoint2D32f q0, CvPoint2D32f q1, CvPoint2D32f q2, double t );
+ double angle( CvPoint2D32f A, CvPoint2D32f B );
+
+ CvPoint2D32f Q0, Q1, Q2;
+ CvPoint2D32f Q1_nm = { 0, 0 }, Q2_nm = { 0, 0 };
+ double d0, d1, d2, des, t_zero;
+ double k_zero, k_nonmon;
+ CvPoint2D32f center;
+ double check01, check02;
+ char check_origin;
+ double d_angle, d_nm_angle;
+/*
+ if( (B0->x==0) && (B0->y==0) )
+ {
+ if( (F0->x==0) && (F0->y==0) )
+ {
+ B1->x = -B1->x;
+ B1->y = -B1->y;
+
+ d_angle = acos( (B1->x*F1->x + B1->y*F1->y)/sqrt( (B1->x*B1->x + B1->y*B1->y)*(F1->x*F1->x + F1->y*F1->y) ) );
+ d_angle = CV_PI - d_angle;
+
+ B1->x = -B1->x;
+ B1->y = -B1->y;
+
+ //return d_angle*K_B;
+ return 100;
+ }
+ K->x = -K->x;
+ K->y = -K->y;
+ B1->x = -B1->x;
+ B1->y = -B1->y;
+
+ d_angle = acos( (B1->x*F1->x + B1->y*F1->y)/sqrt( (B1->x*B1->x + B1->y*B1->y)*(F1->x*F1->x + F1->y*F1->y) ) );
+ d_angle = d_angle - acos( (F0->x*K->x + F0->y*K->y)/sqrt( (F0->x*F0->x + F0->y*F0->y)*(K->x*K->x + K->y*K->y) ) );
+ d_angle = d_angle - CV_PI*0.5;
+ d_angle = fabs(d_angle);
+
+
+ K->x = -K->x;
+ K->y = -K->y;
+ B1->x = -B1->x;
+ B1->y = -B1->y;
+
+ //return d_angle*K_B;
+ return 100;
+ }
+
+
+ if( (F0->x==0) && (F0->y==0) )
+ {
+ K->x = -K->x;
+ K->y = -K->y;
+ B1->x = -B1->x;
+ B1->y = -B1->y;
+
+ d_angle = acos( (B1->x*F1->x + B1->y*F1->y)/sqrt( (B1->x*B1->x + B1->y*B1->y)*(F1->x*F1->x + F1->y*F1->y) ) );
+ d_angle = d_angle - acos( (B0->x*K->x + B0->y*K->y)/sqrt( (B0->x*B0->x + B0->y*B0->y)*(K->x*K->x + K->y*K->y) ) );
+ d_angle = d_angle - CV_PI*0.5;
+ d_angle = fabs(d_angle);
+
+ K->x = -K->x;
+ K->y = -K->y;
+ B1->x = -B1->x;
+ B1->y = -B1->y;
+
+ //return d_angle*K_B;
+ return 100;
+ }
+///////////////
+
+ if( (B1->x==0) && (B1->y==0) )
+ {
+ if( (F1->x==0) && (F1->y==0) )
+ {
+ B0->x = -B0->x;
+ B0->y = -B0->y;
+
+ d_angle = acos( (B0->x*F0->x + B0->y*F0->y)/sqrt( (B0->x*B0->x + B0->y*B0->y)*(F0->x*F0->x + F0->y*F0->y) ) );
+ d_angle = CV_PI - d_angle;
+
+ B0->x = -B0->x;
+ B0->y = -B0->y;
+
+ //return d_angle*K_B;
+ return 100;
+ }
+ K->x = -K->x;
+ K->y = -K->y;
+ B0->x = -B0->x;
+ B0->y = -B0->y;
+
+ d_angle = acos( (B0->x*F0->x + B0->y*F0->y)/sqrt( (B0->x*B0->x + B0->y*B0->y)*(F0->x*F0->x + F0->y*F0->y) ) );
+ d_angle = d_angle - acos( (F1->x*K->x + F1->y*K->y)/sqrt( (F1->x*F1->x + F1->y*F1->y)*(K->x*K->x + K->y*K->y) ) );
+ d_angle = d_angle - CV_PI*0.5;
+ d_angle = fabs(d_angle);
+
+ K->x = -K->x;
+ K->y = -K->y;
+ B0->x = -B0->x;
+ B0->y = -B0->y;
+
+ //return d_angle*K_B;
+ return 100;
+ }
+
+
+ if( (F1->x==0) && (F1->y==0) )
+ {
+ K->x = -K->x;
+ K->y = -K->y;
+ B0->x = -B0->x;
+ B0->y = -B0->y;
+
+ d_angle = acos( (B0->x*F0->x + B0->y*F0->y)/sqrt( (B0->x*B0->x + B0->y*B0->y)*(F0->x*F0->x + F0->y*F0->y) ) );
+ d_angle = d_angle - acos( (B1->x*K->x + B1->y*K->y)/sqrt( (B1->x*B1->x + B1->y*B1->y)*(K->x*K->x + K->y*K->y) ) );
+ d_angle = d_angle - CV_PI*0.5;
+ d_angle = fabs(d_angle);
+
+ K->x = -K->x;
+ K->y = -K->y;
+ B0->x = -B0->x;
+ B0->y = -B0->y;
+
+ //return d_angle*K_B;
+ return 100;
+ }
+
+*/
+
+/*
+ B0->x = -B0->x;
+ B0->y = -B0->y;
+ B1->x = -B1->x;
+ B1->y = -B1->y;
+*/
+ Q0.x = F0->x * (-B0->x) + F0->y * (-B0->y);
+ Q0.y = F0->x * (-B0->y) - F0->y * (-B0->x);
+
+ Q1.x = 0.5f*( (F1->x * (-B0->x) + F1->y * (-B0->y)) + (F0->x * (-B1->x) + F0->y * (-B1->y)) );
+ Q1.y = 0.5f*( (F1->x * (-B0->y) - F1->y * (-B0->x)) + (F0->x * (-B1->y) - F0->y * (-B1->x)) );
+
+ Q2.x = F1->x * (-B1->x) + F1->y * (-B1->y);
+ Q2.y = F1->x * (-B1->y) - F1->y * (-B1->x);
+
+ d0 = Q0.x * Q1.y - Q0.y * Q1.x;
+ d1 = 0.5f*(Q0.x * Q2.y - Q0.y * Q2.x);
+ d2 = Q1.x * Q2.y - Q1.y * Q2.x;
+
+ // Check angles goes to zero
+ des = Q1.y*Q1.y - Q0.y*Q2.y;
+
+ k_zero = 0;
+
+ if( des >= 0 )
+ {
+ t_zero = ( Q0.y - Q1.y + sqrt(des) )/( Q0.y - 2*Q1.y + Q2.y );
+
+ if( (0 < t_zero) && (t_zero < 1) && ( Q(Q0, Q1, Q2, t_zero).x > 0 ) )
+ {
+ k_zero = inf;
+ }
+
+ t_zero = ( Q0.y - Q1.y - sqrt(des) )/( Q0.y - 2*Q1.y + Q2.y );
+
+ if( (0 < t_zero) && (t_zero < 1) && ( Q(Q0, Q1, Q2, t_zero).x > 0 ) )
+ {
+ k_zero = inf;
+ }
+ }
+
+ // Check nonmonotonic
+ des = d1*d1 - d0*d2;
+
+ k_nonmon = 0;
+
+ if( des >= 0 )
+ {
+ t_zero = ( d0 - d1 - sqrt(des) )/( d0 - 2*d1 + d2 );
+
+ if( (0 < t_zero) && (t_zero < 1) )
+ {
+ k_nonmon = 1;
+ Q1_nm = Q(Q0, Q1, Q2, t_zero);
+ }
+
+ t_zero = ( d0 - d1 + sqrt(des) )/( d0 - 2*d1 + d2 );
+
+ if( (0 < t_zero) && (t_zero < 1) )
+ {
+ k_nonmon += 2;
+ Q2_nm = Q(Q0, Q1, Q2, t_zero);
+ }
+ }
+
+ // Finde origin lie in Q0Q1Q2
+ check_origin = 1;
+
+ center.x = (Q0.x + Q1.x + Q2.x)/3;
+ center.y = (Q0.y + Q1.y + Q2.y)/3;
+
+ check01 = (center.x - Q0.x)*(Q1.y - Q0.y) + (center.y - Q0.y)*(Q1.x - Q0.x);
+ check02 = (-Q0.x)*(Q1.y - Q0.y) + (-Q0.y)*(Q1.x - Q0.x);
+ if( check01*check02 > 0 )
+ {
+ check01 = (center.x - Q1.x)*(Q2.y - Q1.y) + (center.y - Q1.y)*(Q2.x - Q1.x);
+ check02 = (-Q1.x)*(Q2.y - Q1.y) + (-Q1.y)*(Q2.x - Q1.x);
+ if( check01*check02 > 0 )
+ {
+ check01 = (center.x - Q2.x)*(Q0.y - Q2.y) + (center.y - Q2.y)*(Q0.x - Q2.x);
+ check02 = (-Q2.x)*(Q0.y - Q2.y) + (-Q2.y)*(Q0.x - Q2.x);
+ if( check01*check02 > 0 )
+ {
+ check_origin = 0;
+ }
+ }
+ }
+
+ // Calculate angle
+ d_nm_angle = 0;
+ d_angle = angle(Q0,Q2);
+ if( k_nonmon == 0 )
+ {
+ if( check_origin == 0 )
+ {
+ }
+ else
+ {
+ d_angle = 2*CV_PI - d_angle;
+ }
+ }
+ else
+ {
+ if( k_nonmon == 1 )
+ {
+ d_nm_angle = angle(Q0,Q1_nm);
+ if(d_nm_angle > d_angle)
+ {
+ d_nm_angle = d_nm_angle - d_angle;
+ }
+ }
+
+ if( k_nonmon == 2 )
+ {
+ d_nm_angle = angle(Q0,Q2_nm);
+ if(d_nm_angle > d_angle)
+ {
+ d_nm_angle = d_nm_angle - d_angle;
+ }
+ }
+
+ if( k_nonmon == 3 )
+ {
+ d_nm_angle = angle(Q0,Q1_nm);
+ if(d_nm_angle > d_angle)
+ {
+ d_nm_angle = d_nm_angle - d_angle;
+ d_nm_angle = d_nm_angle + angle(Q0, Q2_nm);
+ }
+ else
+ {
+ d_nm_angle = d_nm_angle + angle(Q2,Q2_nm);
+ }
+ }
+ }
+/*
+ B0->x = -B0->x;
+ B0->y = -B0->y;
+ B1->x = -B1->x;
+ B1->y = -B1->y;
+*/
+ return d_angle*K_B + d_nm_angle*K_NM + k_zero*K_Z;
+ //return 0;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////
+void _cvWorkEast(int i, int j, _CvWork** W, CvPoint2D32f* edges1, CvPoint2D32f* edges2)
+{
+ double w1,w2;
+ CvPoint2D32f small_edge;
+
+ //W[i,j].w_east
+ w1 = W[i-1][j].w_east /*+ _cvBendingWork( &edges1[i-2],
+ &edges1[i-1],
+ &null_edge ,
+ &null_edge,
+ NULL)*/;
+
+ small_edge.x = NULL_EDGE*edges1[i-1].x;
+ small_edge.y = NULL_EDGE*edges1[i-1].y;
+
+ w2 = W[i-1][j].w_southeast + _cvBendingWork(&edges1[i-2],
+ &edges1[i-1],
+ &edges2[j-1],
+ /*&null_edge*/&small_edge/*,
+ &edges2[j]*/);
+
+ if(w1<w2)
+ {
+ W[i][j].w_east = w1 + _cvStretchingWork( &edges1[i-1], &null_edge );
+ W[i][j].path_e = PATH_TO_E;
+ }
+ else
+ {
+ W[i][j].w_east = w2 + _cvStretchingWork( &edges1[i-1], &null_edge );
+ W[i][j].path_e = PATH_TO_SE;
+ }
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////////
+void _cvWorkSouthEast(int i, int j, _CvWork** W, CvPoint2D32f* edges1, CvPoint2D32f* edges2)
+{
+ double w1,w2,w3;
+ CvPoint2D32f small_edge;
+
+ //W[i,j].w_southeast
+ small_edge.x = NULL_EDGE*edges1[i-2].x;
+ small_edge.y = NULL_EDGE*edges1[i-2].y;
+
+ w1 = W[i-1][j-1].w_east + _cvBendingWork(&edges1[i-2],
+ &edges1[i-1],
+ /*&null_edge*/&small_edge,
+ &edges2[j-1]/*,
+ &edges2[j-2]*/);
+
+ w2 = W[i-1][j-1].w_southeast + _cvBendingWork( &edges1[i-2],
+ &edges1[i-1],
+ &edges2[j-2],
+ &edges2[j-1]/*,
+ NULL*/);
+
+ small_edge.x = NULL_EDGE*edges2[j-2].x;
+ small_edge.y = NULL_EDGE*edges2[j-2].y;
+
+ w3 = W[i-1][j-1].w_south + _cvBendingWork( /*&null_edge*/&small_edge,
+ &edges1[i-1],
+ &edges2[j-2],
+ &edges2[j-1]/*,
+ &edges1[i-2]*/);
+
+ if( w1<w2 )
+ {
+ if(w1<w3)
+ {
+ W[i][j].w_southeast = w1 + _cvStretchingWork( &edges1[i-1], &edges2[j-1] );
+ W[i][j].path_se = PATH_TO_E;
+ }
+ else
+ {
+ W[i][j].w_southeast = w3 + _cvStretchingWork( &edges1[i-1], &edges2[j-1] );
+ W[i][j].path_se = 3;
+ }
+ }
+ else
+ {
+ if( w2<w3)
+ {
+ W[i][j].w_southeast = w2 + _cvStretchingWork( &edges1[i-1], &edges2[j-1] );
+ W[i][j].path_se = PATH_TO_SE;
+ }
+ else
+ {
+ W[i][j].w_southeast = w3 + _cvStretchingWork( &edges1[i-1], &edges2[j-1] );
+ W[i][j].path_se = 3;
+ }
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+void _cvWorkSouth(int i, int j, _CvWork** W, CvPoint2D32f* edges1, CvPoint2D32f* edges2)
+{
+ double w1,w2;
+ CvPoint2D32f small_edge;
+
+ //W[i,j].w_south
+
+ small_edge.x = NULL_EDGE*edges2[j-1].x;
+ small_edge.y = NULL_EDGE*edges2[j-1].y;
+
+ w1 = W[i][j-1].w_southeast + _cvBendingWork(&edges1[i-1],
+ /*&null_edge*/&small_edge,
+ &edges2[j-2],
+ &edges2[j-1]/*,
+ &edges1[i]*/);
+
+ w2 = W[i][j-1].w_south /*+ _cvBendingWork( &null_edge ,
+ &null_edge,
+ &edges2[j-2],
+ &edges2[j-1],
+ NULL)*/;
+
+ if( w1<w2 )
+ {
+ W[i][j].w_south = w1 + _cvStretchingWork( &null_edge, &edges2[j-1] );
+ W[i][j].path_s = PATH_TO_SE;
+ }
+ else
+ {
+ W[i][j].w_south = w2 + _cvStretchingWork( &null_edge, &edges2[j-1] );
+ W[i][j].path_s = 3;
+ }
+}
+
+//===================================================
+CvPoint2D32f Q(CvPoint2D32f q0,CvPoint2D32f q1,CvPoint2D32f q2,double t)
+{
+ CvPoint2D32f q;
+
+ q.x = (float)(q0.x*(1-t)*(1-t) + 2*q1.x*t*(1-t) + q2.x*t*t);
+ q.y = (float)(q0.y*(1-t)*(1-t) + 2*q1.y*t*(1-t) + q2.y*t*t);
+
+ return q;
+}
+
+double angle(CvPoint2D32f A, CvPoint2D32f B)
+{
+ return acos( (A.x*B.x + A.y*B.y)/sqrt( (double)(A.x*A.x + A.y*A.y)*(B.x*B.x + B.y*B.y) ) );
+}
+
+/***************************************************************************************\
+*
+* This function compute intermediate polygon between contour1 and contour2
+*
+* Correspondence between points of contours specify by corr
+*
+* param = [0,1]; 0 correspondence to contour1, 1 - contour2
+*
+\***************************************************************************************/
+CvSeq* icvBlendContours(CvSeq* contour1,
+ CvSeq* contour2,
+ CvSeq* corr,
+ double param,
+ CvMemStorage* storage)
+{
+ int j;
+
+ CvSeqWriter writer01;
+ CvSeqReader reader01;
+
+ int Ni,Nj; // size of contours
+ int i; // counter
+
+ CvPoint* point1; // array of first contour point
+ CvPoint* point2; // array of second contour point
+
+ CvPoint point_output; // intermediate storage of ouput point
+
+ int corr_point;
+
+ // Create output sequence.
+ CvSeq* output = cvCreateSeq(0,
+ sizeof(CvSeq),
+ sizeof(CvPoint),
+ storage );
+
+ // Find size of contours.
+ Ni = contour1->total + 1;
+ Nj = contour2->total + 1;
+
+ point1 = (CvPoint* )malloc( Ni*sizeof(CvPoint) );
+ point2 = (CvPoint* )malloc( Nj*sizeof(CvPoint) );
+
+ // Initialize arrays of point
+ cvCvtSeqToArray( contour1, point1, CV_WHOLE_SEQ );
+ cvCvtSeqToArray( contour2, point2, CV_WHOLE_SEQ );
+
+ // First and last point mast be equal.
+ point1[Ni-1] = point1[0];
+ point2[Nj-1] = point2[0];
+
+ // Initializes process of writing to sequence.
+ cvStartAppendToSeq( output, &writer01);
+
+ i = Ni-1; //correspondence to points of contour1
+ for( ; corr; corr = corr->h_next )
+ {
+ //Initializes process of sequential reading from sequence
+ cvStartReadSeq( corr, &reader01, 0 );
+
+ for(j=0; j < corr->total; j++)
+ {
+ // Read element from sequence.
+ CV_READ_SEQ_ELEM( corr_point, reader01 );
+
+ // Compute point of intermediate polygon.
+ point_output.x = cvRound(point1[i].x + param*( point2[corr_point].x - point1[i].x ));
+ point_output.y = cvRound(point1[i].y + param*( point2[corr_point].y - point1[i].y ));
+
+ // Write element to sequence.
+ CV_WRITE_SEQ_ELEM( point_output, writer01 );
+ }
+ i--;
+ }
+ // Updates sequence header.
+ cvFlushSeqWriter( &writer01 );
+
+ return output;
+}
+
+/**************************************************************************************************
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+**************************************************************************************************/
+
+
+void icvCalcContoursCorrespondence(CvSeq* contour1,
+ CvSeq* contour2,
+ CvSeq** corr,
+ CvMemStorage* storage)
+{
+ int i,j; // counter of cycles
+ int Ni,Nj; // size of contours
+ _CvWork** W; // graph for search minimum of work
+
+ CvPoint* point1; // array of first contour point
+ CvPoint* point2; // array of second contour point
+ CvPoint2D32f* edges1; // array of first contour edge
+ CvPoint2D32f* edges2; // array of second contour edge
+
+ //CvPoint null_edge = {0,0}; //
+ CvPoint2D32f small_edge;
+ //double inf; // infinity
+
+ CvSeq* corr01;
+ CvSeqWriter writer;
+
+ char path; //
+
+ // Find size of contours
+ Ni = contour1->total + 1;
+ Nj = contour2->total + 1;
+
+ // Create arrays
+ W = (_CvWork**)malloc(sizeof(_CvWork*)*Ni);
+ for(i=0; i<Ni; i++)
+ {
+ W[i] = (_CvWork*)malloc(sizeof(_CvWork)*Nj);
+ }
+
+ point1 = (CvPoint* )malloc( Ni*sizeof(CvPoint) );
+ point2 = (CvPoint* )malloc( Nj*sizeof(CvPoint) );
+ edges1 = (CvPoint2D32f* )malloc( (Ni-1)*sizeof(CvPoint2D32f) );
+ edges2 = (CvPoint2D32f* )malloc( (Nj-1)*sizeof(CvPoint2D32f) );
+
+ // Initialize arrays of point
+ cvCvtSeqToArray( contour1, point1, CV_WHOLE_SEQ );
+ cvCvtSeqToArray( contour2, point2, CV_WHOLE_SEQ );
+
+ point1[Ni-1] = point1[0];
+ point2[Nj-1] = point2[0];
+
+ for(i=0;i<Ni-1;i++)
+ {
+ edges1[i].x = (float)( point1[i+1].x - point1[i].x );
+ edges1[i].y = (float)( point1[i+1].y - point1[i].y );
+ };
+
+ for(i=0;i<Nj-1;i++)
+ {
+ edges2[i].x = (float)( point2[i+1].x - point2[i].x );
+ edges2[i].y = (float)( point2[i+1].y - point2[i].y );
+ };
+
+ // Find infinity constant
+ //inf=1;
+/////////////
+
+//Find min path in graph
+
+/////////////
+ W[0][0].w_east = 0;
+ W[0][0].w_south = 0;
+ W[0][0].w_southeast = 0;
+
+ W[1][1].w_southeast = _cvStretchingWork( &edges1[0], &edges2[0] );
+ W[1][1].w_east = inf;
+ W[1][1].w_south = inf;
+ W[1][1].path_se = PATH_TO_SE;
+
+ W[0][1].w_south = _cvStretchingWork( &null_edge, &edges2[0] );
+ W[0][1].path_s = 3;
+ W[1][0].w_east = _cvStretchingWork( &edges2[0], &null_edge );
+ W[1][0].path_e = PATH_TO_E;
+
+ for( i=1; i<Ni; i++ )
+ {
+ W[i][0].w_south = inf;
+ W[i][0].w_southeast = inf;
+ }
+
+ for(j=1; j<Nj; j++)
+ {
+ W[0][j].w_east = inf;
+ W[0][j].w_southeast = inf;
+ }
+
+ for(i=2; i<Ni; i++)
+ {
+ j=0;/////////
+ W[i][j].w_east = W[i-1][j].w_east;
+ W[i][j].w_east = W[i][j].w_east /*+
+ _cvBendingWork( &edges1[i-2], &edges1[i-1], &null_edge, &null_edge, NULL )*/;
+ W[i][j].w_east = W[i][j].w_east + _cvStretchingWork( &edges2[i-1], &null_edge );
+ W[i][j].path_e = PATH_TO_E;
+
+ j=1;//////////
+ W[i][j].w_south = inf;
+
+ _cvWorkEast (i, j, W, edges1, edges2);
+
+ W[i][j].w_southeast = W[i-1][j-1].w_east;
+ W[i][j].w_southeast = W[i][j].w_southeast + _cvStretchingWork( &edges1[i-1], &edges2[j-1] );
+
+ small_edge.x = NULL_EDGE*edges1[i-2].x;
+ small_edge.y = NULL_EDGE*edges1[i-2].y;
+
+ W[i][j].w_southeast = W[i][j].w_southeast +
+ _cvBendingWork( &edges1[i-2], &edges1[i-1], /*&null_edge*/&small_edge, &edges2[j-1]/*, &edges2[Nj-2]*/);
+
+ W[i][j].path_se = PATH_TO_E;
+ }
+
+ for(j=2; j<Nj; j++)
+ {
+ i=0;//////////
+ W[i][j].w_south = W[i][j-1].w_south;
+ W[i][j].w_south = W[i][j].w_south + _cvStretchingWork( &null_edge, &edges2[j-1] );
+ W[i][j].w_south = W[i][j].w_south /*+
+ _cvBendingWork( &null_edge, &null_edge, &edges2[j-2], &edges2[j-1], NULL )*/;
+ W[i][j].path_s = 3;
+
+ i=1;///////////
+ W[i][j].w_east= inf;
+
+ _cvWorkSouth(i, j, W, edges1, edges2);
+
+ W[i][j].w_southeast = W[i-1][j-1].w_south;
+ W[i][j].w_southeast = W[i][j].w_southeast + _cvStretchingWork( &edges1[i-1], &edges2[j-1] );
+
+ small_edge.x = NULL_EDGE*edges2[j-2].x;
+ small_edge.y = NULL_EDGE*edges2[j-2].y;
+
+ W[i][j].w_southeast = W[i][j].w_southeast +
+ _cvBendingWork( /*&null_edge*/&small_edge, &edges1[i-1], &edges2[j-2], &edges2[j-1]/*, &edges1[Ni-2]*/);
+ W[i][j].path_se = 3;
+ }
+
+ for(i=2; i<Ni; i++)
+ for(j=2; j<Nj; j++)
+ {
+ _cvWorkEast (i, j, W, edges1, edges2);
+ _cvWorkSouthEast(i, j, W, edges1, edges2);
+ _cvWorkSouth (i, j, W, edges1, edges2);
+ }
+
+ i=Ni-1;j=Nj-1;
+
+ *corr = cvCreateSeq(0,
+ sizeof(CvSeq),
+ sizeof(int),
+ storage );
+
+ corr01 = *corr;
+ cvStartAppendToSeq( corr01, &writer );
+ if( W[i][j].w_east > W[i][j].w_southeast )
+ {
+ if( W[i][j].w_southeast > W[i][j].w_south )
+ {
+ path = 3;
+ }
+ else
+ {
+ path = PATH_TO_SE;
+ }
+ }
+ else
+ {
+ if( W[i][j].w_east < W[i][j].w_south )
+ {
+ path = PATH_TO_E;
+ }
+ else
+ {
+ path = 3;
+ }
+ }
+ do
+ {
+ CV_WRITE_SEQ_ELEM( j, writer );
+
+ switch( path )
+ {
+ case PATH_TO_E:
+ path = W[i][j].path_e;
+ i--;
+ cvFlushSeqWriter( &writer );
+ corr01->h_next = cvCreateSeq( 0,
+ sizeof(CvSeq),
+ sizeof(int),
+ storage );
+ corr01 = corr01->h_next;
+ cvStartAppendToSeq( corr01, &writer );
+ break;
+
+ case PATH_TO_SE:
+ path = W[i][j].path_se;
+ j--; i--;
+ cvFlushSeqWriter( &writer );
+ corr01->h_next = cvCreateSeq( 0,
+ sizeof(CvSeq),
+ sizeof(int),
+ storage );
+ corr01 = corr01->h_next;
+ cvStartAppendToSeq( corr01, &writer );
+ break;
+
+ case 3:
+ path = W[i][j].path_s;
+ j--;
+ break;
+ }
+
+ } while( (i>=0) && (j>=0) );
+ cvFlushSeqWriter( &writer );
+
+ // Free memory
+ for(i=1;i<Ni;i++)
+ {
+ free(W[i]);
+ }
+ free(W);
+ free(point1);
+ free(point2);
+ free(edges1);
+ free(edges2);
+}
+
diff --git a/cvaux/src/cvmorphing.cpp b/cvaux/src/cvmorphing.cpp
new file mode 100644
index 0000000..e900c63
--- /dev/null
+++ b/cvaux/src/cvmorphing.cpp
@@ -0,0 +1,396 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cvaux.h"
+#include <assert.h>
+
+
+static CvStatus
+icvMorphEpilines8uC3( uchar * first_pix, /* raster epiline from image 1 */
+ uchar * second_pix, /* raster epiline from image 2 */
+ uchar * dst_pix, /* raster epiline from dest image */
+ /* (it's an output parameter) */
+ float alpha, /* relative position of camera */
+ int *first, /* first sequence of runs */
+ int first_runs, /* it's length */
+ int *second, /* second sequence of runs */
+ int second_runs, int *first_corr, /* corr data for the 1st seq */
+ int *second_corr, /* corr data for the 2nd seq */
+ int dst_len )
+{
+
+ float alpha1; /* alpha - 1.0 */
+ int s, s1; /* integer variant of alpha and alpha1 ( 0 <= s,s1 <= 256 ) */
+ int curr; /* current index in run's array */
+
+ float begLine; /* begin of current run */
+ float endLine; /* end of current run */
+
+ float begCorr; /* begin of correspondence destination of run */
+ float endCorr; /* end of correspondence destination of run */
+
+ int begDestLine; /* begin of current destanation of run */
+ int endDestLine; /* end of current destanation of run */
+ int begLineIndex;
+ int endLineIndex;
+ int indexImg1;
+ float step = 0;
+ int n;
+
+ memset( dst_pix, 0, dst_len );
+ alpha1 = (float) (1.0 - alpha);
+
+ s = (int) (alpha * 256);
+ s1 = 256 - s;
+
+ /* --------------Create first line------------- */
+
+ begLineIndex = first[0];
+ begLine = (float) begLineIndex;
+
+ curr = 0;
+
+ for( n = 0; n < first_runs; n++ )
+ { /* for each run */
+
+ begCorr = (float) first_corr[curr];
+ curr++;
+ endCorr = (float) first_corr[curr];
+ curr++;
+ endLineIndex = first[curr];
+ endLine = (float) endLineIndex;
+
+ begDestLine = (int) (alpha * begLine + alpha1 * begCorr);
+ endDestLine = (int) (alpha * endLine + alpha1 * endCorr);
+
+ indexImg1 = begDestLine * 3;
+
+ step = 0;
+ if( endDestLine != begDestLine )
+ step = (endLine - begLine) / ((float) (endDestLine - begDestLine));
+
+ if( begCorr != endCorr )
+ {
+
+ for( ; begDestLine < endDestLine; begDestLine++ )
+ {
+ /* for each pixel */
+
+ begLineIndex = (int) begLine;
+ begLineIndex *= 3;
+
+ /* Blend R */
+ dst_pix[indexImg1] = (uchar) (((int) (first_pix[begLineIndex]) * s) >> 8);
+
+ indexImg1++;
+
+ /* Blend G */
+ dst_pix[indexImg1] = (uchar) (((int) (first_pix[begLineIndex + 1]) * s) >> 8);
+
+ indexImg1++;
+
+ /* Blend B */
+ dst_pix[indexImg1] = (uchar) (((int) (first_pix[begLineIndex + 2]) * s) >> 8);
+
+ indexImg1++;
+
+ begLine += step;
+
+ } /* for */
+ }
+ else
+ {
+
+ for( ; begDestLine < endDestLine; begDestLine++ )
+ {
+ /* for each pixel */
+
+ begLineIndex = (int) begLine;
+ begLineIndex *= 3;
+
+ /* Blend R */
+ dst_pix[indexImg1] = first_pix[begLineIndex];
+ indexImg1++;
+
+ /* Blend G */
+ dst_pix[indexImg1] = first_pix[begLineIndex + 1];
+ indexImg1++;
+
+ /* Blend B */
+ dst_pix[indexImg1] = first_pix[begLineIndex + 2];
+
+ indexImg1++;
+
+ begLine += step;
+
+ } /* for */
+ } /* if */
+
+ begLineIndex = endLineIndex;
+ begLine = endLine;
+
+
+ } /* for each runs in first line */
+
+ begLineIndex = second[0];
+ begLine = (float) begLineIndex;
+
+ curr = 0;
+
+ /* --------------Create second line------------- */
+ curr = 0;;
+ for( n = 0; n < second_runs; n++ )
+ { /* for each run */
+
+ begCorr = (float) second_corr[curr];
+ curr++;
+ endCorr = (float) second_corr[curr];
+ curr++;
+ endLineIndex = second[curr];
+ endLine = (float) endLineIndex;
+
+ begDestLine = (int) (alpha1 * begLine + alpha * begCorr);
+ endDestLine = (int) (alpha1 * endLine + alpha * endCorr);
+
+ indexImg1 = begDestLine * 3;
+
+ step = 0;
+ if (endDestLine != begDestLine)
+ step = (endLine - begLine) / ((float) (endDestLine - begDestLine));
+
+ if( begCorr != endCorr )
+ {
+
+ for( ; begDestLine < endDestLine; begDestLine++ )
+ {
+ /* for each pixel */
+
+ begLineIndex = (int) begLine;
+ begLineIndex *= 3;
+
+ /* Blend R */
+ dst_pix[indexImg1] =
+ (uchar) (dst_pix[indexImg1] +
+ (uchar) (((unsigned int) (second_pix[begLineIndex]) * s1) >> 8));
+
+ indexImg1++;
+
+ /* Blend G */
+ dst_pix[indexImg1] =
+ (uchar) (dst_pix[indexImg1] +
+ (uchar) (((unsigned int) (second_pix[begLineIndex + 1]) * s1) >>
+ 8));
+
+ indexImg1++;
+
+ /* Blend B */
+ dst_pix[indexImg1] =
+ (uchar) (dst_pix[indexImg1] +
+ (uchar) (((unsigned int) (second_pix[begLineIndex + 2]) * s1) >>
+ 8));
+
+ indexImg1++;
+
+ begLine += step;
+
+ } /* for */
+ }
+ else
+ {
+
+ for( ; begDestLine < endDestLine; begDestLine++ )
+ {
+ /* for each pixel */
+
+ begLineIndex = (int) begLine;
+ begLineIndex *= 3;
+
+ /* Blend R */
+ dst_pix[indexImg1] = (uchar) (dst_pix[indexImg1] + second_pix[begLineIndex]);
+ indexImg1++;
+
+ /* Blend G */
+ dst_pix[indexImg1] =
+ (uchar) (dst_pix[indexImg1] + second_pix[begLineIndex + 1]);
+ indexImg1++;
+
+ /* Blend B */
+ dst_pix[indexImg1] =
+ (uchar) (dst_pix[indexImg1] + second_pix[begLineIndex + 2]);
+ /*assert(indexImg1 < dst_len); */
+
+ indexImg1++;
+
+ begLine += step;
+
+ } /* for */
+ } /* if */
+
+ begLineIndex = endLineIndex;
+ begLine = endLine;
+
+ } /* for each runs in second line */
+
+ return CV_NO_ERR;
+
+} /* icvMorphEpilines8uC3 */
+
+
+/*======================================================================================*/
+
+static CvStatus
+icvMorphEpilines8uC3Multi( int lines, /* number of lines */
+ uchar * first_pix, /* raster epilines from the first image */
+ int *first_num, /* numbers of pixel in first line */
+ uchar * second_pix, /* raster epilines from the second image */
+ int *second_num, /* numbers of pixel in second line */
+ uchar * dst_pix, /* raster epiline from the destination image */
+ /* (it's an output parameter) */
+ int *dst_num, /* numbers of pixel in output line */
+ float alpha, /* relative position of camera */
+ int *first, /* first sequence of runs */
+ int *first_runs, /* it's length */
+ int *second, /* second sequence of runs */
+ int *second_runs, int *first_corr, /* correspond information for the 1st seq */
+ int *second_corr ) /* correspond information for the 2nd seq */
+{
+ CvStatus error;
+ int currLine;
+ int currFirstPix = 0;
+ //int currFirstNum = 0;
+ int currSecondPix = 0;
+ //int currSecondNum = 0;
+ int currDstPix = 0;
+ int currFirst = 0;
+ //int currFirstRuns = 0;
+ int currSecond = 0;
+ //int currSecondRuns = 0;
+ int currFirstCorr = 0;
+ int currSecondCorr = 0;
+
+ if( lines < 1 ||
+ first_pix == 0 ||
+ first_num == 0 ||
+ second_pix == 0 ||
+ second_num == 0 ||
+ dst_pix == 0 ||
+ dst_num == 0 ||
+ alpha < 0 ||
+ alpha > 1 ||
+ first == 0 ||
+ first_runs == 0 ||
+ second == 0 || second_runs == 0 || first_corr == 0 || second_corr == 0 )
+ return CV_BADFACTOR_ERR;
+
+ for( currLine = 0; currLine < lines; currLine++ )
+ {
+
+ error = icvMorphEpilines8uC3( &(first_pix[currFirstPix]),
+ &(second_pix[currSecondPix]),
+ &(dst_pix[currDstPix]),
+ alpha,
+ &(first[currFirst]),
+ first_runs[currLine],
+ &(second[currSecond]),
+ second_runs[currLine],
+ &(first_corr[currFirstCorr]),
+ &(second_corr[currSecondCorr]), dst_num[currLine] * 3 );
+
+
+ if( error != CV_NO_ERR )
+ return CV_NO_ERR;
+
+ currFirstPix += first_num[currLine] * 3;
+ currSecondPix += second_num[currLine] * 3;
+ currDstPix += dst_num[currLine] * 3;
+ currFirst += (first_runs[currLine] * 2) + 1;
+ currSecond += (second_runs[currLine] * 2) + 1;
+ currFirstCorr += first_runs[currLine] * 2;
+ currSecondCorr += second_runs[currLine] * 2;
+
+ } /* for */
+
+ return CV_NO_ERR;
+
+} /* icvMorphEpilines8uC3Multi */
+
+
+
+
+/*======================================================================================*/
+
+CV_IMPL void
+cvMorphEpilinesMulti( int lines, /* number of lines */
+ uchar * first_pix, /* raster epilines from the first image */
+ int *first_num, /* numbers of pixel in first line */
+ uchar * second_pix, /* raster epilines from the second image */
+ int *second_num, /* numbers of pixel in second line */
+ uchar * dst_pix, /* raster epiline from the destination image */
+ /* (it's an output parameter) */
+ int *dst_num, /* numbers of pixel in output line */
+ float alpha, /* relative position of camera */
+ int *first, /* first sequence of runs */
+ int *first_runs, /* it's length */
+ int *second, /* second sequence of runs */
+ int *second_runs, int *first_corr, /* correspond information for the 1st seq */
+ int *second_corr /* correspond information for the 2nd seq */
+ )
+{
+ CV_FUNCNAME( "cvMorphEpilinesMulti" );
+ __BEGIN__;
+
+ IPPI_CALL( icvMorphEpilines8uC3Multi( lines, /* number of lines */
+ first_pix, /* raster epilines from the first image */
+ first_num, /* numbers of pixel in first line */
+ second_pix, /* raster epilines from the second image */
+ second_num, /* numbers of pixel in second line */
+ dst_pix, /* raster epiline from the destination image */
+ /* (it's an output parameter) */
+ dst_num, /* numbers of pixel in output line */
+ alpha, /* relative position of camera */
+ first, /* first sequence of runs */
+ first_runs, /* it's length */
+ second, /* second sequence of runs */
+ second_runs, first_corr, /* correspond information for the 1st seq */
+ second_corr /* correspond information for the 2nd seq */
+ ));
+ __END__;
+}
+
diff --git a/cvaux/src/cvprewarp.cpp b/cvaux/src/cvprewarp.cpp
new file mode 100644
index 0000000..94f7c6e
--- /dev/null
+++ b/cvaux/src/cvprewarp.cpp
@@ -0,0 +1,168 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cvaux.h"
+#include "_cvvm.h"
+
+/* Valery Mosyagin */
+
+static CvStatus
+icvFindRuns( int numLines, /* number of scanlines */
+ uchar * prewarp_1, /* prewarp image 1 */
+ uchar * prewarp_2, /* prewarp image 2 */
+ int *line_lens_1, /* line lengths 1 */
+ int *line_lens_2, /* line lengths 2 */
+ int *runs_1, /* result runs 1 */
+ int *runs_2, /* result runs 2 */
+ int *num_runs_1, /* numbers of first runs */
+ int *num_runs_2 )
+{
+ CvStatus err;
+
+ err = icvFindRunsInOneImage( numLines, prewarp_1, line_lens_1, runs_1, num_runs_1 );
+
+ if( err != CV_NO_ERR )
+ return err;
+
+ err = icvFindRunsInOneImage( numLines, prewarp_2, line_lens_2, runs_2, num_runs_2 );
+
+ return err;
+
+}
+
+
+/*======================================================================================*/
+
+CV_INLINE int
+icvGetColor( uchar * valueRGB )
+{
+ int R = *valueRGB;
+ int G = *(valueRGB + 1);
+ int B = *(valueRGB + 2);
+
+ return ( ((R + G + B) >> 3) & 0xFFFC );
+} /* vm_GetColor */
+
+
+/*======================================================================================*/
+
+CvStatus
+icvFindRunsInOneImage( int numLines, /* number of scanlines */
+ uchar * prewarp, /* prewarp image */
+ int *line_lens, /* line lengths in pixels */
+ int *runs, /* result runs */
+ int *num_runs )
+{
+ int epiLine;
+ int run_index;
+ int curr_color;
+ int index;
+ int color;
+ uchar *curr_point;
+ int num;
+
+
+ run_index = 0;
+
+ curr_point = prewarp;
+
+ for( epiLine = 0; epiLine < numLines; epiLine++ )
+ {
+
+ curr_color = icvGetColor( curr_point );
+
+ runs[run_index++] = 0;
+ runs[run_index++] = curr_color;
+
+ curr_point += 3;
+
+ num = 1;
+ for( index = 1; index < line_lens[epiLine]; index++ )
+ {
+
+ color = icvGetColor( curr_point );
+
+ if( color != curr_color )
+ {
+ runs[run_index++] = index;
+ runs[run_index++] = color;
+ curr_color = color;
+ num++;
+ }
+
+ curr_point += 3;
+ }
+
+ runs[run_index++] = index;
+ num_runs[epiLine] = num;
+ }
+
+ return CV_NO_ERR;
+}
+
+
+/*======================================================================================*/
+
+CV_IMPL void
+cvFindRuns( int numLines, /* number of scanlines */
+ uchar * prewarp_1, /* prewarp image 1 */
+ uchar * prewarp_2, /* prewarp image 2 */
+ int *line_lens_1, /* line lengths 1 */
+ int *line_lens_2, /* line lengths 2 */
+ int *runs_1, /* result runs 1 */
+ int *runs_2, /* result runs 2 */
+ int *num_runs_1, /* numbers of first runs */
+ int *num_runs_2 )
+{
+ CV_FUNCNAME( "cvFindRuns" );
+ __BEGIN__;
+
+ IPPI_CALL( icvFindRuns( numLines, /* number of scanlines */
+ prewarp_1, /* prewarp image 1 */
+ prewarp_2, /* prewarp image 2 */
+ line_lens_1, /* line lengths 1 */
+ line_lens_2, /* line lengths 2 */
+ runs_1, /* result runs 1 */
+ runs_2, /* result runs 2 */
+ num_runs_1, /* numbers of first runs */
+ num_runs_2 ));
+ __CLEANUP__;
+ __END__;
+}
diff --git a/cvaux/src/cvscanlines.cpp b/cvaux/src/cvscanlines.cpp
new file mode 100644
index 0000000..08a7af9
--- /dev/null
+++ b/cvaux/src/cvscanlines.cpp
@@ -0,0 +1,2033 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cvaux.h"
+#include "_cvvm.h"
+
+//#define REAL_ZERO(x) ( (x) < 1e-8 && (x) > -1e-8)
+
+static CvStatus
+icvGetNormalVector3( CvMatrix3 * Matrix, float *v )
+{
+/* return vector v that is any 3-vector perpendicular
+ to all the row vectors of Matrix */
+
+ double *solutions = 0;
+ double M[3 * 3];
+ double B[3] = { 0.f, 0.f, 0.f };
+ int i, j, res;
+
+ if( Matrix == 0 || v == 0 )
+ return CV_NULLPTR_ERR;
+
+ for( i = 0; i < 3; i++ )
+ {
+ for( j = 0; j < 3; j++ )
+ M[i * 3 + j] = (double) (Matrix->m[i][j]);
+ } /* for */
+
+ res = icvGaussMxN( M, B, 3, 3, &solutions );
+
+ if( res == -1 )
+ return CV_BADFACTOR_ERR;
+
+ if( res > 0 && solutions )
+ {
+ v[0] = (float) solutions[0];
+ v[1] = (float) solutions[1];
+ v[2] = (float) solutions[2];
+ res = 0;
+ }
+ else
+ res = 1;
+
+ if( solutions )
+ cvFree( &solutions );
+
+ if( res )
+ return CV_BADFACTOR_ERR;
+ else
+ return CV_NO_ERR;
+
+} /* icvgetNormalVector3 */
+
+
+/*=====================================================================================*/
+
+static CvStatus
+icvMultMatrixVector3( CvMatrix3 * m, float *src, float *dst )
+{
+ if( m == 0 || src == 0 || dst == 0 )
+ return CV_NULLPTR_ERR;
+
+ dst[0] = m->m[0][0] * src[0] + m->m[0][1] * src[1] + m->m[0][2] * src[2];
+ dst[1] = m->m[1][0] * src[0] + m->m[1][1] * src[1] + m->m[1][2] * src[2];
+ dst[2] = m->m[2][0] * src[0] + m->m[2][1] * src[1] + m->m[2][2] * src[2];
+
+ return CV_NO_ERR;
+
+} /* icvMultMatrixVector3 */
+
+
+/*=====================================================================================*/
+
+static CvStatus
+icvMultMatrixTVector3( CvMatrix3 * m, float *src, float *dst )
+{
+ if( m == 0 || src == 0 || dst == 0 )
+ return CV_NULLPTR_ERR;
+
+ dst[0] = m->m[0][0] * src[0] + m->m[1][0] * src[1] + m->m[2][0] * src[2];
+ dst[1] = m->m[0][1] * src[0] + m->m[1][1] * src[1] + m->m[2][1] * src[2];
+ dst[2] = m->m[0][2] * src[0] + m->m[1][2] * src[1] + m->m[2][2] * src[2];
+
+ return CV_NO_ERR;
+
+} /* icvMultMatrixTVector3 */
+
+/*=====================================================================================*/
+
+static CvStatus
+icvCrossLines( float *line1, float *line2, float *cross_point )
+{
+ float delta;
+
+ if( line1 == 0 && line2 == 0 && cross_point == 0 )
+ return CV_NULLPTR_ERR;
+
+ delta = line1[0] * line2[1] - line1[1] * line2[0];
+
+ if( REAL_ZERO( delta ))
+ return CV_BADFACTOR_ERR;
+
+ cross_point[0] = (-line1[2] * line2[1] + line1[1] * line2[2]) / delta;
+ cross_point[1] = (-line1[0] * line2[2] + line1[2] * line2[0]) / delta;
+ cross_point[2] = 1;
+
+ return CV_NO_ERR;
+} /* icvCrossLines */
+
+
+
+/*======================================================================================*/
+
+static CvStatus
+icvMakeScanlines( CvMatrix3 * matrix,
+ CvSize imgSize,
+ int *scanlines_1, int *scanlines_2, int *lens_1, int *lens_2, int *numlines )
+{
+
+ CvStatus error;
+
+ error = icvGetCoefficient( matrix, imgSize, scanlines_2, scanlines_1, numlines );
+
+ /* Make Length of scanlines */
+
+ if( scanlines_1 == 0 && scanlines_2 == 0 )
+ return error;
+
+ icvMakeScanlinesLengths( scanlines_1, *numlines, lens_1 );
+
+ icvMakeScanlinesLengths( scanlines_2, *numlines, lens_2 );
+
+ matrix = matrix;
+ return CV_NO_ERR;
+
+
+} /* icvMakeScanlines */
+
+
+/*======================================================================================*/
+
+CvStatus
+icvMakeScanlinesLengths( int *scanlines, int numlines, int *lens )
+{
+ int index;
+ int x1, y1, x2, y2, dx, dy;
+ int curr;
+
+ curr = 0;
+
+ for( index = 0; index < numlines; index++ )
+ {
+
+ x1 = scanlines[curr++];
+ y1 = scanlines[curr++];
+ x2 = scanlines[curr++];
+ y2 = scanlines[curr++];
+
+ dx = abs( x1 - x2 ) + 1;
+ dy = abs( y1 - y2 ) + 1;
+
+ lens[index] = MAX( dx, dy );
+
+ }
+ return CV_NO_ERR;
+}
+
+/*======================================================================================*/
+
+static CvStatus
+icvMakeAlphaScanlines( int *scanlines_1,
+ int *scanlines_2,
+ int *scanlines_a, int *lens, int numlines, float alpha )
+{
+ int index;
+ int x1, y1, x2, y2;
+ int curr;
+ int dx, dy;
+ int curr_len;
+
+ curr = 0;
+ curr_len = 0;
+ for( index = 0; index < numlines; index++ )
+ {
+
+ x1 = (int) (scanlines_1[curr] * alpha + scanlines_2[curr] * (1.0 - alpha));
+
+ scanlines_a[curr++] = x1;
+
+ y1 = (int) (scanlines_1[curr] * alpha + scanlines_2[curr] * (1.0 - alpha));
+
+ scanlines_a[curr++] = y1;
+
+ x2 = (int) (scanlines_1[curr] * alpha + scanlines_2[curr] * (1.0 - alpha));
+
+ scanlines_a[curr++] = x2;
+
+ y2 = (int) (scanlines_1[curr] * alpha + scanlines_2[curr] * (1.0 - alpha));
+
+ scanlines_a[curr++] = y2;
+
+ dx = abs( x1 - x2 ) + 1;
+ dy = abs( y1 - y2 ) + 1;
+
+ lens[curr_len++] = MAX( dx, dy );
+
+ }
+
+ return CV_NO_ERR;
+}
+
+/*======================================================================================*/
+
+
+
+
+
+
+
+/* //////////////////////////////////////////////////////////////////////////////////// */
+
+CvStatus
+icvGetCoefficient( CvMatrix3 * matrix,
+ CvSize imgSize, int *scanlines_1, int *scanlines_2, int *numlines )
+{
+ float l_epipole[3];
+ float r_epipole[3];
+ CvMatrix3 *F;
+ CvMatrix3 Ft;
+ CvStatus error;
+ int i, j;
+
+ F = matrix;
+
+ l_epipole[2] = -1;
+ r_epipole[2] = -1;
+
+ if( F == 0 )
+ {
+ error = icvGetCoefficientDefault( matrix,
+ imgSize, scanlines_1, scanlines_2, numlines );
+ return error;
+ }
+
+
+ for( i = 0; i < 3; i++ )
+ for( j = 0; j < 3; j++ )
+ Ft.m[i][j] = F->m[j][i];
+
+
+ error = icvGetNormalVector3( &Ft, l_epipole );
+ if( error == CV_NO_ERR && !REAL_ZERO( l_epipole[2] ) && !REAL_ZERO( l_epipole[2] - 1 ))
+ {
+
+ l_epipole[0] /= l_epipole[2];
+ l_epipole[1] /= l_epipole[2];
+ l_epipole[2] = 1;
+ } /* if */
+
+ error = icvGetNormalVector3( F, r_epipole );
+ if( error == CV_NO_ERR && !REAL_ZERO( r_epipole[2] ) && !REAL_ZERO( r_epipole[2] - 1 ))
+ {
+
+ r_epipole[0] /= r_epipole[2];
+ r_epipole[1] /= r_epipole[2];
+ r_epipole[2] = 1;
+ } /* if */
+
+ if( REAL_ZERO( l_epipole[2] - 1 ) && REAL_ZERO( r_epipole[2] - 1 ))
+ {
+ error = icvGetCoefficientStereo( matrix,
+ imgSize,
+ l_epipole,
+ r_epipole, scanlines_1, scanlines_2, numlines );
+ if( error == CV_NO_ERR )
+ return CV_NO_ERR;
+ }
+ else
+ {
+ if( REAL_ZERO( l_epipole[2] ) && REAL_ZERO( r_epipole[2] ))
+ {
+ error = icvGetCoefficientOrto( matrix,
+ imgSize, scanlines_1, scanlines_2, numlines );
+ if( error == CV_NO_ERR )
+ return CV_NO_ERR;
+ }
+ }
+
+
+ error = icvGetCoefficientDefault( matrix, imgSize, scanlines_1, scanlines_2, numlines );
+
+ return error;
+
+} /* icvlGetCoefficient */
+
+/*===========================================================================*/
+CvStatus
+icvGetCoefficientDefault( CvMatrix3 * matrix,
+ CvSize imgSize, int *scanlines_1, int *scanlines_2, int *numlines )
+{
+ int curr;
+ int y;
+
+ *numlines = imgSize.height;
+
+ if( scanlines_1 == 0 && scanlines_2 == 0 )
+ return CV_NO_ERR;
+
+ curr = 0;
+ for( y = 0; y < imgSize.height; y++ )
+ {
+ scanlines_1[curr] = 0;
+ scanlines_1[curr + 1] = y;
+ scanlines_1[curr + 2] = imgSize.width - 1;
+ scanlines_1[curr + 3] = y;
+
+ scanlines_2[curr] = 0;
+ scanlines_2[curr + 1] = y;
+ scanlines_2[curr + 2] = imgSize.width - 1;
+ scanlines_2[curr + 3] = y;
+
+ curr += 4;
+ }
+
+ matrix = matrix;
+ return CV_NO_ERR;
+
+} /* icvlGetCoefficientDefault */
+
+/*===========================================================================*/
+CvStatus
+icvGetCoefficientOrto( CvMatrix3 * matrix,
+ CvSize imgSize, int *scanlines_1, int *scanlines_2, int *numlines )
+{
+ float l_start_end[4], r_start_end[4];
+ double a, b;
+ CvStatus error;
+ CvMatrix3 *F;
+
+ F = matrix;
+
+ if( F->m[0][2] * F->m[1][2] < 0 )
+ { /* on left / */
+
+ if( F->m[2][0] * F->m[2][1] < 0 )
+ { /* on right / */
+ error = icvGetStartEnd1( F, imgSize, l_start_end, r_start_end );
+
+
+ }
+ else
+ { /* on right \ */
+ error = icvGetStartEnd2( F, imgSize, l_start_end, r_start_end );
+ } /* if */
+
+ }
+ else
+ { /* on left \ */
+
+ if( F->m[2][0] * F->m[2][1] < 0 )
+ { /* on right / */
+ error = icvGetStartEnd3( F, imgSize, l_start_end, r_start_end );
+ }
+ else
+ { /* on right \ */
+ error = icvGetStartEnd4( F, imgSize, l_start_end, r_start_end );
+ } /* if */
+ } /* if */
+
+ if( error != CV_NO_ERR )
+ return error;
+
+ a = fabs( l_start_end[0] - l_start_end[2] );
+ b = fabs( r_start_end[0] - r_start_end[2] );
+ if( a > b )
+ {
+
+ error = icvBuildScanlineLeft( F,
+ imgSize,
+ scanlines_1, scanlines_2, l_start_end, numlines );
+
+ }
+ else
+ {
+
+ error = icvBuildScanlineRight( F,
+ imgSize,
+ scanlines_1, scanlines_2, r_start_end, numlines );
+
+ } /* if */
+
+ return error;
+
+} /* icvlGetCoefficientOrto */
+
+/*===========================================================================*/
+CvStatus
+icvGetStartEnd1( CvMatrix3 * matrix, CvSize imgSize, float *l_start_end, float *r_start_end )
+{
+
+ CvMatrix3 *F;
+ int width, height;
+ float l_diagonal[3];
+ float r_diagonal[3];
+ float l_point[3], r_point[3], epiline[3];
+ CvStatus error = CV_OK;
+
+ F = matrix;
+ width = imgSize.width - 1;
+ height = imgSize.height - 1;
+
+ l_diagonal[0] = (float) 1 / width;
+ l_diagonal[1] = (float) 1 / height;
+ l_diagonal[2] = -1;
+
+ r_diagonal[0] = (float) 1 / width;
+ r_diagonal[1] = (float) 1 / height;
+ r_diagonal[2] = -1;
+
+ r_point[0] = (float) width;
+ r_point[1] = 0;
+ r_point[2] = 1;
+
+ icvMultMatrixVector3( F, r_point, epiline );
+ error = icvCrossLines( l_diagonal, epiline, l_point );
+
+ assert( error == CV_NO_ERR );
+
+ if( l_point[0] >= 0 && l_point[0] <= width )
+ {
+
+ l_start_end[0] = l_point[0];
+ l_start_end[1] = l_point[1];
+
+ r_start_end[0] = r_point[0];
+ r_start_end[1] = r_point[1];
+
+ }
+ else
+ {
+
+ if( l_point[0] < 0 )
+ {
+
+ l_point[0] = 0;
+ l_point[1] = (float) height;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+ error = icvCrossLines( r_diagonal, epiline, r_point );
+ assert( error == CV_NO_ERR );
+
+ if( r_point[0] >= 0 && r_point[0] <= width )
+ {
+ l_start_end[0] = l_point[0];
+ l_start_end[1] = l_point[1];
+
+ r_start_end[0] = r_point[0];
+ r_start_end[1] = r_point[1];
+ }
+ else
+ return CV_BADFACTOR_ERR;
+
+ }
+ else
+ { /* if( l_point[0] > width ) */
+
+ l_point[0] = (float) width;
+ l_point[1] = 0;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+ error = icvCrossLines( r_diagonal, epiline, r_point );
+ assert( error == CV_NO_ERR );
+
+ if( r_point[0] >= 0 && r_point[0] <= width )
+ {
+
+ l_start_end[0] = l_point[0];
+ l_start_end[1] = l_point[1];
+
+ r_start_end[0] = r_point[0];
+ r_start_end[1] = r_point[1];
+ }
+ else
+ return CV_BADFACTOR_ERR;
+
+ } /* if */
+ } /* if */
+
+ r_point[0] = 0;
+ r_point[1] = (float) height;
+ r_point[2] = 1;
+
+ icvMultMatrixVector3( F, r_point, epiline );
+ error = icvCrossLines( l_diagonal, epiline, l_point );
+ assert( error == CV_NO_ERR );
+
+ if( l_point[0] >= 0 && l_point[0] <= width )
+ {
+
+ l_start_end[2] = l_point[0];
+ l_start_end[3] = l_point[1];
+
+ r_start_end[2] = r_point[0];
+ r_start_end[3] = r_point[1];
+
+ }
+ else
+ {
+
+ if( l_point[0] < 0 )
+ {
+
+ l_point[0] = 0;
+ l_point[1] = (float) height;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+ error = icvCrossLines( r_diagonal, epiline, r_point );
+ assert( error == CV_NO_ERR );
+
+ if( r_point[0] >= 0 && r_point[0] <= width )
+ {
+
+ l_start_end[2] = l_point[0];
+ l_start_end[3] = l_point[1];
+
+ r_start_end[2] = r_point[0];
+ r_start_end[3] = r_point[1];
+ }
+ else
+ return CV_BADFACTOR_ERR;
+
+ }
+ else
+ { /* if( l_point[0] > width ) */
+
+ l_point[0] = (float) width;
+ l_point[1] = 0;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+ error = icvCrossLines( r_diagonal, epiline, r_point );
+ assert( error == CV_NO_ERR );
+
+ if( r_point[0] >= 0 && r_point[0] <= width )
+ {
+
+ l_start_end[2] = l_point[0];
+ l_start_end[3] = l_point[1];
+
+ r_start_end[2] = r_point[0];
+ r_start_end[3] = r_point[1];
+ }
+ else
+ return CV_BADFACTOR_ERR;
+ } /* if */
+ } /* if */
+
+ return error;
+
+} /* icvlGetStartEnd1 */
+
+/*===========================================================================*/
+CvStatus
+icvGetStartEnd2( CvMatrix3 * matrix, CvSize imgSize, float *l_start_end, float *r_start_end )
+{
+
+
+ CvMatrix3 *F;
+ int width, height;
+ float l_diagonal[3];
+ float r_diagonal[3];
+ float l_point[3], r_point[3], epiline[3];
+ CvStatus error = CV_OK;
+
+ F = matrix;
+
+ width = imgSize.width - 1;
+ height = imgSize.height - 1;
+
+ l_diagonal[0] = (float) 1 / width;
+ l_diagonal[1] = (float) 1 / height;
+ l_diagonal[2] = -1;
+
+ r_diagonal[0] = (float) height / width;
+ r_diagonal[1] = -1;
+ r_diagonal[2] = 0;
+
+ r_point[0] = 0;
+ r_point[1] = 0;
+ r_point[2] = 1;
+
+ icvMultMatrixVector3( F, r_point, epiline );
+
+ error = icvCrossLines( l_diagonal, epiline, l_point );
+
+ assert( error == CV_NO_ERR );
+
+ if( l_point[0] >= 0 && l_point[0] <= width )
+ {
+
+ l_start_end[0] = l_point[0];
+ l_start_end[1] = l_point[1];
+
+ r_start_end[0] = r_point[0];
+ r_start_end[1] = r_point[1];
+
+ }
+ else
+ {
+
+ if( l_point[0] < 0 )
+ {
+
+ l_point[0] = 0;
+ l_point[1] = (float) height;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+ error = icvCrossLines( r_diagonal, epiline, r_point );
+
+ assert( error == CV_NO_ERR );
+
+ if( r_point[0] >= 0 && r_point[0] <= width )
+ {
+
+ l_start_end[0] = l_point[0];
+ l_start_end[1] = l_point[1];
+
+ r_start_end[0] = r_point[0];
+ r_start_end[1] = r_point[1];
+ }
+ else
+ return CV_BADFACTOR_ERR;
+
+ }
+ else
+ { /* if( l_point[0] > width ) */
+
+ l_point[0] = (float) width;
+ l_point[1] = 0;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+ error = icvCrossLines( r_diagonal, epiline, r_point );
+ assert( error == CV_NO_ERR );
+
+ if( r_point[0] >= 0 && r_point[0] <= width )
+ {
+
+ l_start_end[0] = l_point[0];
+ l_start_end[1] = l_point[1];
+
+ r_start_end[0] = r_point[0];
+ r_start_end[1] = r_point[1];
+ }
+ else
+ return CV_BADFACTOR_ERR;
+ } /* if */
+ } /* if */
+
+ r_point[0] = (float) width;
+ r_point[1] = (float) height;
+ r_point[2] = 1;
+
+ icvMultMatrixVector3( F, r_point, epiline );
+ error = icvCrossLines( l_diagonal, epiline, l_point );
+ assert( error == CV_NO_ERR );
+
+ if( l_point[0] >= 0 && l_point[0] <= width )
+ {
+
+ l_start_end[2] = l_point[0];
+ l_start_end[3] = l_point[1];
+
+ r_start_end[2] = r_point[0];
+ r_start_end[3] = r_point[1];
+
+ }
+ else
+ {
+
+ if( l_point[0] < 0 )
+ {
+
+ l_point[0] = 0;
+ l_point[1] = (float) height;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+ error = icvCrossLines( r_diagonal, epiline, r_point );
+ assert( error == CV_NO_ERR );
+
+ if( r_point[0] >= 0 && r_point[0] <= width )
+ {
+
+ l_start_end[2] = l_point[0];
+ l_start_end[3] = l_point[1];
+
+ r_start_end[2] = r_point[0];
+ r_start_end[3] = r_point[1];
+ }
+ else
+ return CV_BADFACTOR_ERR;
+
+ }
+ else
+ { /* if( l_point[0] > width ) */
+
+ l_point[0] = (float) width;
+ l_point[1] = 0;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+ error = icvCrossLines( r_diagonal, epiline, r_point );
+ assert( error == CV_NO_ERR );
+
+ if( r_point[0] >= 0 && r_point[0] <= width )
+ {
+
+ l_start_end[2] = l_point[0];
+ l_start_end[3] = l_point[1];
+
+ r_start_end[2] = r_point[0];
+ r_start_end[3] = r_point[1];
+ }
+ else
+ return CV_BADFACTOR_ERR;
+ }
+ } /* if */
+
+ return error;
+
+} /* icvlGetStartEnd2 */
+
+/*===========================================================================*/
+CvStatus
+icvGetStartEnd3( CvMatrix3 * matrix, CvSize imgSize, float *l_start_end, float *r_start_end )
+{
+
+ CvMatrix3 *F;
+ int width, height;
+ float l_diagonal[3];
+ float r_diagonal[3];
+ float l_point[3], r_point[3], epiline[3];
+ CvStatus error = CV_OK;
+
+ F = matrix;
+
+ width = imgSize.width - 1;
+ height = imgSize.height - 1;
+
+ l_diagonal[0] = (float) height / width;
+ l_diagonal[1] = -1;
+ l_diagonal[2] = 0;
+
+ r_diagonal[0] = (float) 1 / width;
+ r_diagonal[1] = (float) 1 / height;
+ r_diagonal[2] = -1;
+
+ r_point[0] = 0;
+ r_point[1] = 0;
+ r_point[2] = 1;
+
+ icvMultMatrixVector3( F, r_point, epiline );
+
+ error = icvCrossLines( l_diagonal, epiline, l_point );
+
+ assert( error == CV_NO_ERR );
+
+ if( l_point[0] >= 0 && l_point[0] <= width )
+ {
+
+ l_start_end[0] = l_point[0];
+ l_start_end[1] = l_point[1];
+
+ r_start_end[0] = r_point[0];
+ r_start_end[1] = r_point[1];
+
+ }
+ else
+ {
+
+ if( l_point[0] < 0 )
+ {
+
+ l_point[0] = 0;
+ l_point[1] = (float) height;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+ error = icvCrossLines( r_diagonal, epiline, r_point );
+ assert( error == CV_NO_ERR );
+
+ if( r_point[0] >= 0 && r_point[0] <= width )
+ {
+
+ l_start_end[0] = l_point[0];
+ l_start_end[1] = l_point[1];
+
+ r_start_end[0] = r_point[0];
+ r_start_end[1] = r_point[1];
+ }
+ else
+ return CV_BADFACTOR_ERR;
+
+ }
+ else
+ { /* if( l_point[0] > width ) */
+
+ l_point[0] = (float) width;
+ l_point[1] = 0;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+ error = icvCrossLines( r_diagonal, epiline, r_point );
+ assert( error == CV_NO_ERR );
+
+ if( r_point[0] >= 0 && r_point[0] <= width )
+ {
+
+ l_start_end[0] = l_point[0];
+ l_start_end[1] = l_point[1];
+
+ r_start_end[0] = r_point[0];
+ r_start_end[1] = r_point[1];
+ }
+ else
+ return CV_BADFACTOR_ERR;
+ } /* if */
+ } /* if */
+
+ r_point[0] = (float) width;
+ r_point[1] = (float) height;
+ r_point[2] = 1;
+
+ icvMultMatrixVector3( F, r_point, epiline );
+ error = icvCrossLines( l_diagonal, epiline, l_point );
+ assert( error == CV_NO_ERR );
+
+ if( l_point[0] >= 0 && l_point[0] <= width )
+ {
+
+ l_start_end[2] = l_point[0];
+ l_start_end[3] = l_point[1];
+
+ r_start_end[2] = r_point[0];
+ r_start_end[3] = r_point[1];
+
+ }
+ else
+ {
+
+ if( l_point[0] < 0 )
+ {
+
+ l_point[0] = 0;
+ l_point[1] = (float) height;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+
+ error = icvCrossLines( r_diagonal, epiline, r_point );
+
+ assert( error == CV_NO_ERR );
+
+ if( r_point[0] >= 0 && r_point[0] <= width )
+ {
+
+ l_start_end[2] = l_point[0];
+ l_start_end[3] = l_point[1];
+
+ r_start_end[2] = r_point[0];
+ r_start_end[3] = r_point[1];
+ }
+ else
+ return CV_BADFACTOR_ERR;
+
+ }
+ else
+ { /* if( l_point[0] > width ) */
+
+ l_point[0] = (float) width;
+ l_point[1] = 0;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+
+ error = icvCrossLines( r_diagonal, epiline, r_point );
+
+ assert( error == CV_NO_ERR );
+
+ if( r_point[0] >= 0 && r_point[0] <= width )
+ {
+
+ l_start_end[2] = l_point[0];
+ l_start_end[3] = l_point[1];
+
+ r_start_end[2] = r_point[0];
+ r_start_end[3] = r_point[1];
+ }
+ else
+ return CV_BADFACTOR_ERR;
+ } /* if */
+ } /* if */
+
+ return error;
+
+} /* icvlGetStartEnd3 */
+
+/*===========================================================================*/
+CvStatus
+icvGetStartEnd4( CvMatrix3 * matrix, CvSize imgSize, float *l_start_end, float *r_start_end )
+{
+ CvMatrix3 *F;
+ int width, height;
+ float l_diagonal[3];
+ float r_diagonal[3];
+ float l_point[3], r_point[3], epiline[3];
+ CvStatus error;
+
+ F = matrix;
+
+ width = imgSize.width - 1;
+ height = imgSize.height - 1;
+
+ l_diagonal[0] = (float) height / width;
+ l_diagonal[1] = -1;
+ l_diagonal[2] = 0;
+
+ r_diagonal[0] = (float) height / width;
+ r_diagonal[1] = -1;
+ r_diagonal[2] = 0;
+
+ r_point[0] = 0;
+ r_point[1] = 0;
+ r_point[2] = 1;
+
+ icvMultMatrixVector3( F, r_point, epiline );
+ error = icvCrossLines( l_diagonal, epiline, l_point );
+
+ if( error != CV_NO_ERR )
+ return error;
+
+ if( l_point[0] >= 0 && l_point[0] <= width )
+ {
+
+ l_start_end[0] = l_point[0];
+ l_start_end[1] = l_point[1];
+
+ r_start_end[0] = r_point[0];
+ r_start_end[1] = r_point[1];
+
+ }
+ else
+ {
+
+ if( l_point[0] < 0 )
+ {
+
+ l_point[0] = 0;
+ l_point[1] = 0;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+ error = icvCrossLines( r_diagonal, epiline, r_point );
+ assert( error == CV_NO_ERR );
+
+ if( r_point[0] >= 0 && r_point[0] <= width )
+ {
+
+ l_start_end[0] = l_point[0];
+ l_start_end[1] = l_point[1];
+
+ r_start_end[0] = r_point[0];
+ r_start_end[1] = r_point[1];
+ }
+ else
+ return CV_BADFACTOR_ERR;
+
+ }
+ else
+ { /* if( l_point[0] > width ) */
+
+ l_point[0] = (float) width;
+ l_point[1] = (float) height;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+ error = icvCrossLines( r_diagonal, epiline, r_point );
+ assert( error == CV_NO_ERR );
+
+ if( r_point[0] >= 0 && r_point[0] <= width )
+ {
+
+ l_start_end[0] = l_point[0];
+ l_start_end[1] = l_point[1];
+
+ r_start_end[0] = r_point[0];
+ r_start_end[1] = r_point[1];
+ }
+ else
+ return CV_BADFACTOR_ERR;
+ } /* if */
+ } /* if */
+
+ r_point[0] = (float) width;
+ r_point[1] = (float) height;
+ r_point[2] = 1;
+
+ icvMultMatrixVector3( F, r_point, epiline );
+ error = icvCrossLines( l_diagonal, epiline, l_point );
+ assert( error == CV_NO_ERR );
+
+ if( l_point[0] >= 0 && l_point[0] <= width )
+ {
+
+ l_start_end[2] = l_point[0];
+ l_start_end[3] = l_point[1];
+
+ r_start_end[2] = r_point[0];
+ r_start_end[3] = r_point[1];
+
+ }
+ else
+ {
+
+ if( l_point[0] < 0 )
+ {
+
+ l_point[0] = 0;
+ l_point[1] = 0;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+ error = icvCrossLines( r_diagonal, epiline, r_point );
+ assert( error == CV_NO_ERR );
+
+ if( r_point[0] >= 0 && r_point[0] <= width )
+ {
+
+ l_start_end[2] = l_point[0];
+ l_start_end[3] = l_point[1];
+
+ r_start_end[2] = r_point[0];
+ r_start_end[3] = r_point[1];
+ }
+ else
+ return CV_BADFACTOR_ERR;
+
+ }
+ else
+ { /* if( l_point[0] > width ) */
+
+ l_point[0] = (float) width;
+ l_point[1] = (float) height;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+ error = icvCrossLines( r_diagonal, epiline, r_point );
+ assert( error == CV_NO_ERR );
+
+ if( r_point[0] >= 0 && r_point[0] <= width )
+ {
+
+ l_start_end[2] = l_point[0];
+ l_start_end[3] = l_point[1];
+
+ r_start_end[2] = r_point[0];
+ r_start_end[3] = r_point[1];
+ }
+ else
+ return CV_BADFACTOR_ERR;
+ } /* if */
+ } /* if */
+
+ return CV_NO_ERR;
+
+} /* icvlGetStartEnd4 */
+
+/*===========================================================================*/
+CvStatus
+icvBuildScanlineLeft( CvMatrix3 * matrix,
+ CvSize imgSize,
+ int *scanlines_1, int *scanlines_2, float *l_start_end, int *numlines )
+{
+ int prewarp_height;
+ float l_point[3];
+ float r_point[3];
+ float height;
+ float delta_x;
+ float delta_y;
+ CvStatus error = CV_OK;
+ CvMatrix3 *F;
+ float i;
+ int offset;
+ float epiline[3];
+ double a, b;
+
+ assert( l_start_end != 0 );
+
+ a = fabs( l_start_end[2] - l_start_end[0] );
+ b = fabs( l_start_end[3] - l_start_end[1] );
+ prewarp_height = cvRound( MAX(a, b) );
+
+ *numlines = prewarp_height;
+
+ if( scanlines_1 == 0 && scanlines_2 == 0 )
+ return CV_NO_ERR;
+
+ F = matrix;
+
+
+ l_point[2] = 1;
+ height = (float) prewarp_height;
+
+ delta_x = (l_start_end[2] - l_start_end[0]) / height;
+
+ l_start_end[0] += delta_x;
+ l_start_end[2] -= delta_x;
+
+ delta_x = (l_start_end[2] - l_start_end[0]) / height;
+ delta_y = (l_start_end[3] - l_start_end[1]) / height;
+
+ l_start_end[1] += delta_y;
+ l_start_end[3] -= delta_y;
+
+ delta_y = (l_start_end[3] - l_start_end[1]) / height;
+
+ for( i = 0, offset = 0; i < height; i++, offset += 4 )
+ {
+
+ l_point[0] = l_start_end[0] + i * delta_x;
+ l_point[1] = l_start_end[1] + i * delta_y;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+
+ error = icvGetCrossEpilineFrame( imgSize, epiline,
+ scanlines_2 + offset,
+ scanlines_2 + offset + 1,
+ scanlines_2 + offset + 2, scanlines_2 + offset + 3 );
+
+
+
+ assert( error == CV_NO_ERR );
+
+ r_point[0] = -(float) (*(scanlines_2 + offset));
+ r_point[1] = -(float) (*(scanlines_2 + offset + 1));
+ r_point[2] = -1;
+
+ icvMultMatrixVector3( F, r_point, epiline );
+
+ error = icvGetCrossEpilineFrame( imgSize, epiline,
+ scanlines_1 + offset,
+ scanlines_1 + offset + 1,
+ scanlines_1 + offset + 2, scanlines_1 + offset + 3 );
+
+ assert( error == CV_NO_ERR );
+ } /* for */
+
+ *numlines = prewarp_height;
+
+ return error;
+
+} /*icvlBuildScanlineLeft */
+
+/*===========================================================================*/
+CvStatus
+icvBuildScanlineRight( CvMatrix3 * matrix,
+ CvSize imgSize,
+ int *scanlines_1, int *scanlines_2, float *r_start_end, int *numlines )
+{
+ int prewarp_height;
+ float l_point[3];
+ float r_point[3];
+ float height;
+ float delta_x;
+ float delta_y;
+ CvStatus error = CV_OK;
+ CvMatrix3 *F;
+ float i;
+ int offset;
+ float epiline[3];
+ double a, b;
+
+ assert( r_start_end != 0 );
+
+ a = fabs( r_start_end[2] - r_start_end[0] );
+ b = fabs( r_start_end[3] - r_start_end[1] );
+ prewarp_height = cvRound( MAX(a, b) );
+
+ *numlines = prewarp_height;
+
+ if( scanlines_1 == 0 && scanlines_2 == 0 )
+ return CV_NO_ERR;
+
+ F = matrix;
+
+ r_point[2] = 1;
+ height = (float) prewarp_height;
+
+ delta_x = (r_start_end[2] - r_start_end[0]) / height;
+
+ r_start_end[0] += delta_x;
+ r_start_end[2] -= delta_x;
+
+ delta_x = (r_start_end[2] - r_start_end[0]) / height;
+ delta_y = (r_start_end[3] - r_start_end[1]) / height;
+
+ r_start_end[1] += delta_y;
+ r_start_end[3] -= delta_y;
+
+ delta_y = (r_start_end[3] - r_start_end[1]) / height;
+
+ for( i = 0, offset = 0; i < height; i++, offset += 4 )
+ {
+
+ r_point[0] = r_start_end[0] + i * delta_x;
+ r_point[1] = r_start_end[1] + i * delta_y;
+
+ icvMultMatrixVector3( F, r_point, epiline );
+
+ error = icvGetCrossEpilineFrame( imgSize, epiline,
+ scanlines_1 + offset,
+ scanlines_1 + offset + 1,
+ scanlines_1 + offset + 2, scanlines_1 + offset + 3 );
+
+
+ assert( error == CV_NO_ERR );
+
+ l_point[0] = -(float) (*(scanlines_1 + offset));
+ l_point[1] = -(float) (*(scanlines_1 + offset + 1));
+
+ l_point[2] = -1;
+
+ icvMultMatrixTVector3( F, l_point, epiline );
+ error = icvGetCrossEpilineFrame( imgSize, epiline,
+ scanlines_2 + offset,
+ scanlines_2 + offset + 1,
+ scanlines_2 + offset + 2, scanlines_2 + offset + 3 );
+
+
+ assert( error == CV_NO_ERR );
+ } /* for */
+
+ *numlines = prewarp_height;
+
+ return error;
+
+} /*icvlBuildScanlineRight */
+
+/*===========================================================================*/
+#define Abs(x) ( (x)<0 ? -(x):(x) )
+#define Sgn(x) ( (x)<0 ? -1:1 ) /* Sgn(0) = 1 ! */
+
+static CvStatus
+icvBuildScanline( CvSize imgSize, float *epiline, float *kx, float *cx, float *ky, float *cy )
+{
+ float point[4][2], d;
+ int sign[4], i;
+
+ float width, height;
+
+ if( REAL_ZERO( epiline[0] ) && REAL_ZERO( epiline[1] ))
+ return CV_BADFACTOR_ERR;
+
+ width = (float) imgSize.width - 1;
+ height = (float) imgSize.height - 1;
+
+ sign[0] = Sgn( epiline[2] );
+ sign[1] = Sgn( epiline[0] * width + epiline[2] );
+ sign[2] = Sgn( epiline[1] * height + epiline[2] );
+ sign[3] = Sgn( epiline[0] * width + epiline[1] * height + epiline[2] );
+
+ i = 0;
+
+ if( sign[0] * sign[1] < 0 )
+ {
+
+ point[i][0] = -epiline[2] / epiline[0];
+ point[i][1] = 0;
+ i++;
+ } /* if */
+
+ if( sign[0] * sign[2] < 0 )
+ {
+
+ point[i][0] = 0;
+ point[i][1] = -epiline[2] / epiline[1];
+ i++;
+ } /* if */
+
+ if( sign[1] * sign[3] < 0 )
+ {
+
+ point[i][0] = width;
+ point[i][1] = -(epiline[0] * width + epiline[2]) / epiline[1];
+ i++;
+ } /* if */
+
+ if( sign[2] * sign[3] < 0 )
+ {
+
+ point[i][0] = -(epiline[1] * height + epiline[2]) / epiline[0];
+ point[i][1] = height;
+ } /* if */
+
+ if( sign[0] == sign[1] && sign[0] == sign[2] && sign[0] == sign[3] )
+ return CV_BADFACTOR_ERR;
+
+ if( !kx && !ky && !cx && !cy )
+ return CV_BADFACTOR_ERR;
+
+ if( kx && ky )
+ {
+
+ *kx = -epiline[1];
+ *ky = epiline[0];
+
+ d = (float) MAX( Abs( *kx ), Abs( *ky ));
+
+ *kx /= d;
+ *ky /= d;
+ } /* if */
+
+ if( cx && cy )
+ {
+
+ if( (point[0][0] - point[1][0]) * epiline[1] +
+ (point[1][1] - point[0][1]) * epiline[0] > 0 )
+ {
+
+ *cx = point[0][0];
+ *cy = point[0][1];
+
+ }
+ else
+ {
+
+ *cx = point[1][0];
+ *cy = point[1][1];
+ } /* if */
+ } /* if */
+
+ return CV_NO_ERR;
+
+} /* icvlBuildScanline */
+
+/*===========================================================================*/
+CvStatus
+icvGetCoefficientStereo( CvMatrix3 * matrix,
+ CvSize imgSize,
+ float *l_epipole,
+ float *r_epipole, int *scanlines_1, int *scanlines_2, int *numlines )
+{
+ int i, j, turn;
+ float width, height;
+ float l_angle[2], r_angle[2];
+ float l_radius, r_radius;
+ float r_point[3], l_point[3];
+ float l_epiline[3], r_epiline[3], x, y;
+ float swap;
+
+ float radius1, radius2, radius3, radius4;
+
+ float l_start_end[4], r_start_end[4];
+ CvMatrix3 *F;
+ CvStatus error;
+ float Region[3][3][4] = {
+ {{0.f, 0.f, 1.f, 1.f}, {0.f, 1.f, 1.f, 1.f}, {0.f, 1.f, 1.f, 0.f}},
+ {{0.f, 0.f, 0.f, 1.f}, {2.f, 2.f, 2.f, 2.f}, {1.f, 1.f, 1.f, 0.f}},
+ {{1.f, 0.f, 0.f, 1.f}, {1.f, 0.f, 0.f, 0.f}, {1.f, 1.f, 0.f, 0.f}}
+ };
+
+
+ width = (float) imgSize.width - 1;
+ height = (float) imgSize.height - 1;
+
+ F = matrix;
+
+ if( F->m[0][0] * F->m[1][1] - F->m[1][0] * F->m[0][1] > 0 )
+ turn = 1;
+ else
+ turn = -1;
+
+ if( l_epipole[0] < 0 )
+ i = 0;
+ else if( l_epipole[0] < width )
+ i = 1;
+ else
+ i = 2;
+
+ if( l_epipole[1] < 0 )
+ j = 2;
+ else if( l_epipole[1] < height )
+ j = 1;
+ else
+ j = 0;
+
+ l_start_end[0] = Region[j][i][0];
+ l_start_end[1] = Region[j][i][1];
+ l_start_end[2] = Region[j][i][2];
+ l_start_end[3] = Region[j][i][3];
+
+ if( r_epipole[0] < 0 )
+ i = 0;
+ else if( r_epipole[0] < width )
+ i = 1;
+ else
+ i = 2;
+
+ if( r_epipole[1] < 0 )
+ j = 2;
+ else if( r_epipole[1] < height )
+ j = 1;
+ else
+ j = 0;
+
+ r_start_end[0] = Region[j][i][0];
+ r_start_end[1] = Region[j][i][1];
+ r_start_end[2] = Region[j][i][2];
+ r_start_end[3] = Region[j][i][3];
+
+ radius1 = l_epipole[0] * l_epipole[0] + (l_epipole[1] - height) * (l_epipole[1] - height);
+
+ radius2 = (l_epipole[0] - width) * (l_epipole[0] - width) +
+ (l_epipole[1] - height) * (l_epipole[1] - height);
+
+ radius3 = l_epipole[0] * l_epipole[0] + l_epipole[1] * l_epipole[1];
+
+ radius4 = (l_epipole[0] - width) * (l_epipole[0] - width) + l_epipole[1] * l_epipole[1];
+
+
+ l_radius = (float) sqrt( (double)MAX( MAX( radius1, radius2 ), MAX( radius3, radius4 )));
+
+ radius1 = r_epipole[0] * r_epipole[0] + (r_epipole[1] - height) * (r_epipole[1] - height);
+
+ radius2 = (r_epipole[0] - width) * (r_epipole[0] - width) +
+ (r_epipole[1] - height) * (r_epipole[1] - height);
+
+ radius3 = r_epipole[0] * r_epipole[0] + r_epipole[1] * r_epipole[1];
+
+ radius4 = (r_epipole[0] - width) * (r_epipole[0] - width) + r_epipole[1] * r_epipole[1];
+
+
+ r_radius = (float) sqrt( (double)MAX( MAX( radius1, radius2 ), MAX( radius3, radius4 )));
+
+ if( l_start_end[0] == 2 && r_start_end[0] == 2 )
+
+ if( l_radius > r_radius )
+ {
+
+ l_angle[0] = 0.0f;
+ l_angle[1] = (float) CV_PI;
+
+ error = icvBuildScanlineLeftStereo( imgSize,
+ matrix,
+ l_epipole,
+ l_angle,
+ l_radius, scanlines_1, scanlines_2, numlines );
+
+ return error;
+
+ }
+ else
+ {
+
+ r_angle[0] = 0.0f;
+ r_angle[1] = (float) CV_PI;
+
+ error = icvBuildScanlineRightStereo( imgSize,
+ matrix,
+ r_epipole,
+ r_angle,
+ r_radius,
+ scanlines_1, scanlines_2, numlines );
+
+ return error;
+ } /* if */
+
+ if( l_start_end[0] == 2 )
+ {
+
+ r_angle[0] = (float) atan2( r_start_end[1] * height - r_epipole[1],
+ r_start_end[0] * width - r_epipole[0] );
+ r_angle[1] = (float) atan2( r_start_end[3] * height - r_epipole[1],
+ r_start_end[2] * width - r_epipole[0] );
+
+ if( r_angle[0] > r_angle[1] )
+ r_angle[1] += (float) (CV_PI * 2);
+
+ error = icvBuildScanlineRightStereo( imgSize,
+ matrix,
+ r_epipole,
+ r_angle,
+ r_radius, scanlines_1, scanlines_2, numlines );
+
+ return error;
+ } /* if */
+
+ if( r_start_end[0] == 2 )
+ {
+
+ l_point[0] = l_start_end[0] * width;
+ l_point[1] = l_start_end[1] * height;
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, r_epiline );
+
+ l_angle[0] = (float) atan2( l_start_end[1] * height - l_epipole[1],
+ l_start_end[0] * width - l_epipole[0] );
+ l_angle[1] = (float) atan2( l_start_end[3] * height - l_epipole[1],
+ l_start_end[2] * width - l_epipole[0] );
+
+ if( l_angle[0] > l_angle[1] )
+ l_angle[1] += (float) (CV_PI * 2);
+
+ error = icvBuildScanlineLeftStereo( imgSize,
+ matrix,
+ l_epipole,
+ l_angle,
+ l_radius, scanlines_1, scanlines_2, numlines );
+
+ return error;
+
+ } /* if */
+
+ l_start_end[0] *= width;
+ l_start_end[1] *= height;
+ l_start_end[2] *= width;
+ l_start_end[3] *= height;
+
+ r_start_end[0] *= width;
+ r_start_end[1] *= height;
+ r_start_end[2] *= width;
+ r_start_end[3] *= height;
+
+ r_point[0] = r_start_end[0];
+ r_point[1] = r_start_end[1];
+ r_point[2] = 1;
+
+ icvMultMatrixVector3( F, r_point, l_epiline );
+ error = icvBuildScanline( imgSize, l_epiline, 0, &x, 0, &y );
+
+ if( error == CV_NO_ERR )
+ {
+
+ l_angle[0] = (float) atan2( y - l_epipole[1], x - l_epipole[0] );
+
+ r_angle[0] = (float) atan2( r_point[1] - r_epipole[1], r_point[0] - r_epipole[0] );
+
+ }
+ else
+ {
+
+ if( turn == 1 )
+ {
+
+ l_point[0] = l_start_end[0];
+ l_point[1] = l_start_end[1];
+
+ }
+ else
+ {
+
+ l_point[0] = l_start_end[2];
+ l_point[1] = l_start_end[3];
+ } /* if */
+
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, r_epiline );
+ error = icvBuildScanline( imgSize, r_epiline, 0, &x, 0, &y );
+
+ if( error == CV_NO_ERR )
+ {
+
+ r_angle[0] = (float) atan2( y - r_epipole[1], x - r_epipole[0] );
+
+ l_angle[0] = (float) atan2( l_point[1] - l_epipole[1], l_point[0] - l_epipole[0] );
+
+ }
+ else
+ return CV_BADFACTOR_ERR;
+ } /* if */
+
+ r_point[0] = r_start_end[2];
+ r_point[1] = r_start_end[3];
+ r_point[2] = 1;
+
+ icvMultMatrixVector3( F, r_point, l_epiline );
+ error = icvBuildScanline( imgSize, l_epiline, 0, &x, 0, &y );
+
+ if( error == CV_NO_ERR )
+ {
+
+ l_angle[1] = (float) atan2( y - l_epipole[1], x - l_epipole[0] );
+
+ r_angle[1] = (float) atan2( r_point[1] - r_epipole[1], r_point[0] - r_epipole[0] );
+
+ }
+ else
+ {
+
+ if( turn == 1 )
+ {
+
+ l_point[0] = l_start_end[2];
+ l_point[1] = l_start_end[3];
+
+ }
+ else
+ {
+
+ l_point[0] = l_start_end[0];
+ l_point[1] = l_start_end[1];
+ } /* if */
+
+ l_point[2] = 1;
+
+ icvMultMatrixTVector3( F, l_point, r_epiline );
+ error = icvBuildScanline( imgSize, r_epiline, 0, &x, 0, &y );
+
+ if( error == CV_NO_ERR )
+ {
+
+ r_angle[1] = (float) atan2( y - r_epipole[1], x - r_epipole[0] );
+
+ l_angle[1] = (float) atan2( l_point[1] - l_epipole[1], l_point[0] - l_epipole[0] );
+
+ }
+ else
+ return CV_BADFACTOR_ERR;
+ } /* if */
+
+ if( l_angle[0] > l_angle[1] )
+ {
+
+ swap = l_angle[0];
+ l_angle[0] = l_angle[1];
+ l_angle[1] = swap;
+ } /* if */
+
+ if( l_angle[1] - l_angle[0] > CV_PI )
+ {
+
+ swap = l_angle[0];
+ l_angle[0] = l_angle[1];
+ l_angle[1] = swap + (float) (CV_PI * 2);
+ } /* if */
+
+ if( r_angle[0] > r_angle[1] )
+ {
+
+ swap = r_angle[0];
+ r_angle[0] = r_angle[1];
+ r_angle[1] = swap;
+ } /* if */
+
+ if( r_angle[1] - r_angle[0] > CV_PI )
+ {
+
+ swap = r_angle[0];
+ r_angle[0] = r_angle[1];
+ r_angle[1] = swap + (float) (CV_PI * 2);
+ } /* if */
+
+ if( l_radius * (l_angle[1] - l_angle[0]) > r_radius * (r_angle[1] - r_angle[0]) )
+ error = icvBuildScanlineLeftStereo( imgSize,
+ matrix,
+ l_epipole,
+ l_angle,
+ l_radius, scanlines_1, scanlines_2, numlines );
+
+ else
+ error = icvBuildScanlineRightStereo( imgSize,
+ matrix,
+ r_epipole,
+ r_angle,
+ r_radius, scanlines_1, scanlines_2, numlines );
+
+
+ return error;
+
+} /* icvGetCoefficientStereo */
+
+/*===========================================================================*/
+CvStatus
+icvBuildScanlineLeftStereo( CvSize imgSize,
+ CvMatrix3 * matrix,
+ float *l_epipole,
+ float *l_angle,
+ float l_radius, int *scanlines_1, int *scanlines_2, int *numlines )
+{
+ //int prewarp_width;
+ int prewarp_height;
+ float i;
+ int offset;
+ float height;
+ float delta;
+ float angle;
+ float l_point[3];
+ float l_epiline[3];
+ float r_epiline[3];
+ CvStatus error = CV_OK;
+ CvMatrix3 *F;
+
+
+ assert( l_angle != 0 && !REAL_ZERO( l_radius ));
+
+ /*prewarp_width = (int) (sqrt( image_width * image_width +
+ image_height * image_height ) + 1);*/
+
+ prewarp_height = (int) (l_radius * (l_angle[1] - l_angle[0]));
+
+ *numlines = prewarp_height;
+
+ if( scanlines_1 == 0 && scanlines_2 == 0 )
+ return CV_NO_ERR;
+
+ F = matrix;
+
+ l_point[2] = 1;
+ height = (float) prewarp_height;
+
+ delta = (l_angle[1] - l_angle[0]) / height;
+
+ l_angle[0] += delta;
+ l_angle[1] -= delta;
+
+ delta = (l_angle[1] - l_angle[0]) / height;
+
+ for( i = 0, offset = 0; i < height; i++, offset += 4 )
+ {
+
+ angle = l_angle[0] + i * delta;
+
+ l_point[0] = l_epipole[0] + l_radius * (float) cos( angle );
+ l_point[1] = l_epipole[1] + l_radius * (float) sin( angle );
+
+ icvMultMatrixTVector3( F, l_point, r_epiline );
+
+ error = icvGetCrossEpilineFrame( imgSize, r_epiline,
+ scanlines_2 + offset,
+ scanlines_2 + offset + 1,
+ scanlines_2 + offset + 2, scanlines_2 + offset + 3 );
+
+
+ l_epiline[0] = l_point[1] - l_epipole[1];
+ l_epiline[1] = l_epipole[0] - l_point[0];
+ l_epiline[2] = l_point[0] * l_epipole[1] - l_point[1] * l_epipole[0];
+
+ if( Sgn( l_epiline[0] * r_epiline[0] + l_epiline[1] * r_epiline[1] ) < 0 )
+ {
+
+ l_epiline[0] = -l_epiline[0];
+ l_epiline[1] = -l_epiline[1];
+ l_epiline[2] = -l_epiline[2];
+ } /* if */
+
+ error = icvGetCrossEpilineFrame( imgSize, l_epiline,
+ scanlines_1 + offset,
+ scanlines_1 + offset + 1,
+ scanlines_1 + offset + 2, scanlines_1 + offset + 3 );
+
+ } /* for */
+
+ *numlines = prewarp_height;
+
+ return error;
+
+} /* icvlBuildScanlineLeftStereo */
+
+/*===========================================================================*/
+CvStatus
+icvBuildScanlineRightStereo( CvSize imgSize,
+ CvMatrix3 * matrix,
+ float *r_epipole,
+ float *r_angle,
+ float r_radius,
+ int *scanlines_1, int *scanlines_2, int *numlines )
+{
+ //int prewarp_width;
+ int prewarp_height;
+ float i;
+ int offset;
+ float height;
+ float delta;
+ float angle;
+ float r_point[3];
+ float l_epiline[3];
+ float r_epiline[3];
+ CvStatus error = CV_OK;
+ CvMatrix3 *F;
+
+ assert( r_angle != 0 && !REAL_ZERO( r_radius ));
+
+ /*prewarp_width = (int) (sqrt( image_width * image_width +
+ image_height * image_height ) + 1);*/
+
+ prewarp_height = (int) (r_radius * (r_angle[1] - r_angle[0]));
+
+ *numlines = prewarp_height;
+
+ if( scanlines_1 == 0 && scanlines_2 == 0 )
+ return CV_NO_ERR;
+
+ F = matrix;
+
+ r_point[2] = 1;
+ height = (float) prewarp_height;
+
+ delta = (r_angle[1] - r_angle[0]) / height;
+
+ r_angle[0] += delta;
+ r_angle[1] -= delta;
+
+ delta = (r_angle[1] - r_angle[0]) / height;
+
+ for( i = 0, offset = 0; i < height; i++, offset += 4 )
+ {
+
+ angle = r_angle[0] + i * delta;
+
+ r_point[0] = r_epipole[0] + r_radius * (float) cos( angle );
+ r_point[1] = r_epipole[1] + r_radius * (float) sin( angle );
+
+ icvMultMatrixVector3( F, r_point, l_epiline );
+
+ error = icvGetCrossEpilineFrame( imgSize, l_epiline,
+ scanlines_1 + offset,
+ scanlines_1 + offset + 1,
+ scanlines_1 + offset + 2, scanlines_1 + offset + 3 );
+
+ assert( error == CV_NO_ERR );
+
+ r_epiline[0] = r_point[1] - r_epipole[1];
+ r_epiline[1] = r_epipole[0] - r_point[0];
+ r_epiline[2] = r_point[0] * r_epipole[1] - r_point[1] * r_epipole[0];
+
+ if( Sgn( l_epiline[0] * r_epiline[0] + l_epiline[1] * r_epiline[1] ) < 0 )
+ {
+
+ r_epiline[0] = -r_epiline[0];
+ r_epiline[1] = -r_epiline[1];
+ r_epiline[2] = -r_epiline[2];
+ } /* if */
+
+ error = icvGetCrossEpilineFrame( imgSize, r_epiline,
+ scanlines_2 + offset,
+ scanlines_2 + offset + 1,
+ scanlines_2 + offset + 2, scanlines_2 + offset + 3 );
+
+ assert( error == CV_NO_ERR );
+ } /* for */
+
+ *numlines = prewarp_height;
+
+ return error;
+
+} /* icvlBuildScanlineRightStereo */
+
+/*===========================================================================*/
+CvStatus
+icvGetCrossEpilineFrame( CvSize imgSize, float *epiline, int *x1, int *y1, int *x2, int *y2 )
+{
+ int tx, ty;
+ float point[2][2];
+ int sign[4], i;
+ float width, height;
+ double tmpvalue;
+
+ if( REAL_ZERO( epiline[0] ) && REAL_ZERO( epiline[1] ))
+ return CV_BADFACTOR_ERR;
+
+ width = (float) imgSize.width - 1;
+ height = (float) imgSize.height - 1;
+
+ tmpvalue = epiline[2];
+ sign[0] = SIGN( tmpvalue );
+
+ tmpvalue = epiline[0] * width + epiline[2];
+ sign[1] = SIGN( tmpvalue );
+
+ tmpvalue = epiline[1] * height + epiline[2];
+ sign[2] = SIGN( tmpvalue );
+
+ tmpvalue = epiline[0] * width + epiline[1] * height + epiline[2];
+ sign[3] = SIGN( tmpvalue );
+
+ i = 0;
+ for( tx = 0; tx < 2; tx++ )
+ {
+ for( ty = 0; ty < 2; ty++ )
+ {
+
+ if( sign[ty * 2 + tx] == 0 )
+ {
+
+ point[i][0] = width * tx;
+ point[i][1] = height * ty;
+ i++;
+
+ } /* if */
+ } /* for */
+ } /* for */
+
+ if( sign[0] * sign[1] < 0 )
+ {
+ point[i][0] = -epiline[2] / epiline[0];
+ point[i][1] = 0;
+ i++;
+ } /* if */
+
+ if( sign[0] * sign[2] < 0 )
+ {
+ point[i][0] = 0;
+ point[i][1] = -epiline[2] / epiline[1];
+ i++;
+ } /* if */
+
+ if( sign[1] * sign[3] < 0 )
+ {
+ point[i][0] = width;
+ point[i][1] = -(epiline[0] * width + epiline[2]) / epiline[1];
+ i++;
+ } /* if */
+
+ if( sign[2] * sign[3] < 0 )
+ {
+ point[i][0] = -(epiline[1] * height + epiline[2]) / epiline[0];
+ point[i][1] = height;
+ } /* if */
+
+ if( sign[0] == sign[1] && sign[0] == sign[2] && sign[0] == sign[3] )
+ return CV_BADFACTOR_ERR;
+
+ if( (point[0][0] - point[1][0]) * epiline[1] +
+ (point[1][1] - point[0][1]) * epiline[0] > 0 )
+ {
+ *x1 = (int) point[0][0];
+ *y1 = (int) point[0][1];
+ *x2 = (int) point[1][0];
+ *y2 = (int) point[1][1];
+ }
+ else
+ {
+ *x1 = (int) point[1][0];
+ *y1 = (int) point[1][1];
+ *x2 = (int) point[0][0];
+ *y2 = (int) point[0][1];
+ } /* if */
+
+ return CV_NO_ERR;
+} /* icvlGetCrossEpilineFrame */
+
+/*=====================================================================================*/
+
+CV_IMPL void
+cvMakeScanlines( const CvMatrix3* matrix, CvSize imgSize,
+ int *scanlines_1, int *scanlines_2,
+ int *lens_1, int *lens_2, int *numlines )
+{
+ CV_FUNCNAME( "cvMakeScanlines" );
+
+ __BEGIN__;
+
+ IPPI_CALL( icvMakeScanlines( (CvMatrix3*)matrix, imgSize, scanlines_1,
+ scanlines_2, lens_1, lens_2, numlines ));
+ __END__;
+}
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Name: cvDeleteMoire
+// Purpose: The functions
+// Context:
+// Parameters:
+//
+// Notes:
+//F*/
+CV_IMPL void
+cvMakeAlphaScanlines( int *scanlines_1,
+ int *scanlines_2,
+ int *scanlines_a, int *lens, int numlines, float alpha )
+{
+ CV_FUNCNAME( "cvMakeAlphaScanlines" );
+
+ __BEGIN__;
+
+ IPPI_CALL( icvMakeAlphaScanlines( scanlines_1, scanlines_2, scanlines_a,
+ lens, numlines, alpha ));
+
+ __END__;
+}
diff --git a/cvaux/src/cvsegment.cpp b/cvaux/src/cvsegment.cpp
new file mode 100644
index 0000000..74883a3
--- /dev/null
+++ b/cvaux/src/cvsegment.cpp
@@ -0,0 +1,585 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+typedef struct Seg
+{
+ ushort y;
+ ushort l;
+ ushort r;
+ ushort Prevl;
+ ushort Prevr;
+ short fl;
+}
+Seg;
+
+#define UP 1
+#define DOWN -1
+
+#define PUSH(Y,IL,IR,IPL,IPR,FL) { stack[StIn].y=(ushort)(Y); \
+ stack[StIn].l=(ushort)(IL); \
+ stack[StIn].r=(ushort)(IR); \
+ stack[StIn].Prevl=(ushort)(IPL); \
+ stack[StIn].Prevr=(ushort)(IPR); \
+ stack[StIn].fl=(short)(FL); \
+ StIn++; }
+
+#define POP(Y,IL,IR,IPL,IPR,FL) { StIn--; \
+ Y=stack[StIn].y; \
+ IL=stack[StIn].l; \
+ IR=stack[StIn].r;\
+ IPL=stack[StIn].Prevl; \
+ IPR=stack[StIn].Prevr; \
+ FL=stack[StIn].fl; }
+
+
+#define DIFF(p1,p2) ((unsigned)((p1)[0] - (p2)[0] + d_lw)<=Interval && \
+ (unsigned)((p1)[1] - (p2)[1] + d_lw)<=Interval && \
+ (unsigned)((p1)[2] - (p2)[2] + d_lw)<=Interval)
+
+/*#define DIFF(p1,p2) (CV_IABS((p1)[0] - (p2)[0]) + \
+ CV_IABS((p1)[1] - (p2)[1]) + \
+ CV_IABS((p1)[2] - (p2)[2]) <=Interval )*/
+
+static CvStatus
+icvSegmFloodFill_Stage1( uchar* pImage, int step,
+ uchar* pMask, int maskStep,
+ CvSize /*roi*/, CvPoint seed,
+ int* newVal, int d_lw, int d_up,
+ CvConnectedComp * region,
+ void *pStack )
+{
+ uchar* img = pImage + step * seed.y;
+ uchar* mask = pMask + maskStep * (seed.y + 1);
+ unsigned Interval = (unsigned) (d_up + d_lw);
+ Seg *stack = (Seg*)pStack;
+ int StIn = 0;
+ int i, L, R;
+ int area = 0;
+ int sum[] = { 0, 0, 0 };
+ int XMin, XMax, YMin = seed.y, YMax = seed.y;
+ int val0[3];
+
+ L = R = seed.x;
+ img = pImage + seed.y*step;
+ mask = pMask + seed.y*maskStep;
+ mask[L] = 1;
+
+ val0[0] = img[seed.x*3];
+ val0[1] = img[seed.x*3 + 1];
+ val0[2] = img[seed.x*3 + 2];
+
+ while( DIFF( img + (R+1)*3, /*img + R*3*/val0 ) && !mask[R + 1] )
+ mask[++R] = 2;
+
+ while( DIFF( img + (L-1)*3, /*img + L*3*/val0 ) && !mask[L - 1] )
+ mask[--L] = 2;
+
+ XMax = R;
+ XMin = L;
+ PUSH( seed.y, L, R, R + 1, R, UP );
+
+ while( StIn )
+ {
+ int k, YC, PL, PR, flag/*, curstep*/;
+
+ POP( YC, L, R, PL, PR, flag );
+
+ int data[][3] = { {-flag, L, R}, {flag, L, PL-1}, {flag,PR+1,R}};
+
+ if( XMax < R )
+ XMax = R;
+
+ if( XMin > L )
+ XMin = L;
+
+ if( YMax < YC )
+ YMax = YC;
+
+ if( YMin > YC )
+ YMin = YC;
+
+ for( k = 0; k < 3; k++ )
+ {
+ flag = data[k][0];
+ /*curstep = flag * step;*/
+ img = pImage + (YC + flag) * step;
+ mask = pMask + (YC + flag) * maskStep;
+ int left = data[k][1];
+ int right = data[k][2];
+
+ for( i = left; i <= right; i++ )
+ {
+ if( !mask[i] && DIFF( img + i*3, /*img - curstep + i*3*/val0 ))
+ {
+ int j = i;
+ mask[i] = 2;
+ while( !mask[j - 1] && DIFF( img + (j - 1)*3, /*img + j*3*/val0 ))
+ mask[--j] = 2;
+
+ while( !mask[i + 1] &&
+ (DIFF( img + (i+1)*3, /*img + i*3*/val0 ) ||
+ (DIFF( img + (i+1)*3, /*img + (i+1)*3 - curstep*/val0) && i < R)))
+ mask[++i] = 2;
+
+ PUSH( YC + flag, j, i, L, R, -flag );
+ i++;
+ }
+ }
+ }
+
+ img = pImage + YC * step;
+
+ for( i = L; i <= R; i++ )
+ {
+ sum[0] += img[i*3];
+ sum[1] += img[i*3 + 1];
+ sum[2] += img[i*3 + 2];
+ }
+
+ area += R - L + 1;
+ }
+
+ region->area = area;
+ region->rect.x = XMin;
+ region->rect.y = YMin;
+ region->rect.width = XMax - XMin + 1;
+ region->rect.height = YMax - YMin + 1;
+ region->value = cvScalarAll(0);
+
+ {
+ double inv_area = area ? 1./area : 0;
+ newVal[0] = cvRound( sum[0] * inv_area );
+ newVal[1] = cvRound( sum[1] * inv_area );
+ newVal[2] = cvRound( sum[2] * inv_area );
+ }
+
+ return CV_NO_ERR;
+}
+
+
+#undef PUSH
+#undef POP
+#undef DIFF
+
+
+static CvStatus
+icvSegmFloodFill_Stage2( uchar* pImage, int step,
+ uchar* pMask, int maskStep,
+ CvSize /*roi*/, int* newVal,
+ CvRect rect )
+{
+ uchar* img = pImage + step * rect.y + rect.x * 3;
+ uchar* mask = pMask + maskStep * rect.y + rect.x;
+ uchar uv[] = { (uchar)newVal[0], (uchar)newVal[1], (uchar)newVal[2] };
+ int x, y;
+
+ for( y = 0; y < rect.height; y++, img += step, mask += maskStep )
+ for( x = 0; x < rect.width; x++ )
+ if( mask[x] == 2 )
+ {
+ mask[x] = 1;
+ img[x*3] = uv[0];
+ img[x*3+1] = uv[1];
+ img[x*3+2] = uv[2];
+ }
+
+ return CV_OK;
+}
+
+#if 0
+static void color_derv( const CvArr* srcArr, CvArr* dstArr, int thresh )
+{
+ static int tab[] = { 0, 2, 2, 1 };
+
+ uchar *src = 0, *dst = 0;
+ int dst_step, src_step;
+ int x, y;
+ CvSize size;
+
+ cvGetRawData( srcArr, (uchar**)&src, &src_step, &size );
+ cvGetRawData( dstArr, (uchar**)&dst, &dst_step, 0 );
+
+ memset( dst, 0, size.width*sizeof(dst[0]));
+ memset( (uchar*)dst + dst_step*(size.height-1), 0, size.width*sizeof(dst[0]));
+ src += 3;
+
+ #define CV_IABS(a) (((a) ^ ((a) < 0 ? -1 : 0)) - ((a) < 0 ? -1 : 0))
+
+ for( y = 1; y < size.height - 1; y++ )
+ {
+ src += src_step;
+ dst += dst_step;
+ uchar* src0 = src;
+
+ dst[0] = dst[size.width - 1] = 0;
+
+ for( x = 1; x < size.width - 1; x++, src += 3 )
+ {
+ /*int d[3];
+ int ad[3];
+ int f0, f1;
+ int val;*/
+ int m[3];
+ double val;
+ //double xx, yy;
+ int dh[3];
+ int dv[3];
+ dh[0] = src[0] - src[-3];
+ dv[0] = src[0] - src[-src_step];
+ dh[1] = src[1] - src[-2];
+ dv[1] = src[1] - src[1-src_step];
+ dh[2] = src[2] - src[-1];
+ dv[2] = src[2] - src[2-src_step];
+
+ m[0] = dh[0]*dh[0] + dh[1]*dh[1] + dh[2]*dh[2];
+ m[2] = dh[0]*dv[0] + dh[1]*dv[1] + dh[2]*dv[2];
+ m[1] = dv[0]*dv[0] + dv[1]*dv[1] + dh[2]*dh[2];
+
+ val = (m[0] + m[2]) +
+ sqrt(((double)((double)m[0] - m[2]))*(m[0] - m[2]) + (4.*m[1])*m[1]);
+
+ /*
+
+ xx = m[1];
+ yy = v - m[0];
+ v /= sqrt(xx*xx + yy*yy) + 1e-7;
+ xx *= v;
+ yy *= v;
+
+ dx[x] = (short)cvRound(xx);
+ dy[x] = (short)cvRound(yy);
+
+ //dx[x] = (short)cvRound(v);
+
+ //dx[x] = dy[x] = (short)v;
+ d[0] = src[0] - src[-3];
+ ad[0] = CV_IABS(d[0]);
+
+ d[1] = src[1] - src[-2];
+ ad[1] = CV_IABS(d[1]);
+
+ d[2] = src[2] - src[-1];
+ ad[2] = CV_IABS(d[2]);
+
+ f0 = ad[1] > ad[0];
+ f1 = ad[2] > ad[f0];
+
+ val = d[tab[f0*2 + f1]];
+
+ d[0] = src[0] - src[-src_step];
+ ad[0] = CV_IABS(d[0]);
+
+ d[1] = src[1] - src[1-src_step];
+ ad[1] = CV_IABS(d[1]);
+
+ d[2] = src[2] - src[2-src_step];
+ ad[2] = CV_IABS(d[2]);
+
+ f0 = ad[1] > ad[0];
+ f1 = ad[2] > ad[f0];
+
+ dst[x] = (uchar)(val + d[tab[f0*2 + f1]] > thresh ? 255 : 0);*/
+ dst[x] = (uchar)(val > thresh);
+ }
+
+ src = src0;
+ }
+
+}
+#endif
+
+const CvPoint icvCodeDeltas[8] =
+ { {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} };
+
+static CvSeq*
+icvGetComponent( uchar* img, int step, CvRect rect,
+ CvMemStorage* storage )
+{
+ const char nbd = 4;
+ int deltas[16];
+ int x, y;
+ CvSeq* exterior = 0;
+ char* ptr;
+
+ /* initialize local state */
+ CV_INIT_3X3_DELTAS( deltas, step, 1 );
+ memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
+
+ ptr = (char*)(img + step*rect.y);
+ rect.width += rect.x;
+ rect.height += rect.y;
+
+ for( y = rect.y; y < rect.height; y++, ptr += step )
+ {
+ int prev = ptr[rect.x - 1] & -2;
+
+ for( x = rect.x; x < rect.width; x++ )
+ {
+ int p = ptr[x] & -2;
+
+ //assert( exterior || ((p | prev) & -4) == 0 );
+
+ if( p != prev )
+ {
+ CvSeq *seq = 0;
+ int is_hole = 0;
+ CvSeqWriter writer;
+ char *i0, *i1, *i3, *i4 = 0;
+ int prev_s = -1, s, s_end;
+ CvPoint pt = { x, y };
+
+ if( !(prev == 0 && p == 2) ) /* if not external contour */
+ {
+ /* check hole */
+ if( p != 0 || prev < 1 )
+ {
+ prev = p;
+ continue;
+ }
+
+ is_hole = 1;
+ if( !exterior )
+ {
+ assert(0);
+ return 0;
+ }
+ }
+
+ cvStartWriteSeq( CV_SEQ_CONTOUR | (is_hole ? CV_SEQ_FLAG_HOLE : 0),
+ sizeof(CvContour), sizeof(CvPoint), storage, &writer );
+ s_end = s = is_hole ? 0 : 4;
+ i0 = ptr + x - is_hole;
+
+ do
+ {
+ s = (s - 1) & 7;
+ i1 = i0 + deltas[s];
+ if( (*i1 & -2) != 0 )
+ break;
+ }
+ while( s != s_end );
+
+ if( s == s_end ) /* single pixel domain */
+ {
+ *i0 = (char) (nbd | -128);
+ CV_WRITE_SEQ_ELEM( pt, writer );
+ }
+ else
+ {
+ i3 = i0;
+ prev_s = s ^ 4;
+
+ /* follow border */
+ for( ;; )
+ {
+ s_end = s;
+
+ for( ;; )
+ {
+ i4 = i3 + deltas[++s];
+ if( (*i4 & -2) != 0 )
+ break;
+ }
+ s &= 7;
+
+ /* check "right" bound */
+ if( (unsigned) (s - 1) < (unsigned) s_end )
+ {
+ *i3 = (char) (nbd | -128);
+ }
+ else if( *i3 > 0 )
+ {
+ *i3 = nbd;
+ }
+
+ if( s != prev_s )
+ {
+ CV_WRITE_SEQ_ELEM( pt, writer );
+ prev_s = s;
+ }
+
+ pt.x += icvCodeDeltas[s].x;
+ pt.y += icvCodeDeltas[s].y;
+
+ if( i4 == i0 && i3 == i1 )
+ break;
+
+ i3 = i4;
+ s = (s + 4) & 7;
+ } /* end of border following loop */
+ }
+
+ seq = cvEndWriteSeq( &writer );
+ cvContourBoundingRect( seq, 1 );
+
+ if( !is_hole )
+ exterior = seq;
+ else
+ {
+ seq->v_prev = exterior;
+ seq->h_next = exterior->v_next;
+ if( seq->h_next )
+ seq->h_next->h_prev = seq;
+ exterior->v_next = seq;
+ }
+
+ prev = ptr[x] & -2;
+ }
+ }
+ }
+
+ return exterior;
+}
+
+
+
+CV_IMPL CvSeq*
+cvSegmentImage( const CvArr* srcarr, CvArr* dstarr,
+ double canny_threshold,
+ double ffill_threshold,
+ CvMemStorage* storage )
+{
+ CvSeq* root = 0;
+ CvMat* gray = 0;
+ CvMat* canny = 0;
+ //CvMat* temp = 0;
+ void* stack = 0;
+
+ CV_FUNCNAME( "cvSegmentImage" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src;
+ CvMat dststub, *dst;
+ CvMat* mask;
+ CvSize size;
+ CvPoint pt;
+ int ffill_lw_up = cvRound( fabs(ffill_threshold) );
+ CvSeq* prev_seq = 0;
+
+ CV_CALL( src = cvGetMat( srcarr, &srcstub ));
+ CV_CALL( dst = cvGetMat( dstarr, &dststub ));
+
+ size = cvGetSize( src );
+
+ CV_CALL( gray = cvCreateMat( size.height, size.width, CV_8UC1 ));
+ CV_CALL( canny = cvCreateMat( size.height, size.width, CV_8UC1 ));
+ //CV_CALL( temp = cvCreateMat( size.height/2, size.width/2, CV_8UC3 ));
+
+ CV_CALL( stack = cvAlloc( size.width * size.height * sizeof(Seg)));
+
+ cvCvtColor( src, gray, CV_BGR2GRAY );
+ cvCanny( gray, canny, 0/*canny_threshold*0.4*/, canny_threshold, 3 );
+ cvThreshold( canny, canny, 1, 1, CV_THRESH_BINARY );
+ //cvZero( canny );
+ //color_derv( src, canny, canny_threshold );
+
+ //cvPyrDown( src, temp );
+ //cvPyrUp( temp, dst );
+
+ //src = dst;
+ mask = canny; // a new name for new role
+
+ // make a non-zero border.
+ cvRectangle( mask, cvPoint(0,0), cvPoint(size.width-1,size.height-1), cvScalarAll(1), 1 );
+
+ for( pt.y = 0; pt.y < size.height; pt.y++ )
+ {
+ for( pt.x = 0; pt.x < size.width; pt.x++ )
+ {
+ if( mask->data.ptr[mask->step*pt.y + pt.x] == 0 )
+ {
+ CvConnectedComp region;
+ int avgVal[3] = { 0, 0, 0 };
+
+ icvSegmFloodFill_Stage1( src->data.ptr, src->step,
+ mask->data.ptr, mask->step,
+ size, pt, avgVal,
+ ffill_lw_up, ffill_lw_up,
+ &region, stack );
+
+ /*avgVal[0] = (avgVal[0] + 15) & -32;
+ if( avgVal[0] > 255 )
+ avgVal[0] = 255;
+ avgVal[1] = (avgVal[1] + 15) & -32;
+ if( avgVal[1] > 255 )
+ avgVal[1] = 255;
+ avgVal[2] = (avgVal[2] + 15) & -32;
+ if( avgVal[2] > 255 )
+ avgVal[2] = 255;*/
+
+ if( storage )
+ {
+ CvSeq* tmpseq = icvGetComponent( mask->data.ptr, mask->step,
+ region.rect, storage );
+ if( tmpseq != 0 )
+ {
+ ((CvContour*)tmpseq)->color = avgVal[0] + (avgVal[1] << 8) + (avgVal[2] << 16);
+ tmpseq->h_prev = prev_seq;
+ if( prev_seq )
+ prev_seq->h_next = tmpseq;
+ else
+ root = tmpseq;
+ prev_seq = tmpseq;
+ }
+ }
+
+ icvSegmFloodFill_Stage2( dst->data.ptr, dst->step,
+ mask->data.ptr, mask->step,
+ size, avgVal,
+ region.rect );
+ }
+ }
+ }
+
+ __END__;
+
+ //cvReleaseMat( &temp );
+ cvReleaseMat( &gray );
+ cvReleaseMat( &canny );
+ cvFree( &stack );
+
+ return root;
+}
+
+/* End of file. */
diff --git a/cvaux/src/cvsubdiv2.cpp b/cvaux/src/cvsubdiv2.cpp
new file mode 100644
index 0000000..6876e37
--- /dev/null
+++ b/cvaux/src/cvsubdiv2.cpp
@@ -0,0 +1,187 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+CV_IMPL int
+icvSubdiv2DCheck( CvSubdiv2D* subdiv )
+{
+ int i, j, total = subdiv->edges->total;
+ int check_result = 0;
+
+ CV_FUNCNAME("icvSubdiv2DCheck");
+
+ __BEGIN__;
+
+ if( !subdiv )
+ CV_ERROR_FROM_STATUS( CV_NULLPTR_ERR );
+
+ for( i = 0; i < total; i++ )
+ {
+ CvQuadEdge2D* edge = (CvQuadEdge2D*)cvGetSetElem(subdiv->edges,i);
+
+ if( edge && CV_IS_SET_ELEM( edge ))
+ {
+ for( j = 0; j < 4; j++ )
+ {
+ CvSubdiv2DEdge e = (CvSubdiv2DEdge)edge + j;
+ CvSubdiv2DEdge o_next = cvSubdiv2DNextEdge(e);
+ CvSubdiv2DEdge o_prev = cvSubdiv2DGetEdge(e, CV_PREV_AROUND_ORG );
+ CvSubdiv2DEdge d_prev = cvSubdiv2DGetEdge(e, CV_PREV_AROUND_DST );
+ CvSubdiv2DEdge d_next = cvSubdiv2DGetEdge(e, CV_NEXT_AROUND_DST );
+
+ // check points
+ if( cvSubdiv2DEdgeOrg(e) != cvSubdiv2DEdgeOrg(o_next))
+ EXIT;
+ if( cvSubdiv2DEdgeOrg(e) != cvSubdiv2DEdgeOrg(o_prev))
+ EXIT;
+ if( cvSubdiv2DEdgeDst(e) != cvSubdiv2DEdgeDst(d_next))
+ EXIT;
+ if( cvSubdiv2DEdgeDst(e) != cvSubdiv2DEdgeDst(d_prev))
+ EXIT;
+ if( j % 2 == 0 )
+ {
+ if( cvSubdiv2DEdgeDst(o_next) != cvSubdiv2DEdgeOrg(d_prev))
+ EXIT;
+ if( cvSubdiv2DEdgeDst(o_prev) != cvSubdiv2DEdgeOrg(d_next))
+ EXIT;
+ if( cvSubdiv2DGetEdge(cvSubdiv2DGetEdge(cvSubdiv2DGetEdge(
+ e,CV_NEXT_AROUND_LEFT),CV_NEXT_AROUND_LEFT),CV_NEXT_AROUND_LEFT) != e )
+ EXIT;
+ if( cvSubdiv2DGetEdge(cvSubdiv2DGetEdge(cvSubdiv2DGetEdge(
+ e,CV_NEXT_AROUND_RIGHT),CV_NEXT_AROUND_RIGHT),CV_NEXT_AROUND_RIGHT) != e)
+ EXIT;
+ }
+ }
+ }
+ }
+
+ check_result = 1;
+
+ __END__;
+
+ return check_result;
+}
+
+
+
+static void
+draw_subdiv_facet( CvSubdiv2D * subdiv, IplImage * dst, IplImage * src, CvSubdiv2DEdge edge )
+{
+ CvSubdiv2DEdge t = edge;
+ int i, count = 0;
+ CvPoint local_buf[100];
+ CvPoint *buf = local_buf;
+
+ // count number of edges in facet
+ do
+ {
+ count++;
+ t = cvSubdiv2DGetEdge( t, CV_NEXT_AROUND_LEFT );
+ }
+ while( t != edge && count < subdiv->quad_edges * 4 );
+
+ if( count * sizeof( buf[0] ) > sizeof( local_buf ))
+ {
+ buf = (CvPoint *) malloc( count * sizeof( buf[0] ));
+ }
+
+ // gather points
+ t = edge;
+ for( i = 0; i < count; i++ )
+ {
+ CvSubdiv2DPoint *pt = cvSubdiv2DEdgeOrg( t );
+
+ if( !pt )
+ break;
+ assert( fabs( pt->pt.x ) < 10000 && fabs( pt->pt.y ) < 10000 );
+ buf[i] = cvPoint( cvRound( pt->pt.x ), cvRound( pt->pt.y ));
+ t = cvSubdiv2DGetEdge( t, CV_NEXT_AROUND_LEFT );
+ }
+
+ if( i == count )
+ {
+ CvSubdiv2DPoint *pt = cvSubdiv2DEdgeDst( cvSubdiv2DRotateEdge( edge, 1 ));
+ CvPoint ip = cvPoint( cvRound( pt->pt.x ), cvRound( pt->pt.y ));
+ CvScalar color = {{0,0,0,0}};
+
+ //printf("count = %d, (%d,%d)\n", ip.x, ip.y );
+
+ if( 0 <= ip.x && ip.x < src->width && 0 <= ip.y && ip.y < src->height )
+ {
+ uchar *ptr = (uchar*)(src->imageData + ip.y * src->widthStep + ip.x * 3);
+ color = CV_RGB( ptr[2], ptr[1], ptr[0] );
+ }
+
+ cvFillConvexPoly( dst, buf, count, color );
+ //draw_subdiv_point( dst, pt->pt, CV_RGB(0,0,0));
+ }
+
+ if( buf != local_buf )
+ free( buf );
+}
+
+
+CV_IMPL void
+icvDrawMosaic( CvSubdiv2D * subdiv, IplImage * src, IplImage * dst )
+{
+ int i, total = subdiv->edges->total;
+
+ cvCalcSubdivVoronoi2D( subdiv );
+
+ //icvSet( dst, 255 );
+ for( i = 0; i < total; i++ )
+ {
+ CvQuadEdge2D *edge = (CvQuadEdge2D *) cvGetSetElem( subdiv->edges, i );
+
+ if( edge && CV_IS_SET_ELEM( edge ))
+ {
+ CvSubdiv2DEdge e = (CvSubdiv2DEdge) edge;
+
+ // left
+ draw_subdiv_facet( subdiv, dst, src, cvSubdiv2DRotateEdge( e, 1 ));
+ // right
+ draw_subdiv_facet( subdiv, dst, src, cvSubdiv2DRotateEdge( e, 3 ));
+ }
+ }
+}
+
+/* End of file. */
diff --git a/cvaux/src/cvtexture.cpp b/cvaux/src/cvtexture.cpp
new file mode 100644
index 0000000..434baaf
--- /dev/null
+++ b/cvaux/src/cvtexture.cpp
@@ -0,0 +1,648 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/****************************************************************************************\
+
+ Calculation of a texture descriptors from GLCM (Grey Level Co-occurrence Matrix'es)
+ The code was submitted by Daniel Eaton [danieljameseaton@yahoo.com]
+
+\****************************************************************************************/
+
+#include "_cvaux.h"
+
+#include <math.h>
+#include <assert.h>
+
+#define CV_MAX_NUM_GREY_LEVELS_8U 256
+
+struct CvGLCM
+{
+ int matrixSideLength;
+ int numMatrices;
+ double*** matrices;
+
+ int numLookupTableElements;
+ int forwardLookupTable[CV_MAX_NUM_GREY_LEVELS_8U];
+ int reverseLookupTable[CV_MAX_NUM_GREY_LEVELS_8U];
+
+ double** descriptors;
+ int numDescriptors;
+ int descriptorOptimizationType;
+ int optimizationType;
+};
+
+
+static void icvCreateGLCM_LookupTable_8u_C1R( const uchar* srcImageData, int srcImageStep,
+ CvSize srcImageSize, CvGLCM* destGLCM,
+ int* steps, int numSteps, int* memorySteps );
+
+static void
+icvCreateGLCMDescriptors_AllowDoubleNest( CvGLCM* destGLCM, int matrixIndex );
+
+
+CV_IMPL CvGLCM*
+cvCreateGLCM( const IplImage* srcImage,
+ int stepMagnitude,
+ const int* srcStepDirections,/* should be static array..
+ or if not the user should handle de-allocation */
+ int numStepDirections,
+ int optimizationType )
+{
+ static const int defaultStepDirections[] = { 0,1, -1,1, -1,0, -1,-1 };
+
+ int* memorySteps = 0;
+ CvGLCM* newGLCM = 0;
+ int* stepDirections = 0;
+
+ CV_FUNCNAME( "cvCreateGLCM" );
+
+ __BEGIN__;
+
+ uchar* srcImageData = 0;
+ CvSize srcImageSize;
+ int srcImageStep;
+ int stepLoop;
+ const int maxNumGreyLevels8u = CV_MAX_NUM_GREY_LEVELS_8U;
+
+ if( !srcImage )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( srcImage->nChannels != 1 )
+ CV_ERROR( CV_BadNumChannels, "Number of channels must be 1");
+
+ if( srcImage->depth != IPL_DEPTH_8U )
+ CV_ERROR( CV_BadDepth, "Depth must be equal IPL_DEPTH_8U");
+
+ // no Directions provided, use the default ones - 0 deg, 45, 90, 135
+ if( !srcStepDirections )
+ {
+ srcStepDirections = defaultStepDirections;
+ }
+
+ CV_CALL( stepDirections = (int*)cvAlloc( numStepDirections*2*sizeof(stepDirections[0])));
+ memcpy( stepDirections, srcStepDirections, numStepDirections*2*sizeof(stepDirections[0]));
+
+ cvGetImageRawData( srcImage, &srcImageData, &srcImageStep, &srcImageSize );
+
+ // roll together Directions and magnitudes together with knowledge of image (step)
+ CV_CALL( memorySteps = (int*)cvAlloc( numStepDirections*sizeof(memorySteps[0])));
+
+ for( stepLoop = 0; stepLoop < numStepDirections; stepLoop++ )
+ {
+ stepDirections[stepLoop*2 + 0] *= stepMagnitude;
+ stepDirections[stepLoop*2 + 1] *= stepMagnitude;
+
+ memorySteps[stepLoop] = stepDirections[stepLoop*2 + 0]*srcImageStep +
+ stepDirections[stepLoop*2 + 1];
+ }
+
+ CV_CALL( newGLCM = (CvGLCM*)cvAlloc(sizeof(newGLCM)));
+ memset( newGLCM, 0, sizeof(newGLCM) );
+
+ newGLCM->matrices = 0;
+ newGLCM->numMatrices = numStepDirections;
+ newGLCM->optimizationType = optimizationType;
+
+ if( optimizationType <= CV_GLCM_OPTIMIZATION_LUT )
+ {
+ int lookupTableLoop, imageColLoop, imageRowLoop, lineOffset = 0;
+
+ // if optimization type is set to lut, then make one for the image
+ if( optimizationType == CV_GLCM_OPTIMIZATION_LUT )
+ {
+ for( imageRowLoop = 0; imageRowLoop < srcImageSize.height;
+ imageRowLoop++, lineOffset += srcImageStep )
+ {
+ for( imageColLoop = 0; imageColLoop < srcImageSize.width; imageColLoop++ )
+ {
+ newGLCM->forwardLookupTable[srcImageData[lineOffset+imageColLoop]]=1;
+ }
+ }
+
+ newGLCM->numLookupTableElements = 0;
+
+ for( lookupTableLoop = 0; lookupTableLoop < maxNumGreyLevels8u; lookupTableLoop++ )
+ {
+ if( newGLCM->forwardLookupTable[ lookupTableLoop ] != 0 )
+ {
+ newGLCM->forwardLookupTable[ lookupTableLoop ] =
+ newGLCM->numLookupTableElements;
+ newGLCM->reverseLookupTable[ newGLCM->numLookupTableElements ] =
+ lookupTableLoop;
+
+ newGLCM->numLookupTableElements++;
+ }
+ }
+ }
+ // otherwise make a "LUT" which contains all the gray-levels (for code-reuse)
+ else if( optimizationType == CV_GLCM_OPTIMIZATION_NONE )
+ {
+ for( lookupTableLoop = 0; lookupTableLoop <maxNumGreyLevels8u; lookupTableLoop++ )
+ {
+ newGLCM->forwardLookupTable[ lookupTableLoop ] = lookupTableLoop;
+ newGLCM->reverseLookupTable[ lookupTableLoop ] = lookupTableLoop;
+ }
+ newGLCM->numLookupTableElements = maxNumGreyLevels8u;
+ }
+
+ newGLCM->matrixSideLength = newGLCM->numLookupTableElements;
+ icvCreateGLCM_LookupTable_8u_C1R( srcImageData, srcImageStep, srcImageSize,
+ newGLCM, stepDirections,
+ numStepDirections, memorySteps );
+ }
+ else if( optimizationType == CV_GLCM_OPTIMIZATION_HISTOGRAM )
+ {
+ CV_ERROR( CV_StsBadFlag, "Histogram-based method is not implemented" );
+
+ /* newGLCM->numMatrices *= 2;
+ newGLCM->matrixSideLength = maxNumGreyLevels8u*2;
+
+ icvCreateGLCM_Histogram_8uC1R( srcImageStep, srcImageSize, srcImageData,
+ newGLCM, numStepDirections,
+ stepDirections, memorySteps );
+ */
+ }
+
+ __END__;
+
+ cvFree( &memorySteps );
+ cvFree( &stepDirections );
+
+ if( cvGetErrStatus() < 0 )
+ {
+ cvFree( &newGLCM );
+ }
+
+ return newGLCM;
+}
+
+
+CV_IMPL void
+cvReleaseGLCM( CvGLCM** GLCM, int flag )
+{
+ CV_FUNCNAME( "cvReleaseGLCM" );
+
+ __BEGIN__;
+
+ int matrixLoop;
+
+ if( !GLCM )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( *GLCM )
+ EXIT; // repeated deallocation: just skip it.
+
+ if( (flag == CV_GLCM_GLCM || flag == CV_GLCM_ALL) && (*GLCM)->matrices )
+ {
+ for( matrixLoop = 0; matrixLoop < (*GLCM)->numMatrices; matrixLoop++ )
+ {
+ if( (*GLCM)->matrices[ matrixLoop ] )
+ {
+ cvFree( (*GLCM)->matrices[matrixLoop] );
+ cvFree( (*GLCM)->matrices + matrixLoop );
+ }
+ }
+
+ cvFree( &((*GLCM)->matrices) );
+ }
+
+ if( (flag == CV_GLCM_DESC || flag == CV_GLCM_ALL) && (*GLCM)->descriptors )
+ {
+ for( matrixLoop = 0; matrixLoop < (*GLCM)->numMatrices; matrixLoop++ )
+ {
+ cvFree( (*GLCM)->descriptors + matrixLoop );
+ }
+ cvFree( &((*GLCM)->descriptors) );
+ }
+
+ if( flag == CV_GLCM_ALL )
+ {
+ cvFree( GLCM );
+ }
+
+ __END__;
+}
+
+
+static void
+icvCreateGLCM_LookupTable_8u_C1R( const uchar* srcImageData,
+ int srcImageStep,
+ CvSize srcImageSize,
+ CvGLCM* destGLCM,
+ int* steps,
+ int numSteps,
+ int* memorySteps )
+{
+ int* stepIncrementsCounter = 0;
+
+ CV_FUNCNAME( "icvCreateGLCM_LookupTable_8u_C1R" );
+
+ __BEGIN__;
+
+ int matrixSideLength = destGLCM->matrixSideLength;
+ int stepLoop, sideLoop1, sideLoop2;
+ int colLoop, rowLoop, lineOffset = 0;
+ double*** matrices = 0;
+
+ // allocate memory to the matrices
+ CV_CALL( destGLCM->matrices = (double***)cvAlloc( sizeof(matrices[0])*numSteps ));
+ matrices = destGLCM->matrices;
+
+ for( stepLoop=0; stepLoop<numSteps; stepLoop++ )
+ {
+ CV_CALL( matrices[stepLoop] = (double**)cvAlloc( sizeof(matrices[0])*matrixSideLength ));
+ CV_CALL( matrices[stepLoop][0] = (double*)cvAlloc( sizeof(matrices[0][0])*
+ matrixSideLength*matrixSideLength ));
+
+ memset( matrices[stepLoop][0], 0, matrixSideLength*matrixSideLength*
+ sizeof(matrices[0][0]) );
+
+ for( sideLoop1 = 1; sideLoop1 < matrixSideLength; sideLoop1++ )
+ {
+ matrices[stepLoop][sideLoop1] = matrices[stepLoop][sideLoop1-1] + matrixSideLength;
+ }
+ }
+
+ CV_CALL( stepIncrementsCounter = (int*)cvAlloc( numSteps*sizeof(stepIncrementsCounter[0])));
+ memset( stepIncrementsCounter, 0, numSteps*sizeof(stepIncrementsCounter[0]) );
+
+ // generate GLCM for each step
+ for( rowLoop=0; rowLoop<srcImageSize.height; rowLoop++, lineOffset+=srcImageStep )
+ {
+ for( colLoop=0; colLoop<srcImageSize.width; colLoop++ )
+ {
+ int pixelValue1 = destGLCM->forwardLookupTable[srcImageData[lineOffset + colLoop]];
+
+ for( stepLoop=0; stepLoop<numSteps; stepLoop++ )
+ {
+ int col2, row2;
+ row2 = rowLoop + steps[stepLoop*2 + 0];
+ col2 = colLoop + steps[stepLoop*2 + 1];
+
+ if( col2>=0 && row2>=0 && col2<srcImageSize.width && row2<srcImageSize.height )
+ {
+ int memoryStep = memorySteps[ stepLoop ];
+ int pixelValue2 = destGLCM->forwardLookupTable[ srcImageData[ lineOffset + colLoop + memoryStep ] ];
+
+ // maintain symmetry
+ matrices[stepLoop][pixelValue1][pixelValue2] ++;
+ matrices[stepLoop][pixelValue2][pixelValue1] ++;
+
+ // incremenet counter of total number of increments
+ stepIncrementsCounter[stepLoop] += 2;
+ }
+ }
+ }
+ }
+
+ // normalize matrices. each element is a probability of gray value i,j adjacency in direction/magnitude k
+ for( sideLoop1=0; sideLoop1<matrixSideLength; sideLoop1++ )
+ {
+ for( sideLoop2=0; sideLoop2<matrixSideLength; sideLoop2++ )
+ {
+ for( stepLoop=0; stepLoop<numSteps; stepLoop++ )
+ {
+ matrices[stepLoop][sideLoop1][sideLoop2] /= double(stepIncrementsCounter[stepLoop]);
+ }
+ }
+ }
+
+ destGLCM->matrices = matrices;
+
+ __END__;
+
+ cvFree( &stepIncrementsCounter );
+
+ if( cvGetErrStatus() < 0 )
+ cvReleaseGLCM( &destGLCM, CV_GLCM_GLCM );
+}
+
+
+CV_IMPL void
+cvCreateGLCMDescriptors( CvGLCM* destGLCM, int descriptorOptimizationType )
+{
+ CV_FUNCNAME( "cvCreateGLCMDescriptors" );
+
+ __BEGIN__;
+
+ int matrixLoop;
+
+ if( !destGLCM )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !(destGLCM->matrices) )
+ CV_ERROR( CV_StsNullPtr, "Matrices are not allocated" );
+
+ CV_CALL( cvReleaseGLCM( &destGLCM, CV_GLCM_DESC ));
+
+ if( destGLCM->optimizationType != CV_GLCM_OPTIMIZATION_HISTOGRAM )
+ {
+ destGLCM->descriptorOptimizationType = destGLCM->numDescriptors = descriptorOptimizationType;
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadFlag, "Histogram-based method is not implemented" );
+// destGLCM->descriptorOptimizationType = destGLCM->numDescriptors = CV_GLCMDESC_OPTIMIZATION_HISTOGRAM;
+ }
+
+ CV_CALL( destGLCM->descriptors = (double**)
+ cvAlloc( destGLCM->numMatrices*sizeof(destGLCM->descriptors[0])));
+
+ for( matrixLoop = 0; matrixLoop < destGLCM->numMatrices; matrixLoop ++ )
+ {
+ CV_CALL( destGLCM->descriptors[ matrixLoop ] =
+ (double*)cvAlloc( destGLCM->numDescriptors*sizeof(destGLCM->descriptors[0][0])));
+ memset( destGLCM->descriptors[matrixLoop], 0, destGLCM->numDescriptors*sizeof(double) );
+
+ switch( destGLCM->descriptorOptimizationType )
+ {
+ case CV_GLCMDESC_OPTIMIZATION_ALLOWDOUBLENEST:
+ icvCreateGLCMDescriptors_AllowDoubleNest( destGLCM, matrixLoop );
+ break;
+ default:
+ CV_ERROR( CV_StsBadFlag,
+ "descriptorOptimizationType different from CV_GLCMDESC_OPTIMIZATION_ALLOWDOUBLENEST\n"
+ "is not supported" );
+ /*
+ case CV_GLCMDESC_OPTIMIZATION_ALLOWTRIPLENEST:
+ icvCreateGLCMDescriptors_AllowTripleNest( destGLCM, matrixLoop );
+ break;
+ case CV_GLCMDESC_OPTIMIZATION_HISTOGRAM:
+ if(matrixLoop < destGLCM->numMatrices>>1)
+ icvCreateGLCMDescriptors_Histogram( destGLCM, matrixLoop);
+ break;
+ */
+ }
+ }
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvReleaseGLCM( &destGLCM, CV_GLCM_DESC );
+}
+
+
+static void
+icvCreateGLCMDescriptors_AllowDoubleNest( CvGLCM* destGLCM, int matrixIndex )
+{
+ int sideLoop1, sideLoop2;
+ int matrixSideLength = destGLCM->matrixSideLength;
+
+ double** matrix = destGLCM->matrices[ matrixIndex ];
+ double* descriptors = destGLCM->descriptors[ matrixIndex ];
+
+ double* marginalProbability =
+ (double*)cvAlloc( matrixSideLength * sizeof(marginalProbability[0]));
+ memset( marginalProbability, 0, matrixSideLength * sizeof(double) );
+
+ double maximumProbability = 0;
+ double marginalProbabilityEntropy = 0;
+ double correlationMean = 0, correlationStdDeviation = 0, correlationProductTerm = 0;
+
+ for( sideLoop1=0; sideLoop1<matrixSideLength; sideLoop1++ )
+ {
+ int actualSideLoop1 = destGLCM->reverseLookupTable[ sideLoop1 ];
+
+ for( sideLoop2=0; sideLoop2<matrixSideLength; sideLoop2++ )
+ {
+ double entryValue = matrix[ sideLoop1 ][ sideLoop2 ];
+
+ int actualSideLoop2 = destGLCM->reverseLookupTable[ sideLoop2 ];
+ int sideLoopDifference = actualSideLoop1 - actualSideLoop2;
+ int sideLoopDifferenceSquared = sideLoopDifference*sideLoopDifference;
+
+ marginalProbability[ sideLoop1 ] += entryValue;
+ correlationMean += actualSideLoop1*entryValue;
+
+ maximumProbability = MAX( maximumProbability, entryValue );
+
+ if( actualSideLoop2 > actualSideLoop1 )
+ {
+ descriptors[ CV_GLCMDESC_CONTRAST ] += sideLoopDifferenceSquared * entryValue;
+ }
+
+ descriptors[ CV_GLCMDESC_HOMOGENITY ] += entryValue / ( 1.0 + sideLoopDifferenceSquared );
+
+ if( entryValue > 0 )
+ {
+ descriptors[ CV_GLCMDESC_ENTROPY ] += entryValue * log( entryValue );
+ }
+
+ descriptors[ CV_GLCMDESC_ENERGY ] += entryValue*entryValue;
+ }
+
+ if( marginalProbability>0 )
+ marginalProbabilityEntropy += marginalProbability[ actualSideLoop1 ]*log(marginalProbability[ actualSideLoop1 ]);
+ }
+
+ marginalProbabilityEntropy = -marginalProbabilityEntropy;
+
+ descriptors[ CV_GLCMDESC_CONTRAST ] += descriptors[ CV_GLCMDESC_CONTRAST ];
+ descriptors[ CV_GLCMDESC_ENTROPY ] = -descriptors[ CV_GLCMDESC_ENTROPY ];
+ descriptors[ CV_GLCMDESC_MAXIMUMPROBABILITY ] = maximumProbability;
+
+ double HXY = 0, HXY1 = 0, HXY2 = 0;
+
+ HXY = descriptors[ CV_GLCMDESC_ENTROPY ];
+
+ for( sideLoop1=0; sideLoop1<matrixSideLength; sideLoop1++ )
+ {
+ double sideEntryValueSum = 0;
+ int actualSideLoop1 = destGLCM->reverseLookupTable[ sideLoop1 ];
+
+ for( sideLoop2=0; sideLoop2<matrixSideLength; sideLoop2++ )
+ {
+ double entryValue = matrix[ sideLoop1 ][ sideLoop2 ];
+
+ sideEntryValueSum += entryValue;
+
+ int actualSideLoop2 = destGLCM->reverseLookupTable[ sideLoop2 ];
+
+ correlationProductTerm += (actualSideLoop1 - correlationMean) * (actualSideLoop2 - correlationMean) * entryValue;
+
+ double clusterTerm = actualSideLoop1 + actualSideLoop2 - correlationMean - correlationMean;
+
+ descriptors[ CV_GLCMDESC_CLUSTERTENDENCY ] += clusterTerm * clusterTerm * entryValue;
+ descriptors[ CV_GLCMDESC_CLUSTERSHADE ] += clusterTerm * clusterTerm * clusterTerm * entryValue;
+
+ double HXYValue = marginalProbability[ actualSideLoop1 ] * marginalProbability[ actualSideLoop2 ];
+ if( HXYValue>0 )
+ {
+ double HXYValueLog = log( HXYValue );
+ HXY1 += entryValue * HXYValueLog;
+ HXY2 += HXYValue * HXYValueLog;
+ }
+ }
+
+ correlationStdDeviation += (actualSideLoop1-correlationMean) * (actualSideLoop1-correlationMean) * sideEntryValueSum;
+ }
+
+ HXY1 =- HXY1;
+ HXY2 =- HXY2;
+
+ descriptors[ CV_GLCMDESC_CORRELATIONINFO1 ] = ( HXY - HXY1 ) / ( correlationMean );
+ descriptors[ CV_GLCMDESC_CORRELATIONINFO2 ] = sqrt( 1.0 - exp( -2.0 * (HXY2 - HXY ) ) );
+
+ correlationStdDeviation = sqrt( correlationStdDeviation );
+
+ descriptors[ CV_GLCMDESC_CORRELATION ] = correlationProductTerm / (correlationStdDeviation*correlationStdDeviation );
+
+ delete [] marginalProbability;
+}
+
+
+CV_IMPL double cvGetGLCMDescriptor( CvGLCM* GLCM, int step, int descriptor )
+{
+ double value = DBL_MAX;
+
+ CV_FUNCNAME( "cvGetGLCMDescriptor" );
+
+ __BEGIN__;
+
+ if( !GLCM )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !(GLCM->descriptors) )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( (unsigned)step >= (unsigned)(GLCM->numMatrices))
+ CV_ERROR( CV_StsOutOfRange, "step is not in 0 .. GLCM->numMatrices - 1" );
+
+ if( (unsigned)descriptor >= (unsigned)(GLCM->numDescriptors))
+ CV_ERROR( CV_StsOutOfRange, "descriptor is not in 0 .. GLCM->numDescriptors - 1" );
+
+ value = GLCM->descriptors[step][descriptor];
+
+ __END__;
+
+ return value;
+}
+
+
+CV_IMPL void
+cvGetGLCMDescriptorStatistics( CvGLCM* GLCM, int descriptor,
+ double* _average, double* _standardDeviation )
+{
+ CV_FUNCNAME( "cvGetGLCMDescriptorStatistics" );
+
+ if( _average )
+ *_average = DBL_MAX;
+
+ if( _standardDeviation )
+ *_standardDeviation = DBL_MAX;
+
+ __BEGIN__;
+
+ int matrixLoop, numMatrices;
+ double average = 0, squareSum = 0;
+
+ if( !GLCM )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !(GLCM->descriptors))
+ CV_ERROR( CV_StsNullPtr, "Descriptors are not calculated" );
+
+ if( (unsigned)descriptor >= (unsigned)(GLCM->numDescriptors) )
+ CV_ERROR( CV_StsOutOfRange, "Descriptor index is out of range" );
+
+ numMatrices = GLCM->numMatrices;
+
+ for( matrixLoop = 0; matrixLoop < numMatrices; matrixLoop++ )
+ {
+ double temp = GLCM->descriptors[ matrixLoop ][ descriptor ];
+ average += temp;
+ squareSum += temp*temp;
+ }
+
+ average /= numMatrices;
+
+ if( _average )
+ *_average = average;
+
+ if( _standardDeviation )
+ *_standardDeviation = sqrt( (squareSum - average*average*numMatrices)/(numMatrices-1));
+
+ __END__;
+}
+
+
+CV_IMPL IplImage*
+cvCreateGLCMImage( CvGLCM* GLCM, int step )
+{
+ IplImage* dest = 0;
+
+ CV_FUNCNAME( "cvCreateGLCMImage" );
+
+ __BEGIN__;
+
+ float* destData;
+ int sideLoop1, sideLoop2;
+
+ if( !GLCM )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !(GLCM->matrices) )
+ CV_ERROR( CV_StsNullPtr, "Matrices are not allocated" );
+
+ if( (unsigned)step >= (unsigned)(GLCM->numMatrices) )
+ CV_ERROR( CV_StsOutOfRange, "The step index is out of range" );
+
+ dest = cvCreateImage( cvSize( GLCM->matrixSideLength, GLCM->matrixSideLength ), IPL_DEPTH_32F, 1 );
+ destData = (float*)(dest->imageData);
+
+ for( sideLoop1 = 0; sideLoop1 < GLCM->matrixSideLength;
+ sideLoop1++, (float*&)destData += dest->widthStep )
+ {
+ for( sideLoop2=0; sideLoop2 < GLCM->matrixSideLength; sideLoop2++ )
+ {
+ double matrixValue = GLCM->matrices[step][sideLoop1][sideLoop2];
+ destData[ sideLoop2 ] = (float)matrixValue;
+ }
+ }
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvReleaseImage( &dest );
+
+ return dest;
+}
+
diff --git a/cvaux/src/cvtrifocal.cpp b/cvaux/src/cvtrifocal.cpp
new file mode 100644
index 0000000..930cdb2
--- /dev/null
+++ b/cvaux/src/cvtrifocal.cpp
@@ -0,0 +1,2792 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+//#include "cvtypes.h"
+#include <float.h>
+#include <limits.h>
+//#include "cv.h"
+//#include "windows.h"
+
+#include <stdio.h>
+
+/* Valery Mosyagin */
+
+/* Function defenitions */
+
+/* ----------------- */
+
+void cvOptimizeLevenbergMarquardtBundle( CvMat** projMatrs, CvMat** observProjPoints,
+ CvMat** pointsPres, int numImages,
+ CvMat** resultProjMatrs, CvMat* resultPoints4D,int maxIter,double epsilon );
+
+int icvComputeProjectMatrices6Points( CvMat* points1,CvMat* points2,CvMat* points3,
+ CvMat* projMatr1,CvMat* projMatr2,CvMat* projMatr3);
+
+void icvFindBaseTransform(CvMat* points,CvMat* resultT);
+
+void GetGeneratorReduceFundSolution(CvMat* points1,CvMat* points2,CvMat* fundReduceCoef1,CvMat* fundReduceCoef2);
+
+int GetGoodReduceFundamMatrFromTwo(CvMat* fundReduceCoef1,CvMat* fundReduceCoef2,CvMat* resFundReduceCoef);
+
+void GetProjMatrFromReducedFundamental(CvMat* fundReduceCoefs,CvMat* projMatrCoefs);
+
+void icvComputeProjectMatrix(CvMat* objPoints,CvMat* projPoints,CvMat* projMatr);
+
+void icvComputeTransform4D(CvMat* points1,CvMat* points2,CvMat* transMatr);
+
+int icvComputeProjectMatricesNPoints( CvMat* points1,CvMat* points2,CvMat* points3,
+ CvMat* projMatr1,CvMat* projMatr2,CvMat* projMatr3,
+ double threshold,/* Threshold for good point */
+ double p,/* Probability of good result. */
+ CvMat* status,
+ CvMat* points4D);
+
+int icvComputeProjectMatricesNPoints( CvMat* points1,CvMat* points2,CvMat* points3,
+ CvMat* projMatr1,CvMat* projMatr2,CvMat* projMatr3,
+ double threshold,/* Threshold for good point */
+ double p,/* Probability of good result. */
+ CvMat* status,
+ CvMat* points4D);
+
+void icvReconstructPointsFor3View( CvMat* projMatr1,CvMat* projMatr2,CvMat* projMatr3,
+ CvMat* projPoints1,CvMat* projPoints2,CvMat* projPoints3,
+ CvMat* points4D);
+
+void icvReconstructPointsFor3View( CvMat* projMatr1,CvMat* projMatr2,CvMat* projMatr3,
+ CvMat* projPoints1,CvMat* projPoints2,CvMat* projPoints3,
+ CvMat* points4D);
+
+/*==========================================================================================*/
+/* Functions for calculation the tensor */
+/*==========================================================================================*/
+#if 1
+void fprintMatrix(FILE* file,CvMat* matrix)
+{
+ int i,j;
+ fprintf(file,"\n");
+ for( i=0;i<matrix->rows;i++ )
+ {
+ for(j=0;j<matrix->cols;j++)
+ {
+ fprintf(file,"%10.7lf ",cvmGet(matrix,i,j));
+ }
+ fprintf(file,"\n");
+ }
+}
+#endif
+/*==========================================================================================*/
+
+void icvNormalizePoints( CvMat* points, CvMat* normPoints,CvMat* cameraMatr )
+{
+ /* Normalize image points using camera matrix */
+
+ CV_FUNCNAME( "icvNormalizePoints" );
+ __BEGIN__;
+
+ /* Test for null pointers */
+ if( points == 0 || normPoints == 0 || cameraMatr == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(points) || !CV_IS_MAT(normPoints) || !CV_IS_MAT(cameraMatr) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters must be a matrices" );
+ }
+
+ int numPoints;
+ numPoints = points->cols;
+ if( numPoints <= 0 || numPoints != normPoints->cols )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of points must be the same and more than 0" );
+ }
+
+ if( normPoints->rows != 2 || normPoints->rows != points->rows )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Points must have 2 coordinates" );
+ }
+
+ if(cameraMatr->rows != 3 || cameraMatr->cols != 3)
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of camera matrix must be 3x3" );
+ }
+
+ double fx,fy,cx,cy;
+
+ fx = cvmGet(cameraMatr,0,0);
+ fy = cvmGet(cameraMatr,1,1);
+ cx = cvmGet(cameraMatr,0,2);
+ cy = cvmGet(cameraMatr,1,2);
+
+ int i;
+ for( i = 0; i < numPoints; i++ )
+ {
+ cvmSet(normPoints, 0, i, (cvmGet(points,0,i) - cx) / fx );
+ cvmSet(normPoints, 1, i, (cvmGet(points,1,i) - cy) / fy );
+ }
+
+ __END__;
+
+ return;
+}
+
+
+/*=====================================================================================*/
+/*
+Computes projection matrices for given 6 points on 3 images
+May returns 3 results. */
+int icvComputeProjectMatrices6Points( CvMat* points1,CvMat* points2,CvMat* points3,
+ CvMat* projMatr1,CvMat* projMatr2,CvMat* projMatr3/*,
+ CvMat* points4D*/)
+{
+ /* Test input data correctness */
+
+ int numSol = 0;
+
+ CV_FUNCNAME( "icvComputeProjectMatrices6Points" );
+ __BEGIN__;
+
+ /* Test for null pointers */
+ if( points1 == 0 || points2 == 0 || points3 == 0 ||
+ projMatr1 == 0 || projMatr2 == 0 || projMatr3 == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(points1) || !CV_IS_MAT(points2) || !CV_IS_MAT(points3) ||
+ !CV_IS_MAT(projMatr1) || !CV_IS_MAT(projMatr2) || !CV_IS_MAT(projMatr3) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters must be a matrices" );
+ }
+
+ if( (points1->cols != points2->cols) || (points1->cols != points3->cols) || (points1->cols != 6) /* || (points4D->cols !=6) */)
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of points must be same and == 6" );
+ }
+
+ if( points1->rows != 2 || points2->rows != 2 || points3->rows != 2 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of points coordinates must be 2" );
+ }
+
+ if( projMatr1->cols != 4 || projMatr2->cols != 4 || projMatr3->cols != 4 ||
+ !(projMatr1->rows == 3 && projMatr2->rows == 3 && projMatr3->rows == 3) &&
+ !(projMatr1->rows == 9 && projMatr2->rows == 9 && projMatr3->rows == 9) )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of project matrix must be 3x4 or 9x4 (for 3 matrices)" );
+ }
+
+#if 0
+ if( points4D->row != 4 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of coordinates of points4D must be 4" );
+ }
+#endif
+
+ /* Find transform matrix for each camera */
+ int i;
+ CvMat* points[3];
+ points[0] = points1;
+ points[1] = points2;
+ points[2] = points3;
+
+ CvMat* projMatrs[3];
+ projMatrs[0] = projMatr1;
+ projMatrs[1] = projMatr2;
+ projMatrs[2] = projMatr3;
+
+ CvMat transMatr;
+ double transMatr_dat[9];
+ transMatr = cvMat(3,3,CV_64F,transMatr_dat);
+
+ CvMat corrPoints1;
+ CvMat corrPoints2;
+
+ double corrPoints_dat[3*3*2];/* 3-point(images) by 3-coordinates by 2-correspondence*/
+
+ corrPoints1 = cvMat(3,3,CV_64F,corrPoints_dat); /* 3-coordinates for each of 3-points(3-image) */
+ corrPoints2 = cvMat(3,3,CV_64F,corrPoints_dat+9);/* 3-coordinates for each of 3-points(3-image) */
+
+ for( i = 0; i < 3; i++ )/* for each image */
+ {
+ /* Get last 4 points for computing transformation */
+ CvMat tmpPoints;
+ /* find base points transform for last four points on i-th image */
+ cvGetSubRect(points[i],&tmpPoints,cvRect(2,0,4,2));
+ icvFindBaseTransform(&tmpPoints,&transMatr);
+
+ {/* We have base transform. Compute error scales for three first points */
+ CvMat trPoint;
+ double trPoint_dat[3*3];
+ trPoint = cvMat(3,3,CV_64F,trPoint_dat);
+ /* fill points */
+ for( int kk = 0; kk < 3; kk++ )
+ {
+ cvmSet(&trPoint,0,kk,cvmGet(points[i],0,kk+2));
+ cvmSet(&trPoint,1,kk,cvmGet(points[i],1,kk+2));
+ cvmSet(&trPoint,2,kk,1);
+ }
+
+ /* Transform points */
+ CvMat resPnts;
+ double resPnts_dat[9];
+ resPnts = cvMat(3,3,CV_64F,resPnts_dat);
+ cvmMul(&transMatr,&trPoint,&resPnts);
+ }
+
+ /* Transform two first points */
+ for( int j = 0; j < 2; j++ )
+ {
+ CvMat pnt;
+ double pnt_dat[3];
+ pnt = cvMat(3,1,CV_64F,pnt_dat);
+ pnt_dat[0] = cvmGet(points[i],0,j);
+ pnt_dat[1] = cvmGet(points[i],1,j);
+ pnt_dat[2] = 1.0;
+
+ CvMat trPnt;
+ double trPnt_dat[3];
+ trPnt = cvMat(3,1,CV_64F,trPnt_dat);
+
+ cvmMul(&transMatr,&pnt,&trPnt);
+
+ /* Collect transformed points */
+ corrPoints_dat[j * 9 + 0 * 3 + i] = trPnt_dat[0];/* x */
+ corrPoints_dat[j * 9 + 1 * 3 + i] = trPnt_dat[1];/* y */
+ corrPoints_dat[j * 9 + 2 * 3 + i] = trPnt_dat[2];/* w */
+ }
+ }
+
+ /* We have computed corr points. Now we can compute generators for reduced fundamental matrix */
+
+ /* Compute generators for reduced fundamental matrix from 3 pair of collect points */
+ CvMat fundReduceCoef1;
+ CvMat fundReduceCoef2;
+ double fundReduceCoef1_dat[5];
+ double fundReduceCoef2_dat[5];
+
+ fundReduceCoef1 = cvMat(1,5,CV_64F,fundReduceCoef1_dat);
+ fundReduceCoef2 = cvMat(1,5,CV_64F,fundReduceCoef2_dat);
+
+ GetGeneratorReduceFundSolution(&corrPoints1, &corrPoints2, &fundReduceCoef1, &fundReduceCoef2);
+
+ /* Choose best solutions for two generators. We can get 3 solutions */
+ CvMat resFundReduceCoef;
+ double resFundReduceCoef_dat[3*5];
+
+ resFundReduceCoef = cvMat(3,5,CV_64F,resFundReduceCoef_dat);
+
+ numSol = GetGoodReduceFundamMatrFromTwo(&fundReduceCoef1, &fundReduceCoef2,&resFundReduceCoef);
+
+ int maxSol;
+ maxSol = projMatrs[0]->rows / 3;
+
+ int currSol;
+ for( currSol = 0; (currSol < numSol && currSol < maxSol); currSol++ )
+ {
+ /* For current solution compute projection matrix */
+ CvMat fundCoefs;
+ cvGetSubRect(&resFundReduceCoef, &fundCoefs, cvRect(0,currSol,5,1));
+
+ CvMat projMatrCoefs;
+ double projMatrCoefs_dat[4];
+ projMatrCoefs = cvMat(1,4,CV_64F,projMatrCoefs_dat);
+
+ GetProjMatrFromReducedFundamental(&fundCoefs,&projMatrCoefs);
+ /* we have computed coeffs for reduced project matrix */
+
+ CvMat objPoints;
+ double objPoints_dat[4*6];
+ objPoints = cvMat(4,6,CV_64F,objPoints_dat);
+ cvZero(&objPoints);
+
+ /* fill object points */
+ for( i =0; i < 4; i++ )
+ {
+ objPoints_dat[i*6] = 1;
+ objPoints_dat[i*6+1] = projMatrCoefs_dat[i];
+ objPoints_dat[i*7+2] = 1;
+ }
+
+ int currCamera;
+ for( currCamera = 0; currCamera < 3; currCamera++ )
+ {
+
+ CvMat projPoints;
+ double projPoints_dat[3*6];
+ projPoints = cvMat(3,6,CV_64F,projPoints_dat);
+
+ /* fill projected points for current camera */
+ for( i = 0; i < 6; i++ )/* for each points for current camera */
+ {
+ projPoints_dat[6*0+i] = cvmGet(points[currCamera],0,i);/* x */
+ projPoints_dat[6*1+i] = cvmGet(points[currCamera],1,i);/* y */
+ projPoints_dat[6*2+i] = 1;/* w */
+ }
+
+ /* compute project matrix for current camera */
+ CvMat projMatrix;
+ double projMatrix_dat[3*4];
+ projMatrix = cvMat(3,4,CV_64F,projMatrix_dat);
+
+ icvComputeProjectMatrix(&objPoints,&projPoints,&projMatrix);
+
+ /* Add this matrix to result */
+ CvMat tmpSubRes;
+ cvGetSubRect(projMatrs[currCamera],&tmpSubRes,cvRect(0,currSol*3,4,3));
+ cvConvert(&projMatrix,&tmpSubRes);
+ }
+
+ /* We know project matrices. And we can reconstruct 6 3D-points if need */
+#if 0
+ if( points4D )
+ {
+ if( currSol < points4D->rows / 4 )
+ {
+ CvMat tmpPoints4D;
+ double tmpPoints4D_dat[4*6];
+ tmpPoints4D = cvMat(4,6,CV_64F,tmpPoints4D_dat);
+
+ icvReconstructPointsFor3View( &wProjMatr[0], &wProjMatr[1], &wProjMatr[2],
+ points1, points2, points3,
+ &tmpPoints4D);
+
+ CvMat tmpSubRes;
+ cvGetSubRect(points4D,tmpSubRes,cvRect(0,currSol*4,6,4));
+ cvConvert(tmpPoints4D,points4D);
+ }
+ }
+#endif
+
+ }/* for all sollutions */
+
+ __END__;
+ return numSol;
+}
+
+/*==========================================================================================*/
+int icvGetRandNumbers(int range,int count,int* arr)
+{
+ /* Generate random numbers [0,range-1] */
+
+ CV_FUNCNAME( "icvGetRandNumbers" );
+ __BEGIN__;
+
+ /* Test input data */
+ if( arr == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Parameter 'arr' is a NULL pointer" );
+ }
+
+
+ /* Test for errors input data */
+ if( range < count || range <= 0 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Can't generate such numbers. Count must be <= range and range must be > 0" );
+ }
+
+ int i,j;
+ int newRand;
+ for( i = 0; i < count; i++ )
+ {
+
+ int haveRep = 0;/* firstly we have not repeats */
+ do
+ {
+ /* generate new number */
+ newRand = rand()%range;
+ haveRep = 0;
+ /* Test for repeats in previous numbers */
+ for( j = 0; j < i; j++ )
+ {
+ if( arr[j] == newRand )
+ {
+ haveRep = 1;
+ break;
+ }
+ }
+ } while(haveRep);
+
+ /* We have good random number */
+ arr[i] = newRand;
+ }
+ __END__;
+ return 1;
+}
+/*==========================================================================================*/
+void icvSelectColsByNumbers(CvMat* srcMatr, CvMat* dstMatr, int* indexes,int number)
+{
+
+ CV_FUNCNAME( "icvSelectColsByNumbers" );
+ __BEGIN__;
+
+ /* Test input data */
+ if( srcMatr == 0 || dstMatr == 0 || indexes == 0)
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(srcMatr) || !CV_IS_MAT(dstMatr) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "srcMatr and dstMatr must be a matrices" );
+ }
+
+ int srcSize;
+ int numRows;
+ numRows = srcMatr->rows;
+ srcSize = srcMatr->cols;
+
+ if( numRows != dstMatr->rows )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of rows of matrices must be the same" );
+ }
+
+ int dst;
+ for( dst = 0; dst < number; dst++ )
+ {
+ int src = indexes[dst];
+ if( src >=0 && src < srcSize )
+ {
+ /* Copy each elements in column */
+ int i;
+ for( i = 0; i < numRows; i++ )
+ {
+ cvmSet(dstMatr,i,dst,cvmGet(srcMatr,i,src));
+ }
+ }
+ }
+
+ __END__;
+ return;
+}
+
+/*==========================================================================================*/
+void icvProject4DPoints(CvMat* points4D,CvMat* projMatr, CvMat* projPoints)
+{
+
+ CvMat* tmpProjPoints = 0;
+
+ CV_FUNCNAME( "icvProject4DPoints" );
+
+ __BEGIN__;
+
+ if( points4D == 0 || projMatr == 0 || projPoints == 0)
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(points4D) || !CV_IS_MAT(projMatr) || !CV_IS_MAT(projPoints) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters must be a matrices" );
+ }
+
+ int numPoints;
+ numPoints = points4D->cols;
+ if( numPoints < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of points4D must be more than zero" );
+ }
+
+ if( numPoints != projPoints->cols )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of points must be the same");
+ }
+
+ if( projPoints->rows != 2 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of coordinates of projected points must be 2");
+ }
+
+ if( points4D->rows != 4 )
+ {
+ CV_ERROR(CV_StsUnmatchedSizes, "Number of coordinates of 4D points must be 4");
+ }
+
+ if( projMatr->cols != 4 || projMatr->rows != 3 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of projection matrix must be 3x4");
+ }
+
+
+ CV_CALL( tmpProjPoints = cvCreateMat(3,numPoints,CV_64F) );
+
+ cvmMul(projMatr,points4D,tmpProjPoints);
+
+ /* Scale points */
+ int i;
+ for( i = 0; i < numPoints; i++ )
+ {
+ double scale,x,y;
+
+ scale = cvmGet(tmpProjPoints,2,i);
+ x = cvmGet(tmpProjPoints,0,i);
+ y = cvmGet(tmpProjPoints,1,i);
+
+ if( fabs(scale) > 1e-7 )
+ {
+ x /= scale;
+ y /= scale;
+ }
+ else
+ {
+ x = 1e8;
+ y = 1e8;
+ }
+
+ cvmSet(projPoints,0,i,x);
+ cvmSet(projPoints,1,i,y);
+ }
+
+ __END__;
+
+ cvReleaseMat(&tmpProjPoints);
+
+ return;
+}
+/*==========================================================================================*/
+int icvCompute3ProjectMatricesNPointsStatus( CvMat** points,/* 3 arrays of points on image */
+ CvMat** projMatrs,/* array of 3 prejection matrices */
+ CvMat** statuses,/* 3 arrays of status of points */
+ double threshold,/* Threshold for good point */
+ double p,/* Probability of good result. */
+ CvMat* resStatus,
+ CvMat* points4D)
+{
+ int numProjMatrs = 0;
+ unsigned char *comStat = 0;
+ CvMat *triPoints[3] = {0,0,0};
+ CvMat *status = 0;
+ CvMat *triPoints4D = 0;
+
+ CV_FUNCNAME( "icvCompute3ProjectMatricesNPointsStatus" );
+ __BEGIN__;
+
+ /* Test for errors */
+ if( points == 0 || projMatrs == 0 || statuses == 0 || resStatus == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ int currImage;
+ for( currImage = 0; currImage < 3; currImage++ )
+ {
+ /* Test for null pointers */
+ if( points[currImage] == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of points arrays is a NULL pointer" );
+ }
+
+ if( projMatrs[currImage] == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of projMatr is a NULL pointer" );
+ }
+
+ if( statuses[currImage] == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of status arrays is a NULL pointer" );
+ }
+
+ /* Test for matrices */
+ if( !CV_IS_MAT(points[currImage]) )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of points arrays is not a matrix" );
+ }
+
+ if( !CV_IS_MAT(projMatrs[currImage]) )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of projMatr is not a matrix" );
+ }
+
+ if( !CV_IS_MASK_ARR(statuses[currImage]) )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of status arrays is not a mask array" );
+ }
+ }
+
+ int numPoints;
+ numPoints = points[0]->cols;
+ if( numPoints < 6 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number points must be more than 6" );
+ }
+
+ for( currImage = 0; currImage < 3; currImage++ )
+ {
+ if( points[currImage]->cols != numPoints || statuses[currImage]->cols != numPoints )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of points and statuses must be the same" );
+ }
+
+ if( points[currImage]->rows != 2 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of points coordinates must be == 2" );
+ }
+
+ if( statuses[currImage]->rows != 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Each of status must be matrix 1xN" );
+ }
+
+ if( projMatrs[currImage]->rows != 3 || projMatrs[currImage]->cols != 4 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Each of projection matrix must be 3x4" );
+ }
+ }
+
+
+ /* Create common status for all points */
+
+ int i;
+
+ CV_CALL( comStat = (unsigned char*)cvAlloc(sizeof(unsigned char)*numPoints) );
+
+ unsigned char *stats[3];
+
+ stats[0] = statuses[0]->data.ptr;
+ stats[1] = statuses[1]->data.ptr;
+ stats[2] = statuses[2]->data.ptr;
+
+ int numTripl;
+ numTripl = 0;
+ for( i = 0; i < numPoints; i++ )
+ {
+ comStat[i] = (unsigned char)(stats[0][i] * stats[1][i] * stats[2][i]);
+ numTripl += comStat[i];
+ }
+
+ if( numTripl > 0 )
+ {
+ /* Create new arrays with points */
+ CV_CALL( triPoints[0] = cvCreateMat(2,numTripl,CV_64F) );
+ CV_CALL( triPoints[1] = cvCreateMat(2,numTripl,CV_64F) );
+ CV_CALL( triPoints[2] = cvCreateMat(2,numTripl,CV_64F) );
+ if( points4D )
+ {
+ CV_CALL( triPoints4D = cvCreateMat(4,numTripl,CV_64F) );
+ }
+
+ /* Create status array */
+ CV_CALL( status = cvCreateMat(1,numTripl,CV_64F) );
+
+ /* Copy points to new arrays */
+ int currPnt = 0;
+ for( i = 0; i < numPoints; i++ )
+ {
+ if( comStat[i] )
+ {
+ for( currImage = 0; currImage < 3; currImage++ )
+ {
+ cvmSet(triPoints[currImage],0,currPnt,cvmGet(points[currImage],0,i));
+ cvmSet(triPoints[currImage],1,currPnt,cvmGet(points[currImage],1,i));
+ }
+ currPnt++;
+ }
+ }
+
+ /* Call function */
+ numProjMatrs = icvComputeProjectMatricesNPoints( triPoints[0],triPoints[1],triPoints[2],
+ projMatrs[0],projMatrs[1],projMatrs[2],
+ threshold,/* Threshold for good point */
+ p,/* Probability of good result. */
+ status,
+ triPoints4D);
+
+ /* Get computed status and set to result */
+ cvZero(resStatus);
+ currPnt = 0;
+ for( i = 0; i < numPoints; i++ )
+ {
+ if( comStat[i] )
+ {
+ if( cvmGet(status,0,currPnt) > 0 )
+ {
+ resStatus->data.ptr[i] = 1;
+ }
+ currPnt++;
+ }
+ }
+
+ if( triPoints4D )
+ {
+ /* Copy copmuted 4D points */
+ cvZero(points4D);
+ currPnt = 0;
+ for( i = 0; i < numPoints; i++ )
+ {
+ if( comStat[i] )
+ {
+ if( cvmGet(status,0,currPnt) > 0 )
+ {
+ cvmSet( points4D, 0, i, cvmGet( triPoints4D , 0, currPnt) );
+ cvmSet( points4D, 1, i, cvmGet( triPoints4D , 1, currPnt) );
+ cvmSet( points4D, 2, i, cvmGet( triPoints4D , 2, currPnt) );
+ cvmSet( points4D, 3, i, cvmGet( triPoints4D , 3, currPnt) );
+ }
+ currPnt++;
+ }
+ }
+ }
+ }
+
+ __END__;
+
+ /* Free allocated memory */
+ cvReleaseMat(&status);
+ cvFree( &comStat);
+ cvReleaseMat(&status);
+
+ cvReleaseMat(&triPoints[0]);
+ cvReleaseMat(&triPoints[1]);
+ cvReleaseMat(&triPoints[2]);
+ cvReleaseMat(&triPoints4D);
+
+ return numProjMatrs;
+
+}
+
+/*==========================================================================================*/
+int icvComputeProjectMatricesNPoints( CvMat* points1,CvMat* points2,CvMat* points3,
+ CvMat* projMatr1,CvMat* projMatr2,CvMat* projMatr3,
+ double threshold,/* Threshold for good point */
+ double p,/* Probability of good result. */
+ CvMat* status,
+ CvMat* points4D)
+{
+ /* Returns status for each point, Good or bad */
+
+ /* Compute projection matrices using N points */
+
+ char* flags = 0;
+ char* bestFlags = 0;
+
+ int numProjMatrs = 0;
+
+ CvMat* tmpProjPoints[3]={0,0,0};
+ CvMat* recPoints4D = 0;
+ CvMat *reconPoints4D = 0;
+
+
+ CV_FUNCNAME( "icvComputeProjectMatricesNPoints" );
+ __BEGIN__;
+
+ CvMat* points[3];
+ points[0] = points1;
+ points[1] = points2;
+ points[2] = points3;
+
+ /* Test for errors */
+ if( points1 == 0 || points2 == 0 || points3 == 0 ||
+ projMatr1 == 0 || projMatr2 == 0 || projMatr3 == 0 ||
+ status == 0)
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(points1) || !CV_IS_MAT(points2) || !CV_IS_MAT(points3) ||
+ !CV_IS_MAT(projMatr1) || !CV_IS_MAT(projMatr2) || !CV_IS_MAT(projMatr3) ||
+ !CV_IS_MAT(status) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters must be a matrices" );
+ }
+
+ int numPoints;
+ numPoints = points1->cols;
+
+ if( numPoints < 6 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number points must be more than 6" );
+ }
+
+ if( numPoints != points2->cols || numPoints != points3->cols )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "number of points must be the same" );
+ }
+
+ if( p < 0 || p > 1.0 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Probability must be >=0 and <=1" );
+ }
+
+ if( threshold < 0 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Threshold for good points must be at least >= 0" );
+ }
+
+ CvMat* projMatrs[3];
+
+ projMatrs[0] = projMatr1;
+ projMatrs[1] = projMatr2;
+ projMatrs[2] = projMatr3;
+
+ int i;
+ for( i = 0; i < 3; i++ )
+ {
+ if( projMatrs[i]->cols != 4 || projMatrs[i]->rows != 3 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of projection matrices must be 3x4" );
+ }
+ }
+
+ for( i = 0; i < 3; i++ )
+ {
+ if( points[i]->rows != 2)
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of coordinates of points must be 2" );
+ }
+ }
+
+ /* use RANSAC algorithm to compute projection matrices */
+
+ CV_CALL( recPoints4D = cvCreateMat(4,numPoints,CV_64F) );
+ CV_CALL( tmpProjPoints[0] = cvCreateMat(2,numPoints,CV_64F) );
+ CV_CALL( tmpProjPoints[1] = cvCreateMat(2,numPoints,CV_64F) );
+ CV_CALL( tmpProjPoints[2] = cvCreateMat(2,numPoints,CV_64F) );
+
+ CV_CALL( flags = (char*)cvAlloc(sizeof(char)*numPoints) );
+ CV_CALL( bestFlags = (char*)cvAlloc(sizeof(char)*numPoints) );
+
+ {
+ int NumSamples = 500;/* just init number of samples */
+ int wasCount = 0; /* count of choosing samples */
+ int maxGoodPoints = 0;
+ int numGoodPoints = 0;
+
+ double bestProjMatrs_dat[36];
+ CvMat bestProjMatrs[3];
+ bestProjMatrs[0] = cvMat(3,4,CV_64F,bestProjMatrs_dat);
+ bestProjMatrs[1] = cvMat(3,4,CV_64F,bestProjMatrs_dat+12);
+ bestProjMatrs[2] = cvMat(3,4,CV_64F,bestProjMatrs_dat+24);
+
+ double tmpProjMatr_dat[36*3];
+ CvMat tmpProjMatr[3];
+ tmpProjMatr[0] = cvMat(9,4,CV_64F,tmpProjMatr_dat);
+ tmpProjMatr[1] = cvMat(9,4,CV_64F,tmpProjMatr_dat+36);
+ tmpProjMatr[2] = cvMat(9,4,CV_64F,tmpProjMatr_dat+72);
+
+ /* choosen points */
+
+ while( wasCount < NumSamples )
+ {
+ /* select samples */
+ int randNumbs[6];
+ icvGetRandNumbers(numPoints,6,randNumbs);
+
+ /* random numbers of points was generated */
+ /* select points */
+
+ double selPoints_dat[2*6*3];
+ CvMat selPoints[3];
+ selPoints[0] = cvMat(2,6,CV_64F,selPoints_dat);
+ selPoints[1] = cvMat(2,6,CV_64F,selPoints_dat+12);
+ selPoints[2] = cvMat(2,6,CV_64F,selPoints_dat+24);
+
+ /* Copy 6 point for random indexes */
+ icvSelectColsByNumbers( points[0], &selPoints[0], randNumbs,6);
+ icvSelectColsByNumbers( points[1], &selPoints[1], randNumbs,6);
+ icvSelectColsByNumbers( points[2], &selPoints[2], randNumbs,6);
+
+ /* Compute projection matrices for this points */
+ int numProj = icvComputeProjectMatrices6Points( &selPoints[0],&selPoints[1],&selPoints[2],
+ &tmpProjMatr[0],&tmpProjMatr[1],&tmpProjMatr[2]);
+
+ /* Compute number of good points for each matrix */
+ CvMat proj6[3];
+ for( int currProj = 0; currProj < numProj; currProj++ )
+ {
+ cvGetSubArr(&tmpProjMatr[0],&proj6[0],cvRect(0,currProj*3,4,3));
+ cvGetSubArr(&tmpProjMatr[1],&proj6[1],cvRect(0,currProj*3,4,3));
+ cvGetSubArr(&tmpProjMatr[2],&proj6[2],cvRect(0,currProj*3,4,3));
+
+ /* Reconstruct points for projection matrices */
+ icvReconstructPointsFor3View( &proj6[0],&proj6[1],&proj6[2],
+ points[0], points[1], points[2],
+ recPoints4D);
+
+ /* Project points to images using projection matrices */
+ icvProject4DPoints(recPoints4D,&proj6[0],tmpProjPoints[0]);
+ icvProject4DPoints(recPoints4D,&proj6[1],tmpProjPoints[1]);
+ icvProject4DPoints(recPoints4D,&proj6[2],tmpProjPoints[2]);
+
+ /* Compute distances and number of good points (inliers) */
+ int i;
+ int currImage;
+ numGoodPoints = 0;
+ for( i = 0; i < numPoints; i++ )
+ {
+ double dist=-1;
+ dist = 0;
+ /* Choose max distance for each of three points */
+ for( currImage = 0; currImage < 3; currImage++ )
+ {
+ double x1,y1,x2,y2;
+ x1 = cvmGet(tmpProjPoints[currImage],0,i);
+ y1 = cvmGet(tmpProjPoints[currImage],1,i);
+ x2 = cvmGet(points[currImage],0,i);
+ y2 = cvmGet(points[currImage],1,i);
+
+ double dx,dy;
+ dx = x1-x2;
+ dy = y1-y2;
+#if 1
+ double newDist = dx*dx+dy*dy;
+ if( newDist > dist )
+ {
+ dist = newDist;
+ }
+#else
+ dist += sqrt(dx*dx+dy*dy)/3.0;
+#endif
+ }
+ dist = sqrt(dist);
+ flags[i] = (char)(dist > threshold ? 0 : 1);
+ numGoodPoints += flags[i];
+
+ }
+
+
+ if( numGoodPoints > maxGoodPoints )
+ {/* Copy current projection matrices as best */
+
+ cvCopy(&proj6[0],&bestProjMatrs[0]);
+ cvCopy(&proj6[1],&bestProjMatrs[1]);
+ cvCopy(&proj6[2],&bestProjMatrs[2]);
+
+ maxGoodPoints = numGoodPoints;
+ /* copy best flags */
+ memcpy(bestFlags,flags,sizeof(flags[0])*numPoints);
+
+ /* Adaptive number of samples to count*/
+ double ep = 1 - (double)numGoodPoints / (double)numPoints;
+ if( ep == 1 )
+ {
+ ep = 0.5;/* if there is not good points set ration of outliers to 50% */
+ }
+
+ double newNumSamples = (log(1-p) / log(1-pow(1-ep,6)));
+ if( newNumSamples < double(NumSamples) )
+ {
+ NumSamples = cvRound(newNumSamples);
+ }
+ }
+ }
+
+ wasCount++;
+ }
+#if 0
+ char str[300];
+ sprintf(str,"Initial numPoints = %d\nmaxGoodPoints=%d\nRANSAC made %d steps",
+ numPoints,
+ maxGoodPoints,
+ cvRound(wasCount));
+ MessageBox(0,str,"Info",MB_OK|MB_TASKMODAL);
+#endif
+
+ /* we may have best 6-point projection matrices. */
+ /* and best points */
+ /* use these points to improve matrices */
+
+ if( maxGoodPoints < 6 )
+ {
+ /* matrix not found */
+ numProjMatrs = 0;
+ }
+ else
+ {
+ /* We may Improove matrices using ---- method */
+ /* We may try to use Levenberg-Marquardt optimization */
+ //int currIter = 0;
+ int finalGoodPoints = 0;
+ char *goodFlags = 0;
+ goodFlags = (char*)cvAlloc(numPoints*sizeof(char));
+
+ int needRepeat;
+ do
+ {
+#if 0
+/* Version without using status for Levenberg-Marquardt minimization */
+
+ CvMat *optStatus;
+ optStatus = cvCreateMat(1,numPoints,CV_64F);
+ int testNumber = 0;
+ for( i=0;i<numPoints;i++ )
+ {
+ cvmSet(optStatus,0,i,(double)bestFlags[i]);
+ testNumber += bestFlags[i];
+ }
+
+ char str2[200];
+ sprintf(str2,"test good num=%d\nmaxGoodPoints=%d",testNumber,maxGoodPoints);
+ MessageBox(0,str2,"Info",MB_OK|MB_TASKMODAL);
+
+ CvMat *gPresPoints;
+ gPresPoints = cvCreateMat(1,maxGoodPoints,CV_64F);
+ for( i = 0; i < maxGoodPoints; i++)
+ {
+ cvmSet(gPresPoints,0,i,1.0);
+ }
+
+ /* Create array of points pres */
+ CvMat *pointsPres[3];
+ pointsPres[0] = gPresPoints;
+ pointsPres[1] = gPresPoints;
+ pointsPres[2] = gPresPoints;
+
+ /* Create just good points 2D */
+ CvMat *gPoints[3];
+ icvCreateGoodPoints(points[0],&gPoints[0],optStatus);
+ icvCreateGoodPoints(points[1],&gPoints[1],optStatus);
+ icvCreateGoodPoints(points[2],&gPoints[2],optStatus);
+
+ /* Create 4D points array for good points */
+ CvMat *resPoints4D;
+ resPoints4D = cvCreateMat(4,maxGoodPoints,CV_64F);
+
+ CvMat* projMs[3];
+
+ projMs[0] = &bestProjMatrs[0];
+ projMs[1] = &bestProjMatrs[1];
+ projMs[2] = &bestProjMatrs[2];
+
+
+ CvMat resProjMatrs[3];
+ double resProjMatrs_dat[36];
+ resProjMatrs[0] = cvMat(3,4,CV_64F,resProjMatrs_dat);
+ resProjMatrs[1] = cvMat(3,4,CV_64F,resProjMatrs_dat+12);
+ resProjMatrs[2] = cvMat(3,4,CV_64F,resProjMatrs_dat+24);
+
+ CvMat* resMatrs[3];
+ resMatrs[0] = &resProjMatrs[0];
+ resMatrs[1] = &resProjMatrs[1];
+ resMatrs[2] = &resProjMatrs[2];
+
+ cvOptimizeLevenbergMarquardtBundle( projMs,//projMs,
+ gPoints,//points,//points2D,
+ pointsPres,//pointsPres,
+ 3,
+ resMatrs,//resProjMatrs,
+ resPoints4D,//resPoints4D,
+ 100, 1e-9 );
+
+ /* We found optimized projection matrices */
+
+ CvMat *reconPoints4D;
+ reconPoints4D = cvCreateMat(4,numPoints,CV_64F);
+
+ /* Reconstruct all points using found projection matrices */
+ icvReconstructPointsFor3View( &resProjMatrs[0],&resProjMatrs[1],&resProjMatrs[2],
+ points[0], points[1], points[2],
+ reconPoints4D);
+
+ /* Project points to images using projection matrices */
+ icvProject4DPoints(reconPoints4D,&resProjMatrs[0],tmpProjPoints[0]);
+ icvProject4DPoints(reconPoints4D,&resProjMatrs[1],tmpProjPoints[1]);
+ icvProject4DPoints(reconPoints4D,&resProjMatrs[2],tmpProjPoints[2]);
+
+
+ /* Compute error for each point and select good */
+
+ int currImage;
+ finalGoodPoints = 0;
+ for( i = 0; i < numPoints; i++ )
+ {
+ double dist=-1;
+ /* Choose max distance for each of three points */
+ for( currImage = 0; currImage < 3; currImage++ )
+ {
+ double x1,y1,x2,y2;
+ x1 = cvmGet(tmpProjPoints[currImage],0,i);
+ y1 = cvmGet(tmpProjPoints[currImage],1,i);
+ x2 = cvmGet(points[currImage],0,i);
+ y2 = cvmGet(points[currImage],1,i);
+
+ double dx,dy;
+ dx = x1-x2;
+ dy = y1-y2;
+
+ double newDist = dx*dx+dy*dy;
+ if( newDist > dist )
+ {
+ dist = newDist;
+ }
+ }
+ dist = sqrt(dist);
+ goodFlags[i] = (char)(dist > threshold ? 0 : 1);
+ finalGoodPoints += goodFlags[i];
+ }
+
+ char str[200];
+ sprintf(str,"Was num = %d\nNew num=%d",maxGoodPoints,finalGoodPoints);
+ MessageBox(0,str,"Info",MB_OK|MB_TASKMODAL);
+ if( finalGoodPoints > maxGoodPoints )
+ {
+ /* Copy new version of projection matrices */
+ cvCopy(&resProjMatrs[0],&bestProjMatrs[0]);
+ cvCopy(&resProjMatrs[1],&bestProjMatrs[1]);
+ cvCopy(&resProjMatrs[2],&bestProjMatrs[2]);
+ memcpy(bestFlags,goodFlags,numPoints*sizeof(char));
+ maxGoodPoints = finalGoodPoints;
+ }
+
+ cvReleaseMat(&optStatus);
+ cvReleaseMat(&resPoints4D);
+#else
+/* Version with using status for Levenberd-Marquardt minimization */
+
+ /* Create status */
+ CvMat *optStatus;
+ optStatus = cvCreateMat(1,numPoints,CV_64F);
+ for( i=0;i<numPoints;i++ )
+ {
+ cvmSet(optStatus,0,i,(double)bestFlags[i]);
+ }
+
+ CvMat *pointsPres[3];
+ pointsPres[0] = optStatus;
+ pointsPres[1] = optStatus;
+ pointsPres[2] = optStatus;
+
+ /* Create 4D points array for good points */
+ CvMat *resPoints4D;
+ resPoints4D = cvCreateMat(4,numPoints,CV_64F);
+
+ CvMat* projMs[3];
+
+ projMs[0] = &bestProjMatrs[0];
+ projMs[1] = &bestProjMatrs[1];
+ projMs[2] = &bestProjMatrs[2];
+
+ CvMat resProjMatrs[3];
+ double resProjMatrs_dat[36];
+ resProjMatrs[0] = cvMat(3,4,CV_64F,resProjMatrs_dat);
+ resProjMatrs[1] = cvMat(3,4,CV_64F,resProjMatrs_dat+12);
+ resProjMatrs[2] = cvMat(3,4,CV_64F,resProjMatrs_dat+24);
+
+ CvMat* resMatrs[3];
+ resMatrs[0] = &resProjMatrs[0];
+ resMatrs[1] = &resProjMatrs[1];
+ resMatrs[2] = &resProjMatrs[2];
+
+ cvOptimizeLevenbergMarquardtBundle( projMs,//projMs,
+ points,//points2D,
+ pointsPres,//pointsPres,
+ 3,
+ resMatrs,//resProjMatrs,
+ resPoints4D,//resPoints4D,
+ 100, 1e-9 );
+
+ /* We found optimized projection matrices */
+
+ reconPoints4D = cvCreateMat(4,numPoints,CV_64F);
+
+ /* Reconstruct all points using found projection matrices */
+ icvReconstructPointsFor3View( &resProjMatrs[0],&resProjMatrs[1],&resProjMatrs[2],
+ points[0], points[1], points[2],
+ reconPoints4D);
+
+ /* Project points to images using projection matrices */
+ icvProject4DPoints(reconPoints4D,&resProjMatrs[0],tmpProjPoints[0]);
+ icvProject4DPoints(reconPoints4D,&resProjMatrs[1],tmpProjPoints[1]);
+ icvProject4DPoints(reconPoints4D,&resProjMatrs[2],tmpProjPoints[2]);
+
+
+ /* Compute error for each point and select good */
+
+ int currImage;
+ finalGoodPoints = 0;
+ for( i = 0; i < numPoints; i++ )
+ {
+ double dist=-1;
+ /* Choose max distance for each of three points */
+ for( currImage = 0; currImage < 3; currImage++ )
+ {
+ double x1,y1,x2,y2;
+ x1 = cvmGet(tmpProjPoints[currImage],0,i);
+ y1 = cvmGet(tmpProjPoints[currImage],1,i);
+ x2 = cvmGet(points[currImage],0,i);
+ y2 = cvmGet(points[currImage],1,i);
+
+ double dx,dy;
+ dx = x1-x2;
+ dy = y1-y2;
+
+ double newDist = dx*dx+dy*dy;
+ if( newDist > dist )
+ {
+ dist = newDist;
+ }
+ }
+ dist = sqrt(dist);
+ goodFlags[i] = (char)(dist > threshold ? 0 : 1);
+ finalGoodPoints += goodFlags[i];
+ }
+
+ /*char str[200];
+ sprintf(str,"Was num = %d\nNew num=%d",maxGoodPoints,finalGoodPoints);
+ MessageBox(0,str,"Info",MB_OK|MB_TASKMODAL);*/
+
+ needRepeat = 0;
+ if( finalGoodPoints > maxGoodPoints )
+ {
+ /* Copy new version of projection matrices */
+ cvCopy(&resProjMatrs[0],&bestProjMatrs[0]);
+ cvCopy(&resProjMatrs[1],&bestProjMatrs[1]);
+ cvCopy(&resProjMatrs[2],&bestProjMatrs[2]);
+ memcpy(bestFlags,goodFlags,numPoints*sizeof(char));
+ maxGoodPoints = finalGoodPoints;
+ needRepeat = 1;
+ }
+
+ cvReleaseMat(&optStatus);
+ cvReleaseMat(&resPoints4D);
+
+
+#endif
+ } while ( needRepeat );
+
+ cvFree( &goodFlags);
+
+
+
+
+ numProjMatrs = 1;
+
+ /* Copy projection matrices */
+ cvConvert(&bestProjMatrs[0],projMatr1);
+ cvConvert(&bestProjMatrs[1],projMatr2);
+ cvConvert(&bestProjMatrs[2],projMatr3);
+
+ if( status )
+ {
+ /* copy status for each points if need */
+ for( int i = 0; i < numPoints; i++)
+ {
+ cvmSet(status,0,i,(double)bestFlags[i]);
+ }
+ }
+ }
+ }
+
+ if( points4D )
+ {/* Fill reconstructed points */
+
+ cvZero(points4D);
+ icvReconstructPointsFor3View( projMatr1,projMatr2,projMatr3,
+ points[0], points[1], points[2],
+ points4D);
+ }
+
+
+
+ __END__;
+
+ cvFree( &flags);
+ cvFree( &bestFlags);
+
+ cvReleaseMat(&recPoints4D);
+ cvReleaseMat(&tmpProjPoints[0]);
+ cvReleaseMat(&tmpProjPoints[1]);
+ cvReleaseMat(&tmpProjPoints[2]);
+
+ return numProjMatrs;
+}
+
+/*==========================================================================================*/
+
+void icvFindBaseTransform(CvMat* points,CvMat* resultT)
+{
+
+ CV_FUNCNAME( "icvFindBaseTransform" );
+ __BEGIN__;
+
+ if( points == 0 || resultT == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(points) || !CV_IS_MAT(resultT) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "points and resultT must be a matrices" );
+ }
+
+ if( points->rows != 2 || points->cols != 4 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of points must be 4. And they must have 2 coordinates" );
+ }
+
+ if( resultT->rows != 3 || resultT->cols != 3 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "size of matrix resultT must be 3x3" );
+ }
+
+ /* Function gets four points and compute transformation to e1=(100) e2=(010) e3=(001) e4=(111) */
+
+ /* !!! test each three points not collinear. Need to test */
+
+ /* Create matrices */
+ CvMat matrA;
+ CvMat vectB;
+ double matrA_dat[3*3];
+ double vectB_dat[3];
+ matrA = cvMat(3,3,CV_64F,matrA_dat);
+ vectB = cvMat(3,1,CV_64F,vectB_dat);
+
+ /* fill matrices */
+ int i;
+ for( i = 0; i < 3; i++ )
+ {
+ cvmSet(&matrA,0,i,cvmGet(points,0,i));
+ cvmSet(&matrA,1,i,cvmGet(points,1,i));
+ cvmSet(&matrA,2,i,1);
+ }
+
+ /* Fill vector B */
+ cvmSet(&vectB,0,0,cvmGet(points,0,3));
+ cvmSet(&vectB,1,0,cvmGet(points,1,3));
+ cvmSet(&vectB,2,0,1);
+
+ /* result scale */
+ CvMat scale;
+ double scale_dat[3];
+ scale = cvMat(3,1,CV_64F,scale_dat);
+
+ cvSolve(&matrA,&vectB,&scale,CV_SVD);
+
+ /* multiply by scale */
+ int j;
+ for( j = 0; j < 3; j++ )
+ {
+ double sc = scale_dat[j];
+ for( i = 0; i < 3; i++ )
+ {
+ matrA_dat[i*3+j] *= sc;
+ }
+ }
+
+ /* Convert inverse matrix */
+ CvMat tmpRes;
+ double tmpRes_dat[9];
+ tmpRes = cvMat(3,3,CV_64F,tmpRes_dat);
+ cvInvert(&matrA,&tmpRes);
+
+ cvConvert(&tmpRes,resultT);
+
+ __END__;
+
+ return;
+}
+
+
+/*==========================================================================================*/
+void GetGeneratorReduceFundSolution(CvMat* points1,CvMat* points2,CvMat* fundReduceCoef1,CvMat* fundReduceCoef2)
+{
+
+ CV_FUNCNAME( "GetGeneratorReduceFundSolution" );
+ __BEGIN__;
+
+ /* Test input data for errors */
+
+ if( points1 == 0 || points2 == 0 || fundReduceCoef1 == 0 || fundReduceCoef2 == 0)
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(points1) || !CV_IS_MAT(points2) || !CV_IS_MAT(fundReduceCoef1) || !CV_IS_MAT(fundReduceCoef2) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters must be a matrices" );
+ }
+
+
+
+ if( points1->rows != 3 || points1->cols != 3 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of points1 must be 3 and and have 3 coordinates" );
+ }
+
+ if( points2->rows != 3 || points2->cols != 3 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of points2 must be 3 and and have 3 coordinates" );
+ }
+
+ if( fundReduceCoef1->rows != 1 || fundReduceCoef1->cols != 5 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of fundReduceCoef1 must be 1x5" );
+ }
+
+ if( fundReduceCoef2->rows != 1 || fundReduceCoef2->cols != 5 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of fundReduceCoef2 must be 1x5" );
+ }
+
+ /* Using 3 corr. points compute reduce */
+
+ /* Create matrix */
+ CvMat matrA;
+ double matrA_dat[3*5];
+ matrA = cvMat(3,5,CV_64F,matrA_dat);
+ int i;
+ for( i = 0; i < 3; i++ )
+ {
+ double x1,y1,w1,x2,y2,w2;
+ x1 = cvmGet(points1,0,i);
+ y1 = cvmGet(points1,1,i);
+ w1 = cvmGet(points1,2,i);
+
+ x2 = cvmGet(points2,0,i);
+ y2 = cvmGet(points2,1,i);
+ w2 = cvmGet(points2,2,i);
+
+ cvmSet(&matrA,i,0,y1*x2-y1*w2);
+ cvmSet(&matrA,i,1,w1*x2-y1*w2);
+ cvmSet(&matrA,i,2,x1*y2-y1*w2);
+ cvmSet(&matrA,i,3,w1*y2-y1*w2);
+ cvmSet(&matrA,i,4,x1*w2-y1*w2);
+ }
+
+ /* solve system using svd */
+ CvMat matrU;
+ CvMat matrW;
+ CvMat matrV;
+
+ double matrU_dat[3*3];
+ double matrW_dat[3*5];
+ double matrV_dat[5*5];
+
+ matrU = cvMat(3,3,CV_64F,matrU_dat);
+ matrW = cvMat(3,5,CV_64F,matrW_dat);
+ matrV = cvMat(5,5,CV_64F,matrV_dat);
+
+ /* From svd we need just two last vectors of V or two last row V' */
+ /* We get transposed matrixes U and V */
+
+ cvSVD(&matrA,&matrW,0,&matrV,CV_SVD_V_T);
+
+ /* copy results to fundamental matrices */
+ for(i=0;i<5;i++)
+ {
+ cvmSet(fundReduceCoef1,0,i,cvmGet(&matrV,3,i));
+ cvmSet(fundReduceCoef2,0,i,cvmGet(&matrV,4,i));
+ }
+
+ __END__;
+ return;
+
+}
+
+/*==========================================================================================*/
+
+int GetGoodReduceFundamMatrFromTwo(CvMat* fundReduceCoef1,CvMat* fundReduceCoef2,CvMat* resFundReduceCoef)
+{
+ int numRoots = 0;
+
+ CV_FUNCNAME( "GetGoodReduceFundamMatrFromTwo" );
+ __BEGIN__;
+
+ if( fundReduceCoef1 == 0 || fundReduceCoef2 == 0 || resFundReduceCoef == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(fundReduceCoef1) || !CV_IS_MAT(fundReduceCoef2) || !CV_IS_MAT(resFundReduceCoef) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters must be a matrices" );
+ }
+
+ /* using two fundamental matrix comute matrixes for det(F)=0 */
+ /* May compute 1 or 3 matrices. Returns number of solutions */
+ /* Here we will use case F=a*F1+(1-a)*F2 instead of F=m*F1+l*F2 */
+
+ /* Test for errors */
+ if( fundReduceCoef1->rows != 1 || fundReduceCoef1->cols != 5 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of fundReduceCoef1 must be 1x5" );
+ }
+
+ if( fundReduceCoef2->rows != 1 || fundReduceCoef2->cols != 5 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of fundReduceCoef2 must be 1x5" );
+ }
+
+ if( (resFundReduceCoef->rows != 1 && resFundReduceCoef->rows != 3) || resFundReduceCoef->cols != 5 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of resFundReduceCoef must be 1x5" );
+ }
+
+ double p1,q1,r1,s1,t1;
+ double p2,q2,r2,s2,t2;
+ p1 = cvmGet(fundReduceCoef1,0,0);
+ q1 = cvmGet(fundReduceCoef1,0,1);
+ r1 = cvmGet(fundReduceCoef1,0,2);
+ s1 = cvmGet(fundReduceCoef1,0,3);
+ t1 = cvmGet(fundReduceCoef1,0,4);
+
+ p2 = cvmGet(fundReduceCoef2,0,0);
+ q2 = cvmGet(fundReduceCoef2,0,1);
+ r2 = cvmGet(fundReduceCoef2,0,2);
+ s2 = cvmGet(fundReduceCoef2,0,3);
+ t2 = cvmGet(fundReduceCoef2,0,4);
+
+ /* solve equation */
+ CvMat result;
+ CvMat coeffs;
+ double result_dat[2*3];
+ double coeffs_dat[4];
+ result = cvMat(2,3,CV_64F,result_dat);
+ coeffs = cvMat(1,4,CV_64F,coeffs_dat);
+
+ coeffs_dat[0] = ((r1-r2)*(-p1-q1-r1-s1-t1+p2+q2+r2+s2+t2)*(q1-q2)+(p1-p2)*(s1-s2)*(t1-t2));/* *a^3 */
+ coeffs_dat[1] = ((r2*(-p1-q1-r1-s1-t1+p2+q2+r2+s2+t2)+(r1-r2)*(-p2-q2-r2-s2-t2))*(q1-q2)+(r1-r2)*(-p1-q1-r1-s1-t1+p2+q2+r2+s2+t2)*q2+(p2*(s1-s2)+(p1-p2)*s2)*(t1-t2)+(p1-p2)*(s1-s2)*t2);/* *a^2 */
+ coeffs_dat[2] = (r2*(-p2-q2-r2-s2-t2)*(q1-q2)+(r2*(-p1-q1-r1-s1-t1+p2+q2+r2+s2+t2)+(r1-r2)*(-p2-q2-r2-s2-t2))*q2+p2*s2*(t1-t2)+(p2*(s1-s2)+(p1-p2)*s2)*t2);/* *a */
+ coeffs_dat[3] = r2*(-p2-q2-r2-s2-t2)*q2+p2*s2*t2;/* 1 */
+
+ int num;
+ num = cvSolveCubic(&coeffs,&result);
+
+
+ /* test number of solutions and test for real solutions */
+ int i;
+ for( i = 0; i < num; i++ )
+ {
+ if( fabs(cvmGet(&result,1,i)) < 1e-8 )
+ {
+ double alpha = cvmGet(&result,0,i);
+ int j;
+ for( j = 0; j < 5; j++ )
+ {
+ cvmSet(resFundReduceCoef,numRoots,j,
+ alpha * cvmGet(fundReduceCoef1,0,j) + (1-alpha) * cvmGet(fundReduceCoef2,0,j) );
+ }
+ numRoots++;
+ }
+ }
+
+ __END__;
+ return numRoots;
+}
+
+/*==========================================================================================*/
+
+void GetProjMatrFromReducedFundamental(CvMat* fundReduceCoefs,CvMat* projMatrCoefs)
+{
+ CV_FUNCNAME( "GetProjMatrFromReducedFundamental" );
+ __BEGIN__;
+
+ /* Test for errors */
+ if( fundReduceCoefs == 0 || projMatrCoefs == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(fundReduceCoefs) || !CV_IS_MAT(projMatrCoefs) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters must be a matrices" );
+ }
+
+
+ if( fundReduceCoefs->rows != 1 || fundReduceCoefs->cols != 5 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of fundReduceCoefs must be 1x5" );
+ }
+
+ if( projMatrCoefs->rows != 1 || projMatrCoefs->cols != 4 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of projMatrCoefs must be 1x4" );
+ }
+
+ /* Computes project matrix from given reduced matrix */
+ /* we have p,q,r,s,t and need get a,b,c,d */
+ /* Fill matrix to compute ratio a:b:c as A:B:C */
+
+ CvMat matrA;
+ double matrA_dat[3*3];
+ matrA = cvMat(3,3,CV_64F,matrA_dat);
+
+ double p,q,r,s,t;
+ p = cvmGet(fundReduceCoefs,0,0);
+ q = cvmGet(fundReduceCoefs,0,1);
+ r = cvmGet(fundReduceCoefs,0,2);
+ s = cvmGet(fundReduceCoefs,0,3);
+ t = cvmGet(fundReduceCoefs,0,4);
+
+ matrA_dat[0] = p;
+ matrA_dat[1] = r;
+ matrA_dat[2] = 0;
+
+ matrA_dat[3] = q;
+ matrA_dat[4] = 0;
+ matrA_dat[5] = t;
+
+ matrA_dat[6] = 0;
+ matrA_dat[7] = s;
+ matrA_dat[8] = -(p+q+r+s+t);
+
+ CvMat matrU;
+ CvMat matrW;
+ CvMat matrV;
+
+ double matrU_dat[3*3];
+ double matrW_dat[3*3];
+ double matrV_dat[3*3];
+
+ matrU = cvMat(3,3,CV_64F,matrU_dat);
+ matrW = cvMat(3,3,CV_64F,matrW_dat);
+ matrV = cvMat(3,3,CV_64F,matrV_dat);
+
+ /* From svd we need just last vector of V or last row V' */
+ /* We get transposed matrixes U and V */
+
+ cvSVD(&matrA,&matrW,0,&matrV,CV_SVD_V_T);
+
+ double A1,B1,C1;
+ A1 = matrV_dat[6];
+ B1 = matrV_dat[7];
+ C1 = matrV_dat[8];
+
+ /* Get second coeffs */
+ matrA_dat[0] = 0;
+ matrA_dat[1] = r;
+ matrA_dat[2] = t;
+
+ matrA_dat[3] = p;
+ matrA_dat[4] = 0;
+ matrA_dat[5] = -(p+q+r+s+t);
+
+ matrA_dat[6] = q;
+ matrA_dat[7] = s;
+ matrA_dat[8] = 0;
+
+ cvSVD(&matrA,&matrW,0,&matrV,CV_SVD_V_T);
+
+ double A2,B2,C2;
+ A2 = matrV_dat[6];
+ B2 = matrV_dat[7];
+ C2 = matrV_dat[8];
+
+ double a,b,c,d;
+ {
+ CvMat matrK;
+ double matrK_dat[36];
+ matrK = cvMat(6,6,CV_64F,matrK_dat);
+ cvZero(&matrK);
+
+ matrK_dat[0] = 1;
+ matrK_dat[7] = 1;
+ matrK_dat[14] = 1;
+
+ matrK_dat[18] = -1;
+ matrK_dat[25] = -1;
+ matrK_dat[32] = -1;
+
+ matrK_dat[21] = 1;
+ matrK_dat[27] = 1;
+ matrK_dat[33] = 1;
+
+ matrK_dat[0*6+4] = -A1;
+ matrK_dat[1*6+4] = -B1;
+ matrK_dat[2*6+4] = -C1;
+
+ matrK_dat[3*6+5] = -A2;
+ matrK_dat[4*6+5] = -B2;
+ matrK_dat[5*6+5] = -C2;
+
+ CvMat matrU;
+ CvMat matrW;
+ CvMat matrV;
+
+ double matrU_dat[36];
+ double matrW_dat[36];
+ double matrV_dat[36];
+
+ matrU = cvMat(6,6,CV_64F,matrU_dat);
+ matrW = cvMat(6,6,CV_64F,matrW_dat);
+ matrV = cvMat(6,6,CV_64F,matrV_dat);
+
+ /* From svd we need just last vector of V or last row V' */
+ /* We get transposed matrixes U and V */
+
+ cvSVD(&matrK,&matrW,0,&matrV,CV_SVD_V_T);
+
+ a = matrV_dat[6*5+0];
+ b = matrV_dat[6*5+1];
+ c = matrV_dat[6*5+2];
+ d = matrV_dat[6*5+3];
+ /* we don't need last two coefficients. Because it just a k1,k2 */
+
+ cvmSet(projMatrCoefs,0,0,a);
+ cvmSet(projMatrCoefs,0,1,b);
+ cvmSet(projMatrCoefs,0,2,c);
+ cvmSet(projMatrCoefs,0,3,d);
+
+ }
+
+ __END__;
+ return;
+}
+
+/*==========================================================================================*/
+
+void icvComputeProjectMatrix(CvMat* objPoints,CvMat* projPoints,CvMat* projMatr)
+{/* Using SVD method */
+
+ /* Reconstruct points using object points and projected points */
+ /* Number of points must be >=6 */
+
+ CvMat matrV;
+ CvMat* matrA = 0;
+ CvMat* matrW = 0;
+ CvMat* workProjPoints = 0;
+ CvMat* tmpProjPoints = 0;
+
+ CV_FUNCNAME( "icvComputeProjectMatrix" );
+ __BEGIN__;
+
+ /* Test for errors */
+ if( objPoints == 0 || projPoints == 0 || projMatr == 0)
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(objPoints) || !CV_IS_MAT(projPoints) || !CV_IS_MAT(projMatr) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters must be a matrices" );
+ }
+
+ if( projMatr->rows != 3 || projMatr->cols != 4 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of projMatr must be 3x4" );
+ }
+
+ int numPoints;
+ numPoints = projPoints->cols;
+ if( numPoints < 6 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of points must be at least 6" );
+ }
+
+ if( numPoints != objPoints->cols )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of points must be same" );
+ }
+
+ if( objPoints->rows != 4 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Object points must have 4 coordinates" );
+ }
+
+ if( projPoints->rows != 3 && projPoints->rows != 2 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Projected points must have 2 or 3 coordinates" );
+ }
+
+ /* Create and fill matrix A */
+ CV_CALL( matrA = cvCreateMat(numPoints*3, 12, CV_64F) );
+ CV_CALL( matrW = cvCreateMat(numPoints*3, 12, CV_64F) );
+
+ if( projPoints->rows == 2 )
+ {
+ CV_CALL( tmpProjPoints = cvCreateMat(3,numPoints,CV_64F) );
+ cvMake3DPoints(projPoints,tmpProjPoints);
+ workProjPoints = tmpProjPoints;
+ }
+ else
+ {
+ workProjPoints = projPoints;
+ }
+
+ double matrV_dat[144];
+ matrV = cvMat(12,12,CV_64F,matrV_dat);
+ int i;
+
+ char* dat;
+ dat = (char*)(matrA->data.db);
+
+#if 1
+ FILE *file;
+ file = fopen("d:\\test\\recProjMatr.txt","w");
+
+#endif
+ for( i = 0;i < numPoints; i++ )
+ {
+ double x,y,w;
+ double X,Y,Z,W;
+ double* matrDat = (double*)dat;
+
+ x = cvmGet(workProjPoints,0,i);
+ y = cvmGet(workProjPoints,1,i);
+ w = cvmGet(workProjPoints,2,i);
+
+
+ X = cvmGet(objPoints,0,i);
+ Y = cvmGet(objPoints,1,i);
+ Z = cvmGet(objPoints,2,i);
+ W = cvmGet(objPoints,3,i);
+
+#if 1
+ fprintf(file,"%d (%lf %lf %lf %lf) - (%lf %lf %lf)\n",i,X,Y,Z,W,x,y,w );
+#endif
+
+/*---*/
+ matrDat[ 0] = 0;
+ matrDat[ 1] = 0;
+ matrDat[ 2] = 0;
+ matrDat[ 3] = 0;
+
+ matrDat[ 4] = -w*X;
+ matrDat[ 5] = -w*Y;
+ matrDat[ 6] = -w*Z;
+ matrDat[ 7] = -w*W;
+
+ matrDat[ 8] = y*X;
+ matrDat[ 9] = y*Y;
+ matrDat[10] = y*Z;
+ matrDat[11] = y*W;
+/*---*/
+ matrDat[12] = w*X;
+ matrDat[13] = w*Y;
+ matrDat[14] = w*Z;
+ matrDat[15] = w*W;
+
+ matrDat[16] = 0;
+ matrDat[17] = 0;
+ matrDat[18] = 0;
+ matrDat[19] = 0;
+
+ matrDat[20] = -x*X;
+ matrDat[21] = -x*Y;
+ matrDat[22] = -x*Z;
+ matrDat[23] = -x*W;
+/*---*/
+ matrDat[24] = -y*X;
+ matrDat[25] = -y*Y;
+ matrDat[26] = -y*Z;
+ matrDat[27] = -y*W;
+
+ matrDat[28] = x*X;
+ matrDat[29] = x*Y;
+ matrDat[30] = x*Z;
+ matrDat[31] = x*W;
+
+ matrDat[32] = 0;
+ matrDat[33] = 0;
+ matrDat[34] = 0;
+ matrDat[35] = 0;
+/*---*/
+ dat += (matrA->step)*3;
+ }
+#if 1
+ fclose(file);
+
+#endif
+
+ /* Solve this system */
+
+ /* From svd we need just last vector of V or last row V' */
+ /* We get transposed matrix V */
+
+ cvSVD(matrA,matrW,0,&matrV,CV_SVD_V_T);
+
+ /* projected matrix was computed */
+ for( i = 0; i < 12; i++ )
+ {
+ cvmSet(projMatr,i/4,i%4,cvmGet(&matrV,11,i));
+ }
+
+ cvReleaseMat(&matrA);
+ cvReleaseMat(&matrW);
+ cvReleaseMat(&tmpProjPoints);
+ __END__;
+}
+
+
+/*==========================================================================================*/
+/* May be useless function */
+void icvComputeTransform4D(CvMat* points1,CvMat* points2,CvMat* transMatr)
+{
+ CvMat* matrA = 0;
+ CvMat* matrW = 0;
+
+ double matrV_dat[256];
+ CvMat matrV = cvMat(16,16,CV_64F,matrV_dat);
+
+ CV_FUNCNAME( "icvComputeTransform4D" );
+ __BEGIN__;
+
+ if( points1 == 0 || points2 == 0 || transMatr == 0)
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(points1) || !CV_IS_MAT(points2) || !CV_IS_MAT(transMatr) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters must be a matrices" );
+ }
+
+ /* Computes transformation matrix (4x4) for points1 -> points2 */
+ /* p2=H*p1 */
+
+ /* Test for errors */
+ int numPoints;
+ numPoints = points1->cols;
+
+ /* we must have at least 5 points */
+ if( numPoints < 5 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of points must be at least 5" );
+ }
+
+ if( numPoints != points2->cols )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of points must be the same" );
+ }
+
+ if( transMatr->rows != 4 || transMatr->cols != 4 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of transMatr must be 4x4" );
+ }
+
+ if( points1->rows != 4 || points2->rows != 4 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of coordinates of points must be 4" );
+ }
+
+ /* Create matrix */
+ CV_CALL( matrA = cvCreateMat(6*numPoints,16,CV_64F) );
+ CV_CALL( matrW = cvCreateMat(6*numPoints,16,CV_64F) );
+
+ cvZero(matrA);
+
+ /* Fill matrices */
+ int i;
+ for( i = 0; i < numPoints; i++ )/* For each point */
+ {
+ double X1,Y1,Z1,W1;
+ double P[4];
+
+ P[0] = cvmGet(points1,0,i);
+ P[1] = cvmGet(points1,1,i);
+ P[2] = cvmGet(points1,2,i);
+ P[3] = cvmGet(points1,3,i);
+
+ X1 = cvmGet(points2,0,i);
+ Y1 = cvmGet(points2,1,i);
+ Z1 = cvmGet(points2,2,i);
+ W1 = cvmGet(points2,3,i);
+
+ /* Fill matrA */
+ for( int j = 0; j < 4; j++ )/* For each coordinate */
+ {
+ double x,y,z,w;
+
+ x = X1*P[j];
+ y = Y1*P[j];
+ z = Z1*P[j];
+ w = W1*P[j];
+
+ cvmSet(matrA,6*i+0,4*0+j,y);
+ cvmSet(matrA,6*i+0,4*1+j,-x);
+
+ cvmSet(matrA,6*i+1,4*0+j,z);
+ cvmSet(matrA,6*i+1,4*2+j,-x);
+
+ cvmSet(matrA,6*i+2,4*0+j,w);
+ cvmSet(matrA,6*i+2,4*3+j,-x);
+
+ cvmSet(matrA,6*i+3,4*1+j,-z);
+ cvmSet(matrA,6*i+3,4*2+j,y);
+
+ cvmSet(matrA,6*i+4,4*1+j,-w);
+ cvmSet(matrA,6*i+4,4*3+j,y);
+
+ cvmSet(matrA,6*i+5,4*2+j,-w);
+ cvmSet(matrA,6*i+5,4*3+j,z);
+ }
+ }
+
+ /* From svd we need just two last vectors of V or two last row V' */
+ /* We get transposed matrixes U and V */
+
+ cvSVD(matrA,matrW,0,&matrV,CV_SVD_V_T);
+
+ /* Copy result to result matrix */
+ for( i = 0; i < 16; i++ )
+ {
+ cvmSet(transMatr,i/4,i%4,cvmGet(&matrV,15,i));
+ }
+
+ cvReleaseMat(&matrA);
+ cvReleaseMat(&matrW);
+
+ __END__;
+ return;
+}
+
+/*==========================================================================================*/
+
+void icvReconstructPointsFor3View( CvMat* projMatr1,CvMat* projMatr2,CvMat* projMatr3,
+ CvMat* projPoints1,CvMat* projPoints2,CvMat* projPoints3,
+ CvMat* points4D)
+{
+ CV_FUNCNAME( "icvReconstructPointsFor3View" );
+ __BEGIN__;
+
+ if( projMatr1 == 0 || projMatr2 == 0 || projMatr3 == 0 ||
+ projPoints1 == 0 || projPoints2 == 0 || projPoints3 == 0 ||
+ points4D == 0)
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(projMatr1) || !CV_IS_MAT(projMatr2) || !CV_IS_MAT(projMatr3) ||
+ !CV_IS_MAT(projPoints1) || !CV_IS_MAT(projPoints2) || !CV_IS_MAT(projPoints3) ||
+ !CV_IS_MAT(points4D) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters must be a matrices" );
+ }
+
+ int numPoints;
+ numPoints = projPoints1->cols;
+
+ if( numPoints < 1 )
+ {
+ CV_ERROR( CV_StsOutOfRange, "Number of points must be more than zero" );
+ }
+
+ if( projPoints2->cols != numPoints || projPoints3->cols != numPoints || points4D->cols != numPoints )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of points must be the same" );
+ }
+
+ if( projPoints1->rows != 2 || projPoints2->rows != 2 || projPoints3->rows != 2)
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of proj points coordinates must be == 2" );
+ }
+
+ if( points4D->rows != 4 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of world points coordinates must be == 4" );
+ }
+
+ if( projMatr1->cols != 4 || projMatr1->rows != 3 ||
+ projMatr2->cols != 4 || projMatr2->rows != 3 ||
+ projMatr3->cols != 4 || projMatr3->rows != 3)
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of projection matrices must be 3x4" );
+ }
+
+ CvMat matrA;
+ double matrA_dat[36];
+ matrA = cvMat(9,4,CV_64F,matrA_dat);
+
+ //CvMat matrU;
+ CvMat matrW;
+ CvMat matrV;
+ //double matrU_dat[9*9];
+ double matrW_dat[9*4];
+ double matrV_dat[4*4];
+
+ //matrU = cvMat(9,9,CV_64F,matrU_dat);
+ matrW = cvMat(9,4,CV_64F,matrW_dat);
+ matrV = cvMat(4,4,CV_64F,matrV_dat);
+
+ CvMat* projPoints[3];
+ CvMat* projMatrs[3];
+
+ projPoints[0] = projPoints1;
+ projPoints[1] = projPoints2;
+ projPoints[2] = projPoints3;
+
+ projMatrs[0] = projMatr1;
+ projMatrs[1] = projMatr2;
+ projMatrs[2] = projMatr3;
+
+ /* Solve system for each point */
+ int i,j;
+ for( i = 0; i < numPoints; i++ )/* For each point */
+ {
+ /* Fill matrix for current point */
+ for( j = 0; j < 3; j++ )/* For each view */
+ {
+ double x,y;
+ x = cvmGet(projPoints[j],0,i);
+ y = cvmGet(projPoints[j],1,i);
+ for( int k = 0; k < 4; k++ )
+ {
+ cvmSet(&matrA, j*3+0, k, x * cvmGet(projMatrs[j],2,k) - cvmGet(projMatrs[j],0,k) );
+ cvmSet(&matrA, j*3+1, k, y * cvmGet(projMatrs[j],2,k) - cvmGet(projMatrs[j],1,k) );
+ cvmSet(&matrA, j*3+2, k, x * cvmGet(projMatrs[j],1,k) - y * cvmGet(projMatrs[j],0,k) );
+ }
+ }
+ /* Solve system for current point */
+ {
+ cvSVD(&matrA,&matrW,0,&matrV,CV_SVD_V_T);
+
+ /* Copy computed point */
+ cvmSet(points4D,0,i,cvmGet(&matrV,3,0));/* X */
+ cvmSet(points4D,1,i,cvmGet(&matrV,3,1));/* Y */
+ cvmSet(points4D,2,i,cvmGet(&matrV,3,2));/* Z */
+ cvmSet(points4D,3,i,cvmGet(&matrV,3,3));/* W */
+ }
+ }
+
+ /* Points was reconstructed. Try to reproject points */
+ /* We can compute reprojection error if need */
+ {
+ int i;
+ CvMat point3D;
+ double point3D_dat[4];
+ point3D = cvMat(4,1,CV_64F,point3D_dat);
+
+ CvMat point2D;
+ double point2D_dat[3];
+ point2D = cvMat(3,1,CV_64F,point2D_dat);
+
+ for( i = 0; i < numPoints; i++ )
+ {
+ double W = cvmGet(points4D,3,i);
+
+ point3D_dat[0] = cvmGet(points4D,0,i)/W;
+ point3D_dat[1] = cvmGet(points4D,1,i)/W;
+ point3D_dat[2] = cvmGet(points4D,2,i)/W;
+ point3D_dat[3] = 1;
+
+ /* !!! Project this point for each camera */
+ for( int currCamera = 0; currCamera < 3; currCamera++ )
+ {
+ cvmMul(projMatrs[currCamera], &point3D, &point2D);
+
+ float x,y;
+ float xr,yr,wr;
+ x = (float)cvmGet(projPoints[currCamera],0,i);
+ y = (float)cvmGet(projPoints[currCamera],1,i);
+
+ wr = (float)point2D_dat[2];
+ xr = (float)(point2D_dat[0]/wr);
+ yr = (float)(point2D_dat[1]/wr);
+
+ float deltaX,deltaY;
+ deltaX = (float)fabs(x-xr);
+ deltaY = (float)fabs(y-yr);
+ }
+ }
+ }
+
+ __END__;
+ return;
+}
+
+
+
+
+#if 0
+void ReconstructPointsFor3View_bySolve( CvMat* projMatr1,CvMat* projMatr2,CvMat* projMatr3,
+ CvMat* projPoints1,CvMat* projPoints2,CvMat* projPoints3,
+ CvMat* points3D)
+{
+ CV_FUNCNAME( "ReconstructPointsFor3View" );
+ __BEGIN__;
+
+
+ int numPoints;
+ numPoints = projPoints1->cols;
+ if( projPoints2->cols != numPoints || projPoints3->cols != numPoints || points3D->cols != numPoints )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of points must be the same" );
+ }
+
+ if( projPoints1->rows != 2 || projPoints2->rows != 2 || projPoints3->rows != 2)
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of proj points coordinates must be == 2" );
+ }
+
+ if( points3D->rows != 4 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of world points coordinates must be == 4" );
+ }
+
+ if( projMatr1->cols != 4 || projMatr1->rows != 3 ||
+ projMatr2->cols != 4 || projMatr2->rows != 3 ||
+ projMatr3->cols != 4 || projMatr3->rows != 3)
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of proj matrix must be 3x4" );
+ }
+
+ CvMat matrA;
+ double matrA_dat[3*3*3];
+ matrA = cvMat(3*3,3,CV_64F,matrA_dat);
+
+ CvMat vectB;
+ double vectB_dat[9];
+ vectB = cvMat(9,1,CV_64F,vectB_dat);
+
+ CvMat result;
+ double result_dat[3];
+ result = cvMat(3,1,CV_64F,result_dat);
+
+ CvMat* projPoints[3];
+ CvMat* projMatrs[3];
+
+ projPoints[0] = projPoints1;
+ projPoints[1] = projPoints2;
+ projPoints[2] = projPoints3;
+
+ projMatrs[0] = projMatr1;
+ projMatrs[1] = projMatr2;
+ projMatrs[2] = projMatr3;
+
+ /* Solve system for each point */
+ int i,j;
+ for( i = 0; i < numPoints; i++ )/* For each point */
+ {
+ /* Fill matrix for current point */
+ for( j = 0; j < 3; j++ )/* For each view */
+ {
+ double x,y;
+ x = cvmGet(projPoints[j],0,i);
+ y = cvmGet(projPoints[j],1,i);
+
+ cvmSet(&vectB,j*3+0,0,x-cvmGet(projMatrs[j],0,3));
+ cvmSet(&vectB,j*3+1,0,y-cvmGet(projMatrs[j],1,3));
+ cvmSet(&vectB,j*3+2,0,1-cvmGet(projMatrs[j],2,3));
+
+ for( int t = 0; t < 3; t++ )
+ {
+ for( int k = 0; k < 3; k++ )
+ {
+ cvmSet(&matrA, j*3+t, k, cvmGet(projMatrs[j],t,k) );
+ }
+ }
+ }
+
+
+ /* Solve system for current point */
+ cvSolve(&matrA,&vectB,&result,CV_SVD);
+
+ cvmSet(points3D,0,i,result_dat[0]);/* X */
+ cvmSet(points3D,1,i,result_dat[1]);/* Y */
+ cvmSet(points3D,2,i,result_dat[2]);/* Z */
+ cvmSet(points3D,3,i,1);/* W */
+
+ }
+
+ /* Points was reconstructed. Try to reproject points */
+ {
+ int i;
+ CvMat point3D;
+ double point3D_dat[4];
+ point3D = cvMat(4,1,CV_64F,point3D_dat);
+
+ CvMat point2D;
+ double point2D_dat[3];
+ point2D = cvMat(3,1,CV_64F,point2D_dat);
+
+ for( i = 0; i < numPoints; i++ )
+ {
+ double W = cvmGet(points3D,3,i);
+
+ point3D_dat[0] = cvmGet(points3D,0,i)/W;
+ point3D_dat[1] = cvmGet(points3D,1,i)/W;
+ point3D_dat[2] = cvmGet(points3D,2,i)/W;
+ point3D_dat[3] = 1;
+
+ /* Project this point for each camera */
+ for( int currCamera = 0; currCamera < 3; currCamera++ )
+ {
+ cvmMul(projMatrs[currCamera], &point3D, &point2D);
+ float x,y;
+ float xr,yr,wr;
+ x = (float)cvmGet(projPoints[currCamera],0,i);
+ y = (float)cvmGet(projPoints[currCamera],1,i);
+
+ wr = (float)point2D_dat[2];
+ xr = (float)(point2D_dat[0]/wr);
+ yr = (float)(point2D_dat[1]/wr);
+
+ }
+ }
+ }
+
+ __END__;
+ return;
+}
+#endif
+
+/*==========================================================================================*/
+
+void icvComputeCameraExrinnsicByPosition(CvMat* camPos, CvMat* rotMatr, CvMat* transVect)
+{
+ /* We know position of camera. we must to compute rotate matrix and translate vector */
+
+ CV_FUNCNAME( "icvComputeCameraExrinnsicByPosition" );
+ __BEGIN__;
+
+ /* Test input paramaters */
+ if( camPos == 0 || rotMatr == 0 || transVect == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(camPos) || !CV_IS_MAT(rotMatr) || !CV_IS_MAT(transVect) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters must be a matrices" );
+ }
+
+ if( camPos->cols != 1 || camPos->rows != 3 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of coordinates of camera position must be 3x1 vector" );
+ }
+
+ if( rotMatr->cols != 3 || rotMatr->rows != 3 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Rotate matrix must be 3x3" );
+ }
+
+ if( transVect->cols != 1 || transVect->rows != 3 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Translate vector must be 3x1" );
+ }
+
+ double x,y,z;
+ x = cvmGet(camPos,0,0);
+ y = cvmGet(camPos,1,0);
+ z = cvmGet(camPos,2,0);
+
+ /* Set translate vector. It same as camea position */
+ cvmSet(transVect,0,0,x);
+ cvmSet(transVect,1,0,y);
+ cvmSet(transVect,2,0,z);
+
+ /* Compute rotate matrix. Compute each unit transformed vector */
+
+ /* normalize flat direction x,y */
+ double vectorX[3];
+ double vectorY[3];
+ double vectorZ[3];
+
+ vectorX[0] = -z;
+ vectorX[1] = 0;
+ vectorX[2] = x;
+
+ vectorY[0] = x*y;
+ vectorY[1] = x*x+z*z;
+ vectorY[2] = z*y;
+
+ vectorZ[0] = -x;
+ vectorZ[1] = -y;
+ vectorZ[2] = -z;
+
+ /* normaize vectors */
+ double norm;
+ int i;
+
+ /* Norm X */
+ norm = 0;
+ for( i = 0; i < 3; i++ )
+ norm += vectorX[i]*vectorX[i];
+ norm = sqrt(norm);
+ for( i = 0; i < 3; i++ )
+ vectorX[i] /= norm;
+
+ /* Norm Y */
+ norm = 0;
+ for( i = 0; i < 3; i++ )
+ norm += vectorY[i]*vectorY[i];
+ norm = sqrt(norm);
+ for( i = 0; i < 3; i++ )
+ vectorY[i] /= norm;
+
+ /* Norm Z */
+ norm = 0;
+ for( i = 0; i < 3; i++ )
+ norm += vectorZ[i]*vectorZ[i];
+ norm = sqrt(norm);
+ for( i = 0; i < 3; i++ )
+ vectorZ[i] /= norm;
+
+ /* Set output results */
+
+ for( i = 0; i < 3; i++ )
+ {
+ cvmSet(rotMatr,i,0,vectorX[i]);
+ cvmSet(rotMatr,i,1,vectorY[i]);
+ cvmSet(rotMatr,i,2,vectorZ[i]);
+ }
+
+ {/* Try to inverse rotate matrix */
+ CvMat tmpInvRot;
+ double tmpInvRot_dat[9];
+ tmpInvRot = cvMat(3,3,CV_64F,tmpInvRot_dat);
+ cvInvert(rotMatr,&tmpInvRot,CV_SVD);
+ cvConvert(&tmpInvRot,rotMatr);
+
+
+
+ }
+
+ __END__;
+
+ return;
+}
+
+/*==========================================================================================*/
+
+void FindTransformForProjectMatrices(CvMat* projMatr1,CvMat* projMatr2,CvMat* rotMatr,CvMat* transVect)
+{
+ /* Computes homography for project matrix be "canonical" form */
+ CV_FUNCNAME( "computeProjMatrHomography" );
+ __BEGIN__;
+
+ /* Test input paramaters */
+ if( projMatr1 == 0 || projMatr2 == 0 || rotMatr == 0 || transVect == 0 )
+ {
+ CV_ERROR( CV_StsNullPtr, "Some of parameters is a NULL pointer" );
+ }
+
+ if( !CV_IS_MAT(projMatr1) || !CV_IS_MAT(projMatr2) || !CV_IS_MAT(rotMatr) || !CV_IS_MAT(transVect) )
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Input parameters must be a matrices" );
+ }
+
+ if( projMatr1->cols != 4 || projMatr1->rows != 3 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of project matrix 1 must be 3x4" );
+ }
+
+ if( projMatr2->cols != 4 || projMatr2->rows != 3 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of project matrix 2 must be 3x4" );
+ }
+
+ if( rotMatr->cols != 3 || rotMatr->rows != 3 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of rotation matrix must be 3x3" );
+ }
+
+ if( transVect->cols != 1 || transVect->rows != 3 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of translation vector must be 3x1" );
+ }
+
+ CvMat matrA;
+ double matrA_dat[12*12];
+ matrA = cvMat(12,12,CV_64F,matrA_dat);
+ CvMat vectB;
+ double vectB_dat[12];
+ vectB = cvMat(12,1,CV_64F,vectB_dat);
+
+ cvZero(&matrA);
+ cvZero(&vectB);
+ int i,j;
+ for( i = 0; i < 12; i++ )
+ {
+ for( j = 0; j < 12; j++ )
+ {
+ cvmSet(&matrA,i,j,cvmGet(projMatr1,i/4,j%4));
+ }
+ /* Fill vector B */
+
+ double val = cvmGet(projMatr2,i/4,i%4);
+ if( (i+1)%4 == 0 )
+ {
+ val -= cvmGet(projMatr1,i/4,3);
+
+ }
+ cvmSet(&vectB,i,0,val);
+ }
+
+ /* Solve system */
+ CvMat resVect;
+ double resVect_dat[12];
+ resVect = cvMat(12,1,CV_64F,resVect_dat);
+
+ int sing;
+ sing = cvSolve(&matrA,&vectB,&resVect);
+
+ /* Fill rotation matrix */
+ for( i = 0; i < 12; i++ )
+ {
+ double val = cvmGet(&resVect,i,0);
+ if( i < 9 )
+ cvmSet(rotMatr,i%3,i/3,val);
+ else
+ cvmSet(transVect,i-9,0,val);
+ }
+
+ __END__;
+
+ return;
+}
+
+/*==========================================================================================*/
+#if 0
+void icvComputeQknowPrincipalPoint(int numImages, CvMat **projMatrs,CvMat *matrQ, double cx,double cy)
+{
+ /* Computes matrix Q */
+ /* focal x and y eqauls () */
+ /* we know principal point for camera */
+ /* focal may differ from image to image */
+ /* image skew is 0 */
+
+ if( numImages < 10 )
+ {
+ return;
+ //Error. Number of images too few
+ }
+
+ /* Create */
+
+
+ return;
+}
+#endif
+
+/*==========================================================================================*/
+
+/*==========================================================================================*/
+/*==========================================================================================*/
+/*==========================================================================================*/
+/*==========================================================================================*/
+/* Part with metric reconstruction */
+
+#if 1
+void icvComputeQ(int numMatr, CvMat** projMatr, CvMat** cameraMatr, CvMat* matrQ)
+{
+ /* K*K' = P*Q*P' */
+ /* try to solve Q by linear method */
+
+ CvMat* matrA = 0;
+ CvMat* vectB = 0;
+
+ CV_FUNCNAME( "ComputeQ" );
+ __BEGIN__;
+
+ /* Define number of projection matrices */
+ if( numMatr < 2 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Number of projection matrices must be at least 2" );
+ }
+
+
+ /* test matrices sizes */
+ if( matrQ->cols != 4 || matrQ->rows != 4 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of matrix Q must be 3x3" );
+ }
+
+ int currMatr;
+ for( currMatr = 0; currMatr < numMatr; currMatr++ )
+ {
+
+ if( cameraMatr[currMatr]->cols != 3 || cameraMatr[currMatr]->rows != 3 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of each camera matrix must be 3x3" );
+ }
+
+ if( projMatr[currMatr]->cols != 4 || projMatr[currMatr]->rows != 3 )
+ {
+ CV_ERROR( CV_StsUnmatchedSizes, "Size of each camera matrix must be 3x3" );
+ }
+ }
+
+ CvMat matrw;
+ double matrw_dat[9];
+ matrw = cvMat(3,3,CV_64F,matrw_dat);
+
+ CvMat matrKt;
+ double matrKt_dat[9];
+ matrKt = cvMat(3,3,CV_64F,matrKt_dat);
+
+
+ /* Create matrix A and vector B */
+ CV_CALL( matrA = cvCreateMat(9*numMatr,10,CV_64F) );
+ CV_CALL( vectB = cvCreateMat(9*numMatr,1,CV_64F) );
+
+ double dataQ[16];
+
+ for( currMatr = 0; currMatr < numMatr; currMatr++ )
+ {
+ int ord10[10] = {0,1,2,3,5,6,7,10,11,15};
+ /* Fill atrix A by data from matrices */
+
+ /* Compute matrix w for current camera matrix */
+ cvTranspose(cameraMatr[currMatr],&matrKt);
+ cvmMul(cameraMatr[currMatr],&matrKt,&matrw);
+
+ /* Fill matrix A and vector B */
+
+ int currWi,currWj;
+ int currMatr;
+ for( currMatr = 0; currMatr < numMatr; currMatr++ )
+ {
+ for( currWi = 0; currWi < 3; currWi++ )
+ {
+ for( currWj = 0; currWj < 3; currWj++ )
+ {
+ int i,j;
+ for( i = 0; i < 4; i++ )
+ {
+ for( j = 0; j < 4; j++ )
+ {
+ /* get elements from current projection matrix */
+ dataQ[i*4+j] = cvmGet(projMatr[currMatr],currWi,j) *
+ cvmGet(projMatr[currMatr],currWj,i);
+ }
+ }
+
+ /* we know 16 elements in dataQ move them to matrQ 10 */
+ dataQ[1] += dataQ[4];
+ dataQ[2] += dataQ[8];
+ dataQ[3] += dataQ[12];
+ dataQ[6] += dataQ[9];
+ dataQ[7] += dataQ[13];
+ dataQ[11] += dataQ[14];
+ /* Now first 10 elements has coeffs */
+
+ /* copy to matrix A */
+ for( i = 0; i < 10; i++ )
+ {
+ cvmSet(matrA,currMatr*9 + currWi*3+currWj,i,dataQ[ord10[i]]);
+ }
+ }
+ }
+
+ /* Fill vector B */
+ for( int i = 0; i < 9; i++ )
+ {
+ cvmSet(vectB,currMatr*9+i,0,matrw_dat[i]);
+ }
+ }
+ }
+
+ /* Matrix A and vector B filled and we can solve system */
+
+ /* Solve system */
+ CvMat resQ;
+ double resQ_dat[10];
+ resQ = cvMat(10,1,CV_64F,resQ_dat);
+
+ cvSolve(matrA,vectB,&resQ,CV_SVD);
+
+ /* System was solved. We know matrix Q. But we must have condition det Q=0 */
+ /* Just copy result matrix Q */
+ {
+ int curr = 0;
+ int ord16[16] = {0,1,2,3,1,4,5,6,2,5,7,8,3,6,8,9};
+
+ for( int i = 0; i < 4; i++ )
+ {
+ for( int j = 0; j < 4; j++ )
+ {
+ cvmSet(matrQ,i,j,resQ_dat[ord16[curr++]]);
+ }
+ }
+ }
+
+
+ __END__;
+
+ /* Free allocated memory */
+ cvReleaseMat(&matrA);
+ cvReleaseMat(&vectB);
+
+ return;
+}
+#endif
+/*-----------------------------------------------------------------------------------------------------*/
+
+void icvDecomposeQ(CvMat* /*matrQ*/,CvMat* /*matrH*/)
+{
+#if 0
+ /* Use SVD to decompose matrix Q=H*I*H' */
+ /* test input data */
+
+ CvMat matrW;
+ CvMat matrU;
+// CvMat matrV;
+ double matrW_dat[16];
+ double matrU_dat[16];
+// double matrV_dat[16];
+
+ matrW = cvMat(4,4,CV_64F,matrW_dat);
+ matrU = cvMat(4,4,CV_64F,matrU_dat);
+// matrV = cvMat(4,4,CV_64F,matrV_dat);
+
+ cvSVD(matrQ,&matrW,&matrU,0);
+
+ double eig[3];
+ eig[0] = fsqrt(cvmGet(&matrW,0,0));
+ eig[1] = fsqrt(cvmGet(&matrW,1,1));
+ eig[2] = fsqrt(cvmGet(&matrW,2,2));
+
+ CvMat matrIS;
+ double matrIS_dat[16];
+ matrIS =
+
+
+
+
+/* det for matrix Q with q1-q10 */
+/*
++ q1*q5*q8*q10
+- q1*q5*q9*q9
+- q1*q6*q6*q10
++ 2*q1*q6*q7*q9
+- q1*q7*q7*q8
+- q2*q2*q8*q10
++ q2*q2*q9*q9
++ 2*q2*q6*q3*q10
+- 2*q2*q6*q4*q9
+- 2*q2*q7*q3*q9
++ 2*q2*q7*q4*q8
+- q5*q3*q3*q10
++ 2*q3*q5*q4*q9
++ q3*q3*q7*q7
+- 2*q3*q7*q4*q6
+- q5*q4*q4*q8
++ q4*q4*q6*q6
+*/
+
+// (1-a)^4 = 1 - 4 * a + 6 * a * a - 4 * a * a * a + a * a * a * a;
+
+
+#endif
+}
+
diff --git a/cvaux/src/cvvecfacetracking.cpp b/cvaux/src/cvvecfacetracking.cpp
new file mode 100644
index 0000000..75e3509
--- /dev/null
+++ b/cvaux/src/cvvecfacetracking.cpp
@@ -0,0 +1,975 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/****************************************************************************************\
+ Contour-based face feature tracking
+ The code was created by Tatiana Cherepanova (tata@sl.iae.nsk.su)
+\****************************************************************************************/
+
+#include "_cvaux.h"
+#include "_cvvectrack.h"
+
+#define _ASSERT assert
+#define NUM_FACE_ELEMENTS 3
+enum
+{
+ MOUTH = 0,
+ LEYE = 1,
+ REYE = 2,
+};
+
+#define MAX_LAYERS 64
+
+const double pi = 3.1415926535;
+
+struct CvFaceTracker;
+struct CvTrackingRect;
+class CvFaceElement;
+
+void ThresholdingParam(IplImage *imgGray, int iNumLayers, int &iMinLevel, int &iMaxLevel, float &step, float& power, int iHistMin /*= HIST_MIN*/);
+int ChoiceTrackingFace3(CvFaceTracker* pTF, const int nElements, const CvFaceElement* big_face, CvTrackingRect* face, int& new_energy);
+int ChoiceTrackingFace2(CvFaceTracker* pTF, const int nElements, const CvFaceElement* big_face, CvTrackingRect* face, int& new_energy, int noel);
+inline int GetEnergy(CvTrackingRect** ppNew, const CvTrackingRect* pPrev, CvPoint* ptTempl, CvRect* rTempl);
+inline int GetEnergy2(CvTrackingRect** ppNew, const CvTrackingRect* pPrev, CvPoint* ptTempl, CvRect* rTempl, int* element);
+inline double CalculateTransformationLMS3_0( CvPoint* pTemplPoints, CvPoint* pSrcPoints);
+inline double CalculateTransformationLMS3( CvPoint* pTemplPoints,
+ CvPoint* pSrcPoints,
+ double* pdbAverageScale,
+ double* pdbAverageRotate,
+ double* pdbAverageShiftX,
+ double* pdbAverageShiftY );
+
+struct CvTrackingRect
+{
+ CvRect r;
+ CvPoint ptCenter;
+ int iColor;
+ int iEnergy;
+ int nRectsInThis;
+ int nRectsOnLeft;
+ int nRectsOnRight;
+ int nRectsOnTop;
+ int nRectsOnBottom;
+ CvTrackingRect() { memset(this, 0, sizeof(CvTrackingRect)); };
+ int Energy(const CvTrackingRect& prev)
+ {
+ int prev_color = 0 == prev.iColor ? iColor : prev.iColor;
+ iEnergy = 1 * pow2(r.width - prev.r.width) +
+ 1 * pow2(r.height - prev.r.height) +
+ 1 * pow2(iColor - prev_color) / 4 +
+ - 1 * nRectsInThis +
+ - 0 * nRectsOnTop +
+ + 0 * nRectsOnLeft +
+ + 0 * nRectsOnRight +
+ + 0 * nRectsOnBottom;
+ return iEnergy;
+ }
+};
+
+struct CvFaceTracker
+{
+ CvTrackingRect face[NUM_FACE_ELEMENTS];
+ int iTrackingFaceType;
+ double dbRotateDelta;
+ double dbRotateAngle;
+ CvPoint ptRotate;
+
+ CvPoint ptTempl[NUM_FACE_ELEMENTS];
+ CvRect rTempl[NUM_FACE_ELEMENTS];
+
+ IplImage* imgGray;
+ IplImage* imgThresh;
+ CvMemStorage* mstgContours;
+ CvFaceTracker()
+ {
+ ptRotate.x = 0;
+ ptRotate.y = 0;
+ dbRotateDelta = 0;
+ dbRotateAngle = 0;
+ iTrackingFaceType = -1;
+ imgThresh = NULL;
+ imgGray = NULL;
+ mstgContours = NULL;
+ };
+ ~CvFaceTracker()
+ {
+ if (NULL != imgGray)
+ delete imgGray;
+ if (NULL != imgThresh)
+ delete imgThresh;
+ if (NULL != mstgContours)
+ cvReleaseMemStorage(&mstgContours);
+ };
+ int Init(CvRect* pRects, IplImage* imgGray)
+ {
+ for (int i = 0; i < NUM_FACE_ELEMENTS; i++)
+ {
+ face[i].r = pRects[i];
+ face[i].ptCenter = Center(face[i].r);
+ ptTempl[i] = face[i].ptCenter;
+ rTempl[i] = face[i].r;
+ }
+ imgGray = cvCreateImage(cvSize(imgGray->width, imgGray->height), 8, 1);
+ imgThresh = cvCreateImage(cvSize(imgGray->width, imgGray->height), 8, 1);
+ mstgContours = cvCreateMemStorage();
+ if ((NULL == imgGray) ||
+ (NULL == imgThresh) ||
+ (NULL == mstgContours))
+ return FALSE;
+ return TRUE;
+ };
+ int InitNextImage(IplImage* img)
+ {
+ CvSize sz = {img->width, img->height};
+ ReallocImage(&imgGray, sz, 1);
+ ReallocImage(&imgThresh, sz, 1);
+ ptRotate = face[MOUTH].ptCenter;
+ float m[6];
+ CvMat mat = cvMat( 2, 3, CV_32FC1, m );
+
+ if (NULL == imgGray || NULL == imgThresh)
+ return FALSE;
+
+ /*m[0] = (float)cos(-dbRotateAngle*CV_PI/180.);
+ m[1] = (float)sin(-dbRotateAngle*CV_PI/180.);
+ m[2] = (float)ptRotate.x;
+ m[3] = -m[1];
+ m[4] = m[0];
+ m[5] = (float)ptRotate.y;*/
+ cv2DRotationMatrix( cvPointTo32f(ptRotate), -dbRotateAngle, 1., &mat );
+ cvWarpAffine( img, imgGray, &mat );
+
+ if (NULL == mstgContours)
+ mstgContours = cvCreateMemStorage();
+ else
+ cvClearMemStorage(mstgContours);
+ if (NULL == mstgContours)
+ return FALSE;
+ return TRUE;
+ }
+};
+
+class CvFaceElement
+{
+public:
+ CvSeq* m_seqRects;
+ CvMemStorage* m_mstgRects;
+ CvRect m_rROI;
+ CvTrackingRect m_trPrev;
+ inline CvFaceElement()
+ {
+ m_seqRects = NULL;
+ m_mstgRects = NULL;
+ m_rROI.x = 0;
+ m_rROI.y = 0;
+ m_rROI.width = 0;
+ m_rROI.height = 0;
+ };
+ inline int Init(const CvRect& roi, const CvTrackingRect& prev, CvMemStorage* mstg = NULL)
+ {
+ m_rROI = roi;
+ m_trPrev = prev;
+ if (NULL != mstg)
+ m_mstgRects = mstg;
+ if (NULL == m_mstgRects)
+ return FALSE;
+ if (NULL == m_seqRects)
+ m_seqRects = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvTrackingRect), m_mstgRects);
+ else
+ cvClearSeq(m_seqRects);
+ if (NULL == m_seqRects)
+ return FALSE;
+ return TRUE;
+ };
+ void FindRects(IplImage* img, IplImage* thresh, int nLayers, int dMinSize);
+protected:
+ void FindContours(IplImage* img, IplImage* thresh, int nLayers, int dMinSize);
+ void MergeRects(int d);
+ void Energy();
+}; //class CvFaceElement
+
+int CV_CDECL CompareEnergy(const void* el1, const void* el2, void*)
+{
+ return ((CvTrackingRect*)el1)->iEnergy - ((CvTrackingRect*)el2)->iEnergy;
+}// int CV_CDECL CompareEnergy(const void* el1, const void* el2, void*)
+
+void CvFaceElement::FindRects(IplImage* img, IplImage* thresh, int nLayers, int dMinSize)
+{
+ FindContours(img, thresh, nLayers, dMinSize / 4);
+ if (0 == m_seqRects->total)
+ return;
+ Energy();
+ cvSeqSort(m_seqRects, CompareEnergy, NULL);
+ CvTrackingRect* pR = (CvTrackingRect*)cvGetSeqElem(m_seqRects, 0);
+ if (m_seqRects->total < 32)
+ {
+ MergeRects(dMinSize / 8);
+ Energy();
+ cvSeqSort(m_seqRects, CompareEnergy, NULL);
+ }
+ pR = (CvTrackingRect*)cvGetSeqElem(m_seqRects, 0);
+ if ((pR->iEnergy > 100 && m_seqRects->total < 32) || (m_seqRects->total < 16))
+ {
+ MergeRects(dMinSize / 4);
+ Energy();
+ cvSeqSort(m_seqRects, CompareEnergy, NULL);
+ }
+ pR = (CvTrackingRect*)cvGetSeqElem(m_seqRects, 0);
+ if ((pR->iEnergy > 100 && m_seqRects->total < 16) || (pR->iEnergy > 200 && m_seqRects->total < 32))
+ {
+ MergeRects(dMinSize / 2);
+ Energy();
+ cvSeqSort(m_seqRects, CompareEnergy, NULL);
+ }
+
+}// void CvFaceElement::FindRects(IplImage* img, IplImage* thresh, int nLayers, int dMinSize)
+
+void CvFaceElement::FindContours(IplImage* img, IplImage* thresh, int nLayers, int dMinSize)
+{
+ CvSeq* seq;
+ CvRect roi = m_rROI;
+ Extend(roi, 1);
+ cvSetImageROI(img, roi);
+ cvSetImageROI(thresh, roi);
+ // layers
+ int colors[MAX_LAYERS] = {0};
+ int iMinLevel = 0, iMaxLevel = 255;
+ float step, power;
+ ThresholdingParam(img, nLayers / 2, iMinLevel, iMaxLevel, step, power, 4);
+ int iMinLevelPrev = iMinLevel;
+ int iMaxLevelPrev = iMinLevel;
+ if (m_trPrev.iColor != 0)
+ {
+ iMinLevelPrev = m_trPrev.iColor - nLayers / 2;
+ iMaxLevelPrev = m_trPrev.iColor + nLayers / 2;
+ }
+ if (iMinLevelPrev < iMinLevel)
+ {
+ iMaxLevelPrev += iMinLevel - iMinLevelPrev;
+ iMinLevelPrev = iMinLevel;
+ }
+ if (iMaxLevelPrev > iMaxLevel)
+ {
+ iMinLevelPrev -= iMaxLevelPrev - iMaxLevel;
+ if (iMinLevelPrev < iMinLevel)
+ iMinLevelPrev = iMinLevel;
+ iMaxLevelPrev = iMaxLevel;
+ }
+ int n = nLayers;
+ n -= (iMaxLevelPrev - iMinLevelPrev + 1) / 2;
+ step = float(iMinLevelPrev - iMinLevel + iMaxLevel - iMaxLevelPrev) / float(n);
+ int j = 0;
+ float level;
+ for (level = (float)iMinLevel; level < iMinLevelPrev && j < nLayers; level += step, j++)
+ colors[j] = int(level + 0.5);
+ for (level = (float)iMinLevelPrev; level < iMaxLevelPrev && j < nLayers; level += 2.0, j++)
+ colors[j] = int(level + 0.5);
+ for (level = (float)iMaxLevelPrev; level < iMaxLevel && j < nLayers; level += step, j++)
+ colors[j] = int(level + 0.5);
+ //
+ for (int i = 0; i < nLayers; i++)
+ {
+ cvThreshold(img, thresh, colors[i], 255.0, CV_THRESH_BINARY);
+ if (cvFindContours(thresh, m_mstgRects, &seq, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE))
+ {
+ CvTrackingRect cr;
+ for (CvSeq* external = seq; external; external = external->h_next)
+ {
+ cr.r = cvContourBoundingRect(external);
+ Move(cr.r, roi.x, roi.y);
+ if (RectInRect(cr.r, m_rROI) && cr.r.width > dMinSize && cr.r.height > dMinSize)
+ {
+ cr.ptCenter = Center(cr.r);
+ cr.iColor = colors[i];
+ cvSeqPush(m_seqRects, &cr);
+ }
+ for (CvSeq* internal = external->v_next; internal; internal = internal->h_next)
+ {
+ cr.r = cvContourBoundingRect(internal);
+ Move(cr.r, roi.x, roi.y);
+ if (RectInRect(cr.r, m_rROI) && cr.r.width > dMinSize && cr.r.height > dMinSize)
+ {
+ cr.ptCenter = Center(cr.r);
+ cr.iColor = colors[i];
+ cvSeqPush(m_seqRects, &cr);
+ }
+ }
+ }
+ cvClearSeq(seq);
+ }
+ }
+ cvResetImageROI(img);
+ cvResetImageROI(thresh);
+}//void CvFaceElement::FindContours(IplImage* img, IplImage* thresh, int nLayers)
+
+void CvFaceElement::MergeRects(int d)
+{
+ int nRects = m_seqRects->total;
+ CvSeqReader reader, reader2;
+ cvStartReadSeq( m_seqRects, &reader );
+ int i, j;
+ for (i = 0; i < nRects; i++)
+ {
+ CvTrackingRect* pRect1 = (CvTrackingRect*)(reader.ptr);
+ cvStartReadSeq( m_seqRects, &reader2 );
+ cvSetSeqReaderPos(&reader2, i + 1);
+ for (j = i + 1; j < nRects; j++)
+ {
+ CvTrackingRect* pRect2 = (CvTrackingRect*)(reader2.ptr);
+ if (abs(pRect1->ptCenter.y - pRect2->ptCenter.y) < d &&
+ abs(pRect1->r.height - pRect2->r.height) < d)
+ {
+ CvTrackingRect rNew;
+ rNew.iColor = (pRect1->iColor + pRect2->iColor + 1) / 2;
+ rNew.r.x = min(pRect1->r.x, pRect2->r.x);
+ rNew.r.y = min(pRect1->r.y, pRect2->r.y);
+ rNew.r.width = max(pRect1->r.x + pRect1->r.width, pRect2->r.x + pRect2->r.width) - rNew.r.x;
+ rNew.r.height = min(pRect1->r.y + pRect1->r.height, pRect2->r.y + pRect2->r.height) - rNew.r.y;
+ if (rNew.r != pRect1->r && rNew.r != pRect2->r)
+ {
+ rNew.ptCenter = Center(rNew.r);
+ cvSeqPush(m_seqRects, &rNew);
+ }
+ }
+ CV_NEXT_SEQ_ELEM( sizeof(CvTrackingRect), reader2 );
+ }
+ CV_NEXT_SEQ_ELEM( sizeof(CvTrackingRect), reader );
+ }
+ // delete equal rects
+ for (i = 0; i < m_seqRects->total; i++)
+ {
+ CvTrackingRect* pRect1 = (CvTrackingRect*)cvGetSeqElem(m_seqRects, i);
+ int j_begin = i + 1;
+ for (j = j_begin; j < m_seqRects->total;)
+ {
+ CvTrackingRect* pRect2 = (CvTrackingRect*)cvGetSeqElem(m_seqRects, j);
+ if (pRect1->r == pRect2->r)
+ cvSeqRemove(m_seqRects, j);
+ else
+ j++;
+ }
+ }
+
+}//void CvFaceElement::MergeRects(int d)
+
+void CvFaceElement::Energy()
+{
+ CvSeqReader reader, reader2;
+ cvStartReadSeq( m_seqRects, &reader );
+ for (int i = 0; i < m_seqRects->total; i++)
+ {
+ CvTrackingRect* pRect = (CvTrackingRect*)(reader.ptr);
+ // outside and inside rects
+ cvStartReadSeq( m_seqRects, &reader2 );
+ for (int j = 0; j < m_seqRects->total; j++)
+ {
+ CvTrackingRect* pRect2 = (CvTrackingRect*)(reader2.ptr);
+ if (i != j)
+ {
+ if (RectInRect(pRect2->r, pRect->r))
+ pRect->nRectsInThis ++;
+ else if (pRect2->r.y + pRect2->r.height <= pRect->r.y)
+ pRect->nRectsOnTop ++;
+ else if (pRect2->r.y >= pRect->r.y + pRect->r.height)
+ pRect->nRectsOnBottom ++;
+ else if (pRect2->r.x + pRect2->r.width <= pRect->r.x)
+ pRect->nRectsOnLeft ++;
+ else if (pRect2->r.x >= pRect->r.x + pRect->r.width)
+ pRect->nRectsOnRight ++;
+ }
+ CV_NEXT_SEQ_ELEM( sizeof(CvTrackingRect), reader2 );
+ }
+ // energy
+ pRect->Energy(m_trPrev);
+ CV_NEXT_SEQ_ELEM( sizeof(CvTrackingRect), reader );
+ }
+}//void CvFaceElement::Energy()
+
+CV_IMPL CvFaceTracker*
+cvInitFaceTracker(CvFaceTracker* pFaceTracker, const IplImage* imgGray, CvRect* pRects, int nRects)
+{
+ _ASSERT(NULL != imgGray);
+ _ASSERT(NULL != pRects);
+ _ASSERT(nRects >= NUM_FACE_ELEMENTS);
+ if ((NULL == imgGray) ||
+ (NULL == pRects) ||
+ (nRects < NUM_FACE_ELEMENTS))
+ return NULL;
+
+ int new_face = FALSE;
+ CvFaceTracker* pFace = pFaceTracker;
+ if (NULL == pFace)
+ {
+ pFace = new CvFaceTracker;
+ if (NULL == pFace)
+ return NULL;
+ new_face = TRUE;
+ }
+ pFace->Init(pRects, (IplImage*)imgGray);
+ return pFace;
+}//CvFaceTracker* InitFaceTracker(IplImage* imgGray, CvRect* pRects, int nRects)
+
+CV_IMPL void
+cvReleaseFaceTracker(CvFaceTracker** ppFaceTracker)
+{
+ if (NULL == *ppFaceTracker)
+ return;
+ delete *ppFaceTracker;
+ *ppFaceTracker = NULL;
+}//void ReleaseFaceTracker(CvFaceTracker** ppFaceTracker)
+
+
+CV_IMPL int
+cvTrackFace(CvFaceTracker* pFaceTracker, IplImage* imgGray, CvRect* pRects, int nRects, CvPoint* ptRotate, double* dbAngleRotate)
+{
+ _ASSERT(NULL != pFaceTracker);
+ _ASSERT(NULL != imgGray);
+ _ASSERT(NULL != pRects && nRects >= NUM_FACE_ELEMENTS);
+ if ((NULL == pFaceTracker) ||
+ (NULL == imgGray))
+ return FALSE;
+ pFaceTracker->InitNextImage(imgGray);
+ *ptRotate = pFaceTracker->ptRotate;
+ *dbAngleRotate = pFaceTracker->dbRotateAngle;
+
+ int nElements = 16;
+ double dx = pFaceTracker->face[LEYE].ptCenter.x - pFaceTracker->face[REYE].ptCenter.x;
+ double dy = pFaceTracker->face[LEYE].ptCenter.y - pFaceTracker->face[REYE].ptCenter.y;
+ double d_eyes = sqrt(dx*dx + dy*dy);
+ int d = cvRound(0.25 * d_eyes);
+ int dMinSize = d;
+ int nRestarts = 0;
+
+ int elem;
+
+ CvFaceElement big_face[NUM_FACE_ELEMENTS];
+START:
+ // init
+ for (elem = 0; elem < NUM_FACE_ELEMENTS; elem++)
+ {
+ CvRect r = pFaceTracker->face[elem].r;
+ Extend(r, d);
+ if (r.width < 4*d)
+ {
+ r.x -= (4*d - r.width) / 2;
+ r.width += 4*d - r.width;
+ }
+ if (r.height < 3*d)
+ {
+ r.y -= (3*d - r.height) / 2;
+ r.height += 3*d - r.height;
+ }
+ if (r.x < 1)
+ r.x = 1;
+ if (r.y < 1)
+ r.y = 1;
+ if (r.x + r.width > pFaceTracker->imgGray->width - 2)
+ r.width = pFaceTracker->imgGray->width - 2 - r.x;
+ if (r.y + r.height > pFaceTracker->imgGray->height - 2)
+ r.height = pFaceTracker->imgGray->height - 2 - r.y;
+ if (!big_face[elem].Init(r, pFaceTracker->face[elem], pFaceTracker->mstgContours))
+ return FALSE;
+ }
+ // find contours
+ for (elem = 0; elem < NUM_FACE_ELEMENTS; elem++)
+ big_face[elem].FindRects(pFaceTracker->imgGray, pFaceTracker->imgThresh, 32, dMinSize);
+ // candidats
+ CvTrackingRect new_face[NUM_FACE_ELEMENTS];
+ int new_energy = 0;
+ int found = ChoiceTrackingFace3(pFaceTracker, nElements, big_face, new_face, new_energy);
+ int restart = FALSE;
+ int find2 = FALSE;
+ int noel = -1;
+ if (found)
+ {
+ if (new_energy > 100000 && -1 != pFaceTracker->iTrackingFaceType)
+ find2 = TRUE;
+ else if (new_energy > 150000)
+ {
+ int elements = 0;
+ for (int el = 0; el < NUM_FACE_ELEMENTS; el++)
+ {
+ if (big_face[el].m_seqRects->total > 16 || (big_face[el].m_seqRects->total > 8 && new_face[el].iEnergy < 100))
+ elements++;
+ else
+ noel = el;
+ }
+ if (2 == elements)
+ find2 = TRUE;
+ else
+ restart = TRUE;
+ }
+ }
+ else
+ {
+ if (-1 != pFaceTracker->iTrackingFaceType)
+ find2 = TRUE;
+ else
+ restart = TRUE;
+ }
+RESTART:
+ if (restart)
+ {
+ if (nRestarts++ < 2)
+ {
+ d = d + d/4;
+ goto START;
+ }
+ }
+ else if (find2)
+ {
+ if (-1 != pFaceTracker->iTrackingFaceType)
+ noel = pFaceTracker->iTrackingFaceType;
+ int found2 = ChoiceTrackingFace2(pFaceTracker, nElements, big_face, new_face, new_energy, noel);
+ if (found2 && new_energy < 100000)
+ {
+ pFaceTracker->iTrackingFaceType = noel;
+ found = TRUE;
+ }
+ else
+ {
+ restart = TRUE;
+ goto RESTART;
+ }
+ }
+
+ if (found)
+ {
+ // angle by mouth & eyes
+ double vx_prev = double(pFaceTracker->face[LEYE].ptCenter.x + pFaceTracker->face[REYE].ptCenter.x) / 2.0 - pFaceTracker->face[MOUTH].ptCenter.x;
+ double vy_prev = double(pFaceTracker->face[LEYE].ptCenter.y + pFaceTracker->face[REYE].ptCenter.y) / 2.0 - pFaceTracker->face[MOUTH].ptCenter.y;
+ double vx_prev1 = vx_prev * cos(pFaceTracker->dbRotateDelta) - vy_prev * sin(pFaceTracker->dbRotateDelta);
+ double vy_prev1 = vx_prev * sin(pFaceTracker->dbRotateDelta) + vy_prev * cos(pFaceTracker->dbRotateDelta);
+ vx_prev = vx_prev1;
+ vy_prev = vy_prev1;
+ for (elem = 0; elem < NUM_FACE_ELEMENTS; elem++)
+ pFaceTracker->face[elem] = new_face[elem];
+ double vx = double(pFaceTracker->face[LEYE].ptCenter.x + pFaceTracker->face[REYE].ptCenter.x) / 2.0 - pFaceTracker->face[MOUTH].ptCenter.x;
+ double vy = double(pFaceTracker->face[LEYE].ptCenter.y + pFaceTracker->face[REYE].ptCenter.y) / 2.0 - pFaceTracker->face[MOUTH].ptCenter.y;
+ pFaceTracker->dbRotateDelta = 0;
+ double n1_n2 = (vx * vx + vy * vy) * (vx_prev * vx_prev + vy_prev * vy_prev);
+ if (n1_n2 != 0)
+ pFaceTracker->dbRotateDelta = asin((vx * vy_prev - vx_prev * vy) / sqrt(n1_n2));
+ pFaceTracker->dbRotateAngle -= pFaceTracker->dbRotateDelta;
+ }
+ else
+ {
+ pFaceTracker->dbRotateDelta = 0;
+ pFaceTracker->dbRotateAngle = 0;
+ }
+ if ((pFaceTracker->dbRotateAngle >= pi/2 && pFaceTracker->dbRotateAngle > 0) ||
+ (pFaceTracker->dbRotateAngle <= -pi/2 && pFaceTracker->dbRotateAngle < 0))
+ {
+ pFaceTracker->dbRotateDelta = 0;
+ pFaceTracker->dbRotateAngle = 0;
+ found = FALSE;
+ }
+ if (found)
+ {
+ for (int i = 0; i < NUM_FACE_ELEMENTS && i < nRects; i++)
+ pRects[i] = pFaceTracker->face[i].r;
+ }
+ return found;
+}//int FindFaceTracker(CvFaceTracker* pFaceTracker, IplImage* imgGray, CvRect* pRects, int nRects, CvPoint& ptRotate, double& dbAngleRotate)
+
+void ThresholdingParam(IplImage *imgGray, int iNumLayers, int &iMinLevel, int &iMaxLevel, float &step, float& power, int iHistMin /*= HIST_MIN*/)
+{
+ _ASSERT(imgGray != NULL);
+ _ASSERT(imgGray->nChannels == 1);
+ int i, j;
+ // create histogram
+ int histImg[256] = {0};
+ uchar* buffImg = (uchar*)imgGray->imageData;
+ CvRect rROI = cvGetImageROI(imgGray);
+ buffImg += rROI.y * imgGray->widthStep + rROI.x;
+ for (j = 0; j < rROI.height; j++)
+ {
+ for (i = 0; i < rROI.width; i++)
+ histImg[buffImg[i]] ++;
+ buffImg += imgGray->widthStep;
+ }
+ // params
+ for (i = 0; i < 256; i++)
+ {
+ if (histImg[i] > iHistMin)
+ break;
+ }
+ iMinLevel = i;
+ for (i = 255; i >= 0; i--)
+ {
+ if (histImg[i] > iHistMin)
+ break;
+ }
+ iMaxLevel = i;
+ if (iMaxLevel <= iMinLevel)
+ {
+ iMaxLevel = 255;
+ iMinLevel = 0;
+ }
+ // power
+ double black = 1;
+ double white = 1;
+ for (i = iMinLevel; i < (iMinLevel + iMaxLevel) / 2; i++)
+ black += histImg[i];
+ for (i = (iMinLevel + iMaxLevel) / 2; i < iMaxLevel; i++)
+ white += histImg[i];
+ power = float(black) / float(2 * white);
+ //
+ step = float(iMaxLevel - iMinLevel) / float(iNumLayers);
+ if (step < 1.0)
+ step = 1.0;
+}// void ThresholdingParam(IplImage *imgGray, int iNumLayers, int &iMinLevel, int &iMaxLevel, int &iStep)
+
+int ChoiceTrackingFace3(CvFaceTracker* pTF, const int nElements, const CvFaceElement* big_face, CvTrackingRect* face, int& new_energy)
+{
+ CvTrackingRect* curr_face[NUM_FACE_ELEMENTS] = {NULL};
+ CvTrackingRect* new_face[NUM_FACE_ELEMENTS] = {NULL};
+ new_energy = 0x7fffffff;
+ int curr_energy = 0x7fffffff;
+ int found = FALSE;
+ int N = 0;
+ CvSeqReader reader_m, reader_l, reader_r;
+ cvStartReadSeq( big_face[MOUTH].m_seqRects, &reader_m );
+ for (int i_mouth = 0; i_mouth < big_face[MOUTH].m_seqRects->total && i_mouth < nElements; i_mouth++)
+ {
+ curr_face[MOUTH] = (CvTrackingRect*)(reader_m.ptr);
+ cvStartReadSeq( big_face[LEYE].m_seqRects, &reader_l );
+ for (int i_left = 0; i_left < big_face[LEYE].m_seqRects->total && i_left < nElements; i_left++)
+ {
+ curr_face[LEYE] = (CvTrackingRect*)(reader_l.ptr);
+ if (curr_face[LEYE]->r.y + curr_face[LEYE]->r.height < curr_face[MOUTH]->r.y)
+ {
+ cvStartReadSeq( big_face[REYE].m_seqRects, &reader_r );
+ for (int i_right = 0; i_right < big_face[REYE].m_seqRects->total && i_right < nElements; i_right++)
+ {
+ curr_face[REYE] = (CvTrackingRect*)(reader_r.ptr);
+ if (curr_face[REYE]->r.y + curr_face[REYE]->r.height < curr_face[MOUTH]->r.y &&
+ curr_face[REYE]->r.x > curr_face[LEYE]->r.x + curr_face[LEYE]->r.width)
+ {
+ curr_energy = GetEnergy(curr_face, pTF->face, pTF->ptTempl, pTF->rTempl);
+ if (curr_energy < new_energy)
+ {
+ for (int elem = 0; elem < NUM_FACE_ELEMENTS; elem++)
+ new_face[elem] = curr_face[elem];
+ new_energy = curr_energy;
+ found = TRUE;
+ }
+ N++;
+ }
+ }
+ }
+ }
+ }
+ if (found)
+ {
+ for (int elem = 0; elem < NUM_FACE_ELEMENTS; elem++)
+ face[elem] = *(new_face[elem]);
+ }
+ return found;
+} // int ChoiceTrackingFace3(const CvTrackingRect* tr_face, CvTrackingRect* new_face, int& new_energy)
+
+int ChoiceTrackingFace2(CvFaceTracker* pTF, const int nElements, const CvFaceElement* big_face, CvTrackingRect* face, int& new_energy, int noel)
+{
+ int element[NUM_FACE_ELEMENTS];
+ for (int i = 0, elem = 0; i < NUM_FACE_ELEMENTS; i++)
+ {
+ if (i != noel)
+ {
+ element[elem] = i;
+ elem ++;
+ }
+ else
+ element[2] = i;
+ }
+ CvTrackingRect* curr_face[NUM_FACE_ELEMENTS] = {NULL};
+ CvTrackingRect* new_face[NUM_FACE_ELEMENTS] = {NULL};
+ new_energy = 0x7fffffff;
+ int curr_energy = 0x7fffffff;
+ int found = FALSE;
+ int N = 0;
+ CvSeqReader reader0, reader1;
+ cvStartReadSeq( big_face[element[0]].m_seqRects, &reader0 );
+ for (int i0 = 0; i0 < big_face[element[0]].m_seqRects->total && i0 < nElements; i0++)
+ {
+ curr_face[element[0]] = (CvTrackingRect*)(reader0.ptr);
+ cvStartReadSeq( big_face[element[1]].m_seqRects, &reader1 );
+ for (int i1 = 0; i1 < big_face[element[1]].m_seqRects->total && i1 < nElements; i1++)
+ {
+ curr_face[element[1]] = (CvTrackingRect*)(reader1.ptr);
+ curr_energy = GetEnergy2(curr_face, pTF->face, pTF->ptTempl, pTF->rTempl, element);
+ if (curr_energy < new_energy)
+ {
+ for (int elem = 0; elem < NUM_FACE_ELEMENTS; elem++)
+ new_face[elem] = curr_face[elem];
+ new_energy = curr_energy;
+ found = TRUE;
+ }
+ N++;
+ }
+ }
+ if (found)
+ {
+ face[element[0]] = *(new_face[element[0]]);
+ face[element[1]] = *(new_face[element[1]]);
+ // 3 element find by template
+ CvPoint templ_v01 = {pTF->ptTempl[element[1]].x - pTF->ptTempl[element[0]].x, pTF->ptTempl[element[1]].y - pTF->ptTempl[element[0]].y};
+ CvPoint templ_v02 = {pTF->ptTempl[element[2]].x - pTF->ptTempl[element[0]].x, pTF->ptTempl[element[2]].y - pTF->ptTempl[element[0]].y};
+ CvPoint prev_v01 = {pTF->face[element[1]].ptCenter.x - pTF->face[element[0]].ptCenter.x, pTF->face[element[1]].ptCenter.y - pTF->face[element[0]].ptCenter.y};
+ CvPoint prev_v02 = {pTF->face[element[2]].ptCenter.x - pTF->face[element[0]].ptCenter.x, pTF->face[element[2]].ptCenter.y - pTF->face[element[0]].ptCenter.y};
+ CvPoint new_v01 = {new_face[element[1]]->ptCenter.x - new_face[element[0]]->ptCenter.x, new_face[element[1]]->ptCenter.y - new_face[element[0]]->ptCenter.y};
+ double templ_d01 = sqrt((double)templ_v01.x*templ_v01.x + templ_v01.y*templ_v01.y);
+ double templ_d02 = sqrt((double)templ_v02.x*templ_v02.x + templ_v02.y*templ_v02.y);
+ double prev_d01 = sqrt((double)prev_v01.x*prev_v01.x + prev_v01.y*prev_v01.y);
+ double prev_d02 = sqrt((double)prev_v02.x*prev_v02.x + prev_v02.y*prev_v02.y);
+ double new_d01 = sqrt((double)new_v01.x*new_v01.x + new_v01.y*new_v01.y);
+ double scale = templ_d01 / new_d01;
+ double new_d02 = templ_d02 / scale;
+ double sin_a = double(prev_v01.x * prev_v02.y - prev_v01.y * prev_v02.x) / (prev_d01 * prev_d02);
+ double cos_a = cos(asin(sin_a));
+ double x = double(new_v01.x) * cos_a - double(new_v01.y) * sin_a;
+ double y = double(new_v01.x) * sin_a + double(new_v01.y) * cos_a;
+ x = x * new_d02 / new_d01;
+ y = y * new_d02 / new_d01;
+ CvPoint new_v02 = {int(x + 0.5), int(y + 0.5)};
+ face[element[2]].iColor = 0;
+ face[element[2]].iEnergy = 0;
+ face[element[2]].nRectsInThis = 0;
+ face[element[2]].nRectsOnBottom = 0;
+ face[element[2]].nRectsOnLeft = 0;
+ face[element[2]].nRectsOnRight = 0;
+ face[element[2]].nRectsOnTop = 0;
+ face[element[2]].ptCenter.x = new_v02.x + new_face[element[0]]->ptCenter.x;
+ face[element[2]].ptCenter.y = new_v02.y + new_face[element[0]]->ptCenter.y;
+ face[element[2]].r.width = int(double(pTF->rTempl[element[2]].width) / (scale) + 0.5);
+ face[element[2]].r.height = int(double(pTF->rTempl[element[2]].height) / (scale) + 0.5);
+ face[element[2]].r.x = face[element[2]].ptCenter.x - (face[element[2]].r.width + 1) / 2;
+ face[element[2]].r.y = face[element[2]].ptCenter.y - (face[element[2]].r.height + 1) / 2;
+ _ASSERT(face[LEYE].r.x + face[LEYE].r.width <= face[REYE].r.x);
+ }
+ return found;
+} // int ChoiceTrackingFace3(const CvTrackingRect* tr_face, CvTrackingRect* new_face, int& new_energy)
+
+inline int GetEnergy(CvTrackingRect** ppNew, const CvTrackingRect* pPrev, CvPoint* ptTempl, CvRect* rTempl)
+{
+ int energy = 0;
+ CvPoint ptNew[NUM_FACE_ELEMENTS];
+ CvPoint ptPrev[NUM_FACE_ELEMENTS];
+ for (int i = 0; i < NUM_FACE_ELEMENTS; i++)
+ {
+ ptNew[i] = ppNew[i]->ptCenter;
+ ptPrev[i] = pPrev[i].ptCenter;
+ energy += ppNew[i]->iEnergy - 2 * ppNew[i]->nRectsInThis;
+ }
+ double dx = 0, dy = 0, scale = 1, rotate = 0;
+ double e_templ = CalculateTransformationLMS3(ptTempl, ptNew, &scale, &rotate, &dx, &dy);
+ double e_prev = CalculateTransformationLMS3_0(ptPrev, ptNew);
+ double w_eye = double(ppNew[LEYE]->r.width + ppNew[REYE]->r.width) * scale / 2.0;
+ double h_eye = double(ppNew[LEYE]->r.height + ppNew[REYE]->r.height) * scale / 2.0;
+ double w_mouth = double(ppNew[MOUTH]->r.width) * scale;
+ double h_mouth = double(ppNew[MOUTH]->r.height) * scale;
+ energy +=
+ int(512.0 * (e_prev + 16.0 * e_templ)) +
+ 4 * pow2(ppNew[LEYE]->r.width - ppNew[REYE]->r.width) +
+ 4 * pow2(ppNew[LEYE]->r.height - ppNew[REYE]->r.height) +
+ 4 * (int)pow(w_eye - double(rTempl[LEYE].width + rTempl[REYE].width) / 2.0, 2) +
+ 2 * (int)pow(h_eye - double(rTempl[LEYE].height + rTempl[REYE].height) / 2.0, 2) +
+ 1 * (int)pow(w_mouth - double(rTempl[MOUTH].width), 2) +
+ 1 * (int)pow(h_mouth - double(rTempl[MOUTH].height), 2) +
+ 0;
+ return energy;
+}
+
+inline int GetEnergy2(CvTrackingRect** ppNew, const CvTrackingRect* pPrev, CvPoint* ptTempl, CvRect* rTempl, int* element)
+{
+ CvPoint new_v = {ppNew[element[0]]->ptCenter.x - ppNew[element[1]]->ptCenter.x,
+ ppNew[element[0]]->ptCenter.y - ppNew[element[1]]->ptCenter.y};
+ CvPoint prev_v = {pPrev[element[0]].ptCenter.x - pPrev[element[1]].ptCenter.x,
+ pPrev[element[0]].ptCenter.y - pPrev[element[1]].ptCenter.y};
+ double new_d = sqrt((double)new_v.x*new_v.x + new_v.y*new_v.y);
+ double prev_d = sqrt((double)prev_v.x*prev_v.x + prev_v.y*prev_v.y);
+ double dx = ptTempl[element[0]].x - ptTempl[element[1]].x;
+ double dy = ptTempl[element[0]].y - ptTempl[element[1]].y;
+ double templ_d = sqrt(dx*dx + dy*dy);
+ double scale_templ = new_d / templ_d;
+ double w0 = (double)ppNew[element[0]]->r.width * scale_templ;
+ double h0 = (double)ppNew[element[0]]->r.height * scale_templ;
+ double w1 = (double)ppNew[element[1]]->r.width * scale_templ;
+ double h1 = (double)ppNew[element[1]]->r.height * scale_templ;
+
+ int energy = ppNew[element[0]]->iEnergy + ppNew[element[1]]->iEnergy +
+ - 2 * (ppNew[element[0]]->nRectsInThis - ppNew[element[1]]->nRectsInThis) +
+ (int)pow(w0 - (double)rTempl[element[0]].width, 2) +
+ (int)pow(h0 - (double)rTempl[element[0]].height, 2) +
+ (int)pow(w1 - (double)rTempl[element[1]].width, 2) +
+ (int)pow(h1 - (double)rTempl[element[1]].height, 2) +
+ (int)pow(new_d - prev_d, 2) +
+ 0;
+
+ return energy;
+}
+
+inline double CalculateTransformationLMS3( CvPoint* pTemplPoints,
+ CvPoint* pSrcPoints,
+ double* pdbAverageScale,
+ double* pdbAverageRotate,
+ double* pdbAverageShiftX,
+ double* pdbAverageShiftY )
+{
+// double WS = 0;
+ double dbAverageScale = 1;
+ double dbAverageRotate = 0;
+ double dbAverageShiftX = 0;
+ double dbAverageShiftY = 0;
+ double dbLMS = 0;
+
+ _ASSERT( NULL != pTemplPoints);
+ _ASSERT( NULL != pSrcPoints);
+
+ double dbXt = double(pTemplPoints[0].x + pTemplPoints[1].x + pTemplPoints[2].x) / 3.0;
+ double dbYt = double(pTemplPoints[0].y + pTemplPoints[1].y + pTemplPoints[2].y ) / 3.0;
+ double dbXs = double(pSrcPoints[0].x + pSrcPoints[1].x + pSrcPoints[2].x) / 3.0;
+ double dbYs = double(pSrcPoints[0].y + pSrcPoints[1].y + pSrcPoints[2].y) / 3.0;
+
+ double dbXtXt = double(pow2(pTemplPoints[0].x) + pow2(pTemplPoints[1].x) + pow2(pTemplPoints[2].x)) / 3.0;
+ double dbYtYt = double(pow2(pTemplPoints[0].y) + pow2(pTemplPoints[1].y) + pow2(pTemplPoints[2].y)) / 3.0;
+
+ double dbXsXs = double(pow2(pSrcPoints[0].x) + pow2(pSrcPoints[1].x) + pow2(pSrcPoints[2].x)) / 3.0;
+ double dbYsYs = double(pow2(pSrcPoints[0].y) + pow2(pSrcPoints[1].y) + pow2(pSrcPoints[2].y)) / 3.0;
+
+ double dbXtXs = double(pTemplPoints[0].x * pSrcPoints[0].x +
+ pTemplPoints[1].x * pSrcPoints[1].x +
+ pTemplPoints[2].x * pSrcPoints[2].x) / 3.0;
+ double dbYtYs = double(pTemplPoints[0].y * pSrcPoints[0].y +
+ pTemplPoints[1].y * pSrcPoints[1].y +
+ pTemplPoints[2].y * pSrcPoints[2].y) / 3.0;
+
+ double dbXtYs = double(pTemplPoints[0].x * pSrcPoints[0].y +
+ pTemplPoints[1].x * pSrcPoints[1].y +
+ pTemplPoints[2].x * pSrcPoints[2].y) / 3.0;
+ double dbYtXs = double(pTemplPoints[0].y * pSrcPoints[0].x +
+ pTemplPoints[1].y * pSrcPoints[1].x +
+ pTemplPoints[2].y * pSrcPoints[2].x ) / 3.0;
+
+ dbXtXt -= dbXt * dbXt;
+ dbYtYt -= dbYt * dbYt;
+
+ dbXsXs -= dbXs * dbXs;
+ dbYsYs -= dbYs * dbYs;
+
+ dbXtXs -= dbXt * dbXs;
+ dbYtYs -= dbYt * dbYs;
+
+ dbXtYs -= dbXt * dbYs;
+ dbYtXs -= dbYt * dbXs;
+
+ dbAverageRotate = atan2( dbXtYs - dbYtXs, dbXtXs + dbYtYs );
+
+ double cosR = cos(dbAverageRotate);
+ double sinR = sin(dbAverageRotate);
+ double del = dbXsXs + dbYsYs;
+ if( del != 0 )
+ {
+ dbAverageScale = (double(dbXtXs + dbYtYs) * cosR + double(dbXtYs - dbYtXs) * sinR) / del;
+ dbLMS = dbXtXt + dbYtYt - ((double)pow(dbXtXs + dbYtYs,2) + (double)pow(dbXtYs - dbYtXs,2)) / del;
+ }
+
+ dbAverageShiftX = double(dbXt) - dbAverageScale * (double(dbXs) * cosR + double(dbYs) * sinR);
+ dbAverageShiftY = double(dbYt) - dbAverageScale * (double(dbYs) * cosR - double(dbXs) * sinR);
+
+ if( pdbAverageScale != NULL ) *pdbAverageScale = dbAverageScale;
+ if( pdbAverageRotate != NULL ) *pdbAverageRotate = dbAverageRotate;
+ if( pdbAverageShiftX != NULL ) *pdbAverageShiftX = dbAverageShiftX;
+ if( pdbAverageShiftY != NULL ) *pdbAverageShiftY = dbAverageShiftY;
+
+ _ASSERT(dbLMS >= 0);
+ return dbLMS;
+}
+
+inline double CalculateTransformationLMS3_0( CvPoint* pTemplPoints, CvPoint* pSrcPoints)
+{
+ double dbLMS = 0;
+
+ _ASSERT( NULL != pTemplPoints);
+ _ASSERT( NULL != pSrcPoints);
+
+ double dbXt = double(pTemplPoints[0].x + pTemplPoints[1].x + pTemplPoints[2].x) / 3.0;
+ double dbYt = double(pTemplPoints[0].y + pTemplPoints[1].y + pTemplPoints[2].y ) / 3.0;
+ double dbXs = double(pSrcPoints[0].x + pSrcPoints[1].x + pSrcPoints[2].x) / 3.0;
+ double dbYs = double(pSrcPoints[0].y + pSrcPoints[1].y + pSrcPoints[2].y) / 3.0;
+
+ double dbXtXt = double(pow2(pTemplPoints[0].x) + pow2(pTemplPoints[1].x) + pow2(pTemplPoints[2].x)) / 3.0;
+ double dbYtYt = double(pow2(pTemplPoints[0].y) + pow2(pTemplPoints[1].y) + pow2(pTemplPoints[2].y)) / 3.0;
+
+ double dbXsXs = double(pow2(pSrcPoints[0].x) + pow2(pSrcPoints[1].x) + pow2(pSrcPoints[2].x)) / 3.0;
+ double dbYsYs = double(pow2(pSrcPoints[0].y) + pow2(pSrcPoints[1].y) + pow2(pSrcPoints[2].y)) / 3.0;
+
+ double dbXtXs = double(pTemplPoints[0].x * pSrcPoints[0].x +
+ pTemplPoints[1].x * pSrcPoints[1].x +
+ pTemplPoints[2].x * pSrcPoints[2].x) / 3.0;
+ double dbYtYs = double(pTemplPoints[0].y * pSrcPoints[0].y +
+ pTemplPoints[1].y * pSrcPoints[1].y +
+ pTemplPoints[2].y * pSrcPoints[2].y) / 3.0;
+
+ double dbXtYs = double(pTemplPoints[0].x * pSrcPoints[0].y +
+ pTemplPoints[1].x * pSrcPoints[1].y +
+ pTemplPoints[2].x * pSrcPoints[2].y) / 3.0;
+ double dbYtXs = double(pTemplPoints[0].y * pSrcPoints[0].x +
+ pTemplPoints[1].y * pSrcPoints[1].x +
+ pTemplPoints[2].y * pSrcPoints[2].x ) / 3.0;
+
+ dbXtXt -= dbXt * dbXt;
+ dbYtYt -= dbYt * dbYt;
+
+ dbXsXs -= dbXs * dbXs;
+ dbYsYs -= dbYs * dbYs;
+
+ dbXtXs -= dbXt * dbXs;
+ dbYtYs -= dbYt * dbYs;
+
+ dbXtYs -= dbXt * dbYs;
+ dbYtXs -= dbYt * dbXs;
+
+ double del = dbXsXs + dbYsYs;
+ if( del != 0 )
+ dbLMS = dbXtXt + dbYtYt - ((double)pow(dbXtXs + dbYtYs,2) + (double)pow(dbXtYs - dbYtXs,2)) / del;
+ return dbLMS;
+}
+
diff --git a/cvaux/src/cvvideo.cpp b/cvaux/src/cvvideo.cpp
new file mode 100644
index 0000000..0fc022a
--- /dev/null
+++ b/cvaux/src/cvvideo.cpp
@@ -0,0 +1,84 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+CV_IMPL void
+cvDeInterlace( const CvArr* framearr, CvArr* fieldEven, CvArr* fieldOdd )
+{
+ CV_FUNCNAME("cvDeInterlace");
+
+ __BEGIN__;
+
+ CvMat frame_stub, *frame = (CvMat*)framearr;
+ CvMat even_stub, *even = (CvMat*)fieldEven;
+ CvMat odd_stub, *odd = (CvMat*)fieldOdd;
+ CvSize size;
+ int y;
+
+ CV_CALL( frame = cvGetMat( frame, &frame_stub ));
+ CV_CALL( even = cvGetMat( even, &even_stub ));
+ CV_CALL( odd = cvGetMat( odd, &odd_stub ));
+
+ if( !CV_ARE_TYPES_EQ( frame, even ) || !CV_ARE_TYPES_EQ( frame, odd ))
+ CV_ERROR( CV_StsUnmatchedFormats, "All the input images must have the same type" );
+
+ if( frame->cols != even->cols || frame->cols != odd->cols ||
+ frame->rows != even->rows*2 || odd->rows != even->rows )
+ CV_ERROR( CV_StsUnmatchedSizes, "Uncorrelated sizes of the input image and output fields" );
+
+ size = cvGetMatSize( even );
+ size.width *= CV_ELEM_SIZE( even->type );
+
+ for( y = 0; y < size.height; y++ )
+ {
+ memcpy( even->data.ptr + even->step*y,
+ frame->data.ptr + frame->step*y*2, size.width );
+ memcpy( odd->data.ptr + even->step*y,
+ frame->data.ptr + frame->step*(y*2+1), size.width );
+ }
+
+ __END__;
+}
+
+/* End of file. */
+
+
diff --git a/cvaux/src/decomppoly.cpp b/cvaux/src/decomppoly.cpp
new file mode 100644
index 0000000..713a378
--- /dev/null
+++ b/cvaux/src/decomppoly.cpp
@@ -0,0 +1,629 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+#if 0
+
+#include <malloc.h>
+//#include "decomppoly.h"
+
+#define ZERO_CLOSE 0.00001f
+#define ONE_CLOSE 0.99999f
+
+#define CHECK_COLLINEARITY(vec1_x,vec1_y,vec2_x,vec2_y) \
+ if( vec1_x == 0 ) { \
+ if( vec1_y * vec2_y > 0 ) { \
+ return 0; \
+ } \
+ } \
+ else { \
+ if( vec1_x * vec2_x > 0 ) { \
+ return 0; \
+ } \
+ }
+
+// determines if edge number one lies in counterclockwise
+// earlier than edge number two
+inline int icvIsFirstEdgeClosier( int x0,
+ int y0,
+ int x0_end,
+ int y0_end,
+ int x1_end,
+ int y1_end,
+ int x2_end,
+ int y2_end )
+{
+ int mult, mult1, mult2;
+ int vec0_x, vec0_y;
+ int vec1_x, vec1_y;
+ int vec2_x, vec2_y;
+
+ vec0_x = x0_end - x0;
+ vec0_y = y0_end - y0;
+ vec1_x = x1_end - x0;
+ vec1_y = y1_end - y0;
+ vec2_x = x2_end - x0;
+ vec2_y = y2_end - y0;
+
+ mult1 = vec1_x * vec0_y - vec0_x * vec1_y;
+ mult2 = vec2_x * vec0_y - vec0_x * vec2_y;
+
+ if( mult1 == 0 ) {
+ CHECK_COLLINEARITY( vec0_x, vec0_y, vec1_x, vec1_y );
+ }
+ if( mult2 == 0 ) {
+ CHECK_COLLINEARITY( vec0_x, vec0_y, vec2_x, vec2_y );
+ }
+ if( mult1 > 0 && mult2 < 0 ) {
+ return 1;
+ }
+ if( mult1 < 0 && mult2 > 0 ) {
+ return -1;
+ }
+
+ mult = vec1_x * vec2_y - vec2_x * vec1_y;
+ if( mult == 0 ) {
+ CHECK_COLLINEARITY( vec1_x, vec1_y, vec2_x, vec2_y );
+ }
+
+ if( mult1 > 0 )
+ {
+ if( mult > 0 ) {
+ return -1;
+ }
+ else {
+ return 1;
+ }
+ } // if( mult1 > 0 )
+ else
+ {
+ if( mult1 != 0 ) {
+ if( mult > 0 ) {
+ return 1;
+ }
+ else {
+ return -1;
+ }
+ } // if( mult1 != 0 )
+ else {
+ if( mult2 > 0 ) {
+ return -1;
+ }
+ else {
+ return 1;
+ }
+ } // if( mult1 != 0 ) else
+
+ } // if( mult1 > 0 ) else
+
+} // icvIsFirstEdgeClosier
+
+bool icvEarCutTriangulation( CvPoint* contour,
+ int num,
+ int* outEdges,
+ int* numEdges )
+{
+ int i;
+ int notFoundFlag = 0;
+ int begIndex = -1;
+ int isInternal;
+ int currentNum = num;
+ int index1, index2, index3;
+ int ix0, iy0, ix1, iy1, ix2, iy2;
+ int x1, y1, x2, y2, x3, y3;
+ int dx1, dy1, dx2, dy2;
+ int* pointExist = ( int* )0;
+ int det, det1, det2;
+ float t1, t2;
+
+ (*numEdges) = 0;
+
+ if( num <= 2 ) {
+ return false;
+ }
+
+ pointExist = ( int* )malloc( num * sizeof( int ) );
+
+ for( i = 0; i < num; i ++ ) {
+ pointExist[i] = 1;
+ }
+
+ for( i = 0; i < num; i ++ ) {
+ outEdges[ (*numEdges) * 2 ] = i;
+ if( i != num - 1 ) {
+ outEdges[ (*numEdges) * 2 + 1 ] = i + 1;
+ }
+ else {
+ outEdges[ (*numEdges) * 2 + 1 ] = 0;
+ }
+ (*numEdges) ++;
+ } // for( i = 0; i < num; i ++ )
+
+ // initializing data before while cycle
+ index1 = 0;
+ index2 = 1;
+ index3 = 2;
+ x1 = contour[ index1 ].x;
+ y1 = contour[ index1 ].y;
+ x2 = contour[ index2 ].x;
+ y2 = contour[ index2 ].y;
+ x3 = contour[ index3 ].x;
+ y3 = contour[ index3 ].y;
+
+ while( currentNum > 3 )
+ {
+ dx1 = x2 - x1;
+ dy1 = y2 - y1;
+ dx2 = x3 - x2;
+ dy2 = y3 - y2;
+ if( dx1 * dy2 - dx2 * dy1 < 0 ) // convex condition
+ {
+ // checking for noncrossing edge
+ ix1 = x3 - x1;
+ iy1 = y3 - y1;
+ isInternal = 1;
+ for( i = 0; i < num; i ++ )
+ {
+ if( i != num - 1 ) {
+ ix2 = contour[ i + 1 ].x - contour[ i ].x;
+ iy2 = contour[ i + 1 ].y - contour[ i ].y;
+ }
+ else {
+ ix2 = contour[ 0 ].x - contour[ i ].x;
+ iy2 = contour[ 0 ].y - contour[ i ].y;
+ }
+ ix0 = contour[ i ].x - x1;
+ iy0 = contour[ i ].y - y1;
+
+ det = ix2 * iy1 - ix1 * iy2;
+ det1 = ix2 * iy0 - ix0 * iy2;
+ if( det != 0.0f )
+ {
+ t1 = ( ( float )( det1 ) ) / det;
+ if( t1 > ZERO_CLOSE && t1 < ONE_CLOSE )
+ {
+ det2 = ix1 * iy0 - ix0 * iy1;
+ t2 = ( ( float )( det2 ) ) / det;
+ if( t2 > ZERO_CLOSE && t2 < ONE_CLOSE ) {
+ isInternal = 0;
+ }
+
+ } // if( t1 > ZERO_CLOSE && t1 < ONE_CLOSE )
+
+ } // if( det != 0.0f )
+
+ } // for( i = 0; i < (*numEdges); i ++ )
+
+ if( isInternal )
+ {
+ // this edge is internal
+ notFoundFlag = 0;
+ outEdges[ (*numEdges) * 2 ] = index1;
+ outEdges[ (*numEdges) * 2 + 1 ] = index3;
+ (*numEdges) ++;
+ pointExist[ index2 ] = 0;
+ index2 = index3;
+ x2 = x3;
+ y2 = y3;
+ currentNum --;
+ if( currentNum >= 3 ) {
+ do {
+ index3 ++;
+ if( index3 == num ) {
+ index3 = 0;
+ }
+ } while( !pointExist[ index3 ] );
+ x3 = contour[ index3 ].x;
+ y3 = contour[ index3 ].y;
+ } // if( currentNum >= 3 )
+
+ } // if( isInternal )
+ else {
+ // this edge intersects some other initial edges
+ if( !notFoundFlag ) {
+ notFoundFlag = 1;
+ begIndex = index1;
+ }
+ index1 = index2;
+ x1 = x2;
+ y1 = y2;
+ index2 = index3;
+ x2 = x3;
+ y2 = y3;
+ do {
+ index3 ++;
+ if( index3 == num ) {
+ index3 = 0;
+ }
+ if( index3 == begIndex ) {
+ if( pointExist ) {
+ free( pointExist );
+ }
+ return false;
+ }
+ } while( !pointExist[ index3 ] );
+ x3 = contour[ index3 ].x;
+ y3 = contour[ index3 ].y;
+ } // if( isInternal ) else
+
+ } // if( dx1 * dy2 - dx2 * dy1 < 0 )
+ else
+ {
+ if( !notFoundFlag ) {
+ notFoundFlag = 1;
+ begIndex = index1;
+ }
+ index1 = index2;
+ x1 = x2;
+ y1 = y2;
+ index2 = index3;
+ x2 = x3;
+ y2 = y3;
+ do {
+ index3 ++;
+ if( index3 == num ) {
+ index3 = 0;
+ }
+ if( index3 == begIndex ) {
+ if( pointExist ) {
+ free( pointExist );
+ }
+ return false;
+ }
+ } while( !pointExist[ index3 ] );
+ x3 = contour[ index3 ].x;
+ y3 = contour[ index3 ].y;
+ } // if( dx1 * dy2 - dx2 * dy1 < 0 ) else
+
+ } // while( currentNum > 3 )
+
+ if( pointExist ) {
+ free( pointExist );
+ }
+
+ return true;
+
+} // icvEarCutTriangulation
+
+inline bool icvFindTwoNeighbourEdges( CvPoint* contour,
+ int* edges,
+ int numEdges,
+ int vtxIdx,
+ int mainEdgeIdx,
+ int* leftEdgeIdx,
+ int* rightEdgeIdx )
+{
+ int i;
+ int compRes;
+ int vec0_x, vec0_y;
+ int x0, y0, x0_end, y0_end;
+ int x1_left = 0, y1_left = 0, x1_right = 0, y1_right = 0, x2, y2;
+
+ (*leftEdgeIdx) = -1;
+ (*rightEdgeIdx) = -1;
+
+ if( edges[ mainEdgeIdx * 2 ] == vtxIdx ) {
+ x0 = contour[ vtxIdx ].x;
+ y0 = contour[ vtxIdx ].y;
+ x0_end = contour[ edges[ mainEdgeIdx * 2 + 1 ] ].x;
+ y0_end = contour[ edges[ mainEdgeIdx * 2 + 1 ] ].y;
+ vec0_x = x0_end - x0;
+ vec0_y = y0_end - y0;
+ }
+ else {
+ //x0 = contour[ edges[ mainEdgeIdx * 2 ] ].x;
+ //y0 = contour[ edges[ mainEdgeIdx * 2 ] ].y;
+ //x0_end = contour[ vtxIdx ].x;
+ //y0_end = contour[ vtxIdx ].y;
+ x0 = contour[ vtxIdx ].x;
+ y0 = contour[ vtxIdx ].y;
+ x0_end = contour[ edges[ mainEdgeIdx * 2 ] ].x;
+ y0_end = contour[ edges[ mainEdgeIdx * 2 ] ].y;
+ vec0_x = x0_end - x0;
+ vec0_y = y0_end - y0;
+ }
+
+ for( i = 0; i < numEdges; i ++ )
+ {
+ if( ( i != mainEdgeIdx ) &&
+ ( edges[ i * 2 ] == vtxIdx || edges[ i * 2 + 1 ] == vtxIdx ) )
+ {
+ if( (*leftEdgeIdx) == -1 )
+ {
+ (*leftEdgeIdx) = (*rightEdgeIdx) = i;
+ if( edges[ i * 2 ] == vtxIdx ) {
+ x1_left = x1_right = contour[ edges[ i * 2 + 1 ] ].x;
+ y1_left = y1_right = contour[ edges[ i * 2 + 1 ] ].y;
+ }
+ else {
+ x1_left = x1_right = contour[ edges[ i * 2 ] ].x;
+ y1_left = y1_right = contour[ edges[ i * 2 ] ].y;
+ }
+
+ } // if( (*leftEdgeIdx) == -1 )
+ else
+ {
+ if( edges[ i * 2 ] == vtxIdx ) {
+ x2 = contour[ edges[ i * 2 + 1 ] ].x;
+ y2 = contour[ edges[ i * 2 + 1 ] ].y;
+ }
+ else {
+ x2 = contour[ edges[ i * 2 ] ].x;
+ y2 = contour[ edges[ i * 2 ] ].y;
+ }
+
+ compRes = icvIsFirstEdgeClosier( x0,
+ y0, x0_end, y0_end, x1_left, y1_left, x2, y2 );
+ if( compRes == 0 ) {
+ return false;
+ }
+ if( compRes == -1 ) {
+ (*leftEdgeIdx) = i;
+ x1_left = x2;
+ y1_left = y2;
+ } // if( compRes == -1 )
+ else {
+ compRes = icvIsFirstEdgeClosier( x0,
+ y0, x0_end, y0_end, x1_right, y1_right, x2, y2 );
+ if( compRes == 0 ) {
+ return false;
+ }
+ if( compRes == 1 ) {
+ (*rightEdgeIdx) = i;
+ x1_right = x2;
+ y1_right = y2;
+ }
+
+ } // if( compRes == -1 ) else
+
+ } // if( (*leftEdgeIdx) == -1 ) else
+
+ } // if( ( i != mainEdgesIdx ) && ...
+
+ } // for( i = 0; i < numEdges; i ++ )
+
+ return true;
+
+} // icvFindTwoNeighbourEdges
+
+bool icvFindReferences( CvPoint* contour,
+ int num,
+ int* outEdges,
+ int* refer,
+ int* numEdges )
+{
+ int i;
+ int currPntIdx;
+ int leftEdgeIdx, rightEdgeIdx;
+
+ if( icvEarCutTriangulation( contour, num, outEdges, numEdges ) )
+ {
+ for( i = 0; i < (*numEdges); i ++ )
+ {
+ refer[ i * 4 ] = -1;
+ refer[ i * 4 + 1 ] = -1;
+ refer[ i * 4 + 2 ] = -1;
+ refer[ i * 4 + 3 ] = -1;
+ } // for( i = 0; i < (*numEdges); i ++ )
+
+ for( i = 0; i < (*numEdges); i ++ )
+ {
+ currPntIdx = outEdges[ i * 2 ];
+ if( !icvFindTwoNeighbourEdges( contour,
+ outEdges, (*numEdges), currPntIdx,
+ i, &leftEdgeIdx, &rightEdgeIdx ) )
+ {
+ return false;
+ } // if( !icvFindTwoNeighbourEdges( contour, ...
+ else
+ {
+ if( outEdges[ leftEdgeIdx * 2 ] == currPntIdx ) {
+ if( refer[ i * 4 ] == -1 ) {
+ refer[ i * 4 ] = ( leftEdgeIdx << 2 );
+ }
+ }
+ else {
+ if( refer[ i * 4 ] == -1 ) {
+ refer[ i * 4 ] = ( leftEdgeIdx << 2 ) | 2;
+ }
+ }
+ if( outEdges[ rightEdgeIdx * 2 ] == currPntIdx ) {
+ if( refer[ i * 4 + 1 ] == -1 ) {
+ refer[ i * 4 + 1 ] = ( rightEdgeIdx << 2 ) | 3;
+ }
+ }
+ else {
+ if( refer[ i * 4 + 1 ] == -1 ) {
+ refer[ i * 4 + 1 ] = ( rightEdgeIdx << 2 ) | 1;
+ }
+ }
+
+ } // if( !icvFindTwoNeighbourEdges( contour, ... ) else
+
+ currPntIdx = outEdges[ i * 2 + 1 ];
+ if( i == 18 ) {
+ i = i;
+ }
+ if( !icvFindTwoNeighbourEdges( contour,
+ outEdges, (*numEdges), currPntIdx,
+ i, &leftEdgeIdx, &rightEdgeIdx ) )
+ {
+ return false;
+ } // if( !icvFindTwoNeighbourEdges( contour, ...
+ else
+ {
+ if( outEdges[ leftEdgeIdx * 2 ] == currPntIdx ) {
+ if( refer[ i * 4 + 3 ] == -1 ) {
+ refer[ i * 4 + 3 ] = ( leftEdgeIdx << 2 );
+ }
+ }
+ else {
+ if( refer[ i * 4 + 3 ] == -1 ) {
+ refer[ i * 4 + 3 ] = ( leftEdgeIdx << 2 ) | 2;
+ }
+ }
+ if( outEdges[ rightEdgeIdx * 2 ] == currPntIdx ) {
+ if( refer[ i * 4 + 2 ] == -1 ) {
+ refer[ i * 4 + 2 ] = ( rightEdgeIdx << 2 ) | 3;
+ }
+ }
+ else {
+ if( refer[ i * 4 + 2 ] == -1 ) {
+ refer[ i * 4 + 2 ] = ( rightEdgeIdx << 2 ) | 1;
+ }
+ }
+
+ } // if( !icvFindTwoNeighbourEdges( contour, ... ) else
+
+ } // for( i = 0; i < (*numEdges); i ++ )
+
+ } // if( icvEarCutTriangulation( contour, num, outEdges, numEdges ) )
+ else {
+ return false;
+ } // if( icvEarCutTriangulation( contour, num, outEdges, ... ) else
+
+ return true;
+
+} // icvFindReferences
+
+void cvDecompPoly( CvContour* cont,
+ CvSubdiv2D** subdiv,
+ CvMemStorage* storage )
+{
+ int* memory;
+ CvPoint* contour;
+ int* outEdges;
+ int* refer;
+ CvSubdiv2DPoint** pntsPtrs;
+ CvQuadEdge2D** edgesPtrs;
+ int numVtx;
+ int numEdges;
+ int i;
+ CvSeqReader reader;
+ CvPoint2D32f pnt;
+ CvQuadEdge2D* quadEdge;
+
+ numVtx = cont -> total;
+ if( numVtx < 3 ) {
+ return;
+ }
+
+ *subdiv = ( CvSubdiv2D* )0;
+
+ memory = ( int* )malloc( sizeof( int ) * ( numVtx * 2
+ + numVtx * numVtx * 2 * 5 )
+ + sizeof( CvQuadEdge2D* ) * ( numVtx * numVtx )
+ + sizeof( CvSubdiv2DPoint* ) * ( numVtx * 2 ) );
+ contour = ( CvPoint* )memory;
+ outEdges = ( int* )( contour + numVtx );
+ refer = outEdges + numVtx * numVtx * 2;
+ edgesPtrs = ( CvQuadEdge2D** )( refer + numVtx * numVtx * 4 );
+ pntsPtrs = ( CvSubdiv2DPoint** )( edgesPtrs + numVtx * numVtx );
+
+ cvStartReadSeq( ( CvSeq* )cont, &reader, 0 );
+ for( i = 0; i < numVtx; i ++ )
+ {
+ CV_READ_SEQ_ELEM( (contour[ i ]), reader );
+ } // for( i = 0; i < numVtx; i ++ )
+
+ if( !icvFindReferences( contour, numVtx, outEdges, refer, &numEdges ) )
+ {
+ free( memory );
+ return;
+ } // if( !icvFindReferences( contour, numVtx, outEdges, refer, ...
+
+ *subdiv = cvCreateSubdiv2D( CV_SEQ_KIND_SUBDIV2D,
+ sizeof( CvSubdiv2D ),
+ sizeof( CvSubdiv2DPoint ),
+ sizeof( CvQuadEdge2D ),
+ storage );
+
+ for( i = 0; i < numVtx; i ++ )
+ {
+ pnt.x = ( float )contour[ i ].x;
+ pnt.y = ( float )contour[ i ].y;
+ pntsPtrs[ i ] = cvSubdiv2DAddPoint( *subdiv, pnt, 0 );
+ } // for( i = 0; i < numVtx; i ++ )
+
+ for( i = 0; i < numEdges; i ++ )
+ {
+ edgesPtrs[ i ] = ( CvQuadEdge2D* )
+ ( cvSubdiv2DMakeEdge( *subdiv ) & 0xfffffffc );
+ } // for( i = 0; i < numEdges; i ++ )
+
+ for( i = 0; i < numEdges; i ++ )
+ {
+ quadEdge = edgesPtrs[ i ];
+ quadEdge -> next[ 0 ] =
+ ( ( CvSubdiv2DEdge )edgesPtrs[ refer[ i * 4 ] >> 2 ] )
+ | ( refer[ i * 4 ] & 3 );
+ quadEdge -> next[ 1 ] =
+ ( ( CvSubdiv2DEdge )edgesPtrs[ refer[ i * 4 + 1 ] >> 2 ] )
+ | ( refer[ i * 4 + 1 ] & 3 );
+ quadEdge -> next[ 2 ] =
+ ( ( CvSubdiv2DEdge )edgesPtrs[ refer[ i * 4 + 2 ] >> 2 ] )
+ | ( refer[ i * 4 + 2 ] & 3 );
+ quadEdge -> next[ 3 ] =
+ ( ( CvSubdiv2DEdge )edgesPtrs[ refer[ i * 4 + 3 ] >> 2 ] )
+ | ( refer[ i * 4 + 3 ] & 3 );
+ quadEdge -> pt[ 0 ] = pntsPtrs[ outEdges[ i * 2 ] ];
+ quadEdge -> pt[ 1 ] = ( CvSubdiv2DPoint* )0;
+ quadEdge -> pt[ 2 ] = pntsPtrs[ outEdges[ i * 2 + 1 ] ];
+ quadEdge -> pt[ 3 ] = ( CvSubdiv2DPoint* )0;
+ } // for( i = 0; i < numEdges; i ++ )
+
+ (*subdiv) -> topleft.x = ( float )cont -> rect.x;
+ (*subdiv) -> topleft.y = ( float )cont -> rect.y;
+ (*subdiv) -> bottomright.x =
+ ( float )( cont -> rect.x + cont -> rect.width );
+ (*subdiv) -> bottomright.y =
+ ( float )( cont -> rect.y + cont -> rect.height );
+
+ free( memory );
+ return;
+
+} // cvDecompPoly
+
+#endif
+
+// End of file decomppoly.cpp
+
diff --git a/cvaux/src/enmin.cpp b/cvaux/src/enmin.cpp
new file mode 100644
index 0000000..e083380
--- /dev/null
+++ b/cvaux/src/enmin.cpp
@@ -0,0 +1,1381 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+#if 0
+
+//#include "windows.h"
+
+//#define ALPHA_EXPANSION
+
+#ifndef ALPHA_EXPANSION
+ #define ALPHA_BETA_EXCHANGE
+#endif
+
+#define MAX_LABEL 20
+
+#define CV_MODULE(xxx) \
+ ( (xxx) < 0 ? -(xxx) : (xxx) )
+
+#define CV_MAX3(xxx1,xxx2,xxx3) \
+ ( (xxx1) > (xxx2) && (xxx1) > (xxx3) ? (xxx1) : \
+ (xxx2) > (xxx3) ? (xxx2) : (xxx3) )
+
+#define CV_MIN2(xxx1,xxx2) \
+ ( (xxx1) < (xxx2) ? (xxx1) : (xxx2) )
+
+#define getSizeForGraph(xxxType) \
+ ( sizeof(xxxType) < 8 ? 8 : sizeof(xxxType) + 4 - sizeof(xxxType) % 4 )
+
+#define INT_INFINITY 1000000000
+#define MAX_DIFFERENCE 10
+
+
+// struct Vertex is used for storing vertices of graph
+// coord - coordinate corresponding pixel on the real image line
+struct Vertex
+{
+ CvGraphVtx vtx;
+ int coord;
+};
+
+// struct Edge is used for storing edges of graph
+// weight - weight of the edge ( maximum flow via the edge )
+// flow - current flow via the edge
+// srcVtx - coordinate of source vertex on the real image line
+// destVtx - coordinate of destination vertex on the real image line
+struct Edge
+{
+ CV_GRAPH_EDGE_FIELDS()
+ int weight;
+ int flow;
+ int srcVtx;
+ int destVtx;
+};
+
+// function vFunc is energy function which determines the difference
+// between two labels ( alpha and beta )
+// alpha - label number one
+// beta - label number two
+inline int vFunc( int alpha, int beta )
+{
+ if( alpha == beta )
+ return 0;
+ else
+ return /*1*//*5*/10;
+}
+
+// function dFunc is energy function which determines energy of interaction
+// between pixel ( having coordinate xCoord ) and label
+// leftLine - line of left image
+// rightLine - line of right image
+// xCoord - coordinate of pixel on the left image
+// label - label corresponding to the pixel
+// width - width of the image line in pixels
+inline int dFunc( unsigned char* leftLine,
+ unsigned char* rightLine,
+ int xCoord,
+ int label,
+ int width)
+{
+ assert( xCoord >= 0 && xCoord < width );
+ int r, g, b;
+ int yCoord = xCoord + label;
+
+ if( yCoord >= width )
+ yCoord = width;
+ if( yCoord < 0 )
+ yCoord = 0;
+
+ r = leftLine[ 3 * xCoord ] - rightLine[ 3 * yCoord ];
+ g = leftLine[ 3 * xCoord + 1 ] - rightLine[ 3 * yCoord + 1 ];
+ b = leftLine[ 3 * xCoord + 2 ] - rightLine[ 3 * yCoord + 2 ];
+
+ r = CV_MODULE( r );
+ g = CV_MODULE( g );
+ b = CV_MODULE( b );
+
+ return CV_MAX3( r, g, b );
+}
+
+// function allocTempMem allocates all temporary memory needed for work
+// of some function
+// memPtr - pointer to pointer to the large block of memory
+// verticesPtr - pointer to pointer to block of memory for
+// temporary storing vertices
+// width - width of line in pixels
+void allocTempMem( int** memPtr,
+ int** verticesPtr,
+ int width )
+{
+ int* tempPtr = ( int* ) malloc( ( width + 2 ) * 7 * sizeof( int ) );
+ *verticesPtr = tempPtr;
+ *memPtr = *verticesPtr + width + 2;
+}
+
+// function freeTempMem frees all allocated by allocTempMem function memory
+// memPtr - pointer to pointer to the large block of memory
+// verticesPtr - pointer to pointer to block of memory for
+// temporary storing vertices
+void freeTempMem( int** memPtr,
+ int** verticesPtr )
+{
+ free( ( void* )( *verticesPtr ) );
+ *verticesPtr = NULL;
+ *memPtr = NULL;
+}
+
+// function makeGraph creates initial graph to find maximum flow in it
+// graphPtr - pointer to pointer to CvGraph structure to be filled
+// leftLine - pointer to the left image line
+// rightLine - pointer to the right image line
+// alpha - label number one for doing exchange
+// beta - label number two for doing exchange
+// corr - pointer to array of correspondences ( each element
+// of array includes disparity of pixel on right image
+// for pixel each on left image ). This pointer direct
+// to correspondence ofr one line only
+// width - width of image lines in pixels
+// storage - pointer to CvMemStorage structure which contains
+// memory storage
+void makeGraph( CvGraph** graphPtr,
+ unsigned char* leftLine,
+ unsigned char* rightLine,
+ int alpha,
+ int beta,
+ int* corr,
+ int width,
+ CvMemStorage* storage )
+{
+ int i;
+
+ if( *graphPtr ) {
+ cvClearGraph( *graphPtr );
+ }
+ /*else {*/
+ *graphPtr = cvCreateGraph( CV_SEQ_KIND_GRAPH | CV_GRAPH_FLAG_ORIENTED,
+ sizeof( CvGraph ),
+ getSizeForGraph( Vertex ),
+ getSizeForGraph( Edge ),
+ storage );
+ /*}*/
+
+ CvGraph* graph = *graphPtr;
+
+ #ifdef ALPHA_BETA_EXCHANGE
+
+ CvGraphVtx* newVtxPtr;
+ for( i = 0; i < width; i ++ )
+ {
+ if( corr[i] == alpha || corr[i] == beta ) {
+ cvGraphAddVtx( graph, NULL, &newVtxPtr );
+ ( ( Vertex* )newVtxPtr ) -> coord = i;
+ }
+ } /* for( i = 0; i < width; i ++ ) */
+ cvGraphAddVtx( graph, NULL, &newVtxPtr );
+ if( newVtxPtr )
+ ( ( Vertex* )newVtxPtr ) -> coord = -2; /* adding alpha vertex */
+ cvGraphAddVtx( graph, NULL, &newVtxPtr );
+ if( newVtxPtr )
+ ( ( Vertex* )newVtxPtr ) -> coord = -1; /* adding beta vertex */
+
+ int alphaVtx = graph -> total - 2;
+ int betaVtx = graph -> total - 1;
+ CvGraphEdge* newEdgePtr;
+ CvGraphVtx* vtxPtr;
+ if( graph -> total > 2 )
+ {
+ for( i = 0; i < alphaVtx; i ++ )
+ {
+ vtxPtr = cvGetGraphVtx( graph, i );
+
+ /* adding edge oriented from alpha vertex to current vertex */
+ cvGraphAddEdge( graph, alphaVtx, i, NULL, &newEdgePtr );
+ ( ( Edge* )newEdgePtr ) -> weight = dFunc( leftLine,
+ rightLine,
+ ( ( Vertex* )vtxPtr ) -> coord,
+ alpha,
+ width );
+ ( ( Edge* )newEdgePtr ) -> flow = 0;
+ if( i != 0 ) {
+ CvGraphVtx* tempVtxPtr = cvGetGraphVtx( graph, i - 1 );
+ /* if vertices are neighbours */
+ if( ( ( Vertex* )tempVtxPtr ) -> coord + 1 ==
+ ( ( Vertex* )vtxPtr ) -> coord )
+ {
+ ( ( Edge* )newEdgePtr ) -> weight +=
+ vFunc( corr[ ( ( Vertex* )tempVtxPtr ) -> coord ],
+ alpha );
+ /* adding neighbour edge oriented from current vertex
+ to the previous one */
+ CvGraphEdge* tempEdgePtr;
+ cvGraphAddEdge( graph, i, i - 1, NULL, &tempEdgePtr );
+ ( ( Edge* )tempEdgePtr ) -> weight = vFunc( alpha, beta );
+ ( ( Edge* )tempEdgePtr ) -> flow = 0;
+ ( ( Edge* )tempEdgePtr ) -> srcVtx =
+ ( ( Vertex* )vtxPtr ) -> coord;
+ ( ( Edge* )tempEdgePtr ) -> destVtx =
+ ( ( Vertex* )tempVtxPtr ) -> coord;
+ }
+ } /* if( i != 0 ) */
+ if( i != alphaVtx - 1 ) {
+ CvGraphVtx* tempVtxPtr = cvGetGraphVtx( graph, i + 1 );
+ /* if vertices are neighbours */
+ if( ( ( Vertex* )tempVtxPtr ) -> coord - 1 ==
+ ( ( Vertex* )vtxPtr ) -> coord )
+ {
+ ( ( Edge* )newEdgePtr ) -> weight +=
+ vFunc( corr[ ( ( Vertex* )tempVtxPtr ) -> coord ],
+ alpha );
+ /* adding neighbour edge oriented from current vertex
+ to the next one */
+ CvGraphEdge* tempEdgePtr;
+ cvGraphAddEdge( graph, i, i + 1, NULL, &tempEdgePtr );
+ ( ( Edge* )tempEdgePtr ) -> weight = vFunc( alpha, beta );
+ ( ( Edge* )tempEdgePtr ) -> flow = 0;
+ ( ( Edge* )tempEdgePtr ) -> srcVtx =
+ ( ( Vertex* )vtxPtr ) -> coord;
+ ( ( Edge* )tempEdgePtr ) -> destVtx =
+ ( ( Vertex* )tempVtxPtr ) -> coord;
+ }
+ } /* if( i != alphaVtx - 1 ) */
+ ( ( Edge* )newEdgePtr ) -> flow = 0;
+ ( ( Edge* )newEdgePtr ) -> srcVtx = -1; /* source vertex is alpha
+ vertex */
+ ( ( Edge* )newEdgePtr ) -> destVtx = ( ( Vertex* )vtxPtr ) -> coord;
+
+ /* adding edge oriented from current vertex to beta vertex */
+ cvGraphAddEdge( graph, i, betaVtx, NULL, &newEdgePtr );
+ ( ( Edge* )newEdgePtr ) -> weight = dFunc( leftLine,
+ rightLine,
+ ( ( Vertex* )vtxPtr ) -> coord,
+ beta,
+ width );
+ ( ( Edge* )newEdgePtr ) -> flow = 0;
+ if( i != 0 ) {
+ CvGraphVtx* tempVtxPtr = cvGetGraphVtx( graph, i - 1 );
+ /* if vertices are neighbours */
+ if( ( ( Vertex* )tempVtxPtr ) -> coord + 1 ==
+ ( ( Vertex* )vtxPtr ) -> coord )
+ {
+ ( ( Edge* )newEdgePtr ) -> weight +=
+ vFunc( corr[ ( ( Vertex* )tempVtxPtr ) -> coord ],
+ beta );
+ }
+ } /* if( i != 0 ) */
+ if( i != alphaVtx - 1 ) {
+ CvGraphVtx* tempVtxPtr = cvGetGraphVtx( graph, i + 1 );
+ /* if vertices are neighbours */
+ if( ( ( Vertex* )tempVtxPtr ) -> coord - 1 ==
+ ( ( Vertex* )vtxPtr ) -> coord )
+ {
+ ( ( Edge* )newEdgePtr ) -> weight +=
+ vFunc( corr[ ( ( Vertex* )tempVtxPtr ) -> coord ],
+ beta );
+ }
+ } /* if( i != alphaVtx - 1 ) */
+ ( ( Edge* )newEdgePtr ) -> flow = 0;
+ ( ( Edge* )newEdgePtr ) -> srcVtx =
+ ( ( Vertex* )vtxPtr ) -> coord;
+ ( ( Edge* )newEdgePtr ) -> destVtx = -2; /* destination vertex is
+ beta vertex */
+
+ } /* for( i = 0; i < graph -> total - 2; i ++ ) */
+
+ } /* if( graph -> total > 2 ) */
+
+ #endif /* #ifdef ALPHA_BETA_EXCHANGE */
+
+ #ifdef ALPHA_EXPANSION
+ #endif /* #ifdef ALPHA_EXPANSION */
+
+} /* makeGraph */
+
+// function makeHelpGraph creates help graph using initial graph
+// graph - pointer to initial graph ( represented by CvGraph
+// structure )
+// hlpGraphPtr - pointer to pointer to new help graph
+// storage - pointer to CvStorage structure
+// mem - pointer to memory allocated by allocTempMem function
+// vertices - pointer to memory allocated by allocTempMem function
+// verticesCountPtr- pointer to value containing number of vertices
+// in vertices array
+// width - width of image line in pixels
+int makeHelpGraph( CvGraph* graph,
+ CvGraph** hlpGraphPtr,
+ CvMemStorage* storage,
+ int* mem,
+ int* vertices,
+ int* verticesCountPtr,
+ int width )
+{
+ int u, v;
+ int* order = mem;
+ int* lengthArr = order + width + 2;
+ int s = graph -> total - 2; /* source vertex */
+ int t = graph -> total - 1; /* terminate vertex */
+ int orderFirst;
+ int orderCount;
+ int &verticesCount = *verticesCountPtr;
+ CvGraph* hlpGraph;
+
+ if( *hlpGraphPtr ) {
+ cvClearGraph( *hlpGraphPtr );
+ }
+ else {
+ *hlpGraphPtr = cvCreateGraph( CV_SEQ_KIND_GRAPH |
+ CV_GRAPH_FLAG_ORIENTED,
+ sizeof( CvGraph ),
+ getSizeForGraph( Vertex ),
+ getSizeForGraph( Edge ),
+ storage );
+ }
+
+ hlpGraph = *hlpGraphPtr;
+
+ /* initialization */
+ for( u = 0; u < graph -> total; u ++ )
+ {
+ lengthArr[ u ] = INT_INFINITY;
+ cvGraphAddVtx( hlpGraph, NULL, NULL );
+ } /* for( u = 0; u < graph -> total - 1; u ++ ) */
+
+ orderFirst = 0;
+ orderCount = 0;
+ verticesCount = 0;
+ lengthArr[ s ] = 0;
+
+ /* add vertex s to order */
+ order[ orderCount ] = s;
+ orderCount ++;
+
+ while( orderCount != orderFirst )
+ {
+ /* getting u from order */
+ u = order[ orderFirst ];
+ orderFirst ++;
+
+ /* adding u to vertex array */
+ vertices[ verticesCount ] = u;
+ verticesCount ++;
+
+ int ofs;
+ CvGraphVtx* graphVtx = cvGetGraphVtx( graph, u );
+
+ /* processing all vertices outgoing from vertex u */
+ CvGraphEdge* graphEdge = graphVtx -> first;
+ while( graphEdge )
+ {
+ int tempVtxIdx = cvGraphVtxIdx( graph, graphEdge -> vtx[1] );
+ ofs = tempVtxIdx == u;
+ if( !ofs )
+ {
+ v = tempVtxIdx;
+
+ CvGraphEdge* tempGraphEdge = cvFindGraphEdge( graph, u, v );
+ if( ( lengthArr[ u ] < lengthArr[ v ] )
+ && ( lengthArr[ v ] <= lengthArr[ t ] )
+ && ( ( ( Edge* )tempGraphEdge ) -> flow <
+ ( ( Edge* )tempGraphEdge ) -> weight ) )
+ {
+ if( lengthArr[ v ] == INT_INFINITY )
+ {
+ /* adding vertex v to order */
+ order[ orderCount ] = v;
+ orderCount ++;
+
+ lengthArr[ v ] = lengthArr[ u ] + 1;
+ CvGraphEdge* tempGraphEdge2;
+
+ cvGraphAddEdge( hlpGraph, u, v, NULL, &tempGraphEdge2 );
+ ( ( Edge* )tempGraphEdge2 ) -> flow = 0;
+
+ ( ( Edge* )tempGraphEdge2 ) -> weight =
+ ( ( Edge* )tempGraphEdge ) -> weight -
+ ( ( Edge* )tempGraphEdge ) -> flow;
+
+ } /* if( length[ v ] == INT_INFINITY ) */
+
+ } /* if( ( lengthArr[ u ] < lengthArr[ v ] ) ... */
+
+ } /* if( !ofs ) */
+
+ graphEdge = graphEdge -> next[ ofs ];
+
+ } /* while( graphEdge ) */
+
+ /* processing all vertices incoming to vertex u */
+ graphEdge = graphVtx -> first;
+ while( graphEdge )
+ {
+ int tempVtxIdx = cvGraphVtxIdx( graph, graphEdge -> vtx[1] );
+ ofs = tempVtxIdx == u;
+ if( ofs )
+ {
+ tempVtxIdx = cvGraphVtxIdx( graph, graphEdge -> vtx[0] );
+ v = tempVtxIdx;
+
+ CvGraphEdge* tempGraphEdge = cvFindGraphEdge( graph, v, u );
+ if( ( lengthArr[ u ] < lengthArr[ v ] )
+ && ( lengthArr[ v ] <= lengthArr[ t ] )
+ && ( ( ( Edge* )tempGraphEdge ) -> flow > 0 ) )
+ {
+ if( lengthArr[ v ] == INT_INFINITY )
+ {
+ /* adding vertex v to order */
+ order[ orderCount ] = v;
+ orderCount ++;
+
+ lengthArr[ v ] = lengthArr[ u ] + 1;
+ CvGraphEdge* tempGraphEdge3 = cvFindGraphEdge( hlpGraph, u, v );
+
+ if( tempGraphEdge3 == NULL ||
+ ( ( Edge* )tempGraphEdge3 ) -> weight == 0 )
+ {
+ CvGraphEdge* tempGraphEdge2;
+ cvGraphAddEdge( hlpGraph, u, v, NULL,
+ &tempGraphEdge2 );
+ ( ( Edge* )tempGraphEdge2 ) -> flow = 0;
+ ( ( Edge* )tempGraphEdge2 ) -> weight = 0;
+ } /* if( tempGraphEdge3 == NULL || ... */
+
+ ( ( Edge* )tempGraphEdge3 ) -> weight +=
+ ( ( Edge* )tempGraphEdge ) -> flow;
+
+ } /* if( length[ v ] == INT_INFINITY ) */
+
+ } /* if( ( lengthArr[ u ] < lengthArr[ v ] ) ... */
+
+ } /* if( ofs ) */
+
+ graphEdge = graphEdge -> next[ ofs ];
+
+ } /* while( graphEdge ) */
+
+ } /* while( orderCount != orderFirst ) */
+
+ int i;
+ for( i = 0; i < hlpGraph -> total - 2; i ++ )
+ {
+ CvGraphVtx* hlpGraphVtxTemp = cvGetGraphVtx( hlpGraph, i );
+ if( hlpGraphVtxTemp ) {
+ if( !hlpGraphVtxTemp -> first ) {
+ cvGraphRemoveVtxByPtr( hlpGraph, hlpGraphVtxTemp );
+ }
+ }
+ } /* for( i = 0; i < hlpGraph -> total - 2; i ++ ) */
+
+ return lengthArr[ t ];
+
+} /* makeHelpGraph */
+
+// function makePseudoMaxFlow increases flow in graph by using hlpGraph
+// graph - pointer to initial graph
+// hlpGraph - pointer to help graph
+// vertices - pointer to vertices array
+// verticesCount - number of vertices in vertices array
+// mem - pointer to memory allocated by allocTempMem function
+// width - width of image line in pixels
+void makePseudoMaxFlow( CvGraph* graph,
+ CvGraph* hlpGraph,
+ int* vertices,
+ int verticesCount,
+ int* mem,
+ int width )
+{
+ int stekCount;
+ int orderFirst;
+ int orderCount;
+ int i;
+ int v, u;
+ int* stek = mem;
+ int* order = stek + width + 2;
+ int* incomFlow = order + width + 2;
+ int* outgoFlow = incomFlow + width + 2;
+ int* flow = outgoFlow + width + 2;
+ int* cargo = flow+ width + 2;
+ int s = graph -> total - 2; /* source vertex */
+ int t = graph -> total - 1; /* terminate vertex */
+ int realVerticesCount = verticesCount;
+
+ stekCount = 0;
+
+ for( i = 0; i < verticesCount; i ++ )
+ {
+ v = vertices[ i ];
+
+ incomFlow[ v ] = outgoFlow[ v ] = 0;
+
+ if( v == s ) {
+ incomFlow[ v ] = INT_INFINITY;
+ } /* if( v == s ) */
+ else {
+ CvGraphVtx* hlpGraphVtx = cvGetGraphVtx( hlpGraph, v );
+ CvGraphEdge* hlpGraphEdge = hlpGraphVtx -> first;
+ int ofs;
+
+ while( hlpGraphEdge )
+ {
+ int vtxIdx = cvGraphVtxIdx( hlpGraph,
+ hlpGraphEdge -> vtx[1] );
+ ofs = vtxIdx == v;
+
+ if( ofs )
+ {
+ incomFlow[ v ] += ( ( Edge* )hlpGraphEdge ) -> weight;
+ } /* if( ofs ) */
+
+ hlpGraphEdge = hlpGraphEdge -> next[ ofs ];
+ } /* while( hlpGraphEdge ) */
+
+ } /* if( v == s ) else */
+
+ if( v == t ) {
+ outgoFlow[ v ] = INT_INFINITY;
+ } /* if( v == t ) */
+ else {
+ CvGraphVtx* hlpGraphVtx = cvGetGraphVtx( hlpGraph, v );
+ CvGraphEdge* hlpGraphEdge = hlpGraphVtx -> first;
+ int ofs;
+
+ while( hlpGraphEdge )
+ {
+ int vtxIdx = cvGraphVtxIdx( hlpGraph,
+ hlpGraphEdge -> vtx[1] );
+ ofs = vtxIdx == v;
+
+ if( !ofs )
+ {
+ outgoFlow[ v ] += ( ( Edge* )hlpGraphEdge ) -> weight;
+ } /* if( ofs ) */
+
+ hlpGraphEdge = hlpGraphEdge -> next[ ofs ];
+ } /* while( hlpGraphEdge ) */
+
+ } /* if( v == t ) else */
+
+ flow[ v ] = CV_MIN2( incomFlow[ v ], outgoFlow[ v ] );
+
+ if( !flow[ v ] ) {
+ stek[ stekCount ] = v;
+ stekCount ++;
+ } /* if( !flow[ v ] ) */
+
+ } /* for( i = 0; i < verticesCount; i ++ ) */
+
+ for( i = 0; i < verticesCount; i ++ )
+ {
+ v = vertices[ i ];
+ cargo[ v ] = 0;
+ } /* for( i = 0; i < verticesCount; i ++ ) */
+
+ while( realVerticesCount > 2 )
+ {
+ /* deleting all vertices included in stek */
+ while( stekCount )
+ {
+ v = stek[ stekCount - 1 ];
+ stekCount --;
+
+ /* deleting edges incoming to v and outgoing from v */
+ int ofs;
+ CvGraphVtx* hlpGraphVtx = cvGetGraphVtx( hlpGraph, v );
+ CvGraphEdge* hlpGraphEdge;
+ if( hlpGraphVtx ) {
+ hlpGraphEdge = hlpGraphVtx -> first;
+ }
+ else {
+ hlpGraphEdge = NULL;
+ }
+ while( hlpGraphEdge )
+ {
+ CvGraphVtx* hlpGraphVtx2 = hlpGraphEdge -> vtx[ 1 ];
+ int hlpGraphVtxIdx2 = cvGraphVtxIdx( hlpGraph,
+ hlpGraphVtx2 );
+ ofs = hlpGraphVtxIdx2 == v;
+
+ if( ofs )
+ {
+ /* hlpGraphEdge is incoming edge */
+ CvGraphVtx* hlpGraphVtx3 = hlpGraphEdge -> vtx[0];
+ u = cvGraphVtxIdx( hlpGraph,
+ hlpGraphVtx3 );
+ outgoFlow[ u ] -= ( ( Edge* )hlpGraphEdge ) -> weight
+ - ( ( Edge* )hlpGraphEdge ) -> flow;
+ cvGraphRemoveEdgeByPtr( hlpGraph,
+ hlpGraphVtx3,
+ hlpGraphVtx2 );
+ if( flow[ u ] != 0 ) {
+ flow[ u ] = CV_MIN2( incomFlow[u], outgoFlow[u] );
+ if( flow[ u ] == 0 ) {
+ stek[ stekCount ] = u;
+ stekCount ++;
+ }
+ }
+ } /* if( ofs ) */
+ else
+ {
+ /* hlpGraphEdge is outgoing edge */
+ CvGraphVtx* hlpGraphVtx3 = hlpGraphEdge -> vtx[1];
+ int u = cvGraphVtxIdx( hlpGraph,
+ hlpGraphVtx3 );
+ incomFlow[ u ] -= ( ( Edge* )hlpGraphEdge ) -> weight
+ - ( ( Edge* )hlpGraphEdge ) -> flow;
+ cvGraphRemoveEdgeByPtr( hlpGraph,
+ hlpGraphVtx2,
+ hlpGraphVtx3 );
+ if( flow[ u ] != 0 ) {
+ flow[ u ] = CV_MIN2( incomFlow[u], outgoFlow[u] );
+ if( flow[ u ] == 0 ) {
+ stek[ stekCount ] = u;
+ stekCount ++;
+ }
+ }
+ } /* if( ofs ) else */
+
+ hlpGraphEdge = hlpGraphEdge -> next[ ofs ];
+
+ } /* while( hlpGraphEdge ) */
+
+ /* deleting vertex v */
+ cvGraphRemoveVtx( hlpGraph, v );
+ realVerticesCount --;
+
+ } /* while( stekCount ) */
+
+ if( realVerticesCount > 2 ) /* the flow is not max still */
+ {
+ int p = INT_INFINITY;
+ int r = -1;
+ CvGraphVtx* graphVtx;
+
+ if( realVerticesCount == 3 ) {
+ r = r;
+ }
+ for( i = 0; i < hlpGraph -> total - 2; i ++ )
+ {
+ graphVtx = cvGetGraphVtx( hlpGraph, i );
+ if( graphVtx ) {
+ v = cvGraphVtxIdx( hlpGraph, graphVtx );
+ if( flow[ v ] < p ) {
+ r = v;
+ p = flow[ v ];
+ }
+ }
+
+ } /* for( i = 0; i < hlpGraph -> total - 2; i ++ ) */
+
+ /* building of size p flow from r to t */
+ orderCount = orderFirst = 0;
+ order[ orderCount ] = r;
+ orderCount ++;
+
+ v = order[ orderFirst ];
+ orderFirst ++;
+
+ cargo[ r ] = p;
+ do /* while( v != t ) */
+ {
+ incomFlow[ v ] -= cargo[ v ];
+ outgoFlow[ v ] -= cargo[ v ];
+ flow[ v ] -= cargo[ v ];
+
+ if( flow[ v ] == 0 ) {
+ stek[ stekCount ] = v;
+ stekCount ++;
+ }
+
+ if( v == t ) {
+ cargo[ v ] = p;
+ }
+ else
+ {
+ int ofs;
+ CvGraphVtx* hlpGraphVtx2;
+ CvGraphVtx* hlpGraphVtx = cvGetGraphVtx( hlpGraph, v );
+ CvGraphEdge* hlpGraphEdge = hlpGraphVtx -> first;
+ CvGraphEdge* hlpGraphEdge2 = NULL;
+
+ while( hlpGraphEdge && cargo[ v ] > 0 )
+ {
+ hlpGraphVtx2 = hlpGraphEdge -> vtx[ 1 ];
+ u = cvGraphVtxIdx( hlpGraph, hlpGraphVtx2 );
+ ofs = u == v;
+
+ if( !ofs )
+ {
+ if( cargo[ u ] == 0 ) {
+ order[ orderCount ] = u;
+ orderCount ++;
+ }
+ int delta = ( ( Edge* )hlpGraphEdge ) -> weight
+ - ( ( Edge* )hlpGraphEdge ) -> flow;
+ delta = CV_MIN2( cargo[ v ], delta );
+ ( ( Edge* )hlpGraphEdge ) -> flow += delta;
+ cargo[ v ] -= delta;
+ cargo[ u ] += delta;
+ if( ( ( Edge* )hlpGraphEdge ) -> weight ==
+ ( ( Edge* )hlpGraphEdge ) -> flow )
+ {
+ /* deleting hlpGraphEdge */
+ hlpGraphEdge2 = hlpGraphEdge -> next[ ofs ];
+ CvGraphEdge* graphEdge =
+ cvFindGraphEdge( graph, v, u );
+ ( ( Edge* )graphEdge ) -> flow +=
+ ( ( Edge* )hlpGraphEdge ) -> flow;
+ cvGraphRemoveEdgeByPtr( hlpGraph,
+ hlpGraphEdge -> vtx[0],
+ hlpGraphEdge -> vtx[1] );
+ }
+ } /* if( !ofs ) */
+
+ if( hlpGraphEdge2 ) {
+ hlpGraphEdge = hlpGraphEdge2;
+ hlpGraphEdge2 = NULL;
+ }
+ else {
+ hlpGraphEdge = hlpGraphEdge -> next[ ofs ];
+ }
+ } /* while( hlpGraphEdge && cargo[ v ] > 0 ) */
+
+ } /* if( v == t ) else */
+
+ v = order[ orderFirst ];
+ orderFirst ++;
+
+ } while( v != t ); /* do */
+
+ /* building of size p flow from s to r */
+ orderCount = orderFirst = 0;
+ order[ orderCount ] = r;
+ orderCount ++;
+
+ v = order[ orderFirst ];
+ orderFirst ++;
+
+ cargo[ r ] = p;
+ do /* while( v != s ) */
+ {
+ if( v != r )
+ {
+ incomFlow[ v ] -= cargo[ v ];
+ outgoFlow[ v ] -= cargo[ v ];
+ flow[ v ] -= cargo[ v ];
+ if( flow[ v ] == 0 ) {
+ stek[ stekCount ] = v;
+ stekCount ++;
+ }
+ } /* if( v != r ) */
+
+ if( v == s ) {
+ cargo[ v ] = 0;
+ } /* if( v == s ) */
+ else
+ {
+ int ofs;
+
+ CvGraphVtx* hlpGraphVtx = cvGetGraphVtx( hlpGraph, v );
+ CvGraphEdge* hlpGraphEdge = hlpGraphVtx -> first;
+ CvGraphEdge* hlpGraphEdge2 = NULL;
+ while( hlpGraphEdge && cargo[ v ] > 0 )
+ {
+ u = cvGraphVtxIdx( hlpGraph,
+ hlpGraphEdge -> vtx[ 1 ] );
+ ofs = u == v;
+
+ if( ofs )
+ {
+ u = cvGraphVtxIdx( hlpGraph,
+ hlpGraphEdge -> vtx[ 0 ] );
+
+ if( cargo[ u ] == 0 ) {
+ order[ orderCount ] = u;
+ orderCount ++;
+ }
+
+ int delta = ( ( Edge* )hlpGraphEdge ) -> weight
+ - ( ( Edge* )hlpGraphEdge ) -> flow;
+
+ delta = CV_MIN2( cargo[ v ], delta );
+
+ (( ( Edge* )hlpGraphEdge ) -> flow) += delta;
+
+ cargo[ v ] -= delta;
+ cargo[ u ] += delta;
+
+ if( ( ( Edge* )hlpGraphEdge ) -> weight ==
+ ( ( Edge* )hlpGraphEdge ) -> flow )
+ {
+ hlpGraphEdge2 = hlpGraphEdge -> next[ ofs ];
+ CvGraphEdge* graphEdge =
+ cvFindGraphEdge( graph, u, v );
+ ( ( Edge* )graphEdge ) -> flow +=
+ ( ( Edge* )hlpGraphEdge ) -> flow;
+ cvGraphRemoveEdgeByPtr( hlpGraph,
+ hlpGraphEdge -> vtx[0],
+ hlpGraphEdge -> vtx[1] );
+ }
+ } /* if( ofs ) */
+
+ if( hlpGraphEdge2 ) {
+ hlpGraphEdge = hlpGraphEdge2;
+ hlpGraphEdge2 = NULL;
+ }
+ else {
+ hlpGraphEdge = hlpGraphEdge -> next[ ofs ];
+ }
+ } /* while( hlpGraphEdge && cargo[ v ] > 0 ) */
+
+ } /* if( v == s ) else */
+
+ v = order[ orderFirst ]; //added
+ orderFirst ++; //added
+
+ } while( v != s ); /* do */
+
+ } /* if( hlpGraph -> total > 2 ) */
+
+ } /* while( hlpGraph -> total > 2 ) */
+
+} /* makePseudoMaxFlow */
+
+
+// function oneStep produces one alpha-beta exchange for one line of images
+// leftLine - pointer to the left image line
+// rightLine - pointer to the right image line
+// alpha - label number one
+// beta - label number two
+// corr - pointer to correspondence array for this line
+// width - width of image line in pixels
+// mem - pointer to memory allocated by allocTempMem function
+// vertices - pointer to vertices array allocated by allocTempMem
+// function
+// storage - pointer to CvMemStorage structure
+bool oneStep( unsigned char* leftLine,
+ unsigned char* rightLine,
+ int alpha,
+ int beta,
+ int* corr,
+ int width,
+ int* mem,
+ int* vertices,
+ CvMemStorage* storage )
+{
+ CvGraph* graph = NULL;
+ CvGraph* hlpGraph = NULL;
+ CvMemStoragePos storagePos;
+ int i;
+ bool change = false;
+ cvSaveMemStoragePos( storage, &storagePos );
+
+ int verticesCount;
+
+ makeGraph( &graph, leftLine, rightLine, alpha, beta, corr, width, storage );
+
+ int s = graph -> total - 2; /* source vertex - alpha vertex */
+ //int t = graph -> total - 1; /* terminate vertex - beta vertex */
+
+ int length = makeHelpGraph( graph,
+ &hlpGraph,
+ storage,
+ mem,
+ vertices,
+ &verticesCount,
+ width );
+ while( length != INT_INFINITY )
+ {
+ change = true;
+ makePseudoMaxFlow( graph,
+ hlpGraph,
+ vertices,
+ verticesCount,
+ mem,
+ width );
+ cvClearGraph( hlpGraph );
+ length = makeHelpGraph( graph,
+ &hlpGraph,
+ storage,
+ mem,
+ vertices,
+ &verticesCount,
+ width );
+ } /* while( length != INT_INFINITY ) */
+
+ int coord;
+ CvGraphVtx* graphVtx;
+ for( i = 0; i < s; i ++ )
+ {
+ CvGraphEdge* graphEdge = cvFindGraphEdge( graph, s, i );
+
+ if( ( ( Edge* )graphEdge ) -> weight ==
+ ( ( Edge* )graphEdge ) -> flow )
+ { /* this vertex must have alpha label */
+ graphVtx = cvGetGraphVtx( graph, i );
+ coord = ( ( Vertex* )graphVtx )-> coord;
+ if( corr[ coord ] != alpha ) {
+ corr[ coord ] = alpha; //added
+ change = true;
+ }
+ else {
+ corr[ coord ] = alpha;
+ }
+ } /* if( ( ( Edge* )graphEdge ) -> weight == ... */
+ else
+ { /* this vertex must have beta label */
+ graphVtx = cvGetGraphVtx( graph, i );
+ coord = ( ( Vertex* )graphVtx )-> coord;
+ if( corr[ coord ] != beta ) {
+ corr[ coord ] = beta; //added
+ change = true;
+ }
+ else {
+ corr[ coord ] = beta;
+ }
+ } /* if( ( ( Edge* )graphEdge ) -> weight == ... else */
+
+ } /* for( i = 0; i < s; i ++ ) */
+
+ cvClearGraph( hlpGraph );
+ cvClearGraph( graph );
+
+ cvRestoreMemStoragePos( storage, &storagePos );
+
+ return change;
+
+} /* oneStep */
+
+// function initCorr fills correspondence array with initial values
+// corr - pointer to correspondence array for this line
+// width - width of image line in pixels
+// maxPixelDifference - maximum value of difference between the same
+// point painted on two images
+void initCorr( int* corr, int width, int maxPixelDifference )
+{
+ int i;
+ int pixelDifferenceRange = maxPixelDifference * 2 + 1;
+
+ for( i = 0; i < width; i ++ )
+ {
+ corr[ i ] = i % pixelDifferenceRange - maxPixelDifference;
+ }
+} /* initCorr */
+
+// function oneLineCorr fully computes one line of images
+// leftLine - pointer to the left image line
+// rightLine - pointer to the right image line
+// corr - pointer to the correspondence array for one
+// line
+// mem - pointer to memory allocated by allocTempMem
+// function
+// vertices - pointer to memory allocated by allocTempMem
+// function
+// width - width of image line in pixels
+// maxPixelDifference - maximum value of pixel differences in pixels
+// storage - pointer to CvMemStorage struct which
+// contains memory storage
+void oneLineCorr( unsigned char* leftLine,
+ unsigned char* rightLine,
+ int* corr,
+ int* mem,
+ int* vertices,
+ int width,
+ int maxPixelDifference,
+ CvMemStorage* storage )
+{
+ int result = 1;
+ int count = 0;
+ int i, j;
+
+ initCorr( corr, width, maxPixelDifference );
+ while( result )
+ {
+ result = 0;
+
+ for( i = - maxPixelDifference; i < maxPixelDifference; i ++ )
+ for( j = i + 1; j <= maxPixelDifference; j ++ )
+ {
+ result += (int)oneStep( leftLine,
+ rightLine,
+ i,
+ j,
+ corr,
+ width,
+ mem,
+ vertices,
+ storage );
+ } /* for( j = i + 1; j < width; j ++ ) */
+
+ count ++;
+ if( count > /*0*//*1*/2 ) {
+ break;
+ }
+
+ } /* while( result ) */
+
+} /* oneLineCorr */
+
+// function allLinesCorr computes all lines on the images
+// leftImage - pointer to the left image
+// leftLineStep - size of line on the left image in bytes
+// rightImage - pointer to the right image
+// rightLineStep - size of line on the right image in bytes
+// width - width of line in pixels
+// height - height of image in pixels
+// corr - pointer to correspondence array for all lines
+// maxPixelDifference - maximum value of difference between the same
+// point painted on two images
+// storage - pointer to CvMemStorage which contains memory
+// storage
+void allLinesCorr( unsigned char* leftImage,
+ int leftLineStep,
+ unsigned char* rightImage,
+ int rightLineStep,
+ int width,
+ int height,
+ int* corr,
+ int maxPixelDifference,
+ CvMemStorage* storage )
+{
+ int i;
+ unsigned char* leftLine = leftImage;
+ unsigned char* rightLine = rightImage;
+ int* mem;
+ int* vertices;
+
+ allocTempMem( &mem,
+ &vertices,
+ width );
+
+ for( i = 0; i < height; i ++ )
+ {
+ oneLineCorr( leftLine,
+ rightLine,
+ corr + i * width,
+ mem,
+ vertices,
+ width,
+ maxPixelDifference,
+ storage );
+ leftLine += leftLineStep;
+ rightLine += rightLineStep;
+ } /* for( i = 0; i < height; i ++ ) */
+
+ freeTempMem( &mem,
+ &vertices );
+
+} /* allLinesCorr */
+
+// This function produces morphing of two images into one image, which includes morphed
+// image or depth map
+// _leftImage - pointer to left image
+// _leftLineStep - size of line on left image in bytes
+// _rightImage - pointer to right image
+// _rightLineStep - size of line on right image in bytes
+// _resultImage - pointer to result morphed image
+// _resultLineStep - size of line on result image in bytes
+// _corrArray - pointer to array with correspondences
+// _numCorrArray - pointer to array with numbers correspondeces on each line
+// width - width of images
+// height - height of images
+// alpha - position of virtual camera ( 0 corresponds to left image, 1 - to right one )
+// imageNeed - defines your wishes. if you want to see normal morphed image you have to set
+// this parameter to morphNormalImage ( this is default value ), else if you want
+// to see depth map you have to set this parameter to morphDepthMap and set the
+// next parameter ( maxPixelDifference ) to real value
+// maxPixelDifference - maximum value of pixel difference on two images
+void CCvGraphCutMorpher::Morph( unsigned char* _leftImage,
+ int _leftLineStep,
+ unsigned char* _rightImage,
+ int _rightLineStep,
+ unsigned char* _resultImage,
+ int _resultLineStep,
+ int* _corrArray,
+ int width,
+ int height,
+ float alpha,
+ morphImageType imageNeed,
+ int maxDifference
+ )
+{
+ unsigned char* leftArray = _leftImage;
+ unsigned char* middleArray = _resultImage;
+ unsigned char* rightArray = _rightImage;
+ int leftLineSize = _leftLineStep;
+ int middleLineSize = _resultLineStep;
+ int rightLineSize = _rightLineStep;
+
+ int lineNumber;
+ unsigned char* leftTemp;
+ unsigned char* middleTemp;
+ unsigned char* rightTemp;
+ int leftPixel;
+ int prevLeftPixel;
+ int middlePixel;
+ int prevMiddlePixel;
+ int rightPixel;
+ int prevRightPixel;
+ int leftPixel3;
+ int middlePixel3;
+ int rightPixel3;
+ int i;
+ int j;
+ int tempIndex;
+ int* result;
+ int number;
+ float alpha1 = 1.0f - alpha;
+
+ for( lineNumber = 0; lineNumber < height; lineNumber ++ )
+ {
+ leftTemp = leftArray + leftLineSize * lineNumber;
+ middleTemp = middleArray + middleLineSize * lineNumber;
+ rightTemp = rightArray + rightLineSize * lineNumber;
+ memset( ( void* )middleTemp, 0, middleLineSize );
+
+ result = _corrArray + width * lineNumber;
+ number = width;
+
+ prevLeftPixel = 0;
+ prevRightPixel = prevLeftPixel + result[ 0 ];
+ if( prevRightPixel >= width ) {
+ prevRightPixel = width - 1;
+ }
+ else if ( prevRightPixel < 0 ) {
+ prevRightPixel = 0;
+ }
+ prevMiddlePixel =
+ (int)( prevLeftPixel * alpha1 + prevRightPixel * alpha );
+ for( i = 0; i < number - 1; i ++ )
+ {
+ leftPixel = i;
+ rightPixel = i + result[ i ];
+ if( rightPixel >= width ) {
+ rightPixel = width - 1;
+ }
+ else if( rightPixel < 0 ) {
+ rightPixel = 0;
+ }
+ middlePixel =
+ (int)( leftPixel * alpha1 + rightPixel * alpha );
+ leftPixel3 = leftPixel * 3;
+ middlePixel3 = middlePixel * 3;
+ rightPixel3 = rightPixel * 3;
+
+ if( imageNeed == morphDepthMap ) {
+ int t = leftPixel - rightPixel + maxDifference;
+ t = t < 0 ? -t : t;
+ t = t * 255 / maxDifference / 2;
+ middleTemp[ middlePixel3 ] = ( unsigned char )t;
+ middleTemp[ middlePixel3 + 1 ] = ( unsigned char )t;
+ middleTemp[ middlePixel3 + 2 ] = ( unsigned char )t;
+ } // if( imageNeed == morphDepthMap )
+ else
+ {
+ middleTemp[ middlePixel3 ] =
+ (unsigned char)( leftTemp[ leftPixel3 ] * alpha1
+ + rightTemp[ rightPixel3 ] * alpha );
+ middleTemp[ middlePixel3 + 1 ] =
+ (unsigned char)( leftTemp[ leftPixel3 + 1 ] * alpha1
+ + rightTemp[ rightPixel3 + 1 ] * alpha );
+ middleTemp[ middlePixel3 + 2 ] =
+ (unsigned char)( leftTemp[ leftPixel3 + 2 ] * alpha1
+ + rightTemp[ rightPixel3 + 2 ] * alpha );
+
+ if( middlePixel - prevMiddlePixel > 1 ) // occlusion
+ {
+ if( leftPixel - prevLeftPixel > 1 )
+ {
+ int LenSrc = leftPixel - prevLeftPixel - 2;
+ int LenDest = middlePixel - prevMiddlePixel - 1;
+ for( j = prevMiddlePixel + 1; j < middlePixel; j ++ )
+ {
+ tempIndex = prevLeftPixel + 1 + LenSrc *
+ ( j - prevMiddlePixel - 1 ) / LenDest;
+ middleTemp[ j * 3 ] =
+ leftTemp[ tempIndex * 3 ];
+ middleTemp[ j * 3 + 1 ] =
+ leftTemp[ tempIndex * 3 + 1 ];
+ middleTemp[ j * 3 + 2 ] =
+ leftTemp[ tempIndex * 3 + 2 ];
+ }
+ } // if( leftPixel - prevLeftPixel > 1 )
+ else
+ {
+ int LenSrc = rightPixel - prevRightPixel - 2;
+ int LenDest = middlePixel - prevMiddlePixel - 1;
+ for( j = prevMiddlePixel + 1; j < middlePixel; j ++ )
+ {
+ tempIndex = prevRightPixel + 1 + LenSrc *
+ ( j - prevMiddlePixel - 1 ) / LenDest;
+ middleTemp[ j * 3 ] =
+ rightTemp[ tempIndex * 3 ];
+ middleTemp[ j * 3 + 1 ] =
+ rightTemp[ tempIndex * 3 + 1 ];
+ middleTemp[ j * 3 + 2 ] =
+ rightTemp[ tempIndex * 3 + 2 ];
+ }
+ } // if( leftPixel - prevLeftPixel > 1 ) else
+
+ } // if( middlePixel - prevMiddlePixel > 1 )
+
+ } // if( imageNeed == morphDepthMap ) else
+
+ if( middlePixel > prevMiddlePixel ) {
+ if( leftPixel > prevLeftPixel )
+ prevLeftPixel = leftPixel;
+ if( rightPixel > prevRightPixel )
+ prevRightPixel = rightPixel;
+ prevMiddlePixel = middlePixel;
+ }
+ } // for( i = number - 1; i >= 0; i -- )
+
+ } // for( lineNumber = 0; lineNumber < LeftImage -> m_Raster -> GetHeight() )
+
+} // Morph
+
+bool CCvGraphCutMorpher::OnCalculateStereo()
+{
+ CvSize imageSizeLeft = GetImageSize( m_left_img ),
+ imageSizeRight = GetImageSize( m_right_img );
+
+ if( ( imageSizeLeft.width != imageSizeRight.width )
+ || ( imageSizeLeft.height != imageSizeRight.height ) )
+ {
+ return false;
+ }
+
+ if( m_corr ) {
+ free( m_corr );
+ m_corr = NULL;
+ }
+ m_corr = ( int* ) malloc( m_left_img -> width
+ * m_left_img -> height
+ * sizeof( int ) );
+
+ if( !m_storage ) {
+ m_storage = cvCreateMemStorage( 0 );
+ m_isStorageAllocated = true;
+ }
+ // Find correspondence for full image and store it to corr array
+ allLinesCorr( ( unsigned char* )m_left_img -> imageData,
+ m_left_img -> widthStep,
+ ( unsigned char* )m_right_img -> imageData,
+ m_right_img -> widthStep,
+ m_left_img -> width,
+ m_left_img -> height,
+ m_corr,
+ m_maxPixelDifference,
+ m_storage );
+
+ m_isStereoReady = true;
+
+ return true;
+}
+
+bool CCvGraphCutMorpher::OnCalculateVirtualImage()
+{
+ // Output image to ResultImage window
+ Morph( ( unsigned char* )m_left_img -> imageData,
+ m_left_img ->widthStep,
+ ( unsigned char* )m_right_img -> imageData,
+ m_right_img -> widthStep,
+ ( unsigned char* )m_virtual_img -> imageData,
+ m_virtual_img -> widthStep,
+ m_corr,
+ m_left_img -> width,
+ m_left_img -> height,
+ m_pan );
+
+ m_isVirtualImageReady = true;
+
+ return true;
+}
+
+bool CCvGraphCutMorpher::OnCalculateDisparity()
+{
+ Morph( ( unsigned char* )m_left_img -> imageData,
+ m_left_img ->widthStep,
+ ( unsigned char* )m_right_img -> imageData,
+ m_right_img -> widthStep,
+ ( unsigned char* )m_disparity_img -> imageData,
+ m_disparity_img -> widthStep,
+ m_corr,
+ m_left_img -> width,
+ m_left_img -> height,
+ m_pan,
+ morphDepthMap,
+ m_maxPixelDifference );
+
+ return true;
+}
+
+bool CCvGraphCutMorpher::OnCalculateDisparityImage()
+{
+ Morph( ( unsigned char* )m_left_img -> imageData,
+ m_left_img ->widthStep,
+ ( unsigned char* )m_right_img -> imageData,
+ m_right_img -> widthStep,
+ ( unsigned char* )m_disparity_img -> imageData,
+ m_disparity_img -> widthStep,
+ m_corr,
+ m_left_img -> width,
+ m_left_img -> height,
+ m_pan,
+ morphDepthMap,
+ m_maxPixelDifference );
+
+ return true;
+}
+
+CCvGraphCutMorpher::CCvGraphCutMorpher()
+{
+ m_maxPixelDifference = MAX_DIFFERENCE;
+ m_corr = 0;
+ m_isStereoReady = false;
+ m_isVirtualImageReady = false;
+ m_isDisparityReady = false;
+ m_storage = NULL;
+ m_isStorageAllocated = false;
+}
+
+#endif
+
+/* End of file */
diff --git a/cvaux/src/extendededges.cpp b/cvaux/src/extendededges.cpp
new file mode 100644
index 0000000..c33ff0b
--- /dev/null
+++ b/cvaux/src/extendededges.cpp
@@ -0,0 +1,268 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
+
+#ifdef WIN32 /* make sure it builds under Linux whenever it is included into Makefile.am or not. */
+
+//void icvCutContour( CvSeq* current, IplImage* image );
+CvSeq* icvCutContourRaster( CvSeq* current, CvMemStorage* storage, IplImage* image );
+
+
+//create lists of segments of all contours from image
+CvSeq* cvExtractSingleEdges( IplImage* image, //bw image - it's content will be destroyed by cvFindContours
+ CvMemStorage* storage )
+{
+ CvMemStorage* tmp_storage = cvCreateChildMemStorage( storage );
+ CvSeq* contours = 0;
+ cvFindContours( image, tmp_storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE );
+ cvZero( image );
+
+ //iterate through contours
+ //iterate through tree
+ CvSeq* current = contours;
+ int number = 0;
+ int level = 1;
+
+ CvSeq* output = 0;
+ CvSeq* tail_seq = 0;
+
+ //actually this loop can iterates through tree,
+ //but still we use CV_RETR_LIST it is not useful
+ while( current )
+ {
+ number++;
+
+ //get vertical list of segments for one contour
+ CvSeq* new_seq = icvCutContourRaster( current, storage, image );
+
+ //add this vertical list to horisontal list
+ if( new_seq )
+ {
+ if( tail_seq )
+ {
+ tail_seq->h_next = new_seq;
+ new_seq->h_prev = tail_seq;
+ tail_seq = new_seq;
+ }
+ else
+ {
+ output = tail_seq = new_seq;
+ }
+ }
+
+ //iteration through tree
+ if( current->v_next )
+ {
+ //goto child
+ current = current->v_next;
+ level++;
+ }
+ else
+ {
+ //go parent
+ while( !current->h_next )
+ {
+ current = current->v_prev;
+ level--;
+ if( !level ) break;
+ }
+
+ if( current ) //go brother
+ current = current->h_next;
+ }
+ }
+
+ //free temporary memstorage with initial contours
+ cvReleaseMemStorage( &tmp_storage );
+
+ return output;
+}
+
+//makes vertical list of segments for 1 contour
+CvSeq* icvCutContourRaster( CvSeq* current, CvMemStorage* storage, IplImage* image /*tmp image*/)
+{
+ //iplSet(image, 0 ); // this can cause double edges if two contours have common edge
+ // for example if object is circle with 1 pixel width
+ // to remove such problem - remove this iplSet
+
+ //approx contour by single edges
+ CvSeqReader reader;
+ CvSeqWriter writer;
+
+ int writing = 0;
+ cvStartReadSeq( current, &reader, 0 );
+ //below line just to avoid warning
+ cvStartWriteSeq( current->flags, sizeof(CvContour), sizeof(CvPoint), storage, &writer );
+
+ CvSeq* output = 0;
+ CvSeq* tail = 0;
+
+ //first pass through contour - compute number of branches at every point
+ int i;
+ for( i = 0; i < current->total; i++ )
+ {
+ CvPoint cur;
+
+ CV_READ_SEQ_ELEM( cur, reader );
+
+ //mark point
+ ((uchar*)image->imageData)[image->widthStep * cur.y + cur.x]++;
+ assert( ((uchar*)image->imageData)[image->widthStep * cur.y + cur.x] != 255 );
+
+ }
+
+ //second pass - create separate edges
+ for( i = 0; i < current->total; i++ )
+ {
+ CvPoint cur;
+
+ CV_READ_SEQ_ELEM( cur, reader );
+
+ //get pixel at this point
+ uchar flag = image->imageData[image->widthStep * cur.y + cur.x];
+ if( flag != 255 && flag < 3) //
+ {
+ if(!writing)
+ {
+ cvStartWriteSeq( current->flags, sizeof(CvContour), sizeof(CvPoint), storage, &writer );
+ writing = 1 ;
+ }
+
+ //mark point
+ if( flag < 3 ) ((uchar*)image->imageData)[image->widthStep * cur.y + cur.x] = 255;
+ //add it to another seq
+ CV_WRITE_SEQ_ELEM( cur, writer );
+
+ }
+ else
+ {
+ //exclude this point from contour
+ if( writing )
+ {
+ CvSeq* newseq = cvEndWriteSeq( &writer );
+ writing = 0;
+
+ if( tail )
+ {
+ tail->v_next = newseq;
+ newseq->v_prev = tail;
+ tail = newseq;
+ }
+ else
+ {
+ output = tail = newseq;
+ }
+ }
+ }
+ }
+
+
+ if( writing ) //if were not self intersections
+ {
+ CvSeq* newseq = cvEndWriteSeq( &writer );
+ writing = 0;
+
+ if( tail )
+ {
+ tail->v_next = newseq;
+ newseq->v_prev = tail;
+ tail = newseq;
+ }
+ else
+ {
+ output = tail = newseq;
+ }
+ }
+
+
+ return output;
+
+}
+
+
+/*void icvCutContour( CvSeq* current, IplImage* image )
+{
+ //approx contour by single edges
+ CvSeqReader reader;
+ CvSeqReader rev_reader;
+
+ cvStartReadSeq( current, &reader, 0 );
+
+ int64* cur_pt = (int64*)reader.ptr;
+ int64* prev_pt = (int64*)reader.prev_elem;
+
+ //search for point a in aba position
+ for( int i = 0; i < current->total; i++ )
+ {
+ CV_NEXT_SEQ_ELEM( sizeof(int64), reader );
+
+ //compare current reader pos element with old previous
+ if( prev_pt[0] == ((int64*)reader.ptr)[0] )
+ {
+ //return to prev pos
+ CV_PREV_SEQ_ELEM( sizeof(int64), reader );
+
+
+ //this point is end of edge
+ //start going both directions and collect edge
+ cvStartReadSeq( current, &rev_reader, 1 );
+
+ int pos = cvGetSeqReaderPos( &reader );
+ cvSetSeqReaderPos( &rev_reader, pos );
+
+ //walk in both directions
+ while(1);
+
+
+ }
+ int64* cur_pt = (int64*)reader.ptr;
+ int64* prev_pt = (int64*)reader.prev_elem;
+
+ }
+}
+
+*/
+#endif /* WIN32 */
+
+
+
+
diff --git a/cvaux/src/precomp.cpp b/cvaux/src/precomp.cpp
new file mode 100644
index 0000000..4683b4a
--- /dev/null
+++ b/cvaux/src/precomp.cpp
@@ -0,0 +1,42 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cvaux.h"
diff --git a/cvjni.cpp b/cvjni.cpp
new file mode 100644
index 0000000..14731a9
--- /dev/null
+++ b/cvjni.cpp
@@ -0,0 +1,796 @@
+/*
+OpenCV for Android NDK
+Copyright (c) 2006-2009 SIProp Project http://www.siprop.org/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+#include "cvjni.h"
+#include <time.h>
+
+
+#define THRESHOLD 10
+#define THRESHOLD_MAX_VALUE 255
+
+#define CONTOUR_MAX_LEVEL 1
+#define LINE_THICKNESS 2
+#define LINE_TYPE 8
+
+#define HAAR_SCALE (1.4)
+#define IMAGE_SCALE (2)
+#define MIN_NEIGHBORS (2)
+#define HAAR_FLAGS_SINGLE_FACE (0 | CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_DO_ROUGH_SEARCH)
+#define HAAR_FLAGS_ALL_FACES (0)
+// Other options we dropped out:
+// CV_HAAR_DO_CANNY_PRUNING | CV_HAAR_SCALE_IMAGE
+#define MIN_SIZE_WIDTH (20)
+#define MIN_SIZE_HEIGHT (20)
+#define PAD_FACE_SIZE (10)
+#define PAD_FACE_AREA (40)
+#define PAD_FACE_AREA_2 (PAD_FACE_AREA * 2)
+
+// Initialize a socket capture to grab images from a socket connection.
+JNIEXPORT
+jboolean
+JNICALL
+Java_org_siprop_opencv_OpenCV_createSocketCapture(JNIEnv* env,
+ jobject thiz,
+ jstring address_str,
+ jstring port_str,
+ jint width,
+ jint height) {
+ const char *address_chars = env->GetStringUTFChars(address_str, 0);
+ if (address_chars == 0) {
+ LOGV("Error loading socket address.");
+ return false;
+ }
+
+ const char *port_chars = env->GetStringUTFChars(port_str, 0);
+ if (port_chars == 0) {
+ env->ReleaseStringUTFChars(address_str, address_chars);
+ LOGV("Error loading socket port.");
+ return false;
+ }
+
+ m_capture = cvCreateSocketCapture(address_chars, port_chars, width, height);
+ env->ReleaseStringUTFChars(address_str, address_chars);
+ env->ReleaseStringUTFChars(port_str, port_chars);
+ if (m_capture == 0)
+ {
+ LOGV("Error creating socket capture.");
+ return false;
+ }
+
+ return true;
+}
+
+JNIEXPORT
+void
+JNICALL
+Java_org_siprop_opencv_OpenCV_releaseSocketCapture(JNIEnv* env,
+ jobject thiz) {
+ if (m_capture) {
+ cvReleaseCapture(&m_capture);
+ m_capture = 0;
+ }
+}
+
+JNIEXPORT
+jboolean
+JNICALL
+Java_org_siprop_opencv_OpenCV_grabSourceImageFromCapture(JNIEnv* env,
+ jobject thiz) {
+ if (m_capture == 0)
+ {
+ LOGE("Capture was never initialized.");
+ return false;
+ }
+
+ if (cvGrabFrame(m_capture) == 0)
+ {
+ LOGE("Failed to grab frame from the capture.");
+ return false;
+ }
+
+ IplImage *frame = cvRetrieveFrame(m_capture);
+ if (frame == 0)
+ {
+ LOGE("Failed to retrieve frame from the capture.");
+ return false;
+ }
+
+ if (m_sourceImage) {
+ cvReleaseImage(&m_sourceImage);
+ m_sourceImage = 0;
+ }
+
+ m_sourceImage = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U,
+ frame->nChannels);
+
+ // Check the origin of image. If top left, copy the image frame to frame_copy.
+ // Else flip and copy the image.
+ if (frame->origin == IPL_ORIGIN_TL) {
+ cvCopy(frame, m_sourceImage, 0);
+ }
+ else {
+ cvFlip(frame, m_sourceImage, 0);
+ }
+
+ return true;
+}
+
+// Generate and return a boolean array from the source image.
+// Return 0 if a failure occurs or if the source image is undefined.
+JNIEXPORT
+jbooleanArray
+JNICALL
+Java_org_siprop_opencv_OpenCV_getSourceImage(JNIEnv* env,
+ jobject thiz)
+{
+ if (m_sourceImage == 0) {
+ LOGE("Error source image was not set.");
+ return 0;
+ }
+
+ CvMat stub;
+ CvMat *mat_image = cvGetMat(m_sourceImage, &stub);
+ int channels = CV_MAT_CN( mat_image->type );
+ int ipl_depth = cvCvToIplDepth(mat_image->type);
+
+ WLNonFileByteStream *strm = new WLNonFileByteStream();
+ loadImageBytes(mat_image->data.ptr, mat_image->step, mat_image->width,
+ mat_image->height, ipl_depth, channels, strm);
+
+ int imageSize = strm->GetSize();
+ jbooleanArray res_array = env->NewBooleanArray(imageSize);
+ if (res_array == 0) {
+ LOGE("Unable to allocate a new boolean array for the source image.");
+ return 0;
+ }
+ env->SetBooleanArrayRegion(res_array, 0, imageSize, (jboolean*)strm->GetByte());
+
+ strm->Close();
+ SAFE_DELETE(strm);
+
+ return res_array;
+}
+
+// Given an integer array of image data, load an IplImage.
+// It is the responsibility of the caller to release the IplImage.
+IplImage* getIplImageFromIntArray(JNIEnv* env, jintArray array_data,
+ jint width, jint height) {
+ // Load Image
+ int *pixels = env->GetIntArrayElements(array_data, 0);
+ if (pixels == 0) {
+ LOGE("Error getting int array of pixels.");
+ return 0;
+ }
+
+ IplImage *image = loadPixels(pixels, width, height);
+ env->ReleaseIntArrayElements(array_data, pixels, 0);
+ if(image == 0) {
+ LOGE("Error loading pixel array.");
+ return 0;
+ }
+
+ return image;
+}
+
+// Set the source image and return true if successful or false otherwise.
+JNIEXPORT
+jboolean
+JNICALL
+Java_org_siprop_opencv_OpenCV_setSourceImage(JNIEnv* env,
+ jobject thiz,
+ jintArray photo_data,
+ jint width,
+ jint height)
+{
+ // Release the image if it hasn't already been released.
+ if (m_sourceImage) {
+ cvReleaseImage(&m_sourceImage);
+ m_sourceImage = 0;
+ }
+ m_facesFound = 0;
+
+ m_sourceImage = getIplImageFromIntArray(env, photo_data, width, height);
+ if (m_sourceImage == 0) {
+ LOGE("Error source image could not be created.");
+ return false;
+ }
+
+ return true;
+}
+
+JNIEXPORT
+jbooleanArray
+JNICALL
+Java_org_siprop_opencv_OpenCV_findContours(JNIEnv* env,
+ jobject thiz,
+ jint width,
+ jint height) {
+ IplImage *grayImage = cvCreateImage( cvGetSize(m_sourceImage), IPL_DEPTH_8U, 1 ); // ƒOƒŒ[ƒXƒP[ƒ‹‰æ‘œ—pIplImage
+ IplImage *binaryImage = cvCreateImage( cvGetSize(m_sourceImage), IPL_DEPTH_8U, 1 ); // 2’l‰æ‘œ—pIplImage
+ IplImage *contourImage = cvCreateImage( cvGetSize(m_sourceImage), IPL_DEPTH_8U, 3 ); // —ÖŠs‰æ‘œ—pIplImage
+
+ // BGR‚©‚çƒOƒŒ[ƒXƒP[ƒ‹‚É•ÏŠ·‚·‚é
+ cvCvtColor( m_sourceImage, grayImage, CV_BGR2GRAY );
+
+ // ƒOƒŒ[ƒXƒP[ƒ‹‚©‚ç2’l‚É•ÏŠ·‚·‚é
+ cvThreshold( grayImage, binaryImage, THRESHOLD, THRESHOLD_MAX_VALUE, CV_THRESH_BINARY );
+
+ // —ÖŠs’Šo—p‚̃ƒ‚ƒŠ‚ðŠm•Û‚·‚é
+ CvMemStorage* storage = cvCreateMemStorage( 0 ); // ’Šo‚³‚ꂽ—ÖŠs‚ð•Û‘¶‚·‚é—̈æ
+ CvSeq* find_contour = 0; // —ÖŠs‚ւ̃|ƒCƒ“ƒ^
+
+ // 2’l‰æ‘œ’†‚Ì—ÖŠs‚ðŒ©‚Â‚¯A‚»‚Ì”‚ð•Ô‚·
+ int find_contour_num = cvFindContours(
+ binaryImage, // “ü—͉摜(‚WƒrƒbƒgƒVƒ“ƒOƒ‹ƒ`ƒƒƒ“ƒlƒ‹j
+ storage, // ’Šo‚³‚ꂽ—ÖŠs‚ð•Û‘¶‚·‚é—̈æ
+ &find_contour, // ˆê”ÔŠO‘¤‚Ì—ÖŠs‚ւ̃|ƒCƒ“ƒ^‚ւ̃|ƒCƒ“ƒ^
+ sizeof( CvContour ), // ƒV[ƒPƒ“ƒXƒwƒbƒ_‚̃TƒCƒY
+ CV_RETR_LIST, // ’Šoƒ‚[ƒh
+ CV_CHAIN_APPROX_NONE, // „’èŽè–@
+ cvPoint( 0, 0 ) // ƒIƒtƒZƒbƒg
+ );
+
+ // •¨‘Ì‚Ì—ÖŠs‚ðÔF‚Å•`‰æ‚·‚é
+ CvScalar red = CV_RGB( 255, 0, 0 );
+ cvDrawContours(
+ m_sourceImage, // —ÖŠs‚ð•`‰æ‚·‚é‰æ‘œ
+ find_contour, // ʼn‚Ì—ÖŠs‚ւ̃|ƒCƒ“ƒ^
+ red, // ŠO‘¤—ÖŠsü‚ÌF
+ red, // “à‘¤—ÖŠsüiŒŠj‚ÌF
+ CONTOUR_MAX_LEVEL, // •`‰æ‚³‚ê‚é—ÖŠs‚Ìő僌ƒxƒ‹
+ LINE_THICKNESS, // •`‰æ‚³‚ê‚é—ÖŠsü‚Ì‘¾‚³
+ LINE_TYPE, // ü‚ÌŽí—Þ
+ cvPoint( 0, 0 ) // ƒIƒtƒZƒbƒg
+ );
+
+ int imageSize;
+ CvMat stub, *mat_image;
+ int channels, ipl_depth;
+ mat_image = cvGetMat( m_sourceImage, &stub );
+ channels = CV_MAT_CN( mat_image->type );
+
+ ipl_depth = cvCvToIplDepth(mat_image->type);
+
+ LOGV("Load loadImageBytes.");
+ WLNonFileByteStream* strm = new WLNonFileByteStream();
+ loadImageBytes(mat_image->data.ptr, mat_image->step, mat_image->width,
+ mat_image->height, ipl_depth, channels, strm);
+
+ imageSize = strm->GetSize();
+ jbooleanArray res_array = env->NewBooleanArray(imageSize);
+ LOGV("Load NewBooleanArray.");
+ if (res_array == 0) {
+ return 0;
+ }
+ env->SetBooleanArrayRegion(res_array, 0, imageSize, (jboolean*)strm->GetByte());
+ LOGV("Load SetBooleanArrayRegion.");
+
+ LOGV("Release sourceImage");
+ if (m_sourceImage) {
+ cvReleaseImage(&m_sourceImage);
+ m_sourceImage = 0;
+ }
+ LOGV("Release binaryImage");
+ cvReleaseImage( &binaryImage );
+ LOGV("Release grayImage");
+ cvReleaseImage( &grayImage );
+ LOGV("Release contourImage");
+ cvReleaseImage( &contourImage );
+ LOGV("Release storage");
+ cvReleaseMemStorage( &storage );
+ LOGV("Delete strm");
+ strm->Close();
+ SAFE_DELETE(strm);
+
+ return res_array;
+}
+
+JNIEXPORT
+jboolean
+JNICALL
+Java_org_siprop_opencv_OpenCV_initFaceDetection(JNIEnv* env,
+ jobject thiz,
+ jstring cascade_path_str) {
+
+ // First call release to ensure the memory is empty.
+ Java_org_siprop_opencv_OpenCV_releaseFaceDetection(env, thiz);
+
+ char buffer[100];
+ clock_t total_time_start = clock();
+
+ m_smallestFaceSize.width = MIN_SIZE_WIDTH;
+ m_smallestFaceSize.height = MIN_SIZE_HEIGHT;
+
+ const char *cascade_path_chars = env->GetStringUTFChars(cascade_path_str, 0);
+ if (cascade_path_chars == 0) {
+ LOGE("Error getting cascade string.");
+ return false;
+ }
+
+ m_cascade = (CvHaarClassifierCascade*)cvLoad(cascade_path_chars);
+ env->ReleaseStringUTFChars(cascade_path_str, cascade_path_chars);
+ if (m_cascade == 0) {
+ LOGE("Error loading cascade.");
+ return false;
+ }
+
+ m_storage = cvCreateMemStorage(0);
+
+ clock_t total_time_finish = clock() - total_time_start;
+ sprintf(buffer, "Total Time to init: %f", (double)total_time_finish / (double)CLOCKS_PER_SEC);
+ LOGV(buffer);
+
+ return true;
+}
+
+// Release all of the memory used by face tracking.
+JNIEXPORT
+void
+JNICALL
+Java_org_siprop_opencv_OpenCV_releaseFaceDetection(JNIEnv* env,
+ jobject thiz) {
+
+ m_facesFound = 0;
+ m_faceCropArea.width = m_faceCropArea.height = 0;
+
+ if (m_cascade) {
+ cvReleaseHaarClassifierCascade(&m_cascade);
+ m_cascade = 0;
+ }
+
+ if (m_sourceImage) {
+ cvReleaseImage(&m_sourceImage);
+ m_sourceImage = 0;
+ }
+
+ if (m_grayImage) {
+ cvReleaseImage(&m_grayImage);
+ m_grayImage = 0;
+ }
+
+ if (m_smallImage) {
+ cvReleaseImage(&m_smallImage);
+ m_smallImage = 0;
+ }
+
+ if (m_storage) {
+ cvReleaseMemStorage(&m_storage);
+ m_storage = 0;
+ }
+}
+
+// Initalize the small image and the gray image using the input source image.
+// If a previous face was specified, we will limit the ROI to that face.
+void initFaceDetectionImages(IplImage *sourceImage, double scale = 1.0) {
+ if (m_grayImage == 0) {
+ m_grayImage = cvCreateImage(cvGetSize(sourceImage), IPL_DEPTH_8U, 1);
+ }
+
+ if (m_smallImage == 0) {
+ m_smallImage = cvCreateImage(cvSize(cvRound(sourceImage->width / scale),
+ cvRound(sourceImage->height / scale)), IPL_DEPTH_8U, 1);
+ }
+
+ if(m_faceCropArea.width > 0 && m_faceCropArea.height > 0) {
+ cvSetImageROI(m_smallImage, m_faceCropArea);
+
+ CvRect tPrev = cvRect(m_faceCropArea.x * scale, m_faceCropArea.y * scale,
+ m_faceCropArea.width * scale, m_faceCropArea.height * scale);
+ cvSetImageROI(sourceImage, tPrev);
+ cvSetImageROI(m_grayImage, tPrev);
+ } else {
+ cvResetImageROI(m_smallImage);
+ cvResetImageROI(m_grayImage);
+ }
+
+ cvCvtColor(sourceImage, m_grayImage, CV_BGR2GRAY);
+ cvResize(m_grayImage, m_smallImage, CV_INTER_LINEAR);
+ cvEqualizeHist(m_smallImage, m_smallImage);
+ cvClearMemStorage(m_storage);
+
+ cvResetImageROI(sourceImage);
+}
+
+// Given a sequence of rectangles, return an array of Android Rect objects
+// or null if any errors occur.
+jobjectArray seqRectsToAndroidRects(JNIEnv* env, CvSeq *rects) {
+ if (rects == 0 || rects->total <= 0) {
+ LOGE("No rectangles were specified!");
+ return 0;
+ }
+
+ jclass jcls = env->FindClass("android/graphics/Rect");
+ if (jcls == 0) {
+ LOGE("Unable to find class android.graphics.Rect");
+ return 0;
+ }
+
+ jmethodID jconstruct = env->GetMethodID(jcls, "<init>", "(IIII)V");
+ if (jconstruct == 0) {
+ LOGE("Unable to find constructor Rect(int, int, int, int)");
+ return 0;
+ }
+
+ jobjectArray ary = env->NewObjectArray(rects->total, jcls, 0);
+ if (ary == 0) {
+ LOGE("Unable to create Rect array");
+ return 0;
+ }
+
+ for (int i = 0; i < rects->total; i++) {
+ char buffer[100];
+ CvRect *rect = (CvRect*)cvGetSeqElem(rects, i);
+ if (rect == 0) {
+ sprintf(buffer, "Invalid Rectangle #%d", i);
+ LOGE(buffer);
+ return 0;
+ }
+
+ jobject jrect = env->NewObject(jcls, jconstruct, rect->x, rect->y,
+ rect->width, rect->height);
+ if (jrect == 0) {
+ sprintf(buffer, "Unable to create Android Rect object for rectangle #%d", i);
+ LOGE(buffer);
+ return 0;
+ }
+
+ env->SetObjectArrayElement(ary, i, jrect);
+ env->DeleteLocalRef(jrect);
+ }
+
+ return ary;
+}
+
+// Identify all of the faces in the source image and return an array
+// of Android Rect objects with the face coordinates. If any errors
+// occur, a 0 array will be returned.
+JNIEXPORT
+jobjectArray
+JNICALL
+Java_org_siprop_opencv_OpenCV_findAllFaces(JNIEnv* env,
+ jobject thiz) {
+ char buffer[100];
+ clock_t total_time_start = clock();
+
+ if (m_cascade == 0 || m_storage == 0) {
+ LOGE("Error find faces was not initialized.");
+ return 0;
+ }
+
+ if (m_sourceImage == 0) {
+ LOGE("Error source image was not set.");
+ return 0;
+ }
+
+ initFaceDetectionImages(m_sourceImage, IMAGE_SCALE);
+
+ clock_t haar_detect_time_start = clock();
+ m_facesFound = mycvHaarDetectObjects(m_smallImage, m_cascade, m_storage, HAAR_SCALE,
+ MIN_NEIGHBORS, HAAR_FLAGS_ALL_FACES, cvSize(MIN_SIZE_WIDTH, MIN_SIZE_HEIGHT));
+
+ clock_t haar_detect_time_finish = clock() - haar_detect_time_start;
+ sprintf(buffer, "Total Time to cvHaarDetectObjects in findAllFaces: %f", (double)haar_detect_time_finish / (double)CLOCKS_PER_SEC);
+ LOGV(buffer);
+
+ jobjectArray faceRects = 0;
+ if (m_facesFound == 0 || m_facesFound->total <= 0) {
+ LOGV("FACES_DETECTED 0");
+ } else {
+ sprintf(buffer, "FACES_DETECTED %d", m_facesFound->total);
+ LOGV(buffer);
+ m_faceCropArea.width = m_faceCropArea.height = 0;
+ faceRects = seqRectsToAndroidRects(env, m_facesFound);
+ }
+
+ clock_t total_time_finish = clock() - total_time_start;
+ sprintf(buffer, "Total Time to findAllFaces: %f", (double)total_time_finish / (double)CLOCKS_PER_SEC);
+ LOGV(buffer);
+
+ return faceRects;
+}
+
+// Store the previous face found in the scene.
+void storePreviousFace(CvRect* face) {
+ char buffer[100];
+ if (m_faceCropArea.width > 0 && m_faceCropArea.height > 0) {
+ face->x += m_faceCropArea.x;
+ face->y += m_faceCropArea.y;
+ sprintf(buffer, "Face rect + m_faceCropArea: (%d, %d) to (%d, %d)", face->x, face->y,
+ face->x + face->width, face->y + face->height);
+ LOGV(buffer);
+ }
+
+ int startX = MAX(face->x - PAD_FACE_AREA, 0);
+ int startY = MAX(face->y - PAD_FACE_AREA, 0);
+ int w = m_smallImage->width - startX - face->width - PAD_FACE_AREA_2;
+ int h = m_smallImage->height - startY - face->height - PAD_FACE_AREA_2;
+ int sw = face->x - PAD_FACE_AREA, sh = face->y - PAD_FACE_AREA;
+ m_faceCropArea = cvRect(startX, startY,
+ face->width + PAD_FACE_AREA_2 + ((w < 0) ? w : 0) + ((sw < 0) ? sw : 0),
+ face->height + PAD_FACE_AREA_2 + ((h < 0) ? h : 0) + ((sh < 0) ? sh : 0));
+ sprintf(buffer, "m_faceCropArea: (%d, %d) to (%d, %d)", m_faceCropArea.x, m_faceCropArea.y,
+ m_faceCropArea.x + m_faceCropArea.width, m_faceCropArea.y + m_faceCropArea.height);
+ LOGV(buffer);
+}
+
+// Given a rectangle, return an Android Rect object or null if any
+// errors occur.
+jobject rectToAndroidRect(JNIEnv* env, CvRect *rect) {
+ if (rect == 0) {
+ LOGE("No rectangle was specified!");
+ return 0;
+ }
+
+ jclass jcls = env->FindClass("android/graphics/Rect");
+ if (jcls == 0) {
+ LOGE("Unable to find class android.graphics.Rect");
+ return 0;
+ }
+
+ jmethodID jconstruct = env->GetMethodID(jcls, "<init>", "(IIII)V");
+ if (jconstruct == 0) {
+ LOGE("Unable to find constructor Rect(int, int, int, int)");
+ return 0;
+ }
+
+ return env->NewObject(jcls, jconstruct, rect->x, rect->y,
+ rect->width, rect->height);
+}
+
+// Identify a single face in the source image and return an Android
+// Android Rect object with the face coordinates. This method is
+// optimized by focusing on a single face and cropping the detection
+// region to the area where the face is located plus some additional
+// padding to account for slight head movements. If any errors occur,
+// a 0 array will be returned.
+JNIEXPORT
+jobject
+JNICALL
+Java_org_siprop_opencv_OpenCV_findSingleFace(JNIEnv* env,
+ jobject thiz) {
+ char buffer[100];
+ clock_t total_time_start = clock();
+
+ if (m_cascade == 0 || m_storage == 0) {
+ LOGE("Error find faces was not initialized.");
+ return 0;
+ }
+
+ if (m_sourceImage == 0) {
+ LOGE("Error source image was not set.");
+ return 0;
+ }
+
+ initFaceDetectionImages(m_sourceImage, IMAGE_SCALE);
+
+ clock_t haar_detect_time_start = clock();
+ m_facesFound = mycvHaarDetectObjects(m_smallImage, m_cascade, m_storage, HAAR_SCALE,
+ MIN_NEIGHBORS, HAAR_FLAGS_SINGLE_FACE, m_smallestFaceSize);
+
+ clock_t haar_detect_time_finish = clock() - haar_detect_time_start;
+ sprintf(buffer, "Total Time to cvHaarDetectObjects in findSingleFace: %f", (double)haar_detect_time_finish / (double)CLOCKS_PER_SEC);
+ LOGV(buffer);
+
+ jobject faceRect = 0;
+ if (m_facesFound == 0 || m_facesFound->total <= 0) {
+ LOGV("FACES_DETECTED 0");
+ m_faceCropArea.width = m_faceCropArea.height = 0;
+ m_smallestFaceSize.width = MIN_SIZE_WIDTH;
+ m_smallestFaceSize.height = MIN_SIZE_HEIGHT;
+ } else {
+ LOGV("FACES_DETECTED 1");
+ CvRect *face = (CvRect*)cvGetSeqElem(m_facesFound, 0);
+ if (face == 0) {
+ LOGE("Invalid rectangle detected");
+ return 0;
+ }
+ m_smallestFaceSize.width = MAX(face->width - PAD_FACE_SIZE, MIN_SIZE_WIDTH);
+ m_smallestFaceSize.height = MAX(face->height - PAD_FACE_SIZE, MIN_SIZE_HEIGHT);
+ faceRect = rectToAndroidRect(env, face);
+ storePreviousFace(face);
+ }
+
+ clock_t total_time_finish = clock() - total_time_start;
+ sprintf(buffer, "Total Time to findSingleFace: %f", (double)total_time_finish / (double)CLOCKS_PER_SEC);
+ LOGV(buffer);
+
+ return faceRect;
+}
+
+// Draw a rectangle on the source image around the specified face rectangle.
+// Scale the face area to the draw area based on the specified scale.
+void highlightFace(IplImage *sourceImage, CvRect *face, double scale = 1.0) {
+ char buffer[100];
+ sprintf(buffer, "Face Rectangle: (x: %d, y: %d) to (w: %d, h: %d)",
+ face->x, face->y, face->width, face->height);
+ LOGV(buffer);
+ CvPoint pt1 = cvPoint(int(face->x * scale), int(face->y * scale));
+ CvPoint pt2 = cvPoint(int((face->x + face->width) * scale),
+ int((face->y + face->height) * scale));
+ sprintf(buffer, "Draw Rectangle: (%d, %d) to (%d, %d)", pt1.x, pt1.y, pt2.x, pt2.y);
+ LOGV(buffer);
+ cvRectangle(sourceImage, pt1, pt2, CV_RGB(255, 0, 0), 3, 8, 0);
+}
+
+// Draw rectangles on the source image around each face that was found.
+// Scale the face area to the draw area based on the specified scale.
+// Return true if at least one face was highlighted and false otherwise.
+bool highlightFaces(IplImage *sourceImage, CvSeq *faces, double scale = 1.0) {
+ if (faces == 0 || faces->total <= 0) {
+ LOGV("No faces were highlighted!");
+ return false;
+ } else {
+ LOGV("Drawing rectangles on each face");
+ int count;
+ CvRect* face;
+ for (int i = 0; i < faces->total; i++) {
+ face = (CvRect*)cvGetSeqElem(faces, i);
+ highlightFace(sourceImage, face, scale);
+ }
+ }
+
+ return true;
+}
+
+// Highlight the faces that were detected in the source image.
+// Return true if one or more faces is highlighted or false otherwise.
+JNIEXPORT
+jboolean
+JNICALL
+Java_org_siprop_opencv_OpenCV_highlightFaces(JNIEnv* env,
+ jobject thiz) {
+ if (m_facesFound == 0 || m_facesFound->total <= 0) {
+ LOGV("No faces found to highlight!");
+ return false;
+ } else {
+ highlightFaces(m_sourceImage, m_facesFound, IMAGE_SCALE);
+ }
+
+ return true;
+}
+
+#if 0
+
+JNIEXPORT
+jbooleanArray
+JNICALL
+Java_org_siprop_opencv_OpenCV_faceDetect(JNIEnv* env,
+ jobject thiz,
+ jintArray photo_data1,
+ jintArray photo_data2,
+ jint width,
+ jint height) {
+ LOGV("Load desp.");
+
+ int i, x, y;
+ int* pixels;
+ IplImage *frameImage;
+
+ IplImage *backgroundImage = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
+ IplImage *grayImage = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
+ IplImage *differenceImage = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
+
+ IplImage *hsvImage = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 3 );
+ IplImage *hueImage = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
+ IplImage *saturationImage = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
+ IplImage *valueImage = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
+ IplImage *thresholdImage1 = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
+ IplImage *thresholdImage2 = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
+ IplImage *thresholdImage3 = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
+ IplImage *faceImage = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
+
+ CvMoments moment;
+ double m_00;
+ double m_10;
+ double m_01;
+ int gravityX;
+ int gravityY;
+
+ jbooleanArray res_array;
+ int imageSize;
+
+
+
+ // Load Image
+ pixels = env->GetIntArrayElements(photo_data1, 0);
+ frameImage = loadPixels(pixels, width, height);
+ if(frameImage == 0) {
+ LOGV("Error loadPixels.");
+ return 0;
+ }
+
+
+ cvCvtColor( frameImage, backgroundImage, CV_BGR2GRAY );
+
+
+ pixels = env->GetIntArrayElements(photo_data2, 0);
+ frameImage = loadPixels(pixels, width, height);
+ if(frameImage == 0) {
+ LOGV("Error loadPixels.");
+ return 0;
+ }
+ cvCvtColor( frameImage, grayImage, CV_BGR2GRAY );
+ cvAbsDiff( grayImage, backgroundImage, differenceImage );
+
+ cvCvtColor( frameImage, hsvImage, CV_BGR2HSV );
+ LOGV("Load cvCvtColor.");
+ cvSplit( hsvImage, hueImage, saturationImage, valueImage, 0 );
+ LOGV("Load cvSplit.");
+ cvThreshold( hueImage, thresholdImage1, THRESH_BOTTOM, THRESHOLD_MAX_VALUE, CV_THRESH_BINARY );
+ cvThreshold( hueImage, thresholdImage2, THRESH_TOP, THRESHOLD_MAX_VALUE, CV_THRESH_BINARY_INV );
+ cvAnd( thresholdImage1, thresholdImage2, thresholdImage3, 0 );
+ LOGV("Load cvAnd.");
+
+ cvAnd( differenceImage, thresholdImage3, faceImage, 0 );
+
+ cvMoments( faceImage, &moment, 0 );
+ m_00 = cvGetSpatialMoment( &moment, 0, 0 );
+ m_10 = cvGetSpatialMoment( &moment, 1, 0 );
+ m_01 = cvGetSpatialMoment( &moment, 0, 1 );
+ gravityX = m_10 / m_00;
+ gravityY = m_01 / m_00;
+ LOGV("Load cvMoments.");
+
+
+ cvCircle( frameImage, cvPoint( gravityX, gravityY ), CIRCLE_RADIUS,
+ CV_RGB( 255, 0, 0 ), LINE_THICKNESS, LINE_TYPE, 0 );
+
+
+
+
+ CvMat stub, *mat_image;
+ int channels, ipl_depth;
+ mat_image = cvGetMat( frameImage, &stub );
+ channels = CV_MAT_CN( mat_image->type );
+
+ ipl_depth = cvCvToIplDepth(mat_image->type);
+
+ WLNonFileByteStream* m_strm = new WLNonFileByteStream();
+ loadImageBytes(mat_image->data.ptr, mat_image->step, mat_image->width,
+ mat_image->height, ipl_depth, channels, m_strm);
+ LOGV("Load loadImageBytes.");
+
+
+ imageSize = m_strm->GetSize();
+ res_array = env->NewBooleanArray(imageSize);
+ LOGV("Load NewByteArray.");
+ if (res_array == 0) {
+ return 0;
+ }
+ env->SetBooleanArrayRegion(res_array, 0, imageSize, (jboolean*)m_strm->GetByte());
+ LOGV("Load SetBooleanArrayRegion.");
+
+
+
+
+ cvReleaseImage( &backgroundImage );
+ cvReleaseImage( &grayImage );
+ cvReleaseImage( &differenceImage );
+ cvReleaseImage( &hsvImage );
+ cvReleaseImage( &hueImage );
+ cvReleaseImage( &saturationImage );
+ cvReleaseImage( &valueImage );
+ cvReleaseImage( &thresholdImage1 );
+ cvReleaseImage( &thresholdImage2 );
+ cvReleaseImage( &thresholdImage3 );
+ cvReleaseImage( &faceImage );
+ cvReleaseImage( &frameImage );
+ m_strm->Close();
+ SAFE_DELETE(m_strm);
+
+ return res_array;
+
+}
+#endif
+
diff --git a/cvjni.h b/cvjni.h
new file mode 100644
index 0000000..fff0cae
--- /dev/null
+++ b/cvjni.h
@@ -0,0 +1,342 @@
+/*
+OpenCV for Android NDK
+Copyright (c) 2006-2009 SIProp Project http://www.siprop.org/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <jni.h>
+#include <android/log.h>
+
+#include "cv.h"
+#include "cxcore.h"
+#include "cvaux.h"
+#include "highgui.h"
+#include "ml.h"
+#include "utils.h"
+#include "WLNonFileByteStream.h"
+#include "grfmt_bmp.h"
+
+#define LOGV(...) __android_log_print(ANDROID_LOG_SILENT, LOG_TAG, __VA_ARGS__)
+#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+//ANDROID_LOG_UNKNOWN, ANDROID_LOG_DEFAULT, ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, ANDROID_LOG_SILENT
+//LOGV(ANDROID_LOG_DEBUG, "JNI", "");
+
+#define ANDROID_LOG_VERBOSE ANDROID_LOG_DEBUG
+#define LOG_TAG "CVJNI"
+#define INVALID_ARGUMENT -18456
+
+#define SAFE_DELETE(p) { if(p){ delete (p); (p)=0; } }
+#define SAFE_DELETE_ARRAY(p) { if(p){ delete [](p); (p)=0; } }
+
+
+#define IMAGE( i, x, y, n ) *(( unsigned char * )(( i )->imageData \
+ + ( x ) * sizeof( unsigned char ) * 3 \
+ + ( y ) * ( i )->widthStep ) + ( n ))
+
+// CV Objects
+static const char* fmtSignBmp = "BM";
+
+CvCapture *m_capture = 0;
+CvHaarClassifierCascade *m_cascade = 0;
+IplImage *m_sourceImage = 0;
+IplImage *m_grayImage = 0;
+IplImage *m_smallImage = 0;
+CvMemStorage *m_storage = 0;
+CvSeq *m_facesFound = 0;
+CvRect m_faceCropArea;
+CvSize m_smallestFaceSize;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+JNIEXPORT
+jboolean
+JNICALL
+Java_org_siprop_opencv_OpenCV_createSocketCapture(JNIEnv* env,
+ jobject thiz,
+ jstring address_str,
+ jstring port_str,
+ jint width,
+ jint height);
+
+JNIEXPORT
+void
+JNICALL
+Java_org_siprop_opencv_OpenCV_releaseSocketCapture(JNIEnv* env,
+ jobject thiz);
+
+JNIEXPORT
+jboolean
+JNICALL
+Java_org_siprop_opencv_OpenCV_grabSourceImageFromCapture(JNIEnv* env,
+ jobject thiz);
+
+JNIEXPORT
+jbooleanArray
+JNICALL
+Java_org_siprop_opencv_OpenCV_getSourceImage(JNIEnv* env,
+ jobject thiz);
+
+JNIEXPORT
+jboolean
+JNICALL
+Java_org_siprop_opencv_OpenCV_setSourceImage(JNIEnv* env,
+ jobject thiz,
+ jintArray photo_data,
+ jint width,
+ jint height);
+
+JNIEXPORT
+jbooleanArray
+JNICALL
+Java_org_siprop_opencv_OpenCV_findContours(JNIEnv* env,
+ jobject thiz,
+ jint width,
+ jint height);
+
+JNIEXPORT
+jboolean
+JNICALL
+Java_org_siprop_opencv_OpenCV_initFaceDetection(JNIEnv* env,
+ jobject thiz,
+ jstring cascade_path_str);
+
+JNIEXPORT
+void
+JNICALL
+Java_org_siprop_opencv_OpenCV_releaseFaceDetection(JNIEnv* env,
+ jobject thiz);
+
+JNIEXPORT
+jboolean
+JNICALL
+Java_org_siprop_opencv_OpenCV_highlightFaces(JNIEnv* env,
+ jobject thiz);
+
+JNIEXPORT
+jobjectArray
+JNICALL
+Java_org_siprop_opencv_OpenCV_findAllFaces(JNIEnv* env,
+ jobject thiz);
+
+JNIEXPORT
+jobject
+JNICALL
+Java_org_siprop_opencv_OpenCV_findSingleFace(JNIEnv* env,
+ jobject thiz);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+IplImage* loadPixels(int* pixels, int width, int height) {
+
+ int x, y;
+ IplImage *img = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
+
+ for ( y = 0; y < height; y++ ) {
+ for ( x = 0; x < width; x++ ) {
+ // blue
+ IMAGE( img, x, y, 0 ) = pixels[x+y*width] & 0xFF;
+ // green
+ IMAGE( img, x, y, 1 ) = pixels[x+y*width] >> 8 & 0xFF;
+ // red
+ IMAGE( img, x, y, 2 ) = pixels[x+y*width] >> 16 & 0xFF;
+ }
+ }
+
+ return img;
+}
+
+
+void loadImageBytes(const uchar* data,
+ int step,
+ int width,
+ int height,
+ int depth,
+ int channels,
+ WLNonFileByteStream* m_strm) {
+
+ int fileStep = (width*channels + 3) & -4;
+ uchar zeropad[] = "\0\0\0\0";
+ char log_str[100];
+
+
+ assert( data && width > 0 && height > 0 && step >= fileStep );
+
+ int bitmapHeaderSize = 40;
+ int paletteSize = channels > 1 ? 0 : 1024;
+ int headerSize = 14 /* fileheader */ + bitmapHeaderSize + paletteSize;
+ PaletteEntry palette[256];
+
+ int testSize = fileStep*height + headerSize;
+ m_strm->Open(testSize);
+ sprintf(log_str, "fileStep*height + headerSize=%i", testSize);
+ LOGV(log_str);
+
+ // write signature 'BM'
+ m_strm->PutBytes( fmtSignBmp, (int)strlen(fmtSignBmp) );
+
+ // write file header
+ m_strm->PutDWord( fileStep*height + headerSize ); // file size
+ m_strm->PutDWord( 0 );
+ m_strm->PutDWord( headerSize );
+
+ // write bitmap header
+ m_strm->PutDWord( bitmapHeaderSize );
+ m_strm->PutDWord( width );
+ m_strm->PutDWord( height );
+ m_strm->PutWord( 1 );
+ m_strm->PutWord( channels << 3 );
+ m_strm->PutDWord( BMP_RGB );
+ m_strm->PutDWord( 0 );
+ m_strm->PutDWord( 0 );
+ m_strm->PutDWord( 0 );
+ m_strm->PutDWord( 0 );
+ m_strm->PutDWord( 0 );
+
+ if( channels == 1 )
+ {
+ FillGrayPalette( palette, 8 );
+ m_strm->PutBytes( palette, sizeof(palette));
+ }
+
+ width *= channels;
+ data += step*(height - 1);
+ for( ; height--; data -= step )
+ {
+ m_strm->PutBytes( data, width );
+ if( fileStep > width )
+ m_strm->PutBytes( zeropad, fileStep - width );
+ }
+}
+
+
+
+
+bool is_NULL_field_JavaObj(JNIEnv* env, jobject java_obj, const char* field_name, const char* field_type) {
+
+
+ LOGV("in is_NULL_field_JavaObj!");
+ jclass clazz = env->GetObjectClass(java_obj);
+
+
+ // get field
+ jfieldID fid = env->GetFieldID(clazz, field_name, field_type);
+
+ jobject obj = env->GetObjectField(java_obj, fid);
+ if(obj == 0) {
+ LOGV("Object is NULL!");
+ return true;
+ }
+ return false;
+}
+
+bool is_NULL_vec_field_JavaObj(JNIEnv* env, jobject java_obj, const char* field_name) {
+ return is_NULL_field_JavaObj(env, java_obj, field_name, "Lorg/siprop/opencv/util/Vector3;");
+}
+
+bool is_NULL_point_field_JavaObj(JNIEnv* env, jobject java_obj, const char* field_name) {
+ return is_NULL_field_JavaObj(env, java_obj, field_name, "Lorg/siprop/opencv/util/Point3;");
+}
+
+bool is_NULL_axis_field_JavaObj(JNIEnv* env, jobject java_obj, const char* field_name) {
+ return is_NULL_field_JavaObj(env, java_obj, field_name, "Lorg/siprop/opencv/util/Axis;");
+}
+
+bool is_NULL_pivot_field_JavaObj(JNIEnv* env, jobject java_obj, const char* field_name) {
+ return is_NULL_field_JavaObj(env, java_obj, field_name, "Lorg/siprop/opencv/util/Pivot3;");
+}
+
+bool is_NULL_quat_field_JavaObj(JNIEnv* env, jobject java_obj, const char* field_name) {
+ return is_NULL_field_JavaObj(env, java_obj, field_name, "Lorg/siprop/opencv/util/Quaternion;");
+}
+
+bool is_NULL_mat3x3_field_JavaObj(JNIEnv* env, jobject java_obj, const char* field_name) {
+ return is_NULL_field_JavaObj(env, java_obj, field_name, "Lorg/siprop/opencv/util/Matrix3x3;");
+}
+bool is_NULL_mat3x1_field_JavaObj(JNIEnv* env, jobject java_obj, const char* field_name) {
+ return is_NULL_field_JavaObj(env, java_obj, field_name, "Lorg/siprop/opencv/util/Matrix3x1;");
+}
+
+
+
+
+void set_JavaObj_int(JNIEnv* env, jobject java_obj, const char* field_name, jint val) {
+
+ LOGV("in set_JavaObj_int!");
+
+ jclass clazz = env->GetObjectClass(java_obj);
+ jfieldID fid = env->GetFieldID(clazz, field_name, "I");
+
+ env->SetIntField(java_obj, fid, val);
+
+}
+
+int get_id_by_JavaObj(JNIEnv* env, jobject java_obj) {
+
+ LOGV("in get_id_by_JavaObj!");
+
+ jclass method_clazz = env->GetObjectClass(java_obj);
+ jmethodID get_type_mid = env->GetMethodID(method_clazz, "getID", "()I");
+ return env->CallIntMethod(java_obj, get_type_mid);
+
+}
+
+int get_type_by_JavaObj(JNIEnv* env, jobject java_obj) {
+
+ LOGV("in get_type_by_JavaObj!");
+
+ jclass method_clazz = env->GetObjectClass(java_obj);
+ jmethodID get_type_mid = env->GetMethodID(method_clazz, "getType", "()I");
+ return env->CallIntMethod(java_obj, get_type_mid);
+
+}
+
+
+int get_int_by_JavaObj(JNIEnv* env, jobject java_obj, const char* field_name) {
+
+ LOGV("in get_int_by_JavaObj!");
+
+ jclass clazz = env->GetObjectClass(java_obj);
+ jfieldID int_fid = env->GetFieldID(clazz, field_name, "I");
+ return env->GetIntField(java_obj, int_fid);
+
+}
+
+
+float get_float_by_JavaObj(JNIEnv* env, jobject java_obj, const char* field_name) {
+
+ LOGV("in get_float_by_JavaObj!");
+
+ jclass clazz = env->GetObjectClass(java_obj);
+ jfieldID float_fid = env->GetFieldID(clazz, field_name, "F");
+ return env->GetFloatField(java_obj, float_fid);
+
+}
+
+
+jobject get_obj_by_JavaObj(JNIEnv* env, jobject java_obj, const char* field_name, const char* obj_type) {
+
+ LOGV("in get_obj_by_JavaObj!");
+
+ jclass clazz = env->GetObjectClass(java_obj);
+ jfieldID obj_fid = env->GetFieldID(clazz, field_name, obj_type);
+ return env->GetObjectField(java_obj, obj_fid);
+
+}
+
diff --git a/cxcore/include/cvver.h b/cxcore/include/cvver.h
new file mode 100644
index 0000000..8bd7996
--- /dev/null
+++ b/cxcore/include/cvver.h
@@ -0,0 +1,55 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright( C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+//(including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort(including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/*
+ definition of the current version of OpenCV
+ Usefull to test in user programs
+*/
+
+#ifndef _CVVERSION_H_
+#define _CVVERSION_H_
+
+#define CV_MAJOR_VERSION 1
+#define CV_MINOR_VERSION 1
+#define CV_SUBMINOR_VERSION 0
+#define CV_VERSION "1.1.0"
+
+#endif /*_CVVERSION_H_*/
diff --git a/cxcore/include/cvwimage.h b/cxcore/include/cvwimage.h
new file mode 100644
index 0000000..9da50a7
--- /dev/null
+++ b/cxcore/include/cvwimage.h
@@ -0,0 +1,621 @@
+///////////////////////////////////////////////////////////////////////////////
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to
+// this license. If you do not agree to this license, do not download,
+// install, copy or use the software.
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2008, Google, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation or contributors may not be used to endorse
+// or promote products derived from this software without specific
+// prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is"
+// and any express or implied warranties, including, but not limited to, the
+// implied warranties of merchantability and fitness for a particular purpose
+// are disclaimed. In no event shall the Intel Corporation or contributors be
+// liable for any direct, indirect, incidental, special, exemplary, or
+// consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+// Image class which provides a thin layer around an IplImage. The goals
+// of the class design are:
+// 1. All the data has explicit ownership to avoid memory leaks
+// 2. No hidden allocations or copies for performance.
+// 3. Easy access to OpenCV methods (which will access IPP if available)
+// 4. Can easily treat external data as an image
+// 5. Easy to create images which are subsets of other images
+// 6. Fast pixel access which can take advantage of number of channels
+// if known at compile time.
+//
+// The WImage class is the image class which provides the data accessors.
+// The 'W' comes from the fact that it is also a wrapper around the popular
+// but inconvenient IplImage class. A WImage can be constructed either using a
+// WImageBuffer class which allocates and frees the data,
+// or using a WImageView class which constructs a subimage or a view into
+// external data. The view class does no memory management. Each class
+// actually has two versions, one when the number of channels is known at
+// compile time and one when it isn't. Using the one with the number of
+// channels specified can provide some compile time optimizations by using the
+// fact that the number of channels is a constant.
+//
+// We use the convention (c,r) to refer to column c and row r with (0,0) being
+// the upper left corner. This is similar to standard Euclidean coordinates
+// with the first coordinate varying in the horizontal direction and the second
+// coordinate varying in the vertical direction.
+// Thus (c,r) is usually in the domain [0, width) X [0, height)
+//
+// Example usage:
+// WImageBuffer3_b im(5,7); // Make a 5X7 3 channel image of type uchar
+// WImageView3_b sub_im(im, 2,2, 3,3); // 3X3 submatrix
+// vector<float> vec(10, 3.0f);
+// WImageView1_f user_im(&vec[0], 2, 5); // 2X5 image w/ supplied data
+//
+// im.SetZero(); // same as cvSetZero(im.Ipl())
+// *im(2, 3) = 15; // Modify the element at column 2, row 3
+// MySetRand(&sub_im);
+//
+// // Copy the second row into the first. This can be done with no memory
+// // allocation and will use SSE if IPP is available.
+// int w = im.Width();
+// im.View(0,0, w,1).CopyFrom(im.View(0,1, w,1));
+//
+// // Doesn't care about source of data since using WImage
+// void MySetRand(WImage_b* im) { // Works with any number of channels
+// for (int r = 0; r < im->Height(); ++r) {
+// float* row = im->Row(r);
+// for (int c = 0; c < im->Width(); ++c) {
+// for (int ch = 0; ch < im->Channels(); ++ch, ++row) {
+// *row = uchar(rand() & 255);
+// }
+// }
+// }
+// }
+//
+// Functions that are not part of the basic image allocation, viewing, and
+// access should come from OpenCV, except some useful functions that are not
+// part of OpenCV can be found in wimage_util.h
+#ifndef _CV_WIMAGE_H_
+#define _CV_WIMAGE_H_
+
+#include "cxcore.h"
+
+#ifdef __cplusplus
+
+namespace cv {
+
+template <typename T> class WImage;
+template <typename T> class WImageBuffer;
+template <typename T> class WImageView;
+
+template<typename T, int C> class WImageC;
+template<typename T, int C> class WImageBufferC;
+template<typename T, int C> class WImageViewC;
+
+// Commonly used typedefs.
+typedef WImage<uchar> WImage_b;
+typedef WImageView<uchar> WImageView_b;
+typedef WImageBuffer<uchar> WImageBuffer_b;
+
+typedef WImageC<uchar, 1> WImage1_b;
+typedef WImageViewC<uchar, 1> WImageView1_b;
+typedef WImageBufferC<uchar, 1> WImageBuffer1_b;
+
+typedef WImageC<uchar, 3> WImage3_b;
+typedef WImageViewC<uchar, 3> WImageView3_b;
+typedef WImageBufferC<uchar, 3> WImageBuffer3_b;
+
+typedef WImage<float> WImage_f;
+typedef WImageView<float> WImageView_f;
+typedef WImageBuffer<float> WImageBuffer_f;
+
+typedef WImageC<float, 1> WImage1_f;
+typedef WImageViewC<float, 1> WImageView1_f;
+typedef WImageBufferC<float, 1> WImageBuffer1_f;
+
+typedef WImageC<float, 3> WImage3_f;
+typedef WImageViewC<float, 3> WImageView3_f;
+typedef WImageBufferC<float, 3> WImageBuffer3_f;
+
+// There isn't a standard for signed and unsigned short so be more
+// explicit in the typename for these cases.
+typedef WImage<short> WImage_16s;
+typedef WImageView<short> WImageView_16s;
+typedef WImageBuffer<short> WImageBuffer_16s;
+
+typedef WImageC<short, 1> WImage1_16s;
+typedef WImageViewC<short, 1> WImageView1_16s;
+typedef WImageBufferC<short, 1> WImageBuffer1_16s;
+
+typedef WImageC<short, 3> WImage3_16s;
+typedef WImageViewC<short, 3> WImageView3_16s;
+typedef WImageBufferC<short, 3> WImageBuffer3_16s;
+
+typedef WImage<ushort> WImage_16u;
+typedef WImageView<ushort> WImageView_16u;
+typedef WImageBuffer<ushort> WImageBuffer_16u;
+
+typedef WImageC<ushort, 1> WImage1_16u;
+typedef WImageViewC<ushort, 1> WImageView1_16u;
+typedef WImageBufferC<ushort, 1> WImageBuffer1_16u;
+
+typedef WImageC<ushort, 3> WImage3_16u;
+typedef WImageViewC<ushort, 3> WImageView3_16u;
+typedef WImageBufferC<ushort, 3> WImageBuffer3_16u;
+
+//
+// WImage definitions
+//
+// This WImage class gives access to the data it refers to. It can be
+// constructed either by allocating the data with a WImageBuffer class or
+// using the WImageView class to refer to a subimage or outside data.
+template<typename T>
+class WImage
+{
+public:
+ typedef T BaseType;
+
+ // WImage is an abstract class with no other virtual methods so make the
+ // destructor virtual.
+ virtual ~WImage() = 0;
+
+ // Accessors
+ IplImage* Ipl() {return image_; }
+ const IplImage* Ipl() const {return image_; }
+ T* ImageData() { return reinterpret_cast<T*>(image_->imageData); }
+ const T* ImageData() const {
+ return reinterpret_cast<const T*>(image_->imageData);
+ }
+
+ int Width() const {return image_->width; }
+ int Height() const {return image_->height; }
+
+ // WidthStep is the number of bytes to go to the pixel with the next y coord
+ int WidthStep() const {return image_->widthStep; }
+
+ int Channels() const {return image_->nChannels; }
+ int ChannelSize() const {return sizeof(T); } // number of bytes per channel
+
+ // Number of bytes per pixel
+ int PixelSize() const {return Channels() * ChannelSize(); }
+
+ // Return depth type (e.g. IPL_DEPTH_8U, IPL_DEPTH_32F) which is the number
+ // of bits per channel and with the signed bit set.
+ // This is known at compile time using specializations.
+ int Depth() const;
+
+ inline const T* Row(int r) const {
+ return reinterpret_cast<T*>(image_->imageData + r*image_->widthStep);
+ }
+
+ inline T* Row(int r) {
+ return reinterpret_cast<T*>(image_->imageData + r*image_->widthStep);
+ }
+
+ // Pixel accessors which returns a pointer to the start of the channel
+ inline T* operator() (int c, int r) {
+ return reinterpret_cast<T*>(image_->imageData + r*image_->widthStep) +
+ c*Channels();
+ }
+
+ inline const T* operator() (int c, int r) const {
+ return reinterpret_cast<T*>(image_->imageData + r*image_->widthStep) +
+ c*Channels();
+ }
+
+ // Copy the contents from another image which is just a convenience to cvCopy
+ void CopyFrom(const WImage<T>& src) { cvCopy(src.Ipl(), image_); }
+
+ // Set contents to zero which is just a convenient to cvSetZero
+ void SetZero() { cvSetZero(image_); }
+
+ // Construct a view into a region of this image
+ WImageView<T> View(int c, int r, int width, int height);
+
+protected:
+ // Disallow copy and assignment
+ WImage(const WImage&);
+ void operator=(const WImage&);
+
+ explicit WImage(IplImage* img) : image_(img) {
+ assert(!img || img->depth == Depth());
+ }
+
+ void SetIpl(IplImage* image) {
+ assert(!image || image->depth == Depth());
+ image_ = image;
+ }
+
+ IplImage* image_;
+};
+
+
+
+// Image class when both the pixel type and number of channels
+// are known at compile time. This wrapper will speed up some of the operations
+// like accessing individual pixels using the () operator.
+template<typename T, int C>
+class WImageC : public WImage<T>
+{
+public:
+ typedef typename WImage<T>::BaseType BaseType;
+ enum { kChannels = C };
+
+ explicit WImageC(IplImage* img) : WImage<T>(img) {
+ assert(!img || img->nChannels == Channels());
+ }
+
+ // Construct a view into a region of this image
+ WImageViewC<T, C> View(int c, int r, int width, int height);
+
+ // Copy the contents from another image which is just a convenience to cvCopy
+ void CopyFrom(const WImageC<T, C>& src) {
+ cvCopy(src.Ipl(), WImage<T>::image_);
+ }
+
+ // WImageC is an abstract class with no other virtual methods so make the
+ // destructor virtual.
+ virtual ~WImageC() = 0;
+
+ int Channels() const {return C; }
+
+protected:
+ // Disallow copy and assignment
+ WImageC(const WImageC&);
+ void operator=(const WImageC&);
+
+ void SetIpl(IplImage* image) {
+ assert(!image || image->depth == WImage<T>::Depth());
+ WImage<T>::SetIpl(image);
+ }
+};
+
+//
+// WImageBuffer definitions
+//
+// Image class which owns the data, so it can be allocated and is always
+// freed. It cannot be copied but can be explicity cloned.
+//
+template<typename T>
+class WImageBuffer : public WImage<T>
+{
+public:
+ typedef typename WImage<T>::BaseType BaseType;
+
+ // Default constructor which creates an object that can be
+ WImageBuffer() : WImage<T>(0) {}
+
+ WImageBuffer(int width, int height, int nchannels) : WImage<T>(0) {
+ Allocate(width, height, nchannels);
+ }
+
+ // Constructor which takes ownership of a given IplImage so releases
+ // the image on destruction.
+ explicit WImageBuffer(IplImage* img) : WImage<T>(img) {}
+
+ // Allocate an image. Does nothing if current size is the same as
+ // the new size.
+ void Allocate(int width, int height, int nchannels);
+
+ // Set the data to point to an image, releasing the old data
+ void SetIpl(IplImage* img) {
+ ReleaseImage();
+ WImage<T>::SetIpl(img);
+ }
+
+ // Clone an image which reallocates the image if of a different dimension.
+ void CloneFrom(const WImage<T>& src) {
+ Allocate(src.Width(), src.Height());
+ CopyFrom(src);
+ }
+
+ ~WImageBuffer() {
+ ReleaseImage();
+ }
+
+ // Release the image if it isn't null.
+ void ReleaseImage() {
+ if (WImage<T>::image_) {
+ IplImage* image = WImage<T>::image_;
+ cvReleaseImage(&image);
+ WImage<T>::SetIpl(0);
+ }
+ }
+
+ bool IsNull() const {return WImage<T>::image_ == NULL; }
+
+private:
+ // Disallow copy and assignment
+ WImageBuffer(const WImageBuffer&);
+ void operator=(const WImageBuffer&);
+};
+
+// Like a WImageBuffer class but when the number of channels is known
+// at compile time.
+template<typename T, int C>
+class WImageBufferC : public WImageC<T, C>
+{
+public:
+ typedef typename WImage<T>::BaseType BaseType;
+ enum { kChannels = C };
+
+ // Default constructor which creates an object that can be
+ WImageBufferC() : WImageC<T, C>(0) {}
+
+ WImageBufferC(int width, int height) : WImageC<T, C>(0) {
+ Allocate(width, height);
+ }
+
+ // Constructor which takes ownership of a given IplImage so releases
+ // the image on destruction.
+ explicit WImageBufferC(IplImage* img) : WImageC<T, C>(img) {}
+
+ // Allocate an image. Does nothing if current size is the same as
+ // the new size.
+ void Allocate(int width, int height);
+
+ // Set the data to point to an image, releasing the old data
+ void SetIpl(IplImage* img) {
+ ReleaseImage();
+ WImageC<T, C>::SetIpl(img);
+ }
+
+ // Clone an image which reallocates the image if of a different dimension.
+ void CloneFrom(const WImageC<T, C>& src) {
+ Allocate(src.Width(), src.Height());
+ CopyFrom(src);
+ }
+
+ ~WImageBufferC() {
+ ReleaseImage();
+ }
+
+ // Release the image if it isn't null.
+ void ReleaseImage() {
+ if (WImage<T>::image_) {
+ IplImage* image = WImage<T>::image_;
+ cvReleaseImage(&image);
+ WImageC<T, C>::SetIpl(0);
+ }
+ }
+
+ bool IsNull() const {return WImage<T>::image_ == NULL; }
+
+private:
+ // Disallow copy and assignment
+ WImageBufferC(const WImageBufferC&);
+ void operator=(const WImageBufferC&);
+};
+
+//
+// WImageView definitions
+//
+// View into an image class which allows treating a subimage as an image
+// or treating external data as an image
+//
+template<typename T>
+class WImageView : public WImage<T>
+{
+public:
+ typedef typename WImage<T>::BaseType BaseType;
+
+ // Construct a subimage. No checks are done that the subimage lies
+ // completely inside the original image.
+ WImageView(WImage<T>* img, int c, int r, int width, int height);
+
+ // Refer to external data.
+ // If not given width_step assumed to be same as width.
+ WImageView(T* data, int width, int height, int channels, int width_step = -1);
+
+ // Refer to external data. This does NOT take ownership
+ // of the supplied IplImage.
+ WImageView(IplImage* img) : WImage<T>(img) {}
+
+ // Copy constructor
+ WImageView(const WImage<T>& img) : WImage<T>(0) {
+ header_ = *(img.Ipl());
+ WImage<T>::SetIpl(&header_);
+ }
+
+ WImageView& operator=(const WImage<T>& img) {
+ header_ = *(img.Ipl());
+ WImage<T>::SetIpl(&header_);
+ return *this;
+ }
+
+protected:
+ IplImage header_;
+};
+
+
+template<typename T, int C>
+class WImageViewC : public WImageC<T, C>
+{
+public:
+ typedef typename WImage<T>::BaseType BaseType;
+ enum { kChannels = C };
+
+ // Default constructor needed for vectors of views.
+ WImageViewC();
+
+ virtual ~WImageViewC() {}
+
+ // Construct a subimage. No checks are done that the subimage lies
+ // completely inside the original image.
+ WImageViewC(WImageC<T, C>* img,
+ int c, int r, int width, int height);
+
+ // Refer to external data
+ WImageViewC(T* data, int width, int height, int width_step = -1);
+
+ // Refer to external data. This does NOT take ownership
+ // of the supplied IplImage.
+ WImageViewC(IplImage* img) : WImageC<T, C>(img) {}
+
+ // Copy constructor which does a shallow copy to allow multiple views
+ // of same data. gcc-4.1.1 gets confused if both versions of
+ // the constructor and assignment operator are not provided.
+ WImageViewC(const WImageC<T, C>& img) : WImageC<T, C>(0) {
+ header_ = *(img.Ipl());
+ WImageC<T, C>::SetIpl(&header_);
+ }
+ WImageViewC(const WImageViewC<T, C>& img) : WImageC<T, C>(0) {
+ header_ = *(img.Ipl());
+ WImageC<T, C>::SetIpl(&header_);
+ }
+
+ WImageViewC& operator=(const WImageC<T, C>& img) {
+ header_ = *(img.Ipl());
+ WImageC<T, C>::SetIpl(&header_);
+ return *this;
+ }
+ WImageViewC& operator=(const WImageViewC<T, C>& img) {
+ header_ = *(img.Ipl());
+ WImageC<T, C>::SetIpl(&header_);
+ return *this;
+ }
+
+protected:
+ IplImage header_;
+};
+
+
+// Specializations for depth
+template<>
+inline int WImage<uchar>::Depth() const {return IPL_DEPTH_8U; }
+template<>
+inline int WImage<schar>::Depth() const {return IPL_DEPTH_8S; }
+template<>
+inline int WImage<short>::Depth() const {return IPL_DEPTH_16S; }
+template<>
+inline int WImage<ushort>::Depth() const {return IPL_DEPTH_16U; }
+template<>
+inline int WImage<int>::Depth() const {return IPL_DEPTH_32S; }
+template<>
+inline int WImage<float>::Depth() const {return IPL_DEPTH_32F; }
+template<>
+inline int WImage<double>::Depth() const {return IPL_DEPTH_64F; }
+
+//
+// Pure virtual destructors still need to be defined.
+//
+template<typename T> inline WImage<T>::~WImage() {}
+template<typename T, int C> inline WImageC<T, C>::~WImageC() {}
+
+//
+// Allocate ImageData
+//
+template<typename T>
+inline void WImageBuffer<T>::Allocate(int width, int height, int nchannels)
+{
+ if (IsNull() || WImage<T>::Width() != width ||
+ WImage<T>::Height() != height || WImage<T>::Channels() != nchannels) {
+ ReleaseImage();
+ WImage<T>::image_ = cvCreateImage(cvSize(width, height),
+ WImage<T>::Depth(), nchannels);
+ }
+}
+
+template<typename T, int C>
+inline void WImageBufferC<T, C>::Allocate(int width, int height)
+{
+ if (IsNull() || WImage<T>::Width() != width || WImage<T>::Height() != height) {
+ ReleaseImage();
+ WImageC<T, C>::SetIpl(cvCreateImage(cvSize(width, height),WImage<T>::Depth(), C));
+ }
+}
+
+//
+// ImageView methods
+//
+template<typename T>
+WImageView<T>::WImageView(WImage<T>* img, int c, int r, int width, int height)
+ : WImage<T>(0)
+{
+ header_ = *(img->Ipl());
+ header_.imageData = reinterpret_cast<char*>((*img)(c, r));
+ header_.width = width;
+ header_.height = height;
+ WImage<T>::SetIpl(&header_);
+}
+
+template<typename T>
+WImageView<T>::WImageView(T* data, int width, int height, int nchannels, int width_step)
+ : WImage<T>(0)
+{
+ cvInitImageHeader(&header_, cvSize(width, height), WImage<T>::Depth(), nchannels);
+ header_.imageData = reinterpret_cast<char*>(data);
+ if (width_step > 0) {
+ header_.widthStep = width_step;
+ }
+ WImage<T>::SetIpl(&header_);
+}
+
+template<typename T, int C>
+WImageViewC<T, C>::WImageViewC(WImageC<T, C>* img, int c, int r, int width, int height)
+ : WImageC<T, C>(0)
+{
+ header_ = *(img->Ipl());
+ header_.imageData = reinterpret_cast<char*>((*img)(c, r));
+ header_.width = width;
+ header_.height = height;
+ WImageC<T, C>::SetIpl(&header_);
+}
+
+template<typename T, int C>
+WImageViewC<T, C>::WImageViewC() : WImageC<T, C>(0) {
+ cvInitImageHeader(&header_, cvSize(0, 0), WImage<T>::Depth(), C);
+ header_.imageData = reinterpret_cast<char*>(0);
+ WImageC<T, C>::SetIpl(&header_);
+}
+
+template<typename T, int C>
+WImageViewC<T, C>::WImageViewC(T* data, int width, int height, int width_step)
+ : WImageC<T, C>(0)
+{
+ cvInitImageHeader(&header_, cvSize(width, height), WImage<T>::Depth(), C);
+ header_.imageData = reinterpret_cast<char*>(data);
+ if (width_step > 0) {
+ header_.widthStep = width_step;
+ }
+ WImageC<T, C>::SetIpl(&header_);
+}
+
+// Construct a view into a region of an image
+template<typename T>
+WImageView<T> WImage<T>::View(int c, int r, int width, int height) {
+ return WImageView<T>(this, c, r, width, height);
+}
+
+template<typename T, int C>
+WImageViewC<T, C> WImageC<T, C>::View(int c, int r, int width, int height) {
+ return WImageViewC<T, C>(this, c, r, width, height);
+}
+
+} // end of namespace
+
+#endif // __cplusplus
+
+#endif // _CV_WIMAGE_H_
diff --git a/cxcore/include/cxcore.h b/cxcore/include/cxcore.h
new file mode 100644
index 0000000..ec9cba3
--- /dev/null
+++ b/cxcore/include/cxcore.h
@@ -0,0 +1,1780 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+
+#ifndef _CXCORE_H_
+#define _CXCORE_H_
+
+#ifdef __IPL_H__
+#define HAVE_IPL
+#endif
+
+#ifndef SKIP_INCLUDES
+ #if defined HAVE_IPL && !defined __IPL_H__
+ #ifndef _INC_WINDOWS
+ #define CV_PRETEND_WINDOWS
+ #define _INC_WINDOWS
+ typedef struct tagBITMAPINFOHEADER BITMAPINFOHEADER;
+ typedef int BOOL;
+ #endif
+ #if defined WIN32 || defined WIN64
+ #include "ipl.h"
+ #else
+ #include "ipl/ipl.h"
+ #endif
+ #ifdef CV_PRETEND_WINDOWS
+ #undef _INC_WINDOWS
+ #endif
+ #endif
+#endif // SKIP_INCLUDES
+
+#include "cxtypes.h"
+#include "cxerror.h"
+#include "cvver.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/****************************************************************************************\
+* Array allocation, deallocation, initialization and access to elements *
+\****************************************************************************************/
+
+/* <malloc> wrapper.
+ If there is no enough memory, the function
+ (as well as other OpenCV functions that call cvAlloc)
+ raises an error. */
+CVAPI(void*) cvAlloc( size_t size );
+
+/* <free> wrapper.
+ Here and further all the memory releasing functions
+ (that all call cvFree) take double pointer in order to
+ to clear pointer to the data after releasing it.
+ Passing pointer to NULL pointer is Ok: nothing happens in this case
+*/
+CVAPI(void) cvFree_( void* ptr );
+#define cvFree(ptr) (cvFree_(*(ptr)), *(ptr)=0)
+
+/* Allocates and initializes IplImage header */
+CVAPI(IplImage*) cvCreateImageHeader( CvSize size, int depth, int channels );
+
+/* Inializes IplImage header */
+CVAPI(IplImage*) cvInitImageHeader( IplImage* image, CvSize size, int depth,
+ int channels, int origin CV_DEFAULT(0),
+ int align CV_DEFAULT(4));
+
+/* Creates IPL image (header and data) */
+CVAPI(IplImage*) cvCreateImage( CvSize size, int depth, int channels );
+
+/* Releases (i.e. deallocates) IPL image header */
+CVAPI(void) cvReleaseImageHeader( IplImage** image );
+
+/* Releases IPL image header and data */
+CVAPI(void) cvReleaseImage( IplImage** image );
+
+/* Creates a copy of IPL image (widthStep may differ) */
+CVAPI(IplImage*) cvCloneImage( const IplImage* image );
+
+/* Sets a Channel Of Interest (only a few functions support COI) -
+ use cvCopy to extract the selected channel and/or put it back */
+CVAPI(void) cvSetImageCOI( IplImage* image, int coi );
+
+/* Retrieves image Channel Of Interest */
+CVAPI(int) cvGetImageCOI( const IplImage* image );
+
+/* Sets image ROI (region of interest) (COI is not changed) */
+CVAPI(void) cvSetImageROI( IplImage* image, CvRect rect );
+
+/* Resets image ROI and COI */
+CVAPI(void) cvResetImageROI( IplImage* image );
+
+/* Retrieves image ROI */
+CVAPI(CvRect) cvGetImageROI( const IplImage* image );
+
+/* Allocates and initalizes CvMat header */
+CVAPI(CvMat*) cvCreateMatHeader( int rows, int cols, int type );
+
+#define CV_AUTOSTEP 0x7fffffff
+
+/* Initializes CvMat header */
+CVAPI(CvMat*) cvInitMatHeader( CvMat* mat, int rows, int cols,
+ int type, void* data CV_DEFAULT(NULL),
+ int step CV_DEFAULT(CV_AUTOSTEP) );
+
+/* Allocates and initializes CvMat header and allocates data */
+CVAPI(CvMat*) cvCreateMat( int rows, int cols, int type );
+
+/* Releases CvMat header and deallocates matrix data
+ (reference counting is used for data) */
+CVAPI(void) cvReleaseMat( CvMat** mat );
+
+/* Decrements CvMat data reference counter and deallocates the data if
+ it reaches 0 */
+CV_INLINE void cvDecRefData( CvArr* arr )
+{
+ if( CV_IS_MAT( arr ))
+ {
+ CvMat* mat = (CvMat*)arr;
+ mat->data.ptr = NULL;
+ if( mat->refcount != NULL && --*mat->refcount == 0 )
+ cvFree( &mat->refcount );
+ mat->refcount = NULL;
+ }
+ else if( CV_IS_MATND( arr ))
+ {
+ CvMatND* mat = (CvMatND*)arr;
+ mat->data.ptr = NULL;
+ if( mat->refcount != NULL && --*mat->refcount == 0 )
+ cvFree( &mat->refcount );
+ mat->refcount = NULL;
+ }
+}
+
+/* Increments CvMat data reference counter */
+CV_INLINE int cvIncRefData( CvArr* arr )
+{
+ int refcount = 0;
+ if( CV_IS_MAT( arr ))
+ {
+ CvMat* mat = (CvMat*)arr;
+ if( mat->refcount != NULL )
+ refcount = ++*mat->refcount;
+ }
+ else if( CV_IS_MATND( arr ))
+ {
+ CvMatND* mat = (CvMatND*)arr;
+ if( mat->refcount != NULL )
+ refcount = ++*mat->refcount;
+ }
+ return refcount;
+}
+
+
+/* Creates an exact copy of the input matrix (except, may be, step value) */
+CVAPI(CvMat*) cvCloneMat( const CvMat* mat );
+
+
+/* Makes a new matrix from <rect> subrectangle of input array.
+ No data is copied */
+CVAPI(CvMat*) cvGetSubRect( const CvArr* arr, CvMat* submat, CvRect rect );
+#define cvGetSubArr cvGetSubRect
+
+/* Selects row span of the input array: arr(start_row:delta_row:end_row,:)
+ (end_row is not included into the span). */
+CVAPI(CvMat*) cvGetRows( const CvArr* arr, CvMat* submat,
+ int start_row, int end_row,
+ int delta_row CV_DEFAULT(1));
+
+CV_INLINE CvMat* cvGetRow( const CvArr* arr, CvMat* submat, int row )
+{
+ return cvGetRows( arr, submat, row, row + 1, 1 );
+}
+
+
+/* Selects column span of the input array: arr(:,start_col:end_col)
+ (end_col is not included into the span) */
+CVAPI(CvMat*) cvGetCols( const CvArr* arr, CvMat* submat,
+ int start_col, int end_col );
+
+CV_INLINE CvMat* cvGetCol( const CvArr* arr, CvMat* submat, int col )
+{
+ return cvGetCols( arr, submat, col, col + 1 );
+}
+
+/* Select a diagonal of the input array.
+ (diag = 0 means the main diagonal, >0 means a diagonal above the main one,
+ <0 - below the main one).
+ The diagonal will be represented as a column (nx1 matrix). */
+CVAPI(CvMat*) cvGetDiag( const CvArr* arr, CvMat* submat,
+ int diag CV_DEFAULT(0));
+
+/* low-level scalar <-> raw data conversion functions */
+CVAPI(void) cvScalarToRawData( const CvScalar* scalar, void* data, int type,
+ int extend_to_12 CV_DEFAULT(0) );
+
+CVAPI(void) cvRawDataToScalar( const void* data, int type, CvScalar* scalar );
+
+/* Allocates and initializes CvMatND header */
+CVAPI(CvMatND*) cvCreateMatNDHeader( int dims, const int* sizes, int type );
+
+/* Allocates and initializes CvMatND header and allocates data */
+CVAPI(CvMatND*) cvCreateMatND( int dims, const int* sizes, int type );
+
+/* Initializes preallocated CvMatND header */
+CVAPI(CvMatND*) cvInitMatNDHeader( CvMatND* mat, int dims, const int* sizes,
+ int type, void* data CV_DEFAULT(NULL) );
+
+/* Releases CvMatND */
+CV_INLINE void cvReleaseMatND( CvMatND** mat )
+{
+ cvReleaseMat( (CvMat**)mat );
+}
+
+/* Creates a copy of CvMatND (except, may be, steps) */
+CVAPI(CvMatND*) cvCloneMatND( const CvMatND* mat );
+
+/* Allocates and initializes CvSparseMat header and allocates data */
+CVAPI(CvSparseMat*) cvCreateSparseMat( int dims, const int* sizes, int type );
+
+/* Releases CvSparseMat */
+CVAPI(void) cvReleaseSparseMat( CvSparseMat** mat );
+
+/* Creates a copy of CvSparseMat (except, may be, zero items) */
+CVAPI(CvSparseMat*) cvCloneSparseMat( const CvSparseMat* mat );
+
+/* Initializes sparse array iterator
+ (returns the first node or NULL if the array is empty) */
+CVAPI(CvSparseNode*) cvInitSparseMatIterator( const CvSparseMat* mat,
+ CvSparseMatIterator* mat_iterator );
+
+// returns next sparse array node (or NULL if there is no more nodes)
+CV_INLINE CvSparseNode* cvGetNextSparseNode( CvSparseMatIterator* mat_iterator )
+{
+ if( mat_iterator->node->next )
+ return mat_iterator->node = mat_iterator->node->next;
+ else
+ {
+ int idx;
+ for( idx = ++mat_iterator->curidx; idx < mat_iterator->mat->hashsize; idx++ )
+ {
+ CvSparseNode* node = (CvSparseNode*)mat_iterator->mat->hashtable[idx];
+ if( node )
+ {
+ mat_iterator->curidx = idx;
+ return mat_iterator->node = node;
+ }
+ }
+ return NULL;
+ }
+}
+
+/**************** matrix iterator: used for n-ary operations on dense arrays *********/
+
+#define CV_MAX_ARR 10
+
+typedef struct CvNArrayIterator
+{
+ int count; /* number of arrays */
+ int dims; /* number of dimensions to iterate */
+ CvSize size; /* maximal common linear size: { width = size, height = 1 } */
+ uchar* ptr[CV_MAX_ARR]; /* pointers to the array slices */
+ int stack[CV_MAX_DIM]; /* for internal use */
+ CvMatND* hdr[CV_MAX_ARR]; /* pointers to the headers of the
+ matrices that are processed */
+}
+CvNArrayIterator;
+
+#define CV_NO_DEPTH_CHECK 1
+#define CV_NO_CN_CHECK 2
+#define CV_NO_SIZE_CHECK 4
+
+/* initializes iterator that traverses through several arrays simulteneously
+ (the function together with cvNextArraySlice is used for
+ N-ari element-wise operations) */
+CVAPI(int) cvInitNArrayIterator( int count, CvArr** arrs,
+ const CvArr* mask, CvMatND* stubs,
+ CvNArrayIterator* array_iterator,
+ int flags CV_DEFAULT(0) );
+
+/* returns zero value if iteration is finished, non-zero (slice length) otherwise */
+CVAPI(int) cvNextNArraySlice( CvNArrayIterator* array_iterator );
+
+
+/* Returns type of array elements:
+ CV_8UC1 ... CV_64FC4 ... */
+CVAPI(int) cvGetElemType( const CvArr* arr );
+
+/* Retrieves number of an array dimensions and
+ optionally sizes of the dimensions */
+CVAPI(int) cvGetDims( const CvArr* arr, int* sizes CV_DEFAULT(NULL) );
+
+
+/* Retrieves size of a particular array dimension.
+ For 2d arrays cvGetDimSize(arr,0) returns number of rows (image height)
+ and cvGetDimSize(arr,1) returns number of columns (image width) */
+CVAPI(int) cvGetDimSize( const CvArr* arr, int index );
+
+
+/* ptr = &arr(idx0,idx1,...). All indexes are zero-based,
+ the major dimensions go first (e.g. (y,x) for 2D, (z,y,x) for 3D */
+CVAPI(uchar*) cvPtr1D( const CvArr* arr, int idx0, int* type CV_DEFAULT(NULL));
+CVAPI(uchar*) cvPtr2D( const CvArr* arr, int idx0, int idx1, int* type CV_DEFAULT(NULL) );
+CVAPI(uchar*) cvPtr3D( const CvArr* arr, int idx0, int idx1, int idx2,
+ int* type CV_DEFAULT(NULL));
+
+/* For CvMat or IplImage number of indices should be 2
+ (row index (y) goes first, column index (x) goes next).
+ For CvMatND or CvSparseMat number of infices should match number of <dims> and
+ indices order should match the array dimension order. */
+CVAPI(uchar*) cvPtrND( const CvArr* arr, const int* idx, int* type CV_DEFAULT(NULL),
+ int create_node CV_DEFAULT(1),
+ unsigned* precalc_hashval CV_DEFAULT(NULL));
+
+/* value = arr(idx0,idx1,...) */
+CVAPI(CvScalar) cvGet1D( const CvArr* arr, int idx0 );
+CVAPI(CvScalar) cvGet2D( const CvArr* arr, int idx0, int idx1 );
+CVAPI(CvScalar) cvGet3D( const CvArr* arr, int idx0, int idx1, int idx2 );
+CVAPI(CvScalar) cvGetND( const CvArr* arr, const int* idx );
+
+/* for 1-channel arrays */
+CVAPI(double) cvGetReal1D( const CvArr* arr, int idx0 );
+CVAPI(double) cvGetReal2D( const CvArr* arr, int idx0, int idx1 );
+CVAPI(double) cvGetReal3D( const CvArr* arr, int idx0, int idx1, int idx2 );
+CVAPI(double) cvGetRealND( const CvArr* arr, const int* idx );
+
+/* arr(idx0,idx1,...) = value */
+CVAPI(void) cvSet1D( CvArr* arr, int idx0, CvScalar value );
+CVAPI(void) cvSet2D( CvArr* arr, int idx0, int idx1, CvScalar value );
+CVAPI(void) cvSet3D( CvArr* arr, int idx0, int idx1, int idx2, CvScalar value );
+CVAPI(void) cvSetND( CvArr* arr, const int* idx, CvScalar value );
+
+/* for 1-channel arrays */
+CVAPI(void) cvSetReal1D( CvArr* arr, int idx0, double value );
+CVAPI(void) cvSetReal2D( CvArr* arr, int idx0, int idx1, double value );
+CVAPI(void) cvSetReal3D( CvArr* arr, int idx0,
+ int idx1, int idx2, double value );
+CVAPI(void) cvSetRealND( CvArr* arr, const int* idx, double value );
+
+/* clears element of ND dense array,
+ in case of sparse arrays it deletes the specified node */
+CVAPI(void) cvClearND( CvArr* arr, const int* idx );
+
+/* Converts CvArr (IplImage or CvMat,...) to CvMat.
+ If the last parameter is non-zero, function can
+ convert multi(>2)-dimensional array to CvMat as long as
+ the last array's dimension is continous. The resultant
+ matrix will be have appropriate (a huge) number of rows */
+CVAPI(CvMat*) cvGetMat( const CvArr* arr, CvMat* header,
+ int* coi CV_DEFAULT(NULL),
+ int allowND CV_DEFAULT(0));
+
+/* Converts CvArr (IplImage or CvMat) to IplImage */
+CVAPI(IplImage*) cvGetImage( const CvArr* arr, IplImage* image_header );
+
+
+/* Changes a shape of multi-dimensional array.
+ new_cn == 0 means that number of channels remains unchanged.
+ new_dims == 0 means that number and sizes of dimensions remain the same
+ (unless they need to be changed to set the new number of channels)
+ if new_dims == 1, there is no need to specify new dimension sizes
+ The resultant configuration should be achievable w/o data copying.
+ If the resultant array is sparse, CvSparseMat header should be passed
+ to the function else if the result is 1 or 2 dimensional,
+ CvMat header should be passed to the function
+ else CvMatND header should be passed */
+CVAPI(CvArr*) cvReshapeMatND( const CvArr* arr,
+ int sizeof_header, CvArr* header,
+ int new_cn, int new_dims, int* new_sizes );
+
+#define cvReshapeND( arr, header, new_cn, new_dims, new_sizes ) \
+ cvReshapeMatND( (arr), sizeof(*(header)), (header), \
+ (new_cn), (new_dims), (new_sizes))
+
+CVAPI(CvMat*) cvReshape( const CvArr* arr, CvMat* header,
+ int new_cn, int new_rows CV_DEFAULT(0) );
+
+/* Repeats source 2d array several times in both horizontal and
+ vertical direction to fill destination array */
+CVAPI(void) cvRepeat( const CvArr* src, CvArr* dst );
+
+/* Allocates array data */
+CVAPI(void) cvCreateData( CvArr* arr );
+
+/* Releases array data */
+CVAPI(void) cvReleaseData( CvArr* arr );
+
+/* Attaches user data to the array header. The step is reffered to
+ the pre-last dimension. That is, all the planes of the array
+ must be joint (w/o gaps) */
+CVAPI(void) cvSetData( CvArr* arr, void* data, int step );
+
+/* Retrieves raw data of CvMat, IplImage or CvMatND.
+ In the latter case the function raises an error if
+ the array can not be represented as a matrix */
+CVAPI(void) cvGetRawData( const CvArr* arr, uchar** data,
+ int* step CV_DEFAULT(NULL),
+ CvSize* roi_size CV_DEFAULT(NULL));
+
+/* Returns width and height of array in elements */
+CVAPI(CvSize) cvGetSize( const CvArr* arr );
+
+/* Copies source array to destination array */
+CVAPI(void) cvCopy( const CvArr* src, CvArr* dst,
+ const CvArr* mask CV_DEFAULT(NULL) );
+
+/* Sets all or "masked" elements of input array
+ to the same value*/
+CVAPI(void) cvSet( CvArr* arr, CvScalar value,
+ const CvArr* mask CV_DEFAULT(NULL) );
+
+/* Clears all the array elements (sets them to 0) */
+CVAPI(void) cvSetZero( CvArr* arr );
+#define cvZero cvSetZero
+
+
+/* Splits a multi-channel array into the set of single-channel arrays or
+ extracts particular [color] plane */
+CVAPI(void) cvSplit( const CvArr* src, CvArr* dst0, CvArr* dst1,
+ CvArr* dst2, CvArr* dst3 );
+
+/* Merges a set of single-channel arrays into the single multi-channel array
+ or inserts one particular [color] plane to the array */
+CVAPI(void) cvMerge( const CvArr* src0, const CvArr* src1,
+ const CvArr* src2, const CvArr* src3,
+ CvArr* dst );
+
+/* Copies several channels from input arrays to
+ certain channels of output arrays */
+CVAPI(void) cvMixChannels( const CvArr** src, int src_count,
+ CvArr** dst, int dst_count,
+ const int* from_to, int pair_count );
+
+/* Performs linear transformation on every source array element:
+ dst(x,y,c) = scale*src(x,y,c)+shift.
+ Arbitrary combination of input and output array depths are allowed
+ (number of channels must be the same), thus the function can be used
+ for type conversion */
+CVAPI(void) cvConvertScale( const CvArr* src, CvArr* dst,
+ double scale CV_DEFAULT(1),
+ double shift CV_DEFAULT(0) );
+#define cvCvtScale cvConvertScale
+#define cvScale cvConvertScale
+#define cvConvert( src, dst ) cvConvertScale( (src), (dst), 1, 0 )
+
+
+/* Performs linear transformation on every source array element,
+ stores absolute value of the result:
+ dst(x,y,c) = abs(scale*src(x,y,c)+shift).
+ destination array must have 8u type.
+ In other cases one may use cvConvertScale + cvAbsDiffS */
+CVAPI(void) cvConvertScaleAbs( const CvArr* src, CvArr* dst,
+ double scale CV_DEFAULT(1),
+ double shift CV_DEFAULT(0) );
+#define cvCvtScaleAbs cvConvertScaleAbs
+
+
+/* checks termination criteria validity and
+ sets eps to default_eps (if it is not set),
+ max_iter to default_max_iters (if it is not set)
+*/
+CVAPI(CvTermCriteria) cvCheckTermCriteria( CvTermCriteria criteria,
+ double default_eps,
+ int default_max_iters );
+
+/****************************************************************************************\
+* Arithmetic, logic and comparison operations *
+\****************************************************************************************/
+
+/* dst(mask) = src1(mask) + src2(mask) */
+CVAPI(void) cvAdd( const CvArr* src1, const CvArr* src2, CvArr* dst,
+ const CvArr* mask CV_DEFAULT(NULL));
+
+/* dst(mask) = src(mask) + value */
+CVAPI(void) cvAddS( const CvArr* src, CvScalar value, CvArr* dst,
+ const CvArr* mask CV_DEFAULT(NULL));
+
+/* dst(mask) = src1(mask) - src2(mask) */
+CVAPI(void) cvSub( const CvArr* src1, const CvArr* src2, CvArr* dst,
+ const CvArr* mask CV_DEFAULT(NULL));
+
+/* dst(mask) = src(mask) - value = src(mask) + (-value) */
+CV_INLINE void cvSubS( const CvArr* src, CvScalar value, CvArr* dst,
+ const CvArr* mask CV_DEFAULT(NULL))
+{
+ cvAddS( src, cvScalar( -value.val[0], -value.val[1], -value.val[2], -value.val[3]),
+ dst, mask );
+}
+
+/* dst(mask) = value - src(mask) */
+CVAPI(void) cvSubRS( const CvArr* src, CvScalar value, CvArr* dst,
+ const CvArr* mask CV_DEFAULT(NULL));
+
+/* dst(idx) = src1(idx) * src2(idx) * scale
+ (scaled element-wise multiplication of 2 arrays) */
+CVAPI(void) cvMul( const CvArr* src1, const CvArr* src2,
+ CvArr* dst, double scale CV_DEFAULT(1) );
+
+/* element-wise division/inversion with scaling:
+ dst(idx) = src1(idx) * scale / src2(idx)
+ or dst(idx) = scale / src2(idx) if src1 == 0 */
+CVAPI(void) cvDiv( const CvArr* src1, const CvArr* src2,
+ CvArr* dst, double scale CV_DEFAULT(1));
+
+/* dst = src1 * scale + src2 */
+CVAPI(void) cvScaleAdd( const CvArr* src1, CvScalar scale,
+ const CvArr* src2, CvArr* dst );
+#define cvAXPY( A, real_scalar, B, C ) cvScaleAdd(A, cvRealScalar(real_scalar), B, C)
+
+/* dst = src1 * alpha + src2 * beta + gamma */
+CVAPI(void) cvAddWeighted( const CvArr* src1, double alpha,
+ const CvArr* src2, double beta,
+ double gamma, CvArr* dst );
+
+/* result = sum_i(src1(i) * src2(i)) (results for all channels are accumulated together) */
+CVAPI(double) cvDotProduct( const CvArr* src1, const CvArr* src2 );
+
+/* dst(idx) = src1(idx) & src2(idx) */
+CVAPI(void) cvAnd( const CvArr* src1, const CvArr* src2,
+ CvArr* dst, const CvArr* mask CV_DEFAULT(NULL));
+
+/* dst(idx) = src(idx) & value */
+CVAPI(void) cvAndS( const CvArr* src, CvScalar value,
+ CvArr* dst, const CvArr* mask CV_DEFAULT(NULL));
+
+/* dst(idx) = src1(idx) | src2(idx) */
+CVAPI(void) cvOr( const CvArr* src1, const CvArr* src2,
+ CvArr* dst, const CvArr* mask CV_DEFAULT(NULL));
+
+/* dst(idx) = src(idx) | value */
+CVAPI(void) cvOrS( const CvArr* src, CvScalar value,
+ CvArr* dst, const CvArr* mask CV_DEFAULT(NULL));
+
+/* dst(idx) = src1(idx) ^ src2(idx) */
+CVAPI(void) cvXor( const CvArr* src1, const CvArr* src2,
+ CvArr* dst, const CvArr* mask CV_DEFAULT(NULL));
+
+/* dst(idx) = src(idx) ^ value */
+CVAPI(void) cvXorS( const CvArr* src, CvScalar value,
+ CvArr* dst, const CvArr* mask CV_DEFAULT(NULL));
+
+/* dst(idx) = ~src(idx) */
+CVAPI(void) cvNot( const CvArr* src, CvArr* dst );
+
+/* dst(idx) = lower(idx) <= src(idx) < upper(idx) */
+CVAPI(void) cvInRange( const CvArr* src, const CvArr* lower,
+ const CvArr* upper, CvArr* dst );
+
+/* dst(idx) = lower <= src(idx) < upper */
+CVAPI(void) cvInRangeS( const CvArr* src, CvScalar lower,
+ CvScalar upper, CvArr* dst );
+
+#define CV_CMP_EQ 0
+#define CV_CMP_GT 1
+#define CV_CMP_GE 2
+#define CV_CMP_LT 3
+#define CV_CMP_LE 4
+#define CV_CMP_NE 5
+
+/* The comparison operation support single-channel arrays only.
+ Destination image should be 8uC1 or 8sC1 */
+
+/* dst(idx) = src1(idx) _cmp_op_ src2(idx) */
+CVAPI(void) cvCmp( const CvArr* src1, const CvArr* src2, CvArr* dst, int cmp_op );
+
+/* dst(idx) = src1(idx) _cmp_op_ value */
+CVAPI(void) cvCmpS( const CvArr* src, double value, CvArr* dst, int cmp_op );
+
+/* dst(idx) = min(src1(idx),src2(idx)) */
+CVAPI(void) cvMin( const CvArr* src1, const CvArr* src2, CvArr* dst );
+
+/* dst(idx) = max(src1(idx),src2(idx)) */
+CVAPI(void) cvMax( const CvArr* src1, const CvArr* src2, CvArr* dst );
+
+/* dst(idx) = min(src(idx),value) */
+CVAPI(void) cvMinS( const CvArr* src, double value, CvArr* dst );
+
+/* dst(idx) = max(src(idx),value) */
+CVAPI(void) cvMaxS( const CvArr* src, double value, CvArr* dst );
+
+/* dst(x,y,c) = abs(src1(x,y,c) - src2(x,y,c)) */
+CVAPI(void) cvAbsDiff( const CvArr* src1, const CvArr* src2, CvArr* dst );
+
+/* dst(x,y,c) = abs(src(x,y,c) - value(c)) */
+CVAPI(void) cvAbsDiffS( const CvArr* src, CvArr* dst, CvScalar value );
+#define cvAbs( src, dst ) cvAbsDiffS( (src), (dst), cvScalarAll(0))
+
+/****************************************************************************************\
+* Math operations *
+\****************************************************************************************/
+
+/* Does cartesian->polar coordinates conversion.
+ Either of output components (magnitude or angle) is optional */
+CVAPI(void) cvCartToPolar( const CvArr* x, const CvArr* y,
+ CvArr* magnitude, CvArr* angle CV_DEFAULT(NULL),
+ int angle_in_degrees CV_DEFAULT(0));
+
+/* Does polar->cartesian coordinates conversion.
+ Either of output components (magnitude or angle) is optional.
+ If magnitude is missing it is assumed to be all 1's */
+CVAPI(void) cvPolarToCart( const CvArr* magnitude, const CvArr* angle,
+ CvArr* x, CvArr* y,
+ int angle_in_degrees CV_DEFAULT(0));
+
+/* Does powering: dst(idx) = src(idx)^power */
+CVAPI(void) cvPow( const CvArr* src, CvArr* dst, double power );
+
+/* Does exponention: dst(idx) = exp(src(idx)).
+ Overflow is not handled yet. Underflow is handled.
+ Maximal relative error is ~7e-6 for single-precision input */
+CVAPI(void) cvExp( const CvArr* src, CvArr* dst );
+
+/* Calculates natural logarithms: dst(idx) = log(abs(src(idx))).
+ Logarithm of 0 gives large negative number(~-700)
+ Maximal relative error is ~3e-7 for single-precision output
+*/
+CVAPI(void) cvLog( const CvArr* src, CvArr* dst );
+
+/* Fast arctangent calculation */
+CVAPI(float) cvFastArctan( float y, float x );
+
+/* Fast cubic root calculation */
+CVAPI(float) cvCbrt( float value );
+
+/* Checks array values for NaNs, Infs or simply for too large numbers
+ (if CV_CHECK_RANGE is set). If CV_CHECK_QUIET is set,
+ no runtime errors is raised (function returns zero value in case of "bad" values).
+ Otherwise cvError is called */
+#define CV_CHECK_RANGE 1
+#define CV_CHECK_QUIET 2
+CVAPI(int) cvCheckArr( const CvArr* arr, int flags CV_DEFAULT(0),
+ double min_val CV_DEFAULT(0), double max_val CV_DEFAULT(0));
+#define cvCheckArray cvCheckArr
+
+#define CV_RAND_UNI 0
+#define CV_RAND_NORMAL 1
+CVAPI(void) cvRandArr( CvRNG* rng, CvArr* arr, int dist_type,
+ CvScalar param1, CvScalar param2 );
+
+CVAPI(void) cvRandShuffle( CvArr* mat, CvRNG* rng,
+ double iter_factor CV_DEFAULT(1.));
+
+#define CV_SORT_EVERY_ROW 0
+#define CV_SORT_EVERY_COLUMN 1
+#define CV_SORT_ASCENDING 0
+#define CV_SORT_DESCENDING 16
+
+CVAPI(void) cvSort( const CvArr* src, CvArr* dst CV_DEFAULT(NULL),
+ CvArr* idxmat CV_DEFAULT(NULL),
+ int flags CV_DEFAULT(0));
+
+/* Finds real roots of a cubic equation */
+CVAPI(int) cvSolveCubic( const CvMat* coeffs, CvMat* roots );
+
+/* Finds all real and complex roots of a polynomial equation */
+CVAPI(void) cvSolvePoly(const CvMat* coeffs, CvMat *roots,
+ int maxiter CV_DEFAULT(0), int fig CV_DEFAULT(0));
+
+/****************************************************************************************\
+* Matrix operations *
+\****************************************************************************************/
+
+/* Calculates cross product of two 3d vectors */
+CVAPI(void) cvCrossProduct( const CvArr* src1, const CvArr* src2, CvArr* dst );
+
+/* Matrix transform: dst = A*B + C, C is optional */
+#define cvMatMulAdd( src1, src2, src3, dst ) cvGEMM( (src1), (src2), 1., (src3), 1., (dst), 0 )
+#define cvMatMul( src1, src2, dst ) cvMatMulAdd( (src1), (src2), NULL, (dst))
+
+#define CV_GEMM_A_T 1
+#define CV_GEMM_B_T 2
+#define CV_GEMM_C_T 4
+/* Extended matrix transform:
+ dst = alpha*op(A)*op(B) + beta*op(C), where op(X) is X or X^T */
+CVAPI(void) cvGEMM( const CvArr* src1, const CvArr* src2, double alpha,
+ const CvArr* src3, double beta, CvArr* dst,
+ int tABC CV_DEFAULT(0));
+#define cvMatMulAddEx cvGEMM
+
+/* Transforms each element of source array and stores
+ resultant vectors in destination array */
+CVAPI(void) cvTransform( const CvArr* src, CvArr* dst,
+ const CvMat* transmat,
+ const CvMat* shiftvec CV_DEFAULT(NULL));
+#define cvMatMulAddS cvTransform
+
+/* Does perspective transform on every element of input array */
+CVAPI(void) cvPerspectiveTransform( const CvArr* src, CvArr* dst,
+ const CvMat* mat );
+
+/* Calculates (A-delta)*(A-delta)^T (order=0) or (A-delta)^T*(A-delta) (order=1) */
+CVAPI(void) cvMulTransposed( const CvArr* src, CvArr* dst, int order,
+ const CvArr* delta CV_DEFAULT(NULL),
+ double scale CV_DEFAULT(1.) );
+
+/* Tranposes matrix. Square matrices can be transposed in-place */
+CVAPI(void) cvTranspose( const CvArr* src, CvArr* dst );
+#define cvT cvTranspose
+
+/* Completes the symmetric matrix from the lower (LtoR=0) or from the upper (LtoR!=0) part */
+CVAPI(void) cvCompleteSymm( CvMat* matrix, int LtoR CV_DEFAULT(0) );
+
+/* Mirror array data around horizontal (flip=0),
+ vertical (flip=1) or both(flip=-1) axises:
+ cvFlip(src) flips images vertically and sequences horizontally (inplace) */
+CVAPI(void) cvFlip( const CvArr* src, CvArr* dst CV_DEFAULT(NULL),
+ int flip_mode CV_DEFAULT(0));
+#define cvMirror cvFlip
+
+
+#define CV_SVD_MODIFY_A 1
+#define CV_SVD_U_T 2
+#define CV_SVD_V_T 4
+
+/* Performs Singular Value Decomposition of a matrix */
+CVAPI(void) cvSVD( CvArr* A, CvArr* W, CvArr* U CV_DEFAULT(NULL),
+ CvArr* V CV_DEFAULT(NULL), int flags CV_DEFAULT(0));
+
+/* Performs Singular Value Back Substitution (solves A*X = B):
+ flags must be the same as in cvSVD */
+CVAPI(void) cvSVBkSb( const CvArr* W, const CvArr* U,
+ const CvArr* V, const CvArr* B,
+ CvArr* X, int flags );
+
+#define CV_LU 0
+#define CV_SVD 1
+#define CV_SVD_SYM 2
+#define CV_LSQ 8
+
+/* Inverts matrix */
+CVAPI(double) cvInvert( const CvArr* src, CvArr* dst,
+ int method CV_DEFAULT(CV_LU));
+#define cvInv cvInvert
+
+/* Solves linear system (src1)*(dst) = (src2)
+ (returns 0 if src1 is a singular and CV_LU method is used) */
+CVAPI(int) cvSolve( const CvArr* src1, const CvArr* src2, CvArr* dst,
+ int method CV_DEFAULT(CV_LU));
+
+/* Calculates determinant of input matrix */
+CVAPI(double) cvDet( const CvArr* mat );
+
+/* Calculates trace of the matrix (sum of elements on the main diagonal) */
+CVAPI(CvScalar) cvTrace( const CvArr* mat );
+
+/* Finds eigen values and vectors of a symmetric matrix */
+CVAPI(void) cvEigenVV( CvArr* mat, CvArr* evects,
+ CvArr* evals, double eps CV_DEFAULT(0));
+
+/* Makes an identity matrix (mat_ij = i == j) */
+CVAPI(void) cvSetIdentity( CvArr* mat, CvScalar value CV_DEFAULT(cvRealScalar(1)) );
+
+/* Fills matrix with given range of numbers */
+CVAPI(CvArr*) cvRange( CvArr* mat, double start, double end );
+
+/* Calculates covariation matrix for a set of vectors */
+/* transpose([v1-avg, v2-avg,...]) * [v1-avg,v2-avg,...] */
+#define CV_COVAR_SCRAMBLED 0
+
+/* [v1-avg, v2-avg,...] * transpose([v1-avg,v2-avg,...]) */
+#define CV_COVAR_NORMAL 1
+
+/* do not calc average (i.e. mean vector) - use the input vector instead
+ (useful for calculating covariance matrix by parts) */
+#define CV_COVAR_USE_AVG 2
+
+/* scale the covariance matrix coefficients by number of the vectors */
+#define CV_COVAR_SCALE 4
+
+/* all the input vectors are stored in a single matrix, as its rows */
+#define CV_COVAR_ROWS 8
+
+/* all the input vectors are stored in a single matrix, as its columns */
+#define CV_COVAR_COLS 16
+
+CVAPI(void) cvCalcCovarMatrix( const CvArr** vects, int count,
+ CvArr* cov_mat, CvArr* avg, int flags );
+
+#define CV_PCA_DATA_AS_ROW 0
+#define CV_PCA_DATA_AS_COL 1
+#define CV_PCA_USE_AVG 2
+CVAPI(void) cvCalcPCA( const CvArr* data, CvArr* mean,
+ CvArr* eigenvals, CvArr* eigenvects, int flags );
+
+CVAPI(void) cvProjectPCA( const CvArr* data, const CvArr* mean,
+ const CvArr* eigenvects, CvArr* result );
+
+CVAPI(void) cvBackProjectPCA( const CvArr* proj, const CvArr* mean,
+ const CvArr* eigenvects, CvArr* result );
+
+/* Calculates Mahalanobis(weighted) distance */
+CVAPI(double) cvMahalanobis( const CvArr* vec1, const CvArr* vec2, CvArr* mat );
+#define cvMahalonobis cvMahalanobis
+
+/****************************************************************************************\
+* Array Statistics *
+\****************************************************************************************/
+
+/* Finds sum of array elements */
+CVAPI(CvScalar) cvSum( const CvArr* arr );
+
+/* Calculates number of non-zero pixels */
+CVAPI(int) cvCountNonZero( const CvArr* arr );
+
+/* Calculates mean value of array elements */
+CVAPI(CvScalar) cvAvg( const CvArr* arr, const CvArr* mask CV_DEFAULT(NULL) );
+
+/* Calculates mean and standard deviation of pixel values */
+CVAPI(void) cvAvgSdv( const CvArr* arr, CvScalar* mean, CvScalar* std_dev,
+ const CvArr* mask CV_DEFAULT(NULL) );
+
+/* Finds global minimum, maximum and their positions */
+CVAPI(void) cvMinMaxLoc( const CvArr* arr, double* min_val, double* max_val,
+ CvPoint* min_loc CV_DEFAULT(NULL),
+ CvPoint* max_loc CV_DEFAULT(NULL),
+ const CvArr* mask CV_DEFAULT(NULL) );
+
+/* types of array norm */
+#define CV_C 1
+#define CV_L1 2
+#define CV_L2 4
+#define CV_NORM_MASK 7
+#define CV_RELATIVE 8
+#define CV_DIFF 16
+#define CV_MINMAX 32
+
+#define CV_DIFF_C (CV_DIFF | CV_C)
+#define CV_DIFF_L1 (CV_DIFF | CV_L1)
+#define CV_DIFF_L2 (CV_DIFF | CV_L2)
+#define CV_RELATIVE_C (CV_RELATIVE | CV_C)
+#define CV_RELATIVE_L1 (CV_RELATIVE | CV_L1)
+#define CV_RELATIVE_L2 (CV_RELATIVE | CV_L2)
+
+/* Finds norm, difference norm or relative difference norm for an array (or two arrays) */
+CVAPI(double) cvNorm( const CvArr* arr1, const CvArr* arr2 CV_DEFAULT(NULL),
+ int norm_type CV_DEFAULT(CV_L2),
+ const CvArr* mask CV_DEFAULT(NULL) );
+
+CVAPI(void) cvNormalize( const CvArr* src, CvArr* dst,
+ double a CV_DEFAULT(1.), double b CV_DEFAULT(0.),
+ int norm_type CV_DEFAULT(CV_L2),
+ const CvArr* mask CV_DEFAULT(NULL) );
+
+
+#define CV_REDUCE_SUM 0
+#define CV_REDUCE_AVG 1
+#define CV_REDUCE_MAX 2
+#define CV_REDUCE_MIN 3
+
+CVAPI(void) cvReduce( const CvArr* src, CvArr* dst, int dim CV_DEFAULT(-1),
+ int op CV_DEFAULT(CV_REDUCE_SUM) );
+
+/****************************************************************************************\
+* Discrete Linear Transforms and Related Functions *
+\****************************************************************************************/
+
+#define CV_DXT_FORWARD 0
+#define CV_DXT_INVERSE 1
+#define CV_DXT_SCALE 2 /* divide result by size of array */
+#define CV_DXT_INV_SCALE (CV_DXT_INVERSE + CV_DXT_SCALE)
+#define CV_DXT_INVERSE_SCALE CV_DXT_INV_SCALE
+#define CV_DXT_ROWS 4 /* transform each row individually */
+#define CV_DXT_MUL_CONJ 8 /* conjugate the second argument of cvMulSpectrums */
+
+/* Discrete Fourier Transform:
+ complex->complex,
+ real->ccs (forward),
+ ccs->real (inverse) */
+CVAPI(void) cvDFT( const CvArr* src, CvArr* dst, int flags,
+ int nonzero_rows CV_DEFAULT(0) );
+#define cvFFT cvDFT
+
+/* Multiply results of DFTs: DFT(X)*DFT(Y) or DFT(X)*conj(DFT(Y)) */
+CVAPI(void) cvMulSpectrums( const CvArr* src1, const CvArr* src2,
+ CvArr* dst, int flags );
+
+/* Finds optimal DFT vector size >= size0 */
+CVAPI(int) cvGetOptimalDFTSize( int size0 );
+
+/* Discrete Cosine Transform */
+CVAPI(void) cvDCT( const CvArr* src, CvArr* dst, int flags );
+
+/****************************************************************************************\
+* Dynamic data structures *
+\****************************************************************************************/
+
+/* Calculates length of sequence slice (with support of negative indices). */
+CVAPI(int) cvSliceLength( CvSlice slice, const CvSeq* seq );
+
+
+/* Creates new memory storage.
+ block_size == 0 means that default,
+ somewhat optimal size, is used (currently, it is 64K) */
+CVAPI(CvMemStorage*) cvCreateMemStorage( int block_size CV_DEFAULT(0));
+
+
+/* Creates a memory storage that will borrow memory blocks from parent storage */
+CVAPI(CvMemStorage*) cvCreateChildMemStorage( CvMemStorage* parent );
+
+
+/* Releases memory storage. All the children of a parent must be released before
+ the parent. A child storage returns all the blocks to parent when it is released */
+CVAPI(void) cvReleaseMemStorage( CvMemStorage** storage );
+
+
+/* Clears memory storage. This is the only way(!!!) (besides cvRestoreMemStoragePos)
+ to reuse memory allocated for the storage - cvClearSeq,cvClearSet ...
+ do not free any memory.
+ A child storage returns all the blocks to the parent when it is cleared */
+CVAPI(void) cvClearMemStorage( CvMemStorage* storage );
+
+/* Remember a storage "free memory" position */
+CVAPI(void) cvSaveMemStoragePos( const CvMemStorage* storage, CvMemStoragePos* pos );
+
+/* Restore a storage "free memory" position */
+CVAPI(void) cvRestoreMemStoragePos( CvMemStorage* storage, CvMemStoragePos* pos );
+
+/* Allocates continuous buffer of the specified size in the storage */
+CVAPI(void*) cvMemStorageAlloc( CvMemStorage* storage, size_t size );
+
+/* Allocates string in memory storage */
+CVAPI(CvString) cvMemStorageAllocString( CvMemStorage* storage, const char* ptr,
+ int len CV_DEFAULT(-1) );
+
+/* Creates new empty sequence that will reside in the specified storage */
+CVAPI(CvSeq*) cvCreateSeq( int seq_flags, int header_size,
+ int elem_size, CvMemStorage* storage );
+
+/* Changes default size (granularity) of sequence blocks.
+ The default size is ~1Kbyte */
+CVAPI(void) cvSetSeqBlockSize( CvSeq* seq, int delta_elems );
+
+
+/* Adds new element to the end of sequence. Returns pointer to the element */
+CVAPI(schar*) cvSeqPush( CvSeq* seq, void* element CV_DEFAULT(NULL));
+
+
+/* Adds new element to the beginning of sequence. Returns pointer to it */
+CVAPI(schar*) cvSeqPushFront( CvSeq* seq, void* element CV_DEFAULT(NULL));
+
+
+/* Removes the last element from sequence and optionally saves it */
+CVAPI(void) cvSeqPop( CvSeq* seq, void* element CV_DEFAULT(NULL));
+
+
+/* Removes the first element from sequence and optioanally saves it */
+CVAPI(void) cvSeqPopFront( CvSeq* seq, void* element CV_DEFAULT(NULL));
+
+
+#define CV_FRONT 1
+#define CV_BACK 0
+/* Adds several new elements to the end of sequence */
+CVAPI(void) cvSeqPushMulti( CvSeq* seq, void* elements,
+ int count, int in_front CV_DEFAULT(0) );
+
+/* Removes several elements from the end of sequence and optionally saves them */
+CVAPI(void) cvSeqPopMulti( CvSeq* seq, void* elements,
+ int count, int in_front CV_DEFAULT(0) );
+
+/* Inserts a new element in the middle of sequence.
+ cvSeqInsert(seq,0,elem) == cvSeqPushFront(seq,elem) */
+CVAPI(schar*) cvSeqInsert( CvSeq* seq, int before_index,
+ void* element CV_DEFAULT(NULL));
+
+/* Removes specified sequence element */
+CVAPI(void) cvSeqRemove( CvSeq* seq, int index );
+
+
+/* Removes all the elements from the sequence. The freed memory
+ can be reused later only by the same sequence unless cvClearMemStorage
+ or cvRestoreMemStoragePos is called */
+CVAPI(void) cvClearSeq( CvSeq* seq );
+
+
+/* Retrieves pointer to specified sequence element.
+ Negative indices are supported and mean counting from the end
+ (e.g -1 means the last sequence element) */
+CVAPI(schar*) cvGetSeqElem( const CvSeq* seq, int index );
+
+/* Calculates index of the specified sequence element.
+ Returns -1 if element does not belong to the sequence */
+CVAPI(int) cvSeqElemIdx( const CvSeq* seq, const void* element,
+ CvSeqBlock** block CV_DEFAULT(NULL) );
+
+/* Initializes sequence writer. The new elements will be added to the end of sequence */
+CVAPI(void) cvStartAppendToSeq( CvSeq* seq, CvSeqWriter* writer );
+
+
+/* Combination of cvCreateSeq and cvStartAppendToSeq */
+CVAPI(void) cvStartWriteSeq( int seq_flags, int header_size,
+ int elem_size, CvMemStorage* storage,
+ CvSeqWriter* writer );
+
+/* Closes sequence writer, updates sequence header and returns pointer
+ to the resultant sequence
+ (which may be useful if the sequence was created using cvStartWriteSeq))
+*/
+CVAPI(CvSeq*) cvEndWriteSeq( CvSeqWriter* writer );
+
+
+/* Updates sequence header. May be useful to get access to some of previously
+ written elements via cvGetSeqElem or sequence reader */
+CVAPI(void) cvFlushSeqWriter( CvSeqWriter* writer );
+
+
+/* Initializes sequence reader.
+ The sequence can be read in forward or backward direction */
+CVAPI(void) cvStartReadSeq( const CvSeq* seq, CvSeqReader* reader,
+ int reverse CV_DEFAULT(0) );
+
+
+/* Returns current sequence reader position (currently observed sequence element) */
+CVAPI(int) cvGetSeqReaderPos( CvSeqReader* reader );
+
+
+/* Changes sequence reader position. It may seek to an absolute or
+ to relative to the current position */
+CVAPI(void) cvSetSeqReaderPos( CvSeqReader* reader, int index,
+ int is_relative CV_DEFAULT(0));
+
+/* Copies sequence content to a continuous piece of memory */
+CVAPI(void*) cvCvtSeqToArray( const CvSeq* seq, void* elements,
+ CvSlice slice CV_DEFAULT(CV_WHOLE_SEQ) );
+
+/* Creates sequence header for array.
+ After that all the operations on sequences that do not alter the content
+ can be applied to the resultant sequence */
+CVAPI(CvSeq*) cvMakeSeqHeaderForArray( int seq_type, int header_size,
+ int elem_size, void* elements, int total,
+ CvSeq* seq, CvSeqBlock* block );
+
+/* Extracts sequence slice (with or without copying sequence elements) */
+CVAPI(CvSeq*) cvSeqSlice( const CvSeq* seq, CvSlice slice,
+ CvMemStorage* storage CV_DEFAULT(NULL),
+ int copy_data CV_DEFAULT(0));
+
+CV_INLINE CvSeq* cvCloneSeq( const CvSeq* seq, CvMemStorage* storage CV_DEFAULT(NULL))
+{
+ return cvSeqSlice( seq, CV_WHOLE_SEQ, storage, 1 );
+}
+
+/* Removes sequence slice */
+CVAPI(void) cvSeqRemoveSlice( CvSeq* seq, CvSlice slice );
+
+/* Inserts a sequence or array into another sequence */
+CVAPI(void) cvSeqInsertSlice( CvSeq* seq, int before_index, const CvArr* from_arr );
+
+/* a < b ? -1 : a > b ? 1 : 0 */
+typedef int (CV_CDECL* CvCmpFunc)(const void* a, const void* b, void* userdata );
+
+/* Sorts sequence in-place given element comparison function */
+CVAPI(void) cvSeqSort( CvSeq* seq, CvCmpFunc func, void* userdata CV_DEFAULT(NULL) );
+
+/* Finds element in a [sorted] sequence */
+CVAPI(schar*) cvSeqSearch( CvSeq* seq, const void* elem, CvCmpFunc func,
+ int is_sorted, int* elem_idx,
+ void* userdata CV_DEFAULT(NULL) );
+
+/* Reverses order of sequence elements in-place */
+CVAPI(void) cvSeqInvert( CvSeq* seq );
+
+/* Splits sequence into one or more equivalence classes using the specified criteria */
+CVAPI(int) cvSeqPartition( const CvSeq* seq, CvMemStorage* storage,
+ CvSeq** labels, CvCmpFunc is_equal, void* userdata );
+
+/************ Internal sequence functions ************/
+CVAPI(void) cvChangeSeqBlock( void* reader, int direction );
+CVAPI(void) cvCreateSeqBlock( CvSeqWriter* writer );
+
+
+/* Creates a new set */
+CVAPI(CvSet*) cvCreateSet( int set_flags, int header_size,
+ int elem_size, CvMemStorage* storage );
+
+/* Adds new element to the set and returns pointer to it */
+CVAPI(int) cvSetAdd( CvSet* set_header, CvSetElem* elem CV_DEFAULT(NULL),
+ CvSetElem** inserted_elem CV_DEFAULT(NULL) );
+
+/* Fast variant of cvSetAdd */
+CV_INLINE CvSetElem* cvSetNew( CvSet* set_header )
+{
+ CvSetElem* elem = set_header->free_elems;
+ if( elem )
+ {
+ set_header->free_elems = elem->next_free;
+ elem->flags = elem->flags & CV_SET_ELEM_IDX_MASK;
+ set_header->active_count++;
+ }
+ else
+ cvSetAdd( set_header, NULL, (CvSetElem**)&elem );
+ return elem;
+}
+
+/* Removes set element given its pointer */
+CV_INLINE void cvSetRemoveByPtr( CvSet* set_header, void* elem )
+{
+ CvSetElem* _elem = (CvSetElem*)elem;
+ assert( _elem->flags >= 0 /*&& (elem->flags & CV_SET_ELEM_IDX_MASK) < set_header->total*/ );
+ _elem->next_free = set_header->free_elems;
+ _elem->flags = (_elem->flags & CV_SET_ELEM_IDX_MASK) | CV_SET_ELEM_FREE_FLAG;
+ set_header->free_elems = _elem;
+ set_header->active_count--;
+}
+
+/* Removes element from the set by its index */
+CVAPI(void) cvSetRemove( CvSet* set_header, int index );
+
+/* Returns a set element by index. If the element doesn't belong to the set,
+ NULL is returned */
+CV_INLINE CvSetElem* cvGetSetElem( const CvSet* set_header, int index )
+{
+ CvSetElem* elem = (CvSetElem*)cvGetSeqElem( (CvSeq*)set_header, index );
+ return elem && CV_IS_SET_ELEM( elem ) ? elem : 0;
+}
+
+/* Removes all the elements from the set */
+CVAPI(void) cvClearSet( CvSet* set_header );
+
+/* Creates new graph */
+CVAPI(CvGraph*) cvCreateGraph( int graph_flags, int header_size,
+ int vtx_size, int edge_size,
+ CvMemStorage* storage );
+
+/* Adds new vertex to the graph */
+CVAPI(int) cvGraphAddVtx( CvGraph* graph, const CvGraphVtx* vtx CV_DEFAULT(NULL),
+ CvGraphVtx** inserted_vtx CV_DEFAULT(NULL) );
+
+
+/* Removes vertex from the graph together with all incident edges */
+CVAPI(int) cvGraphRemoveVtx( CvGraph* graph, int index );
+CVAPI(int) cvGraphRemoveVtxByPtr( CvGraph* graph, CvGraphVtx* vtx );
+
+
+/* Link two vertices specifed by indices or pointers if they
+ are not connected or return pointer to already existing edge
+ connecting the vertices.
+ Functions return 1 if a new edge was created, 0 otherwise */
+CVAPI(int) cvGraphAddEdge( CvGraph* graph,
+ int start_idx, int end_idx,
+ const CvGraphEdge* edge CV_DEFAULT(NULL),
+ CvGraphEdge** inserted_edge CV_DEFAULT(NULL) );
+
+CVAPI(int) cvGraphAddEdgeByPtr( CvGraph* graph,
+ CvGraphVtx* start_vtx, CvGraphVtx* end_vtx,
+ const CvGraphEdge* edge CV_DEFAULT(NULL),
+ CvGraphEdge** inserted_edge CV_DEFAULT(NULL) );
+
+/* Remove edge connecting two vertices */
+CVAPI(void) cvGraphRemoveEdge( CvGraph* graph, int start_idx, int end_idx );
+CVAPI(void) cvGraphRemoveEdgeByPtr( CvGraph* graph, CvGraphVtx* start_vtx,
+ CvGraphVtx* end_vtx );
+
+/* Find edge connecting two vertices */
+CVAPI(CvGraphEdge*) cvFindGraphEdge( const CvGraph* graph, int start_idx, int end_idx );
+CVAPI(CvGraphEdge*) cvFindGraphEdgeByPtr( const CvGraph* graph,
+ const CvGraphVtx* start_vtx,
+ const CvGraphVtx* end_vtx );
+#define cvGraphFindEdge cvFindGraphEdge
+#define cvGraphFindEdgeByPtr cvFindGraphEdgeByPtr
+
+/* Remove all vertices and edges from the graph */
+CVAPI(void) cvClearGraph( CvGraph* graph );
+
+
+/* Count number of edges incident to the vertex */
+CVAPI(int) cvGraphVtxDegree( const CvGraph* graph, int vtx_idx );
+CVAPI(int) cvGraphVtxDegreeByPtr( const CvGraph* graph, const CvGraphVtx* vtx );
+
+
+/* Retrieves graph vertex by given index */
+#define cvGetGraphVtx( graph, idx ) (CvGraphVtx*)cvGetSetElem((CvSet*)(graph), (idx))
+
+/* Retrieves index of a graph vertex given its pointer */
+#define cvGraphVtxIdx( graph, vtx ) ((vtx)->flags & CV_SET_ELEM_IDX_MASK)
+
+/* Retrieves index of a graph edge given its pointer */
+#define cvGraphEdgeIdx( graph, edge ) ((edge)->flags & CV_SET_ELEM_IDX_MASK)
+
+#define cvGraphGetVtxCount( graph ) ((graph)->active_count)
+#define cvGraphGetEdgeCount( graph ) ((graph)->edges->active_count)
+
+#define CV_GRAPH_VERTEX 1
+#define CV_GRAPH_TREE_EDGE 2
+#define CV_GRAPH_BACK_EDGE 4
+#define CV_GRAPH_FORWARD_EDGE 8
+#define CV_GRAPH_CROSS_EDGE 16
+#define CV_GRAPH_ANY_EDGE 30
+#define CV_GRAPH_NEW_TREE 32
+#define CV_GRAPH_BACKTRACKING 64
+#define CV_GRAPH_OVER -1
+
+#define CV_GRAPH_ALL_ITEMS -1
+
+/* flags for graph vertices and edges */
+#define CV_GRAPH_ITEM_VISITED_FLAG (1 << 30)
+#define CV_IS_GRAPH_VERTEX_VISITED(vtx) \
+ (((CvGraphVtx*)(vtx))->flags & CV_GRAPH_ITEM_VISITED_FLAG)
+#define CV_IS_GRAPH_EDGE_VISITED(edge) \
+ (((CvGraphEdge*)(edge))->flags & CV_GRAPH_ITEM_VISITED_FLAG)
+#define CV_GRAPH_SEARCH_TREE_NODE_FLAG (1 << 29)
+#define CV_GRAPH_FORWARD_EDGE_FLAG (1 << 28)
+
+typedef struct CvGraphScanner
+{
+ CvGraphVtx* vtx; /* current graph vertex (or current edge origin) */
+ CvGraphVtx* dst; /* current graph edge destination vertex */
+ CvGraphEdge* edge; /* current edge */
+
+ CvGraph* graph; /* the graph */
+ CvSeq* stack; /* the graph vertex stack */
+ int index; /* the lower bound of certainly visited vertices */
+ int mask; /* event mask */
+}
+CvGraphScanner;
+
+/* Creates new graph scanner. */
+CVAPI(CvGraphScanner*) cvCreateGraphScanner( CvGraph* graph,
+ CvGraphVtx* vtx CV_DEFAULT(NULL),
+ int mask CV_DEFAULT(CV_GRAPH_ALL_ITEMS));
+
+/* Releases graph scanner. */
+CVAPI(void) cvReleaseGraphScanner( CvGraphScanner** scanner );
+
+/* Get next graph element */
+CVAPI(int) cvNextGraphItem( CvGraphScanner* scanner );
+
+/* Creates a copy of graph */
+CVAPI(CvGraph*) cvCloneGraph( const CvGraph* graph, CvMemStorage* storage );
+
+/****************************************************************************************\
+* Drawing *
+\****************************************************************************************/
+
+/****************************************************************************************\
+* Drawing functions work with images/matrices of arbitrary type. *
+* For color images the channel order is BGR[A] *
+* Antialiasing is supported only for 8-bit image now. *
+* All the functions include parameter color that means rgb value (that may be *
+* constructed with CV_RGB macro) for color images and brightness *
+* for grayscale images. *
+* If a drawn figure is partially or completely outside of the image, it is clipped.*
+\****************************************************************************************/
+
+#define CV_RGB( r, g, b ) cvScalar( (b), (g), (r), 0 )
+#define CV_FILLED -1
+
+#define CV_AA 16
+
+/* Draws 4-connected, 8-connected or antialiased line segment connecting two points */
+CVAPI(void) cvLine( CvArr* img, CvPoint pt1, CvPoint pt2,
+ CvScalar color, int thickness CV_DEFAULT(1),
+ int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0) );
+
+/* Draws a rectangle given two opposite corners of the rectangle (pt1 & pt2),
+ if thickness<0 (e.g. thickness == CV_FILLED), the filled box is drawn */
+CVAPI(void) cvRectangle( CvArr* img, CvPoint pt1, CvPoint pt2,
+ CvScalar color, int thickness CV_DEFAULT(1),
+ int line_type CV_DEFAULT(8),
+ int shift CV_DEFAULT(0));
+
+/* Draws a circle with specified center and radius.
+ Thickness works in the same way as with cvRectangle */
+CVAPI(void) cvCircle( CvArr* img, CvPoint center, int radius,
+ CvScalar color, int thickness CV_DEFAULT(1),
+ int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0));
+
+/* Draws ellipse outline, filled ellipse, elliptic arc or filled elliptic sector,
+ depending on <thickness>, <start_angle> and <end_angle> parameters. The resultant figure
+ is rotated by <angle>. All the angles are in degrees */
+CVAPI(void) cvEllipse( CvArr* img, CvPoint center, CvSize axes,
+ double angle, double start_angle, double end_angle,
+ CvScalar color, int thickness CV_DEFAULT(1),
+ int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0));
+
+CV_INLINE void cvEllipseBox( CvArr* img, CvBox2D box, CvScalar color,
+ int thickness CV_DEFAULT(1),
+ int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0) )
+{
+ CvSize axes;
+ axes.width = cvRound(box.size.height*0.5);
+ axes.height = cvRound(box.size.width*0.5);
+
+ cvEllipse( img, cvPointFrom32f( box.center ), axes, box.angle,
+ 0, 360, color, thickness, line_type, shift );
+}
+
+/* Fills convex or monotonous polygon. */
+CVAPI(void) cvFillConvexPoly( CvArr* img, CvPoint* pts, int npts, CvScalar color,
+ int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0));
+
+/* Fills an area bounded by one or more arbitrary polygons */
+CVAPI(void) cvFillPoly( CvArr* img, CvPoint** pts, int* npts, int contours, CvScalar color,
+ int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0) );
+
+/* Draws one or more polygonal curves */
+CVAPI(void) cvPolyLine( CvArr* img, CvPoint** pts, int* npts, int contours,
+ int is_closed, CvScalar color, int thickness CV_DEFAULT(1),
+ int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0) );
+
+#define cvDrawRect cvRectangle
+#define cvDrawLine cvLine
+#define cvDrawCircle cvCircle
+#define cvDrawEllipse cvEllipse
+#define cvDrawPolyLine cvPolyLine
+
+/* Clips the line segment connecting *pt1 and *pt2
+ by the rectangular window
+ (0<=x<img_size.width, 0<=y<img_size.height). */
+CVAPI(int) cvClipLine( CvSize img_size, CvPoint* pt1, CvPoint* pt2 );
+
+/* Initializes line iterator. Initially, line_iterator->ptr will point
+ to pt1 (or pt2, see left_to_right description) location in the image.
+ Returns the number of pixels on the line between the ending points. */
+CVAPI(int) cvInitLineIterator( const CvArr* image, CvPoint pt1, CvPoint pt2,
+ CvLineIterator* line_iterator,
+ int connectivity CV_DEFAULT(8),
+ int left_to_right CV_DEFAULT(0));
+
+/* Moves iterator to the next line point */
+#define CV_NEXT_LINE_POINT( line_iterator ) \
+{ \
+ int _line_iterator_mask = (line_iterator).err < 0 ? -1 : 0; \
+ (line_iterator).err += (line_iterator).minus_delta + \
+ ((line_iterator).plus_delta & _line_iterator_mask); \
+ (line_iterator).ptr += (line_iterator).minus_step + \
+ ((line_iterator).plus_step & _line_iterator_mask); \
+}
+
+
+/* basic font types */
+#define CV_FONT_HERSHEY_SIMPLEX 0
+#define CV_FONT_HERSHEY_PLAIN 1
+#define CV_FONT_HERSHEY_DUPLEX 2
+#define CV_FONT_HERSHEY_COMPLEX 3
+#define CV_FONT_HERSHEY_TRIPLEX 4
+#define CV_FONT_HERSHEY_COMPLEX_SMALL 5
+#define CV_FONT_HERSHEY_SCRIPT_SIMPLEX 6
+#define CV_FONT_HERSHEY_SCRIPT_COMPLEX 7
+
+/* font flags */
+#define CV_FONT_ITALIC 16
+
+#define CV_FONT_VECTOR0 CV_FONT_HERSHEY_SIMPLEX
+
+/* Font structure */
+typedef struct CvFont
+{
+ int font_face; /* =CV_FONT_* */
+ const int* ascii; /* font data and metrics */
+ const int* greek;
+ const int* cyrillic;
+ float hscale, vscale;
+ float shear; /* slope coefficient: 0 - normal, >0 - italic */
+ int thickness; /* letters thickness */
+ float dx; /* horizontal interval between letters */
+ int line_type;
+}
+CvFont;
+
+/* Initializes font structure used further in cvPutText */
+CVAPI(void) cvInitFont( CvFont* font, int font_face,
+ double hscale, double vscale,
+ double shear CV_DEFAULT(0),
+ int thickness CV_DEFAULT(1),
+ int line_type CV_DEFAULT(8));
+
+CV_INLINE CvFont cvFont( double scale, int thickness CV_DEFAULT(1) )
+{
+ CvFont font;
+ cvInitFont( &font, CV_FONT_HERSHEY_PLAIN, scale, scale, 0, thickness, CV_AA );
+ return font;
+}
+
+/* Renders text stroke with specified font and color at specified location.
+ CvFont should be initialized with cvInitFont */
+CVAPI(void) cvPutText( CvArr* img, const char* text, CvPoint org,
+ const CvFont* font, CvScalar color );
+
+/* Calculates bounding box of text stroke (useful for alignment) */
+CVAPI(void) cvGetTextSize( const char* text_string, const CvFont* font,
+ CvSize* text_size, int* baseline );
+
+/* Unpacks color value, if arrtype is CV_8UC?, <color> is treated as
+ packed color value, otherwise the first channels (depending on arrtype)
+ of destination scalar are set to the same value = <color> */
+CVAPI(CvScalar) cvColorToScalar( double packed_color, int arrtype );
+
+/* Returns the polygon points which make up the given ellipse. The ellipse is define by
+ the box of size 'axes' rotated 'angle' around the 'center'. A partial sweep
+ of the ellipse arc can be done by spcifying arc_start and arc_end to be something
+ other than 0 and 360, respectively. The input array 'pts' must be large enough to
+ hold the result. The total number of points stored into 'pts' is returned by this
+ function. */
+CVAPI(int) cvEllipse2Poly( CvPoint center, CvSize axes,
+ int angle, int arc_start, int arc_end, CvPoint * pts, int delta );
+
+/* Draws contour outlines or filled interiors on the image */
+CVAPI(void) cvDrawContours( CvArr *img, CvSeq* contour,
+ CvScalar external_color, CvScalar hole_color,
+ int max_level, int thickness CV_DEFAULT(1),
+ int line_type CV_DEFAULT(8),
+ CvPoint offset CV_DEFAULT(cvPoint(0,0)));
+
+/* Does look-up transformation. Elements of the source array
+ (that should be 8uC1 or 8sC1) are used as indexes in lutarr 256-element table */
+CVAPI(void) cvLUT( const CvArr* src, CvArr* dst, const CvArr* lut );
+
+
+/******************* Iteration through the sequence tree *****************/
+typedef struct CvTreeNodeIterator
+{
+ const void* node;
+ int level;
+ int max_level;
+}
+CvTreeNodeIterator;
+
+CVAPI(void) cvInitTreeNodeIterator( CvTreeNodeIterator* tree_iterator,
+ const void* first, int max_level );
+CVAPI(void*) cvNextTreeNode( CvTreeNodeIterator* tree_iterator );
+CVAPI(void*) cvPrevTreeNode( CvTreeNodeIterator* tree_iterator );
+
+/* Inserts sequence into tree with specified "parent" sequence.
+ If parent is equal to frame (e.g. the most external contour),
+ then added contour will have null pointer to parent. */
+CVAPI(void) cvInsertNodeIntoTree( void* node, void* parent, void* frame );
+
+/* Removes contour from tree (together with the contour children). */
+CVAPI(void) cvRemoveNodeFromTree( void* node, void* frame );
+
+/* Gathers pointers to all the sequences,
+ accessible from the <first>, to the single sequence */
+CVAPI(CvSeq*) cvTreeToNodeSeq( const void* first, int header_size,
+ CvMemStorage* storage );
+
+/* The function implements the K-means algorithm for clustering an array of sample
+ vectors in a specified number of classes */
+CVAPI(void) cvKMeans2( const CvArr* samples, int cluster_count,
+ CvArr* labels, CvTermCriteria termcrit );
+
+/****************************************************************************************\
+* System functions *
+\****************************************************************************************/
+
+/* Add the function pointers table with associated information to the IPP primitives list */
+CVAPI(int) cvRegisterModule( const CvModuleInfo* module_info );
+
+/* Loads optimized functions from IPP, MKL etc. or switches back to pure C code */
+CVAPI(int) cvUseOptimized( int on_off );
+
+/* Retrieves information about the registered modules and loaded optimized plugins */
+CVAPI(void) cvGetModuleInfo( const char* module_name,
+ const char** version,
+ const char** loaded_addon_plugins );
+
+/* Get current OpenCV error status */
+CVAPI(int) cvGetErrStatus( void );
+
+/* Sets error status silently */
+CVAPI(void) cvSetErrStatus( int status );
+
+#define CV_ErrModeLeaf 0 /* Print error and exit program */
+#define CV_ErrModeParent 1 /* Print error and continue */
+#define CV_ErrModeSilent 2 /* Don't print and continue */
+
+/* Retrives current error processing mode */
+CVAPI(int) cvGetErrMode( void );
+
+/* Sets error processing mode, returns previously used mode */
+CVAPI(int) cvSetErrMode( int mode );
+
+/* Sets error status and performs some additonal actions (displaying message box,
+ writing message to stderr, terminating application etc.)
+ depending on the current error mode */
+CVAPI(void) cvError( int status, const char* func_name,
+ const char* err_msg, const char* file_name, int line );
+
+/* Retrieves textual description of the error given its code */
+CVAPI(const char*) cvErrorStr( int status );
+
+/* Retrieves detailed information about the last error occured */
+CVAPI(int) cvGetErrInfo( const char** errcode_desc, const char** description,
+ const char** filename, int* line );
+
+/* Maps IPP error codes to the counterparts from OpenCV */
+CVAPI(int) cvErrorFromIppStatus( int ipp_status );
+
+typedef int (CV_CDECL *CvErrorCallback)( int status, const char* func_name,
+ const char* err_msg, const char* file_name, int line, void* userdata );
+
+/* Assigns a new error-handling function */
+CVAPI(CvErrorCallback) cvRedirectError( CvErrorCallback error_handler,
+ void* userdata CV_DEFAULT(NULL),
+ void** prev_userdata CV_DEFAULT(NULL) );
+
+/*
+ Output to:
+ cvNulDevReport - nothing
+ cvStdErrReport - console(fprintf(stderr,...))
+ cvGuiBoxReport - MessageBox(WIN32)
+*/
+CVAPI(int) cvNulDevReport( int status, const char* func_name, const char* err_msg,
+ const char* file_name, int line, void* userdata );
+
+CVAPI(int) cvStdErrReport( int status, const char* func_name, const char* err_msg,
+ const char* file_name, int line, void* userdata );
+
+CVAPI(int) cvGuiBoxReport( int status, const char* func_name, const char* err_msg,
+ const char* file_name, int line, void* userdata );
+
+typedef void* (CV_CDECL *CvAllocFunc)(size_t size, void* userdata);
+typedef int (CV_CDECL *CvFreeFunc)(void* pptr, void* userdata);
+
+/* Set user-defined memory managment functions (substitutors for malloc and free) that
+ will be called by cvAlloc, cvFree and higher-level functions (e.g. cvCreateImage) */
+CVAPI(void) cvSetMemoryManager( CvAllocFunc alloc_func CV_DEFAULT(NULL),
+ CvFreeFunc free_func CV_DEFAULT(NULL),
+ void* userdata CV_DEFAULT(NULL));
+
+
+typedef IplImage* (CV_STDCALL* Cv_iplCreateImageHeader)
+ (int,int,int,char*,char*,int,int,int,int,int,
+ IplROI*,IplImage*,void*,IplTileInfo*);
+typedef void (CV_STDCALL* Cv_iplAllocateImageData)(IplImage*,int,int);
+typedef void (CV_STDCALL* Cv_iplDeallocate)(IplImage*,int);
+typedef IplROI* (CV_STDCALL* Cv_iplCreateROI)(int,int,int,int,int);
+typedef IplImage* (CV_STDCALL* Cv_iplCloneImage)(const IplImage*);
+
+/* Makes OpenCV use IPL functions for IplImage allocation/deallocation */
+CVAPI(void) cvSetIPLAllocators( Cv_iplCreateImageHeader create_header,
+ Cv_iplAllocateImageData allocate_data,
+ Cv_iplDeallocate deallocate,
+ Cv_iplCreateROI create_roi,
+ Cv_iplCloneImage clone_image );
+
+#define CV_TURN_ON_IPL_COMPATIBILITY() \
+ cvSetIPLAllocators( iplCreateImageHeader, iplAllocateImage, \
+ iplDeallocate, iplCreateROI, iplCloneImage )
+
+/****************************************************************************************\
+* Data Persistence *
+\****************************************************************************************/
+
+/********************************** High-level functions ********************************/
+
+/* opens existing or creates new file storage */
+CVAPI(CvFileStorage*) cvOpenFileStorage( const char* filename,
+ CvMemStorage* memstorage,
+ int flags );
+
+/* closes file storage and deallocates buffers */
+CVAPI(void) cvReleaseFileStorage( CvFileStorage** fs );
+
+/* returns attribute value or 0 (NULL) if there is no such attribute */
+CVAPI(const char*) cvAttrValue( const CvAttrList* attr, const char* attr_name );
+
+/* starts writing compound structure (map or sequence) */
+CVAPI(void) cvStartWriteStruct( CvFileStorage* fs, const char* name,
+ int struct_flags, const char* type_name CV_DEFAULT(NULL),
+ CvAttrList attributes CV_DEFAULT(cvAttrList()));
+
+/* finishes writing compound structure */
+CVAPI(void) cvEndWriteStruct( CvFileStorage* fs );
+
+/* writes an integer */
+CVAPI(void) cvWriteInt( CvFileStorage* fs, const char* name, int value );
+
+/* writes a floating-point number */
+CVAPI(void) cvWriteReal( CvFileStorage* fs, const char* name, double value );
+
+/* writes a string */
+CVAPI(void) cvWriteString( CvFileStorage* fs, const char* name,
+ const char* str, int quote CV_DEFAULT(0) );
+
+/* writes a comment */
+CVAPI(void) cvWriteComment( CvFileStorage* fs, const char* comment,
+ int eol_comment );
+
+/* writes instance of a standard type (matrix, image, sequence, graph etc.)
+ or user-defined type */
+CVAPI(void) cvWrite( CvFileStorage* fs, const char* name, const void* ptr,
+ CvAttrList attributes CV_DEFAULT(cvAttrList()));
+
+/* starts the next stream */
+CVAPI(void) cvStartNextStream( CvFileStorage* fs );
+
+/* helper function: writes multiple integer or floating-point numbers */
+CVAPI(void) cvWriteRawData( CvFileStorage* fs, const void* src,
+ int len, const char* dt );
+
+/* returns the hash entry corresponding to the specified literal key string or 0
+ if there is no such a key in the storage */
+CVAPI(CvStringHashNode*) cvGetHashedKey( CvFileStorage* fs, const char* name,
+ int len CV_DEFAULT(-1),
+ int create_missing CV_DEFAULT(0));
+
+/* returns file node with the specified key within the specified map
+ (collection of named nodes) */
+CVAPI(CvFileNode*) cvGetRootFileNode( const CvFileStorage* fs,
+ int stream_index CV_DEFAULT(0) );
+
+/* returns file node with the specified key within the specified map
+ (collection of named nodes) */
+CVAPI(CvFileNode*) cvGetFileNode( CvFileStorage* fs, CvFileNode* map,
+ const CvStringHashNode* key,
+ int create_missing CV_DEFAULT(0) );
+
+/* this is a slower version of cvGetFileNode that takes the key as a literal string */
+CVAPI(CvFileNode*) cvGetFileNodeByName( const CvFileStorage* fs,
+ const CvFileNode* map,
+ const char* name );
+
+CV_INLINE int cvReadInt( const CvFileNode* node, int default_value CV_DEFAULT(0) )
+{
+ return !node ? default_value :
+ CV_NODE_IS_INT(node->tag) ? node->data.i :
+ CV_NODE_IS_REAL(node->tag) ? cvRound(node->data.f) : 0x7fffffff;
+}
+
+
+CV_INLINE int cvReadIntByName( const CvFileStorage* fs, const CvFileNode* map,
+ const char* name, int default_value CV_DEFAULT(0) )
+{
+ return cvReadInt( cvGetFileNodeByName( fs, map, name ), default_value );
+}
+
+
+CV_INLINE double cvReadReal( const CvFileNode* node, double default_value CV_DEFAULT(0.) )
+{
+ return !node ? default_value :
+ CV_NODE_IS_INT(node->tag) ? (double)node->data.i :
+ CV_NODE_IS_REAL(node->tag) ? node->data.f : 1e300;
+}
+
+
+CV_INLINE double cvReadRealByName( const CvFileStorage* fs, const CvFileNode* map,
+ const char* name, double default_value CV_DEFAULT(0.) )
+{
+ return cvReadReal( cvGetFileNodeByName( fs, map, name ), default_value );
+}
+
+
+CV_INLINE const char* cvReadString( const CvFileNode* node,
+ const char* default_value CV_DEFAULT(NULL) )
+{
+ return !node ? default_value : CV_NODE_IS_STRING(node->tag) ? node->data.str.ptr : 0;
+}
+
+
+CV_INLINE const char* cvReadStringByName( const CvFileStorage* fs, const CvFileNode* map,
+ const char* name, const char* default_value CV_DEFAULT(NULL) )
+{
+ return cvReadString( cvGetFileNodeByName( fs, map, name ), default_value );
+}
+
+
+/* decodes standard or user-defined object and returns it */
+CVAPI(void*) cvRead( CvFileStorage* fs, CvFileNode* node,
+ CvAttrList* attributes CV_DEFAULT(NULL));
+
+/* decodes standard or user-defined object and returns it */
+CV_INLINE void* cvReadByName( CvFileStorage* fs, const CvFileNode* map,
+ const char* name, CvAttrList* attributes CV_DEFAULT(NULL) )
+{
+ return cvRead( fs, cvGetFileNodeByName( fs, map, name ), attributes );
+}
+
+
+/* starts reading data from sequence or scalar numeric node */
+CVAPI(void) cvStartReadRawData( const CvFileStorage* fs, const CvFileNode* src,
+ CvSeqReader* reader );
+
+/* reads multiple numbers and stores them to array */
+CVAPI(void) cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader,
+ int count, void* dst, const char* dt );
+
+/* combination of two previous functions for easier reading of whole sequences */
+CVAPI(void) cvReadRawData( const CvFileStorage* fs, const CvFileNode* src,
+ void* dst, const char* dt );
+
+/* writes a copy of file node to file storage */
+CVAPI(void) cvWriteFileNode( CvFileStorage* fs, const char* new_node_name,
+ const CvFileNode* node, int embed );
+
+/* returns name of file node */
+CVAPI(const char*) cvGetFileNodeName( const CvFileNode* node );
+
+/*********************************** Adding own types ***********************************/
+
+CVAPI(void) cvRegisterType( const CvTypeInfo* info );
+CVAPI(void) cvUnregisterType( const char* type_name );
+CVAPI(CvTypeInfo*) cvFirstType(void);
+CVAPI(CvTypeInfo*) cvFindType( const char* type_name );
+CVAPI(CvTypeInfo*) cvTypeOf( const void* struct_ptr );
+
+/* universal functions */
+CVAPI(void) cvRelease( void** struct_ptr );
+CVAPI(void*) cvClone( const void* struct_ptr );
+
+/* simple API for reading/writing data */
+CVAPI(void) cvSave( const char* filename, const void* struct_ptr,
+ const char* name CV_DEFAULT(NULL),
+ const char* comment CV_DEFAULT(NULL),
+ CvAttrList attributes CV_DEFAULT(cvAttrList()));
+CVAPI(void*) cvLoad( const char* filename,
+ CvMemStorage* memstorage CV_DEFAULT(NULL),
+ const char* name CV_DEFAULT(NULL),
+ const char** real_name CV_DEFAULT(NULL) );
+
+/*********************************** Measuring Execution Time ***************************/
+
+/* helper functions for RNG initialization and accurate time measurement:
+ uses internal clock counter on x86 */
+CVAPI(int64) cvGetTickCount( void );
+CVAPI(double) cvGetTickFrequency( void );
+
+/*********************************** Multi-Threading ************************************/
+
+/* retrieve/set the number of threads used in OpenMP implementations */
+CVAPI(int) cvGetNumThreads( void );
+CVAPI(void) cvSetNumThreads( int threads CV_DEFAULT(0) );
+/* get index of the thread being executed */
+CVAPI(int) cvGetThreadNum( void );
+
+/*************** Convenience functions for better interaction with HighGUI **************/
+
+typedef IplImage* (CV_CDECL * CvLoadImageFunc)( const char* filename, int colorness );
+typedef CvMat* (CV_CDECL * CvLoadImageMFunc)( const char* filename, int colorness );
+typedef int (CV_CDECL * CvSaveImageFunc)( const char* filename, const CvArr* image );
+typedef void (CV_CDECL * CvShowImageFunc)( const char* windowname, const CvArr* image );
+
+CVAPI(int) cvSetImageIOFunctions( CvLoadImageFunc _load_image, CvLoadImageMFunc _load_image_m,
+ CvSaveImageFunc _save_image, CvShowImageFunc _show_image );
+
+#define CV_SET_IMAGE_IO_FUNCTIONS() \
+ cvSetImageIOFunctions( cvLoadImage, cvLoadImageM, cvSaveImage, cvShowImage )
+
+#ifdef __cplusplus
+}
+
+#include "cxcore.hpp"
+#endif
+
+#endif /*_CXCORE_H_*/
diff --git a/cxcore/include/cxcore.hpp b/cxcore/include/cxcore.hpp
new file mode 100644
index 0000000..62ef176
--- /dev/null
+++ b/cxcore/include/cxcore.hpp
@@ -0,0 +1,375 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+
+#ifndef _CXCORE_HPP_
+#define _CXCORE_HPP_
+
+class CV_EXPORTS CvImage
+{
+public:
+ CvImage() : image(0), refcount(0) {}
+ CvImage( CvSize size, int depth, int channels )
+ {
+ image = cvCreateImage( size, depth, channels );
+ refcount = image ? new int(1) : 0;
+ }
+
+ CvImage( IplImage* img ) : image(img)
+ {
+ refcount = image ? new int(1) : 0;
+ }
+
+ CvImage( const CvImage& img ) : image(img.image), refcount(img.refcount)
+ {
+ if( refcount ) ++(*refcount);
+ }
+
+ CvImage( const char* filename, const char* imgname=0, int color=-1 ) : image(0), refcount(0)
+ { load( filename, imgname, color ); }
+
+ CvImage( CvFileStorage* fs, const char* mapname, const char* imgname ) : image(0), refcount(0)
+ { read( fs, mapname, imgname ); }
+
+ CvImage( CvFileStorage* fs, const char* seqname, int idx ) : image(0), refcount(0)
+ { read( fs, seqname, idx ); }
+
+ ~CvImage()
+ {
+ if( refcount && !(--*refcount) )
+ {
+ cvReleaseImage( &image );
+ delete refcount;
+ }
+ }
+
+ CvImage clone() { return CvImage(image ? cvCloneImage(image) : 0); }
+
+ void create( CvSize size, int depth, int channels )
+ {
+ if( !image || !refcount ||
+ image->width != size.width || image->height != size.height ||
+ image->depth != depth || image->nChannels != channels )
+ attach( cvCreateImage( size, depth, channels ));
+ }
+
+ void release() { detach(); }
+ void clear() { detach(); }
+
+ void attach( IplImage* img, bool use_refcount=true )
+ {
+ if( refcount && --*refcount == 0 )
+ {
+ cvReleaseImage( &image );
+ delete refcount;
+ }
+ image = img;
+ refcount = use_refcount && image ? new int(1) : 0;
+ }
+
+ void detach()
+ {
+ if( refcount && --*refcount == 0 )
+ {
+ cvReleaseImage( &image );
+ delete refcount;
+ }
+ image = 0;
+ refcount = 0;
+ }
+
+ bool load( const char* filename, const char* imgname=0, int color=-1 );
+ bool read( CvFileStorage* fs, const char* mapname, const char* imgname );
+ bool read( CvFileStorage* fs, const char* seqname, int idx );
+ void save( const char* filename, const char* imgname );
+ void write( CvFileStorage* fs, const char* imgname );
+
+ void show( const char* window_name );
+ bool is_valid() { return image != 0; }
+
+ int width() const { return image ? image->width : 0; }
+ int height() const { return image ? image->height : 0; }
+
+ CvSize size() const { return image ? cvSize(image->width, image->height) : cvSize(0,0); }
+
+ CvSize roi_size() const
+ {
+ return !image ? cvSize(0,0) :
+ !image->roi ? cvSize(image->width,image->height) :
+ cvSize(image->roi->width, image->roi->height);
+ }
+
+ CvRect roi() const
+ {
+ return !image ? cvRect(0,0,0,0) :
+ !image->roi ? cvRect(0,0,image->width,image->height) :
+ cvRect(image->roi->xOffset,image->roi->yOffset,
+ image->roi->width,image->roi->height);
+ }
+
+ int coi() const { return !image || !image->roi ? 0 : image->roi->coi; }
+
+ void set_roi(CvRect roi) { cvSetImageROI(image,roi); }
+ void reset_roi() { cvResetImageROI(image); }
+ void set_coi(int coi) { cvSetImageCOI(image,coi); }
+ int depth() const { return image ? image->depth : 0; }
+ int channels() const { return image ? image->nChannels : 0; }
+ int pix_size() const { return image ? ((image->depth & 255)>>3)*image->nChannels : 0; }
+
+ uchar* data() { return image ? (uchar*)image->imageData : 0; }
+ const uchar* data() const { return image ? (const uchar*)image->imageData : 0; }
+ int step() const { return image ? image->widthStep : 0; }
+ int origin() const { return image ? image->origin : 0; }
+
+ uchar* roi_row(int y)
+ {
+ assert(0<=y);
+ assert(!image ?
+ 1 : image->roi ?
+ y<image->roi->height : y<image->height);
+
+ return !image ? 0 :
+ !image->roi ?
+ (uchar*)(image->imageData + y*image->widthStep) :
+ (uchar*)(image->imageData + (y+image->roi->yOffset)*image->widthStep +
+ image->roi->xOffset*((image->depth & 255)>>3)*image->nChannels);
+ }
+
+ const uchar* roi_row(int y) const
+ {
+ assert(0<=y);
+ assert(!image ?
+ 1 : image->roi ?
+ y<image->roi->height : y<image->height);
+
+ return !image ? 0 :
+ !image->roi ?
+ (const uchar*)(image->imageData + y*image->widthStep) :
+ (const uchar*)(image->imageData + (y+image->roi->yOffset)*image->widthStep +
+ image->roi->xOffset*((image->depth & 255)>>3)*image->nChannels);
+ }
+
+ operator const IplImage* () const { return image; }
+ operator IplImage* () { return image; }
+
+ CvImage& operator = (const CvImage& img)
+ {
+ if( img.refcount )
+ ++*img.refcount;
+ if( refcount && !(--*refcount) )
+ cvReleaseImage( &image );
+ image=img.image;
+ refcount=img.refcount;
+ return *this;
+ }
+
+protected:
+ IplImage* image;
+ int* refcount;
+};
+
+
+class CV_EXPORTS CvMatrix
+{
+public:
+ CvMatrix() : matrix(0) {}
+ CvMatrix( int rows, int cols, int type )
+ { matrix = cvCreateMat( rows, cols, type ); }
+
+ CvMatrix( int rows, int cols, int type, CvMat* hdr,
+ void* data=0, int step=CV_AUTOSTEP )
+ { matrix = cvInitMatHeader( hdr, rows, cols, type, data, step ); }
+
+ CvMatrix( int rows, int cols, int type, CvMemStorage* storage, bool alloc_data=true );
+
+ CvMatrix( int rows, int cols, int type, void* data, int step=CV_AUTOSTEP )
+ { matrix = cvCreateMatHeader( rows, cols, type );
+ cvSetData( matrix, data, step ); }
+
+ CvMatrix( CvMat* m )
+ { matrix = m; }
+
+ CvMatrix( const CvMatrix& m )
+ {
+ matrix = m.matrix;
+ addref();
+ }
+
+ CvMatrix( const char* filename, const char* matname=0, int color=-1 ) : matrix(0)
+ { load( filename, matname, color ); }
+
+ CvMatrix( CvFileStorage* fs, const char* mapname, const char* matname ) : matrix(0)
+ { read( fs, mapname, matname ); }
+
+ CvMatrix( CvFileStorage* fs, const char* seqname, int idx ) : matrix(0)
+ { read( fs, seqname, idx ); }
+
+ ~CvMatrix()
+ {
+ release();
+ }
+
+ CvMatrix clone() { return CvMatrix(matrix ? cvCloneMat(matrix) : 0); }
+
+ void set( CvMat* m, bool add_ref )
+ {
+ release();
+ matrix = m;
+ if( add_ref )
+ addref();
+ }
+
+ void create( int rows, int cols, int type )
+ {
+ if( !matrix || !matrix->refcount ||
+ matrix->rows != rows || matrix->cols != cols ||
+ CV_MAT_TYPE(matrix->type) != type )
+ set( cvCreateMat( rows, cols, type ), false );
+ }
+
+ void addref() const
+ {
+ if( matrix )
+ {
+ if( matrix->hdr_refcount )
+ ++matrix->hdr_refcount;
+ else if( matrix->refcount )
+ ++*matrix->refcount;
+ }
+ }
+
+ void release()
+ {
+ if( matrix )
+ {
+ if( matrix->hdr_refcount )
+ {
+ if( --matrix->hdr_refcount == 0 )
+ cvReleaseMat( &matrix );
+ }
+ else if( matrix->refcount )
+ {
+ if( --*matrix->refcount == 0 )
+ cvFree( &matrix->refcount );
+ }
+ matrix = 0;
+ }
+ }
+
+ void clear()
+ {
+ release();
+ }
+
+ bool load( const char* filename, const char* matname=0, int color=-1 );
+ bool read( CvFileStorage* fs, const char* mapname, const char* matname );
+ bool read( CvFileStorage* fs, const char* seqname, int idx );
+ void save( const char* filename, const char* matname );
+ void write( CvFileStorage* fs, const char* matname );
+
+ void show( const char* window_name );
+
+ bool is_valid() { return matrix != 0; }
+
+ int rows() const { return matrix ? matrix->rows : 0; }
+ int cols() const { return matrix ? matrix->cols : 0; }
+
+ CvSize size() const
+ {
+ return !matrix ? cvSize(0,0) : cvSize(matrix->rows,matrix->cols);
+ }
+
+ int type() const { return matrix ? CV_MAT_TYPE(matrix->type) : 0; }
+ int depth() const { return matrix ? CV_MAT_DEPTH(matrix->type) : 0; }
+ int channels() const { return matrix ? CV_MAT_CN(matrix->type) : 0; }
+ int pix_size() const { return matrix ? CV_ELEM_SIZE(matrix->type) : 0; }
+
+ uchar* data() { return matrix ? matrix->data.ptr : 0; }
+ const uchar* data() const { return matrix ? matrix->data.ptr : 0; }
+ int step() const { return matrix ? matrix->step : 0; }
+
+ void set_data( void* data, int step=CV_AUTOSTEP )
+ { cvSetData( matrix, data, step ); }
+
+ uchar* row(int i) { return !matrix ? 0 : matrix->data.ptr + i*matrix->step; }
+ const uchar* row(int i) const
+ { return !matrix ? 0 : matrix->data.ptr + i*matrix->step; }
+
+ operator const CvMat* () const { return matrix; }
+ operator CvMat* () { return matrix; }
+
+ CvMatrix& operator = (const CvMatrix& _m)
+ {
+ _m.addref();
+ release();
+ matrix = _m.matrix;
+ return *this;
+ }
+
+protected:
+ CvMat* matrix;
+};
+
+
+// classes for automatic module/RTTI data registration/unregistration
+struct CV_EXPORTS CvModule
+{
+ CvModule( CvModuleInfo* _info );
+ ~CvModule();
+ CvModuleInfo* info;
+
+ static CvModuleInfo* first;
+ static CvModuleInfo* last;
+};
+
+struct CV_EXPORTS CvType
+{
+ CvType( const char* type_name,
+ CvIsInstanceFunc is_instance, CvReleaseFunc release=0,
+ CvReadFunc read=0, CvWriteFunc write=0, CvCloneFunc clone=0 );
+ ~CvType();
+ CvTypeInfo* info;
+
+ static CvTypeInfo* first;
+ static CvTypeInfo* last;
+};
+
+#endif /*_CXCORE_HPP_*/
diff --git a/cxcore/include/cxerror.h b/cxcore/include/cxerror.h
new file mode 100644
index 0000000..de4011a
--- /dev/null
+++ b/cxcore/include/cxerror.h
@@ -0,0 +1,189 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _CXCORE_ERROR_H_
+#define _CXCORE_ERROR_H_
+
+/************Below is declaration of error handling stuff in PLSuite manner**/
+
+typedef int CVStatus;
+
+/* this part of CVStatus is compatible with IPLStatus
+ Some of below symbols are not [yet] used in OpenCV
+*/
+#define CV_StsOk 0 /* everithing is ok */
+#define CV_StsBackTrace -1 /* pseudo error for back trace */
+#define CV_StsError -2 /* unknown /unspecified error */
+#define CV_StsInternal -3 /* internal error (bad state) */
+#define CV_StsNoMem -4 /* insufficient memory */
+#define CV_StsBadArg -5 /* function arg/param is bad */
+#define CV_StsBadFunc -6 /* unsupported function */
+#define CV_StsNoConv -7 /* iter. didn't converge */
+#define CV_StsAutoTrace -8 /* tracing */
+
+#define CV_HeaderIsNull -9 /* image header is NULL */
+#define CV_BadImageSize -10 /* image size is invalid */
+#define CV_BadOffset -11 /* offset is invalid */
+#define CV_BadDataPtr -12 /**/
+#define CV_BadStep -13 /**/
+#define CV_BadModelOrChSeq -14 /**/
+#define CV_BadNumChannels -15 /**/
+#define CV_BadNumChannel1U -16 /**/
+#define CV_BadDepth -17 /**/
+#define CV_BadAlphaChannel -18 /**/
+#define CV_BadOrder -19 /**/
+#define CV_BadOrigin -20 /**/
+#define CV_BadAlign -21 /**/
+#define CV_BadCallBack -22 /**/
+#define CV_BadTileSize -23 /**/
+#define CV_BadCOI -24 /**/
+#define CV_BadROISize -25 /**/
+
+#define CV_MaskIsTiled -26 /**/
+
+#define CV_StsNullPtr -27 /* null pointer */
+#define CV_StsVecLengthErr -28 /* incorrect vector length */
+#define CV_StsFilterStructContentErr -29 /* incorr. filter structure content */
+#define CV_StsKernelStructContentErr -30 /* incorr. transform kernel content */
+#define CV_StsFilterOffsetErr -31 /* incorrect filter ofset value */
+
+/*extra for CV */
+#define CV_StsBadSize -201 /* the input/output structure size is incorrect */
+#define CV_StsDivByZero -202 /* division by zero */
+#define CV_StsInplaceNotSupported -203 /* in-place operation is not supported */
+#define CV_StsObjectNotFound -204 /* request can't be completed */
+#define CV_StsUnmatchedFormats -205 /* formats of input/output arrays differ */
+#define CV_StsBadFlag -206 /* flag is wrong or not supported */
+#define CV_StsBadPoint -207 /* bad CvPoint */
+#define CV_StsBadMask -208 /* bad format of mask (neither 8uC1 nor 8sC1)*/
+#define CV_StsUnmatchedSizes -209 /* sizes of input/output structures do not match */
+#define CV_StsUnsupportedFormat -210 /* the data format/type is not supported by the function*/
+#define CV_StsOutOfRange -211 /* some of parameters are out of range */
+#define CV_StsParseError -212 /* invalid syntax/structure of the parsed file */
+#define CV_StsNotImplemented -213 /* the requested function/feature is not implemented */
+#define CV_StsBadMemBlock -214 /* an allocated block has been corrupted */
+
+/********************************* Error handling Macros ********************************/
+
+#define OPENCV_ERROR(status,func,context) \
+ cvError((status),(func),(context),__FILE__,__LINE__)
+
+#define OPENCV_ERRCHK(func,context) \
+ {if (cvGetErrStatus() >= 0) \
+ {OPENCV_ERROR(CV_StsBackTrace,(func),(context));}}
+
+#define OPENCV_ASSERT(expr,func,context) \
+ {if (! (expr)) \
+ {OPENCV_ERROR(CV_StsInternal,(func),(context));}}
+
+#define OPENCV_RSTERR() (cvSetErrStatus(CV_StsOk))
+
+#define OPENCV_CALL( Func ) \
+{ \
+ Func; \
+}
+
+
+/**************************** OpenCV-style error handling *******************************/
+
+/* CV_FUNCNAME macro defines icvFuncName constant which is used by CV_ERROR macro */
+#ifdef CV_NO_FUNC_NAMES
+ #define CV_FUNCNAME( Name )
+ #define cvFuncName ""
+#else
+ #define CV_FUNCNAME( Name ) \
+ static char cvFuncName[] = Name
+#endif
+
+
+/*
+ CV_ERROR macro unconditionally raises error with passed code and message.
+ After raising error, control will be transferred to the exit label.
+*/
+#define CV_ERROR( Code, Msg ) \
+{ \
+ cvError( (Code), cvFuncName, Msg, __FILE__, __LINE__ ); \
+ EXIT; \
+}
+
+/* Simplified form of CV_ERROR */
+#define CV_ERROR_FROM_CODE( code ) \
+ CV_ERROR( code, "" )
+
+/*
+ CV_CHECK macro checks error status after CV (or IPL)
+ function call. If error detected, control will be transferred to the exit
+ label.
+*/
+#define CV_CHECK() \
+{ \
+ if( cvGetErrStatus() < 0 ) \
+ CV_ERROR( CV_StsBackTrace, "Inner function failed." ); \
+}
+
+
+/*
+ CV_CALL macro calls CV (or IPL) function, checks error status and
+ signals a error if the function failed. Useful in "parent node"
+ error procesing mode
+*/
+#define CV_CALL( Func ) \
+{ \
+ Func; \
+ CV_CHECK(); \
+}
+
+
+/* Runtime assertion macro */
+#define CV_ASSERT( Condition ) \
+{ \
+ if( !(Condition) ) \
+ CV_ERROR( CV_StsInternal, "Assertion: " #Condition " failed" ); \
+}
+
+#define __BEGIN__ {
+#define __END__ goto exit; exit: ; }
+#define __CLEANUP__
+#define EXIT goto exit
+
+#endif /* _CXCORE_ERROR_H_ */
+
+/* End of file. */
diff --git a/cxcore/include/cxmisc.h b/cxcore/include/cxmisc.h
new file mode 100644
index 0000000..def4b77
--- /dev/null
+++ b/cxcore/include/cxmisc.h
@@ -0,0 +1,918 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/* The header is mostly for internal use and it is likely to change.
+ It contains some macro definitions that are used in cxcore, cv, cvaux
+ and, probably, other libraries. If you need some of this functionality,
+ the safe way is to copy it into your code and rename the macros.
+*/
+#ifndef _CXCORE_MISC_H_
+#define _CXCORE_MISC_H_
+
+#ifdef HAVE_CONFIG_H
+ #include "cvconfig.h"
+#endif
+
+#include <limits.h>
+#ifdef _OPENMP
+#include "omp.h"
+#endif
+
+/****************************************************************************************\
+* Compile-time tuning parameters *
+\****************************************************************************************/
+
+/* maximal size of vector to run matrix operations on it inline (i.e. w/o ipp calls) */
+#define CV_MAX_INLINE_MAT_OP_SIZE 10
+
+/* maximal linear size of matrix to allocate it on stack. */
+#define CV_MAX_LOCAL_MAT_SIZE 32
+
+/* maximal size of local memory storage */
+#define CV_MAX_LOCAL_SIZE \
+ (CV_MAX_LOCAL_MAT_SIZE*CV_MAX_LOCAL_MAT_SIZE*(int)sizeof(double))
+
+/* default image row align (in bytes) */
+#define CV_DEFAULT_IMAGE_ROW_ALIGN 4
+
+/* matrices are continuous by default */
+#define CV_DEFAULT_MAT_ROW_ALIGN 1
+
+/* maximum size of dynamic memory buffer.
+ cvAlloc reports an error if a larger block is requested. */
+#define CV_MAX_ALLOC_SIZE (((size_t)1 << (sizeof(size_t)*8-2)))
+
+/* the alignment of all the allocated buffers */
+#define CV_MALLOC_ALIGN 32
+
+/* default alignment for dynamic data strucutures, resided in storages. */
+#define CV_STRUCT_ALIGN ((int)sizeof(double))
+
+/* default storage block size */
+#define CV_STORAGE_BLOCK_SIZE ((1<<16) - 128)
+
+/* default memory block for sparse array elements */
+#define CV_SPARSE_MAT_BLOCK (1<<12)
+
+/* initial hash table size */
+#define CV_SPARSE_HASH_SIZE0 (1<<10)
+
+/* maximal average node_count/hash_size ratio beyond which hash table is resized */
+#define CV_SPARSE_HASH_RATIO 3
+
+/* max length of strings */
+#define CV_MAX_STRLEN 1024
+
+/* maximum possible number of threads in parallel implementations */
+#ifdef _OPENMP
+#define CV_MAX_THREADS 128
+#else
+#define CV_MAX_THREADS 1
+#endif
+
+#if 0 /*def CV_CHECK_FOR_NANS*/
+ #define CV_CHECK_NANS( arr ) cvCheckArray((arr))
+#else
+ #define CV_CHECK_NANS( arr )
+#endif
+
+/****************************************************************************************\
+* Common declarations *
+\****************************************************************************************/
+
+/* get alloca declaration */
+#ifdef __GNUC__
+ #undef alloca
+ #define alloca __builtin_alloca
+#elif defined WIN32 || defined WIN64
+ #if defined _MSC_VER || defined __BORLANDC__
+ #include <malloc.h>
+ #endif
+#elif defined HAVE_ALLOCA_H
+ #include <alloca.h>
+#elif defined HAVE_ALLOCA
+ #include <stdlib.h>
+#else
+ #error
+#endif
+
+/* ! DO NOT make it an inline function */
+#define cvStackAlloc(size) cvAlignPtr( alloca((size) + CV_MALLOC_ALIGN), CV_MALLOC_ALIGN )
+
+#if defined _MSC_VER || defined __BORLANDC__
+ #define CV_BIG_INT(n) n##I64
+ #define CV_BIG_UINT(n) n##UI64
+#else
+ #define CV_BIG_INT(n) n##LL
+ #define CV_BIG_UINT(n) n##ULL
+#endif
+
+#define CV_IMPL CV_EXTERN_C
+
+#define CV_DBG_BREAK() { volatile int* crashMe = 0; *crashMe = 0; }
+
+/* default step, set in case of continuous data
+ to work around checks for valid step in some ipp functions */
+#define CV_STUB_STEP (1 << 30)
+
+#define CV_SIZEOF_FLOAT ((int)sizeof(float))
+#define CV_SIZEOF_SHORT ((int)sizeof(short))
+
+#define CV_ORIGIN_TL 0
+#define CV_ORIGIN_BL 1
+
+/* IEEE754 constants and macros */
+#define CV_POS_INF 0x7f800000
+#define CV_NEG_INF 0x807fffff /* CV_TOGGLE_FLT(0xff800000) */
+#define CV_1F 0x3f800000
+#define CV_TOGGLE_FLT(x) ((x)^((int)(x) < 0 ? 0x7fffffff : 0))
+#define CV_TOGGLE_DBL(x) \
+ ((x)^((int64)(x) < 0 ? CV_BIG_INT(0x7fffffffffffffff) : 0))
+
+#define CV_NOP(a) (a)
+#define CV_ADD(a, b) ((a) + (b))
+#define CV_SUB(a, b) ((a) - (b))
+#define CV_MUL(a, b) ((a) * (b))
+#define CV_AND(a, b) ((a) & (b))
+#define CV_OR(a, b) ((a) | (b))
+#define CV_XOR(a, b) ((a) ^ (b))
+#define CV_ANDN(a, b) (~(a) & (b))
+#define CV_ORN(a, b) (~(a) | (b))
+#define CV_SQR(a) ((a) * (a))
+
+#define CV_LT(a, b) ((a) < (b))
+#define CV_LE(a, b) ((a) <= (b))
+#define CV_EQ(a, b) ((a) == (b))
+#define CV_NE(a, b) ((a) != (b))
+#define CV_GT(a, b) ((a) > (b))
+#define CV_GE(a, b) ((a) >= (b))
+
+#define CV_NONZERO(a) ((a) != 0)
+#define CV_NONZERO_FLT(a) (((a)+(a)) != 0)
+
+/* general-purpose saturation macros */
+#define CV_CAST_8U(t) (uchar)(!((t) & ~255) ? (t) : (t) > 0 ? 255 : 0)
+#define CV_CAST_8S(t) (schar)(!(((t)+128) & ~255) ? (t) : (t) > 0 ? 127 : -128)
+#define CV_CAST_16U(t) (ushort)(!((t) & ~65535) ? (t) : (t) > 0 ? 65535 : 0)
+#define CV_CAST_16S(t) (short)(!(((t)+32768) & ~65535) ? (t) : (t) > 0 ? 32767 : -32768)
+#define CV_CAST_32S(t) (int)(t)
+#define CV_CAST_64S(t) (int64)(t)
+#define CV_CAST_32F(t) (float)(t)
+#define CV_CAST_64F(t) (double)(t)
+
+#define CV_PASTE2(a,b) a##b
+#define CV_PASTE(a,b) CV_PASTE2(a,b)
+
+#define CV_EMPTY
+#define CV_MAKE_STR(a) #a
+
+#define CV_DEFINE_MASK \
+ float maskTab[2]; maskTab[0] = 0.f; maskTab[1] = 1.f;
+#define CV_ANDMASK( m, x ) ((x) & (((m) == 0) - 1))
+
+/* (x) * ((m) == 1 ? 1.f : (m) == 0 ? 0.f : <ERR> */
+#define CV_MULMASK( m, x ) (maskTab[(m) != 0]*(x))
+
+/* (x) * ((m) == -1 ? 1.f : (m) == 0 ? 0.f : <ERR> */
+#define CV_MULMASK1( m, x ) (maskTab[(m)+1]*(x))
+
+#define CV_ZERO_OBJ(x) memset((x), 0, sizeof(*(x)))
+
+#define CV_DIM(static_array) ((int)(sizeof(static_array)/sizeof((static_array)[0])))
+
+#define CV_UN_ENTRY_C1(worktype) \
+ worktype s0 = scalar[0]
+
+#define CV_UN_ENTRY_C2(worktype) \
+ worktype s0 = scalar[0], s1 = scalar[1]
+
+#define CV_UN_ENTRY_C3(worktype) \
+ worktype s0 = scalar[0], s1 = scalar[1], s2 = scalar[2]
+
+#define CV_UN_ENTRY_C4(worktype) \
+ worktype s0 = scalar[0], s1 = scalar[1], s2 = scalar[2], s3 = scalar[3]
+
+#define cvUnsupportedFormat "Unsupported format"
+
+CV_INLINE void* cvAlignPtr( const void* ptr, int align=32 )
+{
+ assert( (align & (align-1)) == 0 );
+ return (void*)( ((size_t)ptr + align - 1) & ~(size_t)(align-1) );
+}
+
+CV_INLINE int cvAlign( int size, int align )
+{
+ assert( (align & (align-1)) == 0 && size < INT_MAX );
+ return (size + align - 1) & -align;
+}
+
+CV_INLINE CvSize cvGetMatSize( const CvMat* mat )
+{
+ CvSize size = { mat->width, mat->height };
+ return size;
+}
+
+#define CV_DESCALE(x,n) (((x) + (1 << ((n)-1))) >> (n))
+#define CV_FLT_TO_FIX(x,n) cvRound((x)*(1<<(n)))
+
+#if 0
+/* This is a small engine for performing fast division of multiple numbers
+ by the same constant. Most compilers do it too if they know the divisor value
+ at compile-time. The algorithm was taken from Agner Fog's optimization guide
+ at http://www.agner.org/assem */
+typedef struct CvFastDiv
+{
+ unsigned delta, scale, divisor;
+}
+CvFastDiv;
+
+#define CV_FAST_DIV_SHIFT 32
+
+CV_INLINE CvFastDiv cvFastDiv( int divisor )
+{
+ CvFastDiv fastdiv;
+
+ assert( divisor >= 1 );
+ uint64 temp = ((uint64)1 << CV_FAST_DIV_SHIFT)/divisor;
+
+ fastdiv.divisor = divisor;
+ fastdiv.delta = (unsigned)(((temp & 1) ^ 1) + divisor - 1);
+ fastdiv.scale = (unsigned)((temp + 1) >> 1);
+
+ return fastdiv;
+}
+
+#define CV_FAST_DIV( x, fastdiv ) \
+ ((int)(((int64)((x)*2 + (int)(fastdiv).delta))*(int)(fastdiv).scale>>CV_FAST_DIV_SHIFT))
+
+#define CV_FAST_UDIV( x, fastdiv ) \
+ ((int)(((uint64)((x)*2 + (fastdiv).delta))*(fastdiv).scale>>CV_FAST_DIV_SHIFT))
+#endif
+
+#define CV_MEMCPY_CHAR( dst, src, len ) \
+{ \
+ size_t _icv_memcpy_i_, _icv_memcpy_len_ = (len); \
+ char* _icv_memcpy_dst_ = (char*)(dst); \
+ const char* _icv_memcpy_src_ = (const char*)(src); \
+ \
+ for( _icv_memcpy_i_ = 0; _icv_memcpy_i_ < _icv_memcpy_len_; _icv_memcpy_i_++ ) \
+ _icv_memcpy_dst_[_icv_memcpy_i_] = _icv_memcpy_src_[_icv_memcpy_i_]; \
+}
+
+
+#define CV_MEMCPY_INT( dst, src, len ) \
+{ \
+ size_t _icv_memcpy_i_, _icv_memcpy_len_ = (len); \
+ int* _icv_memcpy_dst_ = (int*)(dst); \
+ const int* _icv_memcpy_src_ = (const int*)(src); \
+ assert( ((size_t)_icv_memcpy_src_&(sizeof(int)-1)) == 0 && \
+ ((size_t)_icv_memcpy_dst_&(sizeof(int)-1)) == 0 ); \
+ \
+ for(_icv_memcpy_i_=0;_icv_memcpy_i_<_icv_memcpy_len_;_icv_memcpy_i_++) \
+ _icv_memcpy_dst_[_icv_memcpy_i_] = _icv_memcpy_src_[_icv_memcpy_i_]; \
+}
+
+
+#define CV_MEMCPY_AUTO( dst, src, len ) \
+{ \
+ size_t _icv_memcpy_i_, _icv_memcpy_len_ = (len); \
+ char* _icv_memcpy_dst_ = (char*)(dst); \
+ const char* _icv_memcpy_src_ = (const char*)(src); \
+ if( (_icv_memcpy_len_ & (sizeof(int)-1)) == 0 ) \
+ { \
+ assert( ((size_t)_icv_memcpy_src_&(sizeof(int)-1)) == 0 && \
+ ((size_t)_icv_memcpy_dst_&(sizeof(int)-1)) == 0 ); \
+ for( _icv_memcpy_i_ = 0; _icv_memcpy_i_ < _icv_memcpy_len_; \
+ _icv_memcpy_i_+=sizeof(int) ) \
+ { \
+ *(int*)(_icv_memcpy_dst_+_icv_memcpy_i_) = \
+ *(const int*)(_icv_memcpy_src_+_icv_memcpy_i_); \
+ } \
+ } \
+ else \
+ { \
+ for(_icv_memcpy_i_ = 0; _icv_memcpy_i_ < _icv_memcpy_len_; _icv_memcpy_i_++)\
+ _icv_memcpy_dst_[_icv_memcpy_i_] = _icv_memcpy_src_[_icv_memcpy_i_]; \
+ } \
+}
+
+
+#define CV_ZERO_CHAR( dst, len ) \
+{ \
+ size_t _icv_memcpy_i_, _icv_memcpy_len_ = (len); \
+ char* _icv_memcpy_dst_ = (char*)(dst); \
+ \
+ for( _icv_memcpy_i_ = 0; _icv_memcpy_i_ < _icv_memcpy_len_; _icv_memcpy_i_++ ) \
+ _icv_memcpy_dst_[_icv_memcpy_i_] = '\0'; \
+}
+
+
+#define CV_ZERO_INT( dst, len ) \
+{ \
+ size_t _icv_memcpy_i_, _icv_memcpy_len_ = (len); \
+ int* _icv_memcpy_dst_ = (int*)(dst); \
+ assert( ((size_t)_icv_memcpy_dst_&(sizeof(int)-1)) == 0 ); \
+ \
+ for(_icv_memcpy_i_=0;_icv_memcpy_i_<_icv_memcpy_len_;_icv_memcpy_i_++) \
+ _icv_memcpy_dst_[_icv_memcpy_i_] = 0; \
+}
+
+
+/****************************************************************************************\
+
+ Generic implementation of QuickSort algorithm.
+ ----------------------------------------------
+ Using this macro user can declare customized sort function that can be much faster
+ than built-in qsort function because of lower overhead on elements
+ comparison and exchange. The macro takes less_than (or LT) argument - a macro or function
+ that takes 2 arguments returns non-zero if the first argument should be before the second
+ one in the sorted sequence and zero otherwise.
+
+ Example:
+
+ Suppose that the task is to sort points by ascending of y coordinates and if
+ y's are equal x's should ascend.
+
+ The code is:
+ ------------------------------------------------------------------------------
+ #define cmp_pts( pt1, pt2 ) \
+ ((pt1).y < (pt2).y || ((pt1).y < (pt2).y && (pt1).x < (pt2).x))
+
+ [static] CV_IMPLEMENT_QSORT( icvSortPoints, CvPoint, cmp_pts )
+ ------------------------------------------------------------------------------
+
+ After that the function "void icvSortPoints( CvPoint* array, size_t total, int aux );"
+ is available to user.
+
+ aux is an additional parameter, which can be used when comparing elements.
+ The current implementation was derived from *BSD system qsort():
+
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+
+\****************************************************************************************/
+
+#define CV_IMPLEMENT_QSORT_EX( func_name, T, LT, user_data_type ) \
+void func_name( T *array, size_t total, user_data_type aux ) \
+{ \
+ int isort_thresh = 7; \
+ T t; \
+ int sp = 0; \
+ \
+ struct \
+ { \
+ T *lb; \
+ T *ub; \
+ } \
+ stack[48]; \
+ \
+ aux = aux; \
+ \
+ if( total <= 1 ) \
+ return; \
+ \
+ stack[0].lb = array; \
+ stack[0].ub = array + (total - 1); \
+ \
+ while( sp >= 0 ) \
+ { \
+ T* left = stack[sp].lb; \
+ T* right = stack[sp--].ub; \
+ \
+ for(;;) \
+ { \
+ int i, n = (int)(right - left) + 1, m; \
+ T* ptr; \
+ T* ptr2; \
+ \
+ if( n <= isort_thresh ) \
+ { \
+ insert_sort: \
+ for( ptr = left + 1; ptr <= right; ptr++ ) \
+ { \
+ for( ptr2 = ptr; ptr2 > left && LT(ptr2[0],ptr2[-1]); ptr2--) \
+ CV_SWAP( ptr2[0], ptr2[-1], t ); \
+ } \
+ break; \
+ } \
+ else \
+ { \
+ T* left0; \
+ T* left1; \
+ T* right0; \
+ T* right1; \
+ T* pivot; \
+ T* a; \
+ T* b; \
+ T* c; \
+ int swap_cnt = 0; \
+ \
+ left0 = left; \
+ right0 = right; \
+ pivot = left + (n/2); \
+ \
+ if( n > 40 ) \
+ { \
+ int d = n / 8; \
+ a = left, b = left + d, c = left + 2*d; \
+ left = LT(*a, *b) ? (LT(*b, *c) ? b : (LT(*a, *c) ? c : a)) \
+ : (LT(*c, *b) ? b : (LT(*a, *c) ? a : c)); \
+ \
+ a = pivot - d, b = pivot, c = pivot + d; \
+ pivot = LT(*a, *b) ? (LT(*b, *c) ? b : (LT(*a, *c) ? c : a)) \
+ : (LT(*c, *b) ? b : (LT(*a, *c) ? a : c)); \
+ \
+ a = right - 2*d, b = right - d, c = right; \
+ right = LT(*a, *b) ? (LT(*b, *c) ? b : (LT(*a, *c) ? c : a)) \
+ : (LT(*c, *b) ? b : (LT(*a, *c) ? a : c)); \
+ } \
+ \
+ a = left, b = pivot, c = right; \
+ pivot = LT(*a, *b) ? (LT(*b, *c) ? b : (LT(*a, *c) ? c : a)) \
+ : (LT(*c, *b) ? b : (LT(*a, *c) ? a : c)); \
+ if( pivot != left0 ) \
+ { \
+ CV_SWAP( *pivot, *left0, t ); \
+ pivot = left0; \
+ } \
+ left = left1 = left0 + 1; \
+ right = right1 = right0; \
+ \
+ for(;;) \
+ { \
+ while( left <= right && !LT(*pivot, *left) ) \
+ { \
+ if( !LT(*left, *pivot) ) \
+ { \
+ if( left > left1 ) \
+ CV_SWAP( *left1, *left, t ); \
+ swap_cnt = 1; \
+ left1++; \
+ } \
+ left++; \
+ } \
+ \
+ while( left <= right && !LT(*right, *pivot) ) \
+ { \
+ if( !LT(*pivot, *right) ) \
+ { \
+ if( right < right1 ) \
+ CV_SWAP( *right1, *right, t ); \
+ swap_cnt = 1; \
+ right1--; \
+ } \
+ right--; \
+ } \
+ \
+ if( left > right ) \
+ break; \
+ CV_SWAP( *left, *right, t ); \
+ swap_cnt = 1; \
+ left++; \
+ right--; \
+ } \
+ \
+ if( swap_cnt == 0 ) \
+ { \
+ left = left0, right = right0; \
+ goto insert_sort; \
+ } \
+ \
+ n = MIN( (int)(left1 - left0), (int)(left - left1) ); \
+ for( i = 0; i < n; i++ ) \
+ CV_SWAP( left0[i], left[i-n], t ); \
+ \
+ n = MIN( (int)(right0 - right1), (int)(right1 - right) ); \
+ for( i = 0; i < n; i++ ) \
+ CV_SWAP( left[i], right0[i-n+1], t ); \
+ n = (int)(left - left1); \
+ m = (int)(right1 - right); \
+ if( n > 1 ) \
+ { \
+ if( m > 1 ) \
+ { \
+ if( n > m ) \
+ { \
+ stack[++sp].lb = left0; \
+ stack[sp].ub = left0 + n - 1; \
+ left = right0 - m + 1, right = right0; \
+ } \
+ else \
+ { \
+ stack[++sp].lb = right0 - m + 1; \
+ stack[sp].ub = right0; \
+ left = left0, right = left0 + n - 1; \
+ } \
+ } \
+ else \
+ left = left0, right = left0 + n - 1; \
+ } \
+ else if( m > 1 ) \
+ left = right0 - m + 1, right = right0; \
+ else \
+ break; \
+ } \
+ } \
+ } \
+}
+
+#define CV_IMPLEMENT_QSORT( func_name, T, cmp ) \
+ CV_IMPLEMENT_QSORT_EX( func_name, T, cmp, int )
+
+/****************************************************************************************\
+* Structures and macros for integration with IPP *
+\****************************************************************************************/
+
+/* IPP-compatible return codes */
+typedef enum CvStatus
+{
+ CV_BADMEMBLOCK_ERR = -113,
+ CV_INPLACE_NOT_SUPPORTED_ERR= -112,
+ CV_UNMATCHED_ROI_ERR = -111,
+ CV_NOTFOUND_ERR = -110,
+ CV_BADCONVERGENCE_ERR = -109,
+
+ CV_BADDEPTH_ERR = -107,
+ CV_BADROI_ERR = -106,
+ CV_BADHEADER_ERR = -105,
+ CV_UNMATCHED_FORMATS_ERR = -104,
+ CV_UNSUPPORTED_COI_ERR = -103,
+ CV_UNSUPPORTED_CHANNELS_ERR = -102,
+ CV_UNSUPPORTED_DEPTH_ERR = -101,
+ CV_UNSUPPORTED_FORMAT_ERR = -100,
+
+ CV_BADARG_ERR = -49, //ipp comp
+ CV_NOTDEFINED_ERR = -48, //ipp comp
+
+ CV_BADCHANNELS_ERR = -47, //ipp comp
+ CV_BADRANGE_ERR = -44, //ipp comp
+ CV_BADSTEP_ERR = -29, //ipp comp
+
+ CV_BADFLAG_ERR = -12,
+ CV_DIV_BY_ZERO_ERR = -11, //ipp comp
+ CV_BADCOEF_ERR = -10,
+
+ CV_BADFACTOR_ERR = -7,
+ CV_BADPOINT_ERR = -6,
+ CV_BADSCALE_ERR = -4,
+ CV_OUTOFMEM_ERR = -3,
+ CV_NULLPTR_ERR = -2,
+ CV_BADSIZE_ERR = -1,
+ CV_NO_ERR = 0,
+ CV_OK = CV_NO_ERR
+}
+CvStatus;
+
+#define CV_ERROR_FROM_STATUS( result ) \
+ CV_ERROR( cvErrorFromIppStatus( result ), "OpenCV function failed" )
+
+#define IPPI_CALL( Func ) \
+{ \
+ CvStatus ippi_call_result; \
+ ippi_call_result = Func; \
+ \
+ if( ippi_call_result < 0 ) \
+ CV_ERROR_FROM_STATUS( (ippi_call_result)); \
+}
+
+#define CV_PLUGIN_NONE 0
+#define CV_PLUGIN_OPTCV 1 /* custom "emerged" ippopencv library */
+#define CV_PLUGIN_IPPCV 2 /* IPP: computer vision */
+#define CV_PLUGIN_IPPI 3 /* IPP: image processing */
+#define CV_PLUGIN_IPPS 4 /* IPP: signal processing */
+#define CV_PLUGIN_IPPVM 5 /* IPP: vector math functions */
+#define CV_PLUGIN_IPPCC 6 /* IPP: color space conversion */
+#define CV_PLUGIN_MKL 8 /* Intel Math Kernel Library */
+
+#define CV_PLUGIN_MAX 16
+
+#define CV_PLUGINS1(lib1) ((lib1)&15)
+#define CV_PLUGINS2(lib1,lib2) (((lib1)&15)|(((lib2)&15)<<4))
+#define CV_PLUGINS3(lib1,lib2,lib3) (((lib1)&15)|(((lib2)&15)<<4)|(((lib2)&15)<<8))
+
+#define CV_NOTHROW throw()
+
+#ifndef IPCVAPI
+#define IPCVAPI(type,declspec,name,args) \
+ /* function pointer */ \
+ typedef type (declspec* name##_t) args; \
+ extern name##_t name##_p; \
+ type declspec name args;
+#endif
+
+#define IPCVAPI_EX(type,name,ipp_name,ipp_search_modules,args) \
+ IPCVAPI(type,CV_STDCALL,name,args)
+
+#define IPCVAPI_C_EX(type,name,ipp_name,ipp_search_modules,args)\
+ IPCVAPI(type,CV_CDECL,name,args)
+
+#ifndef IPCVAPI_IMPL
+#define IPCVAPI_IMPL(type,name,args,arg_names) \
+ static type CV_STDCALL name##_f args; \
+ name##_t name##_p = name##_f; \
+ type CV_STDCALL name args { return name##_p arg_names; } \
+ static type CV_STDCALL name##_f args
+#endif
+
+/* IPP types' enumeration */
+typedef enum CvDataType {
+ cv1u,
+ cv8u, cv8s,
+ cv16u, cv16s, cv16sc,
+ cv32u, cv32s, cv32sc,
+ cv32f, cv32fc,
+ cv64u, cv64s, cv64sc,
+ cv64f, cv64fc
+} CvDataType;
+
+typedef enum CvHintAlgorithm {
+ cvAlgHintNone,
+ cvAlgHintFast,
+ cvAlgHintAccurate
+} CvHintAlgorithm;
+
+typedef enum CvCmpOp {
+ cvCmpLess,
+ cvCmpLessEq,
+ cvCmpEq,
+ cvCmpGreaterEq,
+ cvCmpGreater
+} CvCmpOp;
+
+typedef struct CvFuncTable
+{
+ void* fn_2d[CV_DEPTH_MAX];
+}
+CvFuncTable;
+
+typedef struct CvBigFuncTable
+{
+ void* fn_2d[CV_DEPTH_MAX*CV_CN_MAX];
+}
+CvBigFuncTable;
+
+
+typedef struct CvBtFuncTable
+{
+ void* fn_2d[33];
+}
+CvBtFuncTable;
+
+typedef CvStatus (CV_STDCALL *CvFunc2D_1A)(void* arr, int step, CvSize size);
+
+typedef CvStatus (CV_STDCALL *CvFunc2D_1A1P)(void* arr, int step, CvSize size, void* param);
+
+typedef CvStatus (CV_STDCALL *CvFunc2D_1A1P1I)(void* arr, int step, CvSize size,
+ void* param, int flag);
+
+typedef CvStatus (CV_STDCALL *CvFunc2DnC_1A1P)( void* arr, int step, CvSize size,
+ int cn, int coi, void* param );
+
+typedef CvStatus (CV_STDCALL *CvFunc2DnC_1A1P)( void* arr, int step, CvSize size,
+ int cn, int coi, void* param );
+
+typedef CvStatus (CV_STDCALL *CvFunc2D_1A2P)( void* arr, int step, CvSize size,
+ void* param1, void* param2 );
+
+typedef CvStatus (CV_STDCALL *CvFunc2DnC_1A2P)( void* arr, int step,
+ CvSize size, int cn, int coi,
+ void* param1, void* param2 );
+
+typedef CvStatus (CV_STDCALL *CvFunc2D_1A4P)( void* arr, int step, CvSize size,
+ void* param1, void* param2,
+ void* param3, void* param4 );
+
+typedef CvStatus (CV_STDCALL *CvFunc2DnC_1A4P)( void* arr, int step,
+ CvSize size, int cn, int coi,
+ void* param1, void* param2,
+ void* param3, void* param4 );
+
+typedef CvStatus (CV_STDCALL *CvFunc2D_2A)( void* arr0, int step0,
+ void* arr1, int step1, CvSize size );
+
+typedef CvStatus (CV_STDCALL *CvFunc2D_2A1P)( void* arr0, int step0,
+ void* arr1, int step1,
+ CvSize size, void* param );
+
+typedef CvStatus (CV_STDCALL *CvFunc2DnC_2A1P)( void* arr0, int step0,
+ void* arr1, int step1,
+ CvSize size, int cn,
+ int coi, void* param );
+
+typedef CvStatus (CV_STDCALL *CvFunc2DnC_2A1P)( void* arr0, int step0,
+ void* arr1, int step1,
+ CvSize size, int cn,
+ int coi, void* param );
+
+typedef CvStatus (CV_STDCALL *CvFunc2D_2A2P)( void* arr0, int step0,
+ void* arr1, int step1, CvSize size,
+ void* param1, void* param2 );
+
+typedef CvStatus (CV_STDCALL *CvFunc2DnC_2A2P)( void* arr0, int step0,
+ void* arr1, int step1,
+ CvSize size, int cn, int coi,
+ void* param1, void* param2 );
+
+typedef CvStatus (CV_STDCALL *CvFunc2D_2A1P1I)( void* arr0, int step0,
+ void* arr1, int step1, CvSize size,
+ void* param, int flag );
+
+typedef CvStatus (CV_STDCALL *CvFunc2D_2A4P)( void* arr0, int step0,
+ void* arr1, int step1, CvSize size,
+ void* param1, void* param2,
+ void* param3, void* param4 );
+
+typedef CvStatus (CV_STDCALL *CvFunc2DnC_2A4P)( void* arr0, int step0,
+ void* arr1, int step1, CvSize size,
+ int cn, int coi,
+ void* param1, void* param2,
+ void* param3, void* param4 );
+
+typedef CvStatus (CV_STDCALL *CvFunc2D_3A)( void* arr0, int step0,
+ void* arr1, int step1,
+ void* arr2, int step2, CvSize size );
+
+typedef CvStatus (CV_STDCALL *CvFunc2D_3A1P)( void* arr0, int step0,
+ void* arr1, int step1,
+ void* arr2, int step2,
+ CvSize size, void* param );
+
+typedef CvStatus (CV_STDCALL *CvFunc2D_3A1I)( void* arr0, int step0,
+ void* arr1, int step1,
+ void* arr2, int step2,
+ CvSize size, int flag );
+
+typedef CvStatus (CV_STDCALL *CvFunc2DnC_3A1P)( void* arr0, int step0,
+ void* arr1, int step1,
+ void* arr2, int step2,
+ CvSize size, int cn,
+ int coi, void* param );
+
+typedef CvStatus (CV_STDCALL *CvFunc2D_4A)( void* arr0, int step0,
+ void* arr1, int step1,
+ void* arr2, int step2,
+ void* arr3, int step3,
+ CvSize size );
+
+typedef CvStatus (CV_STDCALL *CvFunc0D)( const void* src, void* dst, int param );
+
+#define CV_DEF_INIT_FUNC_TAB_2D( FUNCNAME, FLAG ) \
+static void icvInit##FUNCNAME##FLAG##Table( CvFuncTable* tab ) \
+{ \
+ assert( tab ); \
+ \
+ tab->fn_2d[CV_8U] = (void*)icv##FUNCNAME##_8u_##FLAG; \
+ tab->fn_2d[CV_8S] = (void*)icv##FUNCNAME##_8s_##FLAG; \
+ tab->fn_2d[CV_16U] = (void*)icv##FUNCNAME##_16u_##FLAG; \
+ tab->fn_2d[CV_16S] = (void*)icv##FUNCNAME##_16s_##FLAG; \
+ tab->fn_2d[CV_32S] = (void*)icv##FUNCNAME##_32s_##FLAG; \
+ tab->fn_2d[CV_32F] = (void*)icv##FUNCNAME##_32f_##FLAG; \
+ tab->fn_2d[CV_64F] = (void*)icv##FUNCNAME##_64f_##FLAG; \
+}
+
+
+#define CV_DEF_INIT_BIG_FUNC_TAB_2D( FUNCNAME, FLAG ) \
+static void icvInit##FUNCNAME##FLAG##Table( CvBigFuncTable* tab ) \
+{ \
+ assert( tab ); \
+ \
+ tab->fn_2d[CV_8UC1] = (void*)icv##FUNCNAME##_8u_C1##FLAG; \
+ tab->fn_2d[CV_8UC2] = (void*)icv##FUNCNAME##_8u_C2##FLAG; \
+ tab->fn_2d[CV_8UC3] = (void*)icv##FUNCNAME##_8u_C3##FLAG; \
+ tab->fn_2d[CV_8UC4] = (void*)icv##FUNCNAME##_8u_C4##FLAG; \
+ \
+ tab->fn_2d[CV_8SC1] = (void*)icv##FUNCNAME##_8s_C1##FLAG; \
+ tab->fn_2d[CV_8SC2] = (void*)icv##FUNCNAME##_8s_C2##FLAG; \
+ tab->fn_2d[CV_8SC3] = (void*)icv##FUNCNAME##_8s_C3##FLAG; \
+ tab->fn_2d[CV_8SC4] = (void*)icv##FUNCNAME##_8s_C4##FLAG; \
+ \
+ tab->fn_2d[CV_16UC1] = (void*)icv##FUNCNAME##_16u_C1##FLAG; \
+ tab->fn_2d[CV_16UC2] = (void*)icv##FUNCNAME##_16u_C2##FLAG; \
+ tab->fn_2d[CV_16UC3] = (void*)icv##FUNCNAME##_16u_C3##FLAG; \
+ tab->fn_2d[CV_16UC4] = (void*)icv##FUNCNAME##_16u_C4##FLAG; \
+ \
+ tab->fn_2d[CV_16SC1] = (void*)icv##FUNCNAME##_16s_C1##FLAG; \
+ tab->fn_2d[CV_16SC2] = (void*)icv##FUNCNAME##_16s_C2##FLAG; \
+ tab->fn_2d[CV_16SC3] = (void*)icv##FUNCNAME##_16s_C3##FLAG; \
+ tab->fn_2d[CV_16SC4] = (void*)icv##FUNCNAME##_16s_C4##FLAG; \
+ \
+ tab->fn_2d[CV_32SC1] = (void*)icv##FUNCNAME##_32s_C1##FLAG; \
+ tab->fn_2d[CV_32SC2] = (void*)icv##FUNCNAME##_32s_C2##FLAG; \
+ tab->fn_2d[CV_32SC3] = (void*)icv##FUNCNAME##_32s_C3##FLAG; \
+ tab->fn_2d[CV_32SC4] = (void*)icv##FUNCNAME##_32s_C4##FLAG; \
+ \
+ tab->fn_2d[CV_32FC1] = (void*)icv##FUNCNAME##_32f_C1##FLAG; \
+ tab->fn_2d[CV_32FC2] = (void*)icv##FUNCNAME##_32f_C2##FLAG; \
+ tab->fn_2d[CV_32FC3] = (void*)icv##FUNCNAME##_32f_C3##FLAG; \
+ tab->fn_2d[CV_32FC4] = (void*)icv##FUNCNAME##_32f_C4##FLAG; \
+ \
+ tab->fn_2d[CV_64FC1] = (void*)icv##FUNCNAME##_64f_C1##FLAG; \
+ tab->fn_2d[CV_64FC2] = (void*)icv##FUNCNAME##_64f_C2##FLAG; \
+ tab->fn_2d[CV_64FC3] = (void*)icv##FUNCNAME##_64f_C3##FLAG; \
+ tab->fn_2d[CV_64FC4] = (void*)icv##FUNCNAME##_64f_C4##FLAG; \
+}
+
+#define CV_DEF_INIT_FUNC_TAB_0D( FUNCNAME ) \
+static void icvInit##FUNCNAME##Table( CvFuncTable* tab ) \
+{ \
+ tab->fn_2d[CV_8U] = (void*)icv##FUNCNAME##_8u; \
+ tab->fn_2d[CV_8S] = (void*)icv##FUNCNAME##_8s; \
+ tab->fn_2d[CV_16U] = (void*)icv##FUNCNAME##_16u; \
+ tab->fn_2d[CV_16S] = (void*)icv##FUNCNAME##_16s; \
+ tab->fn_2d[CV_32S] = (void*)icv##FUNCNAME##_32s; \
+ tab->fn_2d[CV_32F] = (void*)icv##FUNCNAME##_32f; \
+ tab->fn_2d[CV_64F] = (void*)icv##FUNCNAME##_64f; \
+}
+
+#define CV_DEF_INIT_FUNC_TAB_1D CV_DEF_INIT_FUNC_TAB_0D
+
+
+#define CV_DEF_INIT_PIXSIZE_TAB_2D( FUNCNAME, FLAG ) \
+static void icvInit##FUNCNAME##FLAG##Table( CvBtFuncTable* table ) \
+{ \
+ table->fn_2d[1] = (void*)icv##FUNCNAME##_8u_C1##FLAG; \
+ table->fn_2d[2] = (void*)icv##FUNCNAME##_8u_C2##FLAG; \
+ table->fn_2d[3] = (void*)icv##FUNCNAME##_8u_C3##FLAG; \
+ table->fn_2d[4] = (void*)icv##FUNCNAME##_16u_C2##FLAG; \
+ table->fn_2d[6] = (void*)icv##FUNCNAME##_16u_C3##FLAG; \
+ table->fn_2d[8] = (void*)icv##FUNCNAME##_32s_C2##FLAG; \
+ table->fn_2d[12] = (void*)icv##FUNCNAME##_32s_C3##FLAG; \
+ table->fn_2d[16] = (void*)icv##FUNCNAME##_64s_C2##FLAG; \
+ table->fn_2d[24] = (void*)icv##FUNCNAME##_64s_C3##FLAG; \
+ table->fn_2d[32] = (void*)icv##FUNCNAME##_64s_C4##FLAG; \
+}
+
+#define CV_GET_FUNC_PTR( func, table_entry ) \
+ func = (table_entry); \
+ \
+ if( !func ) \
+ CV_ERROR( CV_StsUnsupportedFormat, "" )
+
+
+#endif /*_CXCORE_MISC_H_*/
diff --git a/cxcore/include/cxtypes.h b/cxcore/include/cxtypes.h
new file mode 100644
index 0000000..6d9218e
--- /dev/null
+++ b/cxcore/include/cxtypes.h
@@ -0,0 +1,1780 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _CXCORE_TYPES_H_
+#define _CXCORE_TYPES_H_
+
+#if !defined _CRT_SECURE_NO_DEPRECATE && _MSC_VER > 1300
+#define _CRT_SECURE_NO_DEPRECATE /* to avoid multiple Visual Studio 2005 warnings */
+#endif
+
+#ifndef SKIP_INCLUDES
+ #include <assert.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <float.h>
+
+ #if defined __ICL
+ #define CV_ICC __ICL
+ #elif defined __ICC
+ #define CV_ICC __ICC
+ #elif defined __ECL
+ #define CV_ICC __ECL
+ #elif defined __ECC
+ #define CV_ICC __ECC
+ #endif
+
+ #if defined WIN32 && (!defined WIN64 || defined EM64T) && \
+ (_MSC_VER >= 1400 || defined CV_ICC) \
+ || (defined __SSE2__ && defined __GNUC__ && __GNUC__ >= 4)
+ #include <emmintrin.h>
+ #define CV_SSE2 1
+ #else
+ #define CV_SSE2 0
+ #endif
+
+ #if defined __BORLANDC__
+ #include <fastmath.h>
+ #elif defined WIN64 && !defined EM64T && defined CV_ICC
+ #include <mathimf.h>
+ #else
+ #include <math.h>
+ #endif
+
+ #ifdef HAVE_IPL
+ #ifndef __IPL_H__
+ #if defined WIN32 || defined WIN64
+ #include <ipl.h>
+ #else
+ #include <ipl/ipl.h>
+ #endif
+ #endif
+ #elif defined __IPL_H__
+ #define HAVE_IPL
+ #endif
+#endif // SKIP_INCLUDES
+
+#if defined WIN32 || defined WIN64
+ #define CV_CDECL __cdecl
+ #define CV_STDCALL __stdcall
+#else
+ #define CV_CDECL
+ #define CV_STDCALL
+#endif
+
+#ifndef CV_EXTERN_C
+ #ifdef __cplusplus
+ #define CV_EXTERN_C extern "C"
+ #define CV_DEFAULT(val) = val
+ #else
+ #define CV_EXTERN_C
+ #define CV_DEFAULT(val)
+ #endif
+#endif
+
+#ifndef CV_EXTERN_C_FUNCPTR
+ #ifdef __cplusplus
+ #define CV_EXTERN_C_FUNCPTR(x) extern "C" { typedef x; }
+ #else
+ #define CV_EXTERN_C_FUNCPTR(x) typedef x
+ #endif
+#endif
+
+#ifndef CV_INLINE
+#if defined __cplusplus
+ #define CV_INLINE inline
+#elif (defined WIN32 || defined WIN64) && !defined __GNUC__
+ #define CV_INLINE __inline
+#else
+ #define CV_INLINE static
+#endif
+#endif /* CV_INLINE */
+
+#if (defined WIN32 || defined WIN64) && defined CVAPI_EXPORTS
+ #define CV_EXPORTS __declspec(dllexport)
+#else
+ #define CV_EXPORTS
+#endif
+
+#ifndef CVAPI
+ #define CVAPI(rettype) CV_EXTERN_C CV_EXPORTS rettype CV_CDECL
+#endif
+
+#if defined _MSC_VER || defined __BORLANDC__
+typedef __int64 int64;
+typedef unsigned __int64 uint64;
+#else
+typedef long long int64;
+typedef unsigned long long uint64;
+#endif
+
+#ifndef HAVE_IPL
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+#endif
+
+typedef signed char schar;
+
+/* CvArr* is used to pass arbitrary
+ * array-like data structures
+ * into functions where the particular
+ * array type is recognized at runtime:
+ */
+typedef void CvArr;
+
+typedef union Cv32suf
+{
+ int i;
+ unsigned u;
+ float f;
+}
+Cv32suf;
+
+typedef union Cv64suf
+{
+ int64 i;
+ uint64 u;
+ double f;
+}
+Cv64suf;
+
+/****************************************************************************************\
+* Common macros and inline functions *
+\****************************************************************************************/
+
+#define CV_PI 3.1415926535897932384626433832795
+#define CV_LOG2 0.69314718055994530941723212145818
+
+#define CV_SWAP(a,b,t) ((t) = (a), (a) = (b), (b) = (t))
+
+#ifndef MIN
+#define MIN(a,b) ((a) > (b) ? (b) : (a))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#endif
+
+/* min & max without jumps */
+#define CV_IMIN(a, b) ((a) ^ (((a)^(b)) & (((a) < (b)) - 1)))
+
+#define CV_IMAX(a, b) ((a) ^ (((a)^(b)) & (((a) > (b)) - 1)))
+
+/* absolute value without jumps */
+#ifndef __cplusplus
+#define CV_IABS(a) (((a) ^ ((a) < 0 ? -1 : 0)) - ((a) < 0 ? -1 : 0))
+#else
+#define CV_IABS(a) abs(a)
+#endif
+#define CV_CMP(a,b) (((a) > (b)) - ((a) < (b)))
+#define CV_SIGN(a) CV_CMP((a),0)
+
+CV_INLINE int cvRound( double value )
+{
+#if CV_SSE2
+ __m128d t = _mm_load_sd( &value );
+ return _mm_cvtsd_si32(t);
+#elif defined WIN32 && !defined WIN64 && defined _MSC_VER
+ int t;
+ __asm
+ {
+ fld value;
+ fistp t;
+ }
+ return t;
+#elif (defined HAVE_LRINT) || (defined WIN64 && !defined EM64T && defined CV_ICC)
+ return (int)lrint(value);
+#else
+ /*
+ the algorithm was taken from Agner Fog's optimization guide
+ at http://www.agner.org/assem
+ */
+ Cv64suf temp;
+ temp.f = value + 6755399441055744.0;
+ return (int)temp.u;
+#endif
+}
+
+
+CV_INLINE int cvFloor( double value )
+{
+#if CV_SSE2
+ __m128d t = _mm_load_sd( &value );
+ int i = _mm_cvtsd_si32(t);
+ return i - _mm_movemask_pd(_mm_cmplt_sd(t,_mm_cvtsi32_sd(t,i)));
+#else
+ int temp = cvRound(value);
+ Cv32suf diff;
+ diff.f = (float)(value - temp);
+ return temp - (diff.i < 0);
+#endif
+}
+
+
+CV_INLINE int cvCeil( double value )
+{
+#if CV_SSE2
+ __m128d t = _mm_load_sd( &value );
+ int i = _mm_cvtsd_si32(t);
+ return i + _mm_movemask_pd(_mm_cmplt_sd(_mm_cvtsi32_sd(t,i),t));
+#else
+ int temp = cvRound(value);
+ Cv32suf diff;
+ diff.f = (float)(temp - value);
+ return temp + (diff.i < 0);
+#endif
+}
+
+#define cvInvSqrt(value) ((float)(1./sqrt(value)))
+#define cvSqrt(value) ((float)sqrt(value))
+
+CV_INLINE int cvIsNaN( double value )
+{
+#if 1/*defined _MSC_VER || defined __BORLANDC__
+ return _isnan(value);
+#elif defined __GNUC__
+ return isnan(value);
+#else*/
+ Cv64suf ieee754;
+ ieee754.f = value;
+ return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) +
+ ((unsigned)ieee754.u != 0) > 0x7ff00000;
+#endif
+}
+
+
+CV_INLINE int cvIsInf( double value )
+{
+#if 1/*defined _MSC_VER || defined __BORLANDC__
+ return !_finite(value);
+#elif defined __GNUC__
+ return isinf(value);
+#else*/
+ Cv64suf ieee754;
+ ieee754.f = value;
+ return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 &&
+ (unsigned)ieee754.u == 0;
+#endif
+}
+
+
+/*************** Random number generation *******************/
+
+typedef uint64 CvRNG;
+
+CV_INLINE CvRNG cvRNG( int64 seed CV_DEFAULT(-1))
+{
+ CvRNG rng = seed ? (uint64)seed : (uint64)(int64)-1;
+ return rng;
+}
+
+/* Return random 32-bit unsigned integer: */
+CV_INLINE unsigned cvRandInt( CvRNG* rng )
+{
+ uint64 temp = *rng;
+ temp = (uint64)(unsigned)temp*1554115554 + (temp >> 32);
+ *rng = temp;
+ return (unsigned)temp;
+}
+
+/* Returns random floating-point number between 0 and 1: */
+CV_INLINE double cvRandReal( CvRNG* rng )
+{
+ return cvRandInt(rng)*2.3283064365386962890625e-10 /* 2^-32 */;
+}
+
+/****************************************************************************************\
+* Image type (IplImage) *
+\****************************************************************************************/
+
+#ifndef HAVE_IPL
+
+/*
+ * The following definitions (until #endif)
+ * is an extract from IPL headers.
+ * Copyright (c) 1995 Intel Corporation.
+ */
+#define IPL_DEPTH_SIGN 0x80000000
+
+#define IPL_DEPTH_1U 1
+#define IPL_DEPTH_8U 8
+#define IPL_DEPTH_16U 16
+#define IPL_DEPTH_32F 32
+
+#define IPL_DEPTH_8S (IPL_DEPTH_SIGN| 8)
+#define IPL_DEPTH_16S (IPL_DEPTH_SIGN|16)
+#define IPL_DEPTH_32S (IPL_DEPTH_SIGN|32)
+
+#define IPL_DATA_ORDER_PIXEL 0
+#define IPL_DATA_ORDER_PLANE 1
+
+#define IPL_ORIGIN_TL 0
+#define IPL_ORIGIN_BL 1
+
+#define IPL_ALIGN_4BYTES 4
+#define IPL_ALIGN_8BYTES 8
+#define IPL_ALIGN_16BYTES 16
+#define IPL_ALIGN_32BYTES 32
+
+#define IPL_ALIGN_DWORD IPL_ALIGN_4BYTES
+#define IPL_ALIGN_QWORD IPL_ALIGN_8BYTES
+
+#define IPL_BORDER_CONSTANT 0
+#define IPL_BORDER_REPLICATE 1
+#define IPL_BORDER_REFLECT 2
+#define IPL_BORDER_WRAP 3
+
+typedef struct _IplImage
+{
+ int nSize; /* sizeof(IplImage) */
+ int ID; /* version (=0)*/
+ int nChannels; /* Most of OpenCV functions support 1,2,3 or 4 channels */
+ int alphaChannel; /* Ignored by OpenCV */
+ int depth; /* Pixel depth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16S,
+ IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F are supported. */
+ char colorModel[4]; /* Ignored by OpenCV */
+ char channelSeq[4]; /* ditto */
+ int dataOrder; /* 0 - interleaved color channels, 1 - separate color channels.
+ cvCreateImage can only create interleaved images */
+ int origin; /* 0 - top-left origin,
+ 1 - bottom-left origin (Windows bitmaps style). */
+ int align; /* Alignment of image rows (4 or 8).
+ OpenCV ignores it and uses widthStep instead. */
+ int width; /* Image width in pixels. */
+ int height; /* Image height in pixels. */
+ struct _IplROI *roi; /* Image ROI. If NULL, the whole image is selected. */
+ struct _IplImage *maskROI; /* Must be NULL. */
+ void *imageId; /* " " */
+ struct _IplTileInfo *tileInfo; /* " " */
+ int imageSize; /* Image data size in bytes
+ (==image->height*image->widthStep
+ in case of interleaved data)*/
+ char *imageData; /* Pointer to aligned image data. */
+ int widthStep; /* Size of aligned image row in bytes. */
+ int BorderMode[4]; /* Ignored by OpenCV. */
+ int BorderConst[4]; /* Ditto. */
+ char *imageDataOrigin; /* Pointer to very origin of image data
+ (not necessarily aligned) -
+ needed for correct deallocation */
+}
+IplImage;
+
+typedef struct _IplTileInfo IplTileInfo;
+
+typedef struct _IplROI
+{
+ int coi; /* 0 - no COI (all channels are selected), 1 - 0th channel is selected ...*/
+ int xOffset;
+ int yOffset;
+ int width;
+ int height;
+}
+IplROI;
+
+typedef struct _IplConvKernel
+{
+ int nCols;
+ int nRows;
+ int anchorX;
+ int anchorY;
+ int *values;
+ int nShiftR;
+}
+IplConvKernel;
+
+typedef struct _IplConvKernelFP
+{
+ int nCols;
+ int nRows;
+ int anchorX;
+ int anchorY;
+ float *values;
+}
+IplConvKernelFP;
+
+#define IPL_IMAGE_HEADER 1
+#define IPL_IMAGE_DATA 2
+#define IPL_IMAGE_ROI 4
+
+#endif/*HAVE_IPL*/
+
+/* extra border mode */
+#define IPL_BORDER_REFLECT_101 4
+
+#define IPL_IMAGE_MAGIC_VAL ((int)sizeof(IplImage))
+#define CV_TYPE_NAME_IMAGE "opencv-image"
+
+#define CV_IS_IMAGE_HDR(img) \
+ ((img) != NULL && ((const IplImage*)(img))->nSize == sizeof(IplImage))
+
+#define CV_IS_IMAGE(img) \
+ (CV_IS_IMAGE_HDR(img) && ((IplImage*)img)->imageData != NULL)
+
+/* for storing double-precision
+ floating point data in IplImage's */
+#define IPL_DEPTH_64F 64
+
+/* get reference to pixel at (col,row),
+ for multi-channel images (col) should be multiplied by number of channels */
+#define CV_IMAGE_ELEM( image, elemtype, row, col ) \
+ (((elemtype*)((image)->imageData + (image)->widthStep*(row)))[(col)])
+
+/****************************************************************************************\
+* Matrix type (CvMat) *
+\****************************************************************************************/
+
+#define CV_CN_MAX 64
+#define CV_CN_SHIFT 3
+#define CV_DEPTH_MAX (1 << CV_CN_SHIFT)
+
+#define CV_8U 0
+#define CV_8S 1
+#define CV_16U 2
+#define CV_16S 3
+#define CV_32S 4
+#define CV_32F 5
+#define CV_64F 6
+#define CV_USRTYPE1 7
+
+#define CV_MAKETYPE(depth,cn) ((depth) + (((cn)-1) << CV_CN_SHIFT))
+#define CV_MAKE_TYPE CV_MAKETYPE
+
+#define CV_8UC1 CV_MAKETYPE(CV_8U,1)
+#define CV_8UC2 CV_MAKETYPE(CV_8U,2)
+#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
+#define CV_8UC4 CV_MAKETYPE(CV_8U,4)
+#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n))
+
+#define CV_8SC1 CV_MAKETYPE(CV_8S,1)
+#define CV_8SC2 CV_MAKETYPE(CV_8S,2)
+#define CV_8SC3 CV_MAKETYPE(CV_8S,3)
+#define CV_8SC4 CV_MAKETYPE(CV_8S,4)
+#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n))
+
+#define CV_16UC1 CV_MAKETYPE(CV_16U,1)
+#define CV_16UC2 CV_MAKETYPE(CV_16U,2)
+#define CV_16UC3 CV_MAKETYPE(CV_16U,3)
+#define CV_16UC4 CV_MAKETYPE(CV_16U,4)
+#define CV_16UC(n) CV_MAKETYPE(CV_16U,(n))
+
+#define CV_16SC1 CV_MAKETYPE(CV_16S,1)
+#define CV_16SC2 CV_MAKETYPE(CV_16S,2)
+#define CV_16SC3 CV_MAKETYPE(CV_16S,3)
+#define CV_16SC4 CV_MAKETYPE(CV_16S,4)
+#define CV_16SC(n) CV_MAKETYPE(CV_16S,(n))
+
+#define CV_32SC1 CV_MAKETYPE(CV_32S,1)
+#define CV_32SC2 CV_MAKETYPE(CV_32S,2)
+#define CV_32SC3 CV_MAKETYPE(CV_32S,3)
+#define CV_32SC4 CV_MAKETYPE(CV_32S,4)
+#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n))
+
+#define CV_32FC1 CV_MAKETYPE(CV_32F,1)
+#define CV_32FC2 CV_MAKETYPE(CV_32F,2)
+#define CV_32FC3 CV_MAKETYPE(CV_32F,3)
+#define CV_32FC4 CV_MAKETYPE(CV_32F,4)
+#define CV_32FC(n) CV_MAKETYPE(CV_32F,(n))
+
+#define CV_64FC1 CV_MAKETYPE(CV_64F,1)
+#define CV_64FC2 CV_MAKETYPE(CV_64F,2)
+#define CV_64FC3 CV_MAKETYPE(CV_64F,3)
+#define CV_64FC4 CV_MAKETYPE(CV_64F,4)
+#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n))
+
+#define CV_AUTO_STEP 0x7fffffff
+#define CV_WHOLE_ARR cvSlice( 0, 0x3fffffff )
+
+#define CV_MAT_CN_MASK ((CV_CN_MAX - 1) << CV_CN_SHIFT)
+#define CV_MAT_CN(flags) ((((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1)
+#define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX - 1)
+#define CV_MAT_DEPTH(flags) ((flags) & CV_MAT_DEPTH_MASK)
+#define CV_MAT_TYPE_MASK (CV_DEPTH_MAX*CV_CN_MAX - 1)
+#define CV_MAT_TYPE(flags) ((flags) & CV_MAT_TYPE_MASK)
+#define CV_MAT_CONT_FLAG_SHIFT 14
+#define CV_MAT_CONT_FLAG (1 << CV_MAT_CONT_FLAG_SHIFT)
+#define CV_IS_MAT_CONT(flags) ((flags) & CV_MAT_CONT_FLAG)
+#define CV_IS_CONT_MAT CV_IS_MAT_CONT
+#define CV_MAT_TEMP_FLAG_SHIFT 15
+#define CV_MAT_TEMP_FLAG (1 << CV_MAT_TEMP_FLAG_SHIFT)
+#define CV_IS_TEMP_MAT(flags) ((flags) & CV_MAT_TEMP_FLAG)
+
+#define CV_MAGIC_MASK 0xFFFF0000
+#define CV_MAT_MAGIC_VAL 0x42420000
+#define CV_TYPE_NAME_MAT "opencv-matrix"
+
+typedef struct CvMat
+{
+ int type;
+ int step;
+
+ /* for internal use only */
+ int* refcount;
+ int hdr_refcount;
+
+ union
+ {
+ uchar* ptr;
+ short* s;
+ int* i;
+ float* fl;
+ double* db;
+ } data;
+
+#ifdef __cplusplus
+ union
+ {
+ int rows;
+ int height;
+ };
+
+ union
+ {
+ int cols;
+ int width;
+ };
+#else
+ int rows;
+ int cols;
+#endif
+
+}
+CvMat;
+
+
+#define CV_IS_MAT_HDR(mat) \
+ ((mat) != NULL && \
+ (((const CvMat*)(mat))->type & CV_MAGIC_MASK) == CV_MAT_MAGIC_VAL && \
+ ((const CvMat*)(mat))->cols > 0 && ((const CvMat*)(mat))->rows > 0)
+
+#define CV_IS_MAT(mat) \
+ (CV_IS_MAT_HDR(mat) && ((const CvMat*)(mat))->data.ptr != NULL)
+
+#define CV_IS_MASK_ARR(mat) \
+ (((mat)->type & (CV_MAT_TYPE_MASK & ~CV_8SC1)) == 0)
+
+#define CV_ARE_TYPES_EQ(mat1, mat2) \
+ ((((mat1)->type ^ (mat2)->type) & CV_MAT_TYPE_MASK) == 0)
+
+#define CV_ARE_CNS_EQ(mat1, mat2) \
+ ((((mat1)->type ^ (mat2)->type) & CV_MAT_CN_MASK) == 0)
+
+#define CV_ARE_DEPTHS_EQ(mat1, mat2) \
+ ((((mat1)->type ^ (mat2)->type) & CV_MAT_DEPTH_MASK) == 0)
+
+#define CV_ARE_SIZES_EQ(mat1, mat2) \
+ ((mat1)->rows == (mat2)->rows && (mat1)->cols == (mat2)->cols)
+
+#define CV_IS_MAT_CONST(mat) \
+ (((mat)->rows|(mat)->cols) == 1)
+
+/* Size of each channel item,
+ 0x124489 = 1000 0100 0100 0010 0010 0001 0001 ~ array of sizeof(arr_type_elem) */
+#define CV_ELEM_SIZE1(type) \
+ ((((sizeof(size_t)<<28)|0x8442211) >> CV_MAT_DEPTH(type)*4) & 15)
+
+/* 0x3a50 = 11 10 10 01 01 00 00 ~ array of log2(sizeof(arr_type_elem)) */
+#define CV_ELEM_SIZE(type) \
+ (CV_MAT_CN(type) << ((((sizeof(size_t)/4+1)*16384|0x3a50) >> CV_MAT_DEPTH(type)*2) & 3))
+
+/* Inline constructor. No data is allocated internally!!!
+ * (Use together with cvCreateData, or use cvCreateMat instead to
+ * get a matrix with allocated data):
+ */
+CV_INLINE CvMat cvMat( int rows, int cols, int type, void* data CV_DEFAULT(NULL))
+{
+ CvMat m;
+
+ assert( (unsigned)CV_MAT_DEPTH(type) <= CV_64F );
+ type = CV_MAT_TYPE(type);
+ m.type = CV_MAT_MAGIC_VAL | CV_MAT_CONT_FLAG | type;
+ m.cols = cols;
+ m.rows = rows;
+ m.step = rows > 1 ? m.cols*CV_ELEM_SIZE(type) : 0;
+ m.data.ptr = (uchar*)data;
+ m.refcount = NULL;
+ m.hdr_refcount = 0;
+
+ return m;
+}
+
+
+#define CV_MAT_ELEM_PTR_FAST( mat, row, col, pix_size ) \
+ (assert( (unsigned)(row) < (unsigned)(mat).rows && \
+ (unsigned)(col) < (unsigned)(mat).cols ), \
+ (mat).data.ptr + (size_t)(mat).step*(row) + (pix_size)*(col))
+
+#define CV_MAT_ELEM_PTR( mat, row, col ) \
+ CV_MAT_ELEM_PTR_FAST( mat, row, col, CV_ELEM_SIZE((mat).type) )
+
+#define CV_MAT_ELEM( mat, elemtype, row, col ) \
+ (*(elemtype*)CV_MAT_ELEM_PTR_FAST( mat, row, col, sizeof(elemtype)))
+
+
+CV_INLINE double cvmGet( const CvMat* mat, int row, int col )
+{
+ int type;
+
+ type = CV_MAT_TYPE(mat->type);
+ assert( (unsigned)row < (unsigned)mat->rows &&
+ (unsigned)col < (unsigned)mat->cols );
+
+ if( type == CV_32FC1 )
+ return ((float*)(mat->data.ptr + (size_t)mat->step*row))[col];
+ else
+ {
+ assert( type == CV_64FC1 );
+ return ((double*)(mat->data.ptr + (size_t)mat->step*row))[col];
+ }
+}
+
+
+CV_INLINE void cvmSet( CvMat* mat, int row, int col, double value )
+{
+ int type;
+ type = CV_MAT_TYPE(mat->type);
+ assert( (unsigned)row < (unsigned)mat->rows &&
+ (unsigned)col < (unsigned)mat->cols );
+
+ if( type == CV_32FC1 )
+ ((float*)(mat->data.ptr + (size_t)mat->step*row))[col] = (float)value;
+ else
+ {
+ assert( type == CV_64FC1 );
+ ((double*)(mat->data.ptr + (size_t)mat->step*row))[col] = (double)value;
+ }
+}
+
+
+CV_INLINE int cvCvToIplDepth( int type )
+{
+ int depth = CV_MAT_DEPTH(type);
+ return CV_ELEM_SIZE1(depth)*8 | (depth == CV_8S || depth == CV_16S ||
+ depth == CV_32S ? IPL_DEPTH_SIGN : 0);
+}
+
+
+/****************************************************************************************\
+* Multi-dimensional dense array (CvMatND) *
+\****************************************************************************************/
+
+#define CV_MATND_MAGIC_VAL 0x42430000
+#define CV_TYPE_NAME_MATND "opencv-nd-matrix"
+
+#define CV_MAX_DIM 32
+#define CV_MAX_DIM_HEAP (1 << 16)
+
+typedef struct CvMatND
+{
+ int type;
+ int dims;
+
+ int* refcount;
+ int hdr_refcount;
+
+ union
+ {
+ uchar* ptr;
+ float* fl;
+ double* db;
+ int* i;
+ short* s;
+ } data;
+
+ struct
+ {
+ int size;
+ int step;
+ }
+ dim[CV_MAX_DIM];
+}
+CvMatND;
+
+#define CV_IS_MATND_HDR(mat) \
+ ((mat) != NULL && (((const CvMatND*)(mat))->type & CV_MAGIC_MASK) == CV_MATND_MAGIC_VAL)
+
+#define CV_IS_MATND(mat) \
+ (CV_IS_MATND_HDR(mat) && ((const CvMatND*)(mat))->data.ptr != NULL)
+
+
+/****************************************************************************************\
+* Multi-dimensional sparse array (CvSparseMat) *
+\****************************************************************************************/
+
+#define CV_SPARSE_MAT_MAGIC_VAL 0x42440000
+#define CV_TYPE_NAME_SPARSE_MAT "opencv-sparse-matrix"
+
+struct CvSet;
+
+typedef struct CvSparseMat
+{
+ int type;
+ int dims;
+ int* refcount;
+ int hdr_refcount;
+
+ struct CvSet* heap;
+ void** hashtable;
+ int hashsize;
+ int valoffset;
+ int idxoffset;
+ int size[CV_MAX_DIM];
+}
+CvSparseMat;
+
+#define CV_IS_SPARSE_MAT_HDR(mat) \
+ ((mat) != NULL && \
+ (((const CvSparseMat*)(mat))->type & CV_MAGIC_MASK) == CV_SPARSE_MAT_MAGIC_VAL)
+
+#define CV_IS_SPARSE_MAT(mat) \
+ CV_IS_SPARSE_MAT_HDR(mat)
+
+/**************** iteration through a sparse array *****************/
+
+typedef struct CvSparseNode
+{
+ unsigned hashval;
+ struct CvSparseNode* next;
+}
+CvSparseNode;
+
+typedef struct CvSparseMatIterator
+{
+ CvSparseMat* mat;
+ CvSparseNode* node;
+ int curidx;
+}
+CvSparseMatIterator;
+
+#define CV_NODE_VAL(mat,node) ((void*)((uchar*)(node) + (mat)->valoffset))
+#define CV_NODE_IDX(mat,node) ((int*)((uchar*)(node) + (mat)->idxoffset))
+
+/****************************************************************************************\
+* Histogram *
+\****************************************************************************************/
+
+typedef int CvHistType;
+
+#define CV_HIST_MAGIC_VAL 0x42450000
+#define CV_HIST_UNIFORM_FLAG (1 << 10)
+
+/* indicates whether bin ranges are set already or not */
+#define CV_HIST_RANGES_FLAG (1 << 11)
+
+#define CV_HIST_ARRAY 0
+#define CV_HIST_SPARSE 1
+#define CV_HIST_TREE CV_HIST_SPARSE
+
+/* should be used as a parameter only,
+ it turns to CV_HIST_UNIFORM_FLAG of hist->type */
+#define CV_HIST_UNIFORM 1
+
+typedef struct CvHistogram
+{
+ int type;
+ CvArr* bins;
+ float thresh[CV_MAX_DIM][2]; /* For uniform histograms. */
+ float** thresh2; /* For non-uniform histograms. */
+ CvMatND mat; /* Embedded matrix header for array histograms. */
+}
+CvHistogram;
+
+#define CV_IS_HIST( hist ) \
+ ((hist) != NULL && \
+ (((CvHistogram*)(hist))->type & CV_MAGIC_MASK) == CV_HIST_MAGIC_VAL && \
+ (hist)->bins != NULL)
+
+#define CV_IS_UNIFORM_HIST( hist ) \
+ (((hist)->type & CV_HIST_UNIFORM_FLAG) != 0)
+
+#define CV_IS_SPARSE_HIST( hist ) \
+ CV_IS_SPARSE_MAT((hist)->bins)
+
+#define CV_HIST_HAS_RANGES( hist ) \
+ (((hist)->type & CV_HIST_RANGES_FLAG) != 0)
+
+/****************************************************************************************\
+* Other supplementary data type definitions *
+\****************************************************************************************/
+
+/*************************************** CvRect *****************************************/
+
+typedef struct CvRect
+{
+ int x;
+ int y;
+ int width;
+ int height;
+}
+CvRect;
+
+CV_INLINE CvRect cvRect( int x, int y, int width, int height )
+{
+ CvRect r;
+
+ r.x = x;
+ r.y = y;
+ r.width = width;
+ r.height = height;
+
+ return r;
+}
+
+
+CV_INLINE IplROI cvRectToROI( CvRect rect, int coi )
+{
+ IplROI roi;
+ roi.xOffset = rect.x;
+ roi.yOffset = rect.y;
+ roi.width = rect.width;
+ roi.height = rect.height;
+ roi.coi = coi;
+
+ return roi;
+}
+
+
+CV_INLINE CvRect cvROIToRect( IplROI roi )
+{
+ return cvRect( roi.xOffset, roi.yOffset, roi.width, roi.height );
+}
+
+/*********************************** CvTermCriteria *************************************/
+
+#define CV_TERMCRIT_ITER 1
+#define CV_TERMCRIT_NUMBER CV_TERMCRIT_ITER
+#define CV_TERMCRIT_EPS 2
+
+typedef struct CvTermCriteria
+{
+ int type; /* may be combination of
+ CV_TERMCRIT_ITER
+ CV_TERMCRIT_EPS */
+ int max_iter;
+ double epsilon;
+}
+CvTermCriteria;
+
+CV_INLINE CvTermCriteria cvTermCriteria( int type, int max_iter, double epsilon )
+{
+ CvTermCriteria t;
+
+ t.type = type;
+ t.max_iter = max_iter;
+ t.epsilon = (float)epsilon;
+
+ return t;
+}
+
+
+/******************************* CvPoint and variants ***********************************/
+
+typedef struct CvPoint
+{
+ int x;
+ int y;
+}
+CvPoint;
+
+
+CV_INLINE CvPoint cvPoint( int x, int y )
+{
+ CvPoint p;
+
+ p.x = x;
+ p.y = y;
+
+ return p;
+}
+
+
+typedef struct CvPoint2D32f
+{
+ float x;
+ float y;
+}
+CvPoint2D32f;
+
+
+CV_INLINE CvPoint2D32f cvPoint2D32f( double x, double y )
+{
+ CvPoint2D32f p;
+
+ p.x = (float)x;
+ p.y = (float)y;
+
+ return p;
+}
+
+
+CV_INLINE CvPoint2D32f cvPointTo32f( CvPoint point )
+{
+ return cvPoint2D32f( (float)point.x, (float)point.y );
+}
+
+
+CV_INLINE CvPoint cvPointFrom32f( CvPoint2D32f point )
+{
+ CvPoint ipt;
+ ipt.x = cvRound(point.x);
+ ipt.y = cvRound(point.y);
+
+ return ipt;
+}
+
+
+typedef struct CvPoint3D32f
+{
+ float x;
+ float y;
+ float z;
+}
+CvPoint3D32f;
+
+
+CV_INLINE CvPoint3D32f cvPoint3D32f( double x, double y, double z )
+{
+ CvPoint3D32f p;
+
+ p.x = (float)x;
+ p.y = (float)y;
+ p.z = (float)z;
+
+ return p;
+}
+
+
+typedef struct CvPoint2D64f
+{
+ double x;
+ double y;
+}
+CvPoint2D64f;
+
+
+CV_INLINE CvPoint2D64f cvPoint2D64f( double x, double y )
+{
+ CvPoint2D64f p;
+
+ p.x = x;
+ p.y = y;
+
+ return p;
+}
+
+
+typedef struct CvPoint3D64f
+{
+ double x;
+ double y;
+ double z;
+}
+CvPoint3D64f;
+
+
+CV_INLINE CvPoint3D64f cvPoint3D64f( double x, double y, double z )
+{
+ CvPoint3D64f p;
+
+ p.x = x;
+ p.y = y;
+ p.z = z;
+
+ return p;
+}
+
+
+/******************************** CvSize's & CvBox **************************************/
+
+typedef struct
+{
+ int width;
+ int height;
+}
+CvSize;
+
+CV_INLINE CvSize cvSize( int width, int height )
+{
+ CvSize s;
+
+ s.width = width;
+ s.height = height;
+
+ return s;
+}
+
+typedef struct CvSize2D32f
+{
+ float width;
+ float height;
+}
+CvSize2D32f;
+
+
+CV_INLINE CvSize2D32f cvSize2D32f( double width, double height )
+{
+ CvSize2D32f s;
+
+ s.width = (float)width;
+ s.height = (float)height;
+
+ return s;
+}
+
+typedef struct CvBox2D
+{
+ CvPoint2D32f center; /* Center of the box. */
+ CvSize2D32f size; /* Box width and length. */
+ float angle; /* Angle between the horizontal axis */
+ /* and the first side (i.e. length) in degrees */
+}
+CvBox2D;
+
+
+/* Line iterator state: */
+typedef struct CvLineIterator
+{
+ /* Pointer to the current point: */
+ uchar* ptr;
+
+ /* Bresenham algorithm state: */
+ int err;
+ int plus_delta;
+ int minus_delta;
+ int plus_step;
+ int minus_step;
+}
+CvLineIterator;
+
+
+
+/************************************* CvSlice ******************************************/
+
+typedef struct CvSlice
+{
+ int start_index, end_index;
+}
+CvSlice;
+
+CV_INLINE CvSlice cvSlice( int start, int end )
+{
+ CvSlice slice;
+ slice.start_index = start;
+ slice.end_index = end;
+
+ return slice;
+}
+
+#define CV_WHOLE_SEQ_END_INDEX 0x3fffffff
+#define CV_WHOLE_SEQ cvSlice(0, CV_WHOLE_SEQ_END_INDEX)
+
+
+/************************************* CvScalar *****************************************/
+
+typedef struct CvScalar
+{
+ double val[4];
+}
+CvScalar;
+
+CV_INLINE CvScalar cvScalar( double val0, double val1 CV_DEFAULT(0),
+ double val2 CV_DEFAULT(0), double val3 CV_DEFAULT(0))
+{
+ CvScalar scalar;
+ scalar.val[0] = val0; scalar.val[1] = val1;
+ scalar.val[2] = val2; scalar.val[3] = val3;
+ return scalar;
+}
+
+
+CV_INLINE CvScalar cvRealScalar( double val0 )
+{
+ CvScalar scalar;
+ scalar.val[0] = val0;
+ scalar.val[1] = scalar.val[2] = scalar.val[3] = 0;
+ return scalar;
+}
+
+CV_INLINE CvScalar cvScalarAll( double val0123 )
+{
+ CvScalar scalar;
+ scalar.val[0] = val0123;
+ scalar.val[1] = val0123;
+ scalar.val[2] = val0123;
+ scalar.val[3] = val0123;
+ return scalar;
+}
+
+/****************************************************************************************\
+* Dynamic Data structures *
+\****************************************************************************************/
+
+/******************************** Memory storage ****************************************/
+
+typedef struct CvMemBlock
+{
+ struct CvMemBlock* prev;
+ struct CvMemBlock* next;
+}
+CvMemBlock;
+
+#define CV_STORAGE_MAGIC_VAL 0x42890000
+
+typedef struct CvMemStorage
+{
+ int signature;
+ CvMemBlock* bottom; /* First allocated block. */
+ CvMemBlock* top; /* Current memory block - top of the stack. */
+ struct CvMemStorage* parent; /* We get new blocks from parent as needed. */
+ int block_size; /* Block size. */
+ int free_space; /* Remaining free space in current block. */
+}
+CvMemStorage;
+
+#define CV_IS_STORAGE(storage) \
+ ((storage) != NULL && \
+ (((CvMemStorage*)(storage))->signature & CV_MAGIC_MASK) == CV_STORAGE_MAGIC_VAL)
+
+
+typedef struct CvMemStoragePos
+{
+ CvMemBlock* top;
+ int free_space;
+}
+CvMemStoragePos;
+
+
+/*********************************** Sequence *******************************************/
+
+typedef struct CvSeqBlock
+{
+ struct CvSeqBlock* prev; /* Previous sequence block. */
+ struct CvSeqBlock* next; /* Next sequence block. */
+ int start_index; /* Index of the first element in the block + */
+ /* sequence->first->start_index. */
+ int count; /* Number of elements in the block. */
+ schar* data; /* Pointer to the first element of the block. */
+}
+CvSeqBlock;
+
+
+#define CV_TREE_NODE_FIELDS(node_type) \
+ int flags; /* Miscellaneous flags. */ \
+ int header_size; /* Size of sequence header. */ \
+ struct node_type* h_prev; /* Previous sequence. */ \
+ struct node_type* h_next; /* Next sequence. */ \
+ struct node_type* v_prev; /* 2nd previous sequence. */ \
+ struct node_type* v_next /* 2nd next sequence. */
+
+/*
+ Read/Write sequence.
+ Elements can be dynamically inserted to or deleted from the sequence.
+*/
+#define CV_SEQUENCE_FIELDS() \
+ CV_TREE_NODE_FIELDS(CvSeq); \
+ int total; /* Total number of elements. */ \
+ int elem_size; /* Size of sequence element in bytes. */ \
+ schar* block_max; /* Maximal bound of the last block. */ \
+ schar* ptr; /* Current write pointer. */ \
+ int delta_elems; /* Grow seq this many at a time. */ \
+ CvMemStorage* storage; /* Where the seq is stored. */ \
+ CvSeqBlock* free_blocks; /* Free blocks list. */ \
+ CvSeqBlock* first; /* Pointer to the first sequence block. */
+
+typedef struct CvSeq
+{
+ CV_SEQUENCE_FIELDS()
+}
+CvSeq;
+
+#define CV_TYPE_NAME_SEQ "opencv-sequence"
+#define CV_TYPE_NAME_SEQ_TREE "opencv-sequence-tree"
+
+/*************************************** Set ********************************************/
+/*
+ Set.
+ Order is not preserved. There can be gaps between sequence elements.
+ After the element has been inserted it stays in the same place all the time.
+ The MSB(most-significant or sign bit) of the first field (flags) is 0 iff the element exists.
+*/
+#define CV_SET_ELEM_FIELDS(elem_type) \
+ int flags; \
+ struct elem_type* next_free;
+
+typedef struct CvSetElem
+{
+ CV_SET_ELEM_FIELDS(CvSetElem)
+}
+CvSetElem;
+
+#define CV_SET_FIELDS() \
+ CV_SEQUENCE_FIELDS() \
+ CvSetElem* free_elems; \
+ int active_count;
+
+typedef struct CvSet
+{
+ CV_SET_FIELDS()
+}
+CvSet;
+
+
+#define CV_SET_ELEM_IDX_MASK ((1 << 26) - 1)
+#define CV_SET_ELEM_FREE_FLAG (1 << (sizeof(int)*8-1))
+
+/* Checks whether the element pointed by ptr belongs to a set or not */
+#define CV_IS_SET_ELEM( ptr ) (((CvSetElem*)(ptr))->flags >= 0)
+
+/************************************* Graph ********************************************/
+
+/*
+ We represent a graph as a set of vertices.
+ Vertices contain their adjacency lists (more exactly, pointers to first incoming or
+ outcoming edge (or 0 if isolated vertex)). Edges are stored in another set.
+ There is a singly-linked list of incoming/outcoming edges for each vertex.
+
+ Each edge consists of
+
+ o Two pointers to the starting and ending vertices
+ (vtx[0] and vtx[1] respectively).
+
+ A graph may be oriented or not. In the latter case, edges between
+ vertex i to vertex j are not distinguished during search operations.
+
+ o Two pointers to next edges for the starting and ending vertices, where
+ next[0] points to the next edge in the vtx[0] adjacency list and
+ next[1] points to the next edge in the vtx[1] adjacency list.
+*/
+#define CV_GRAPH_EDGE_FIELDS() \
+ int flags; \
+ float weight; \
+ struct CvGraphEdge* next[2]; \
+ struct CvGraphVtx* vtx[2];
+
+
+#define CV_GRAPH_VERTEX_FIELDS() \
+ int flags; \
+ struct CvGraphEdge* first;
+
+
+typedef struct CvGraphEdge
+{
+ CV_GRAPH_EDGE_FIELDS()
+}
+CvGraphEdge;
+
+typedef struct CvGraphVtx
+{
+ CV_GRAPH_VERTEX_FIELDS()
+}
+CvGraphVtx;
+
+typedef struct CvGraphVtx2D
+{
+ CV_GRAPH_VERTEX_FIELDS()
+ CvPoint2D32f* ptr;
+}
+CvGraphVtx2D;
+
+/*
+ Graph is "derived" from the set (this is set a of vertices)
+ and includes another set (edges)
+*/
+#define CV_GRAPH_FIELDS() \
+ CV_SET_FIELDS() \
+ CvSet* edges;
+
+typedef struct CvGraph
+{
+ CV_GRAPH_FIELDS()
+}
+CvGraph;
+
+#define CV_TYPE_NAME_GRAPH "opencv-graph"
+
+/*********************************** Chain/Countour *************************************/
+
+typedef struct CvChain
+{
+ CV_SEQUENCE_FIELDS()
+ CvPoint origin;
+}
+CvChain;
+
+#define CV_CONTOUR_FIELDS() \
+ CV_SEQUENCE_FIELDS() \
+ CvRect rect; \
+ int color; \
+ int reserved[3];
+
+typedef struct CvContour
+{
+ CV_CONTOUR_FIELDS()
+}
+CvContour;
+
+typedef CvContour CvPoint2DSeq;
+
+/****************************************************************************************\
+* Sequence types *
+\****************************************************************************************/
+
+#define CV_SEQ_MAGIC_VAL 0x42990000
+
+#define CV_IS_SEQ(seq) \
+ ((seq) != NULL && (((CvSeq*)(seq))->flags & CV_MAGIC_MASK) == CV_SEQ_MAGIC_VAL)
+
+#define CV_SET_MAGIC_VAL 0x42980000
+#define CV_IS_SET(set) \
+ ((set) != NULL && (((CvSeq*)(set))->flags & CV_MAGIC_MASK) == CV_SET_MAGIC_VAL)
+
+#define CV_SEQ_ELTYPE_BITS 9
+#define CV_SEQ_ELTYPE_MASK ((1 << CV_SEQ_ELTYPE_BITS) - 1)
+
+#define CV_SEQ_ELTYPE_POINT CV_32SC2 /* (x,y) */
+#define CV_SEQ_ELTYPE_CODE CV_8UC1 /* freeman code: 0..7 */
+#define CV_SEQ_ELTYPE_GENERIC 0
+#define CV_SEQ_ELTYPE_PTR CV_USRTYPE1
+#define CV_SEQ_ELTYPE_PPOINT CV_SEQ_ELTYPE_PTR /* &(x,y) */
+#define CV_SEQ_ELTYPE_INDEX CV_32SC1 /* #(x,y) */
+#define CV_SEQ_ELTYPE_GRAPH_EDGE 0 /* &next_o, &next_d, &vtx_o, &vtx_d */
+#define CV_SEQ_ELTYPE_GRAPH_VERTEX 0 /* first_edge, &(x,y) */
+#define CV_SEQ_ELTYPE_TRIAN_ATR 0 /* vertex of the binary tree */
+#define CV_SEQ_ELTYPE_CONNECTED_COMP 0 /* connected component */
+#define CV_SEQ_ELTYPE_POINT3D CV_32FC3 /* (x,y,z) */
+
+#define CV_SEQ_KIND_BITS 3
+#define CV_SEQ_KIND_MASK (((1 << CV_SEQ_KIND_BITS) - 1)<<CV_SEQ_ELTYPE_BITS)
+
+/* types of sequences */
+#define CV_SEQ_KIND_GENERIC (0 << CV_SEQ_ELTYPE_BITS)
+#define CV_SEQ_KIND_CURVE (1 << CV_SEQ_ELTYPE_BITS)
+#define CV_SEQ_KIND_BIN_TREE (2 << CV_SEQ_ELTYPE_BITS)
+
+/* types of sparse sequences (sets) */
+#define CV_SEQ_KIND_GRAPH (3 << CV_SEQ_ELTYPE_BITS)
+#define CV_SEQ_KIND_SUBDIV2D (4 << CV_SEQ_ELTYPE_BITS)
+
+#define CV_SEQ_FLAG_SHIFT (CV_SEQ_KIND_BITS + CV_SEQ_ELTYPE_BITS)
+
+/* flags for curves */
+#define CV_SEQ_FLAG_CLOSED (1 << CV_SEQ_FLAG_SHIFT)
+#define CV_SEQ_FLAG_SIMPLE (2 << CV_SEQ_FLAG_SHIFT)
+#define CV_SEQ_FLAG_CONVEX (4 << CV_SEQ_FLAG_SHIFT)
+#define CV_SEQ_FLAG_HOLE (8 << CV_SEQ_FLAG_SHIFT)
+
+/* flags for graphs */
+#define CV_GRAPH_FLAG_ORIENTED (1 << CV_SEQ_FLAG_SHIFT)
+
+#define CV_GRAPH CV_SEQ_KIND_GRAPH
+#define CV_ORIENTED_GRAPH (CV_SEQ_KIND_GRAPH|CV_GRAPH_FLAG_ORIENTED)
+
+/* point sets */
+#define CV_SEQ_POINT_SET (CV_SEQ_KIND_GENERIC| CV_SEQ_ELTYPE_POINT)
+#define CV_SEQ_POINT3D_SET (CV_SEQ_KIND_GENERIC| CV_SEQ_ELTYPE_POINT3D)
+#define CV_SEQ_POLYLINE (CV_SEQ_KIND_CURVE | CV_SEQ_ELTYPE_POINT)
+#define CV_SEQ_POLYGON (CV_SEQ_FLAG_CLOSED | CV_SEQ_POLYLINE )
+#define CV_SEQ_CONTOUR CV_SEQ_POLYGON
+#define CV_SEQ_SIMPLE_POLYGON (CV_SEQ_FLAG_SIMPLE | CV_SEQ_POLYGON )
+
+/* chain-coded curves */
+#define CV_SEQ_CHAIN (CV_SEQ_KIND_CURVE | CV_SEQ_ELTYPE_CODE)
+#define CV_SEQ_CHAIN_CONTOUR (CV_SEQ_FLAG_CLOSED | CV_SEQ_CHAIN)
+
+/* binary tree for the contour */
+#define CV_SEQ_POLYGON_TREE (CV_SEQ_KIND_BIN_TREE | CV_SEQ_ELTYPE_TRIAN_ATR)
+
+/* sequence of the connected components */
+#define CV_SEQ_CONNECTED_COMP (CV_SEQ_KIND_GENERIC | CV_SEQ_ELTYPE_CONNECTED_COMP)
+
+/* sequence of the integer numbers */
+#define CV_SEQ_INDEX (CV_SEQ_KIND_GENERIC | CV_SEQ_ELTYPE_INDEX)
+
+#define CV_SEQ_ELTYPE( seq ) ((seq)->flags & CV_SEQ_ELTYPE_MASK)
+#define CV_SEQ_KIND( seq ) ((seq)->flags & CV_SEQ_KIND_MASK )
+
+/* flag checking */
+#define CV_IS_SEQ_INDEX( seq ) ((CV_SEQ_ELTYPE(seq) == CV_SEQ_ELTYPE_INDEX) && \
+ (CV_SEQ_KIND(seq) == CV_SEQ_KIND_GENERIC))
+
+#define CV_IS_SEQ_CURVE( seq ) (CV_SEQ_KIND(seq) == CV_SEQ_KIND_CURVE)
+#define CV_IS_SEQ_CLOSED( seq ) (((seq)->flags & CV_SEQ_FLAG_CLOSED) != 0)
+#define CV_IS_SEQ_CONVEX( seq ) (((seq)->flags & CV_SEQ_FLAG_CONVEX) != 0)
+#define CV_IS_SEQ_HOLE( seq ) (((seq)->flags & CV_SEQ_FLAG_HOLE) != 0)
+#define CV_IS_SEQ_SIMPLE( seq ) ((((seq)->flags & CV_SEQ_FLAG_SIMPLE) != 0) || \
+ CV_IS_SEQ_CONVEX(seq))
+
+/* type checking macros */
+#define CV_IS_SEQ_POINT_SET( seq ) \
+ ((CV_SEQ_ELTYPE(seq) == CV_32SC2 || CV_SEQ_ELTYPE(seq) == CV_32FC2))
+
+#define CV_IS_SEQ_POINT_SUBSET( seq ) \
+ (CV_IS_SEQ_INDEX( seq ) || CV_SEQ_ELTYPE(seq) == CV_SEQ_ELTYPE_PPOINT)
+
+#define CV_IS_SEQ_POLYLINE( seq ) \
+ (CV_SEQ_KIND(seq) == CV_SEQ_KIND_CURVE && CV_IS_SEQ_POINT_SET(seq))
+
+#define CV_IS_SEQ_POLYGON( seq ) \
+ (CV_IS_SEQ_POLYLINE(seq) && CV_IS_SEQ_CLOSED(seq))
+
+#define CV_IS_SEQ_CHAIN( seq ) \
+ (CV_SEQ_KIND(seq) == CV_SEQ_KIND_CURVE && (seq)->elem_size == 1)
+
+#define CV_IS_SEQ_CONTOUR( seq ) \
+ (CV_IS_SEQ_CLOSED(seq) && (CV_IS_SEQ_POLYLINE(seq) || CV_IS_SEQ_CHAIN(seq)))
+
+#define CV_IS_SEQ_CHAIN_CONTOUR( seq ) \
+ (CV_IS_SEQ_CHAIN( seq ) && CV_IS_SEQ_CLOSED( seq ))
+
+#define CV_IS_SEQ_POLYGON_TREE( seq ) \
+ (CV_SEQ_ELTYPE (seq) == CV_SEQ_ELTYPE_TRIAN_ATR && \
+ CV_SEQ_KIND( seq ) == CV_SEQ_KIND_BIN_TREE )
+
+#define CV_IS_GRAPH( seq ) \
+ (CV_IS_SET(seq) && CV_SEQ_KIND((CvSet*)(seq)) == CV_SEQ_KIND_GRAPH)
+
+#define CV_IS_GRAPH_ORIENTED( seq ) \
+ (((seq)->flags & CV_GRAPH_FLAG_ORIENTED) != 0)
+
+#define CV_IS_SUBDIV2D( seq ) \
+ (CV_IS_SET(seq) && CV_SEQ_KIND((CvSet*)(seq)) == CV_SEQ_KIND_SUBDIV2D)
+
+/****************************************************************************************/
+/* Sequence writer & reader */
+/****************************************************************************************/
+
+#define CV_SEQ_WRITER_FIELDS() \
+ int header_size; \
+ CvSeq* seq; /* the sequence written */ \
+ CvSeqBlock* block; /* current block */ \
+ schar* ptr; /* pointer to free space */ \
+ schar* block_min; /* pointer to the beginning of block*/\
+ schar* block_max; /* pointer to the end of block */
+
+typedef struct CvSeqWriter
+{
+ CV_SEQ_WRITER_FIELDS()
+}
+CvSeqWriter;
+
+
+#define CV_SEQ_READER_FIELDS() \
+ int header_size; \
+ CvSeq* seq; /* sequence, beign read */ \
+ CvSeqBlock* block; /* current block */ \
+ schar* ptr; /* pointer to element be read next */ \
+ schar* block_min; /* pointer to the beginning of block */\
+ schar* block_max; /* pointer to the end of block */ \
+ int delta_index;/* = seq->first->start_index */ \
+ schar* prev_elem; /* pointer to previous element */
+
+
+typedef struct CvSeqReader
+{
+ CV_SEQ_READER_FIELDS()
+}
+CvSeqReader;
+
+/****************************************************************************************/
+/* Operations on sequences */
+/****************************************************************************************/
+
+#define CV_SEQ_ELEM( seq, elem_type, index ) \
+/* assert gives some guarantee that <seq> parameter is valid */ \
+( assert(sizeof((seq)->first[0]) == sizeof(CvSeqBlock) && \
+ (seq)->elem_size == sizeof(elem_type)), \
+ (elem_type*)((seq)->first && (unsigned)index < \
+ (unsigned)((seq)->first->count) ? \
+ (seq)->first->data + (index) * sizeof(elem_type) : \
+ cvGetSeqElem( (CvSeq*)(seq), (index) )))
+#define CV_GET_SEQ_ELEM( elem_type, seq, index ) CV_SEQ_ELEM( (seq), elem_type, (index) )
+
+/* Add element to sequence: */
+#define CV_WRITE_SEQ_ELEM_VAR( elem_ptr, writer ) \
+{ \
+ if( (writer).ptr >= (writer).block_max ) \
+ { \
+ cvCreateSeqBlock( &writer); \
+ } \
+ memcpy((writer).ptr, elem_ptr, (writer).seq->elem_size);\
+ (writer).ptr += (writer).seq->elem_size; \
+}
+
+#define CV_WRITE_SEQ_ELEM( elem, writer ) \
+{ \
+ assert( (writer).seq->elem_size == sizeof(elem)); \
+ if( (writer).ptr >= (writer).block_max ) \
+ { \
+ cvCreateSeqBlock( &writer); \
+ } \
+ assert( (writer).ptr <= (writer).block_max - sizeof(elem));\
+ memcpy((writer).ptr, &(elem), sizeof(elem)); \
+ (writer).ptr += sizeof(elem); \
+}
+
+
+/* Move reader position forward: */
+#define CV_NEXT_SEQ_ELEM( elem_size, reader ) \
+{ \
+ if( ((reader).ptr += (elem_size)) >= (reader).block_max ) \
+ { \
+ cvChangeSeqBlock( &(reader), 1 ); \
+ } \
+}
+
+
+/* Move reader position backward: */
+#define CV_PREV_SEQ_ELEM( elem_size, reader ) \
+{ \
+ if( ((reader).ptr -= (elem_size)) < (reader).block_min ) \
+ { \
+ cvChangeSeqBlock( &(reader), -1 ); \
+ } \
+}
+
+/* Read element and move read position forward: */
+#define CV_READ_SEQ_ELEM( elem, reader ) \
+{ \
+ assert( (reader).seq->elem_size == sizeof(elem)); \
+ memcpy( &(elem), (reader).ptr, sizeof((elem))); \
+ CV_NEXT_SEQ_ELEM( sizeof(elem), reader ) \
+}
+
+/* Read element and move read position backward: */
+#define CV_REV_READ_SEQ_ELEM( elem, reader ) \
+{ \
+ assert( (reader).seq->elem_size == sizeof(elem)); \
+ memcpy(&(elem), (reader).ptr, sizeof((elem))); \
+ CV_PREV_SEQ_ELEM( sizeof(elem), reader ) \
+}
+
+
+#define CV_READ_CHAIN_POINT( _pt, reader ) \
+{ \
+ (_pt) = (reader).pt; \
+ if( (reader).ptr ) \
+ { \
+ CV_READ_SEQ_ELEM( (reader).code, (reader)); \
+ assert( ((reader).code & ~7) == 0 ); \
+ (reader).pt.x += (reader).deltas[(int)(reader).code][0]; \
+ (reader).pt.y += (reader).deltas[(int)(reader).code][1]; \
+ } \
+}
+
+#define CV_CURRENT_POINT( reader ) (*((CvPoint*)((reader).ptr)))
+#define CV_PREV_POINT( reader ) (*((CvPoint*)((reader).prev_elem)))
+
+#define CV_READ_EDGE( pt1, pt2, reader ) \
+{ \
+ assert( sizeof(pt1) == sizeof(CvPoint) && \
+ sizeof(pt2) == sizeof(CvPoint) && \
+ reader.seq->elem_size == sizeof(CvPoint)); \
+ (pt1) = CV_PREV_POINT( reader ); \
+ (pt2) = CV_CURRENT_POINT( reader ); \
+ (reader).prev_elem = (reader).ptr; \
+ CV_NEXT_SEQ_ELEM( sizeof(CvPoint), (reader)); \
+}
+
+/************ Graph macros ************/
+
+/* Return next graph edge for given vertex: */
+#define CV_NEXT_GRAPH_EDGE( edge, vertex ) \
+ (assert((edge)->vtx[0] == (vertex) || (edge)->vtx[1] == (vertex)), \
+ (edge)->next[(edge)->vtx[1] == (vertex)])
+
+
+
+/****************************************************************************************\
+* Data structures for persistence (a.k.a serialization) functionality *
+\****************************************************************************************/
+
+/* "black box" file storage */
+typedef struct CvFileStorage CvFileStorage;
+
+/* Storage flags: */
+#define CV_STORAGE_READ 0
+#define CV_STORAGE_WRITE 1
+#define CV_STORAGE_WRITE_TEXT CV_STORAGE_WRITE
+#define CV_STORAGE_WRITE_BINARY CV_STORAGE_WRITE
+#define CV_STORAGE_APPEND 2
+
+/* List of attributes: */
+typedef struct CvAttrList
+{
+ const char** attr; /* NULL-terminated array of (attribute_name,attribute_value) pairs. */
+ struct CvAttrList* next; /* Pointer to next chunk of the attributes list. */
+}
+CvAttrList;
+
+CV_INLINE CvAttrList cvAttrList( const char** attr CV_DEFAULT(NULL),
+ CvAttrList* next CV_DEFAULT(NULL) )
+{
+ CvAttrList l;
+ l.attr = attr;
+ l.next = next;
+
+ return l;
+}
+
+struct CvTypeInfo;
+
+#define CV_NODE_NONE 0
+#define CV_NODE_INT 1
+#define CV_NODE_INTEGER CV_NODE_INT
+#define CV_NODE_REAL 2
+#define CV_NODE_FLOAT CV_NODE_REAL
+#define CV_NODE_STR 3
+#define CV_NODE_STRING CV_NODE_STR
+#define CV_NODE_REF 4 /* not used */
+#define CV_NODE_SEQ 5
+#define CV_NODE_MAP 6
+#define CV_NODE_TYPE_MASK 7
+
+#define CV_NODE_TYPE(flags) ((flags) & CV_NODE_TYPE_MASK)
+
+/* file node flags */
+#define CV_NODE_FLOW 8 /* Used only for writing structures in YAML format. */
+#define CV_NODE_USER 16
+#define CV_NODE_EMPTY 32
+#define CV_NODE_NAMED 64
+
+#define CV_NODE_IS_INT(flags) (CV_NODE_TYPE(flags) == CV_NODE_INT)
+#define CV_NODE_IS_REAL(flags) (CV_NODE_TYPE(flags) == CV_NODE_REAL)
+#define CV_NODE_IS_STRING(flags) (CV_NODE_TYPE(flags) == CV_NODE_STRING)
+#define CV_NODE_IS_SEQ(flags) (CV_NODE_TYPE(flags) == CV_NODE_SEQ)
+#define CV_NODE_IS_MAP(flags) (CV_NODE_TYPE(flags) == CV_NODE_MAP)
+#define CV_NODE_IS_COLLECTION(flags) (CV_NODE_TYPE(flags) >= CV_NODE_SEQ)
+#define CV_NODE_IS_FLOW(flags) (((flags) & CV_NODE_FLOW) != 0)
+#define CV_NODE_IS_EMPTY(flags) (((flags) & CV_NODE_EMPTY) != 0)
+#define CV_NODE_IS_USER(flags) (((flags) & CV_NODE_USER) != 0)
+#define CV_NODE_HAS_NAME(flags) (((flags) & CV_NODE_NAMED) != 0)
+
+#define CV_NODE_SEQ_SIMPLE 256
+#define CV_NODE_SEQ_IS_SIMPLE(seq) (((seq)->flags & CV_NODE_SEQ_SIMPLE) != 0)
+
+typedef struct CvString
+{
+ int len;
+ char* ptr;
+}
+CvString;
+
+/* All the keys (names) of elements in the readed file storage
+ are stored in the hash to speed up the lookup operations: */
+typedef struct CvStringHashNode
+{
+ unsigned hashval;
+ CvString str;
+ struct CvStringHashNode* next;
+}
+CvStringHashNode;
+
+typedef struct CvGenericHash CvFileNodeHash;
+
+/* Basic element of the file storage - scalar or collection: */
+typedef struct CvFileNode
+{
+ int tag;
+ struct CvTypeInfo* info; /* type information
+ (only for user-defined object, for others it is 0) */
+ union
+ {
+ double f; /* scalar floating-point number */
+ int i; /* scalar integer number */
+ CvString str; /* text string */
+ CvSeq* seq; /* sequence (ordered collection of file nodes) */
+ CvFileNodeHash* map; /* map (collection of named file nodes) */
+ } data;
+}
+CvFileNode;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (CV_CDECL *CvIsInstanceFunc)( const void* struct_ptr );
+typedef void (CV_CDECL *CvReleaseFunc)( void** struct_dblptr );
+typedef void* (CV_CDECL *CvReadFunc)( CvFileStorage* storage, CvFileNode* node );
+typedef void (CV_CDECL *CvWriteFunc)( CvFileStorage* storage, const char* name,
+ const void* struct_ptr, CvAttrList attributes );
+typedef void* (CV_CDECL *CvCloneFunc)( const void* struct_ptr );
+#ifdef __cplusplus
+}
+#endif
+
+typedef struct CvTypeInfo
+{
+ int flags;
+ int header_size;
+ struct CvTypeInfo* prev;
+ struct CvTypeInfo* next;
+ const char* type_name;
+ CvIsInstanceFunc is_instance;
+ CvReleaseFunc release;
+ CvReadFunc read;
+ CvWriteFunc write;
+ CvCloneFunc clone;
+}
+CvTypeInfo;
+
+
+/**** System data types ******/
+
+typedef struct CvPluginFuncInfo
+{
+ void** func_addr;
+ void* default_func_addr;
+ const char* func_names;
+ int search_modules;
+ int loaded_from;
+}
+CvPluginFuncInfo;
+
+typedef struct CvModuleInfo
+{
+ struct CvModuleInfo* next;
+ const char* name;
+ const char* version;
+ CvPluginFuncInfo* func_tab;
+}
+CvModuleInfo;
+
+#endif /*_CXCORE_TYPES_H_*/
+
+/* End of file. */
diff --git a/cxcore/src/_cxcore.h b/cxcore/src/_cxcore.h
new file mode 100644
index 0000000..082d052
--- /dev/null
+++ b/cxcore/src/_cxcore.h
@@ -0,0 +1,346 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _CXCORE_INTERNAL_H_
+#define _CXCORE_INTERNAL_H_
+
+#if defined _MSC_VER && _MSC_VER >= 1200
+ /* disable warnings related to inline functions */
+ #pragma warning( disable: 4711 4710 4514 )
+#endif
+
+typedef unsigned long ulong;
+
+#ifdef __BORLANDC__
+ #define WIN32
+ #define CV_DLL
+ #undef _CV_ALWAYS_PROFILE_
+ #define _CV_ALWAYS_NO_PROFILE_
+#endif
+
+#include "cxcore.h"
+#include "cxmisc.h"
+#include "_cxipp.h"
+#include <math.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <float.h>
+
+// -128.f ... 255.f
+extern const float icv8x32fTab[];
+#define CV_8TO32F(x) icv8x32fTab[(x)+128]
+
+extern const ushort icv8x16uSqrTab[];
+#define CV_SQR_8U(x) icv8x16uSqrTab[(x)+255]
+
+extern const char* icvHersheyGlyphs[];
+
+extern const signed char icvDepthToType[];
+
+#define icvIplToCvDepth( depth ) \
+ icvDepthToType[(((depth) & 255) >> 2) + ((depth) < 0)]
+
+extern const uchar icvSaturate8u[];
+#define CV_FAST_CAST_8U(t) (assert(-256 <= (t) && (t) <= 512), icvSaturate8u[(t)+256])
+#define CV_MIN_8U(a,b) ((a) - CV_FAST_CAST_8U((a) - (b)))
+#define CV_MAX_8U(a,b) ((a) + CV_FAST_CAST_8U((b) - (a)))
+
+typedef CvFunc2D_3A1I CvArithmBinMaskFunc2D;
+typedef CvFunc2D_2A1P1I CvArithmUniMaskFunc2D;
+
+
+/****************************************************************************************\
+* Complex arithmetics *
+\****************************************************************************************/
+
+struct CvComplex32f;
+struct CvComplex64f;
+
+struct CvComplex32f
+{
+ float re, im;
+
+ CvComplex32f() {}
+ CvComplex32f( float _re, float _im=0 ) : re(_re), im(_im) {}
+ explicit CvComplex32f( const CvComplex64f& v );
+ //CvComplex32f( const CvComplex32f& v ) : re(v.re), im(v.im) {}
+ //CvComplex32f& operator = (const CvComplex32f& v ) { re = v.re; im = v.im; return *this; }
+ operator CvComplex64f() const;
+};
+
+struct CvComplex64f
+{
+ double re, im;
+
+ CvComplex64f() {}
+ CvComplex64f( double _re, double _im=0 ) : re(_re), im(_im) {}
+ explicit CvComplex64f( const CvComplex32f& v );
+ //CvComplex64f( const CvComplex64f& v ) : re(v.re), im(v.im) {}
+ //CvComplex64f& operator = (const CvComplex64f& v ) { re = v.re; im = v.im; return *this; }
+ operator CvComplex32f() const;
+};
+
+inline CvComplex32f::CvComplex32f( const CvComplex64f& v ) : re((float)v.re), im((float)v.im) {}
+inline CvComplex64f::CvComplex64f( const CvComplex32f& v ) : re(v.re), im(v.im) {}
+
+inline CvComplex32f operator + (CvComplex32f a, CvComplex32f b)
+{
+ return CvComplex32f( a.re + b.re, a.im + b.im );
+}
+
+inline CvComplex32f& operator += (CvComplex32f& a, CvComplex32f b)
+{
+ a.re += b.re;
+ a.im += b.im;
+ return a;
+}
+
+inline CvComplex32f operator - (CvComplex32f a, CvComplex32f b)
+{
+ return CvComplex32f( a.re - b.re, a.im - b.im );
+}
+
+inline CvComplex32f& operator -= (CvComplex32f& a, CvComplex32f b)
+{
+ a.re -= b.re;
+ a.im -= b.im;
+ return a;
+}
+
+inline CvComplex32f operator - (CvComplex32f a)
+{
+ return CvComplex32f( -a.re, -a.im );
+}
+
+inline CvComplex32f operator * (CvComplex32f a, CvComplex32f b)
+{
+ return CvComplex32f( a.re*b.re - a.im*b.im, a.re*b.im + a.im*b.re );
+}
+
+inline double abs(CvComplex32f a)
+{
+ return sqrt( (double)a.re*a.re + (double)a.im*a.im );
+}
+
+inline CvComplex32f conj(CvComplex32f a)
+{
+ return CvComplex32f( a.re, -a.im );
+}
+
+
+inline CvComplex32f operator / (CvComplex32f a, CvComplex32f b)
+{
+ double t = 1./((double)b.re*b.re + (double)b.im*b.im);
+ return CvComplex32f( (float)((a.re*b.re + a.im*b.im)*t),
+ (float)((-a.re*b.im + a.im*b.re)*t) );
+}
+
+inline CvComplex32f operator * (double a, CvComplex32f b)
+{
+ return CvComplex32f( (float)(a*b.re), (float)(a*b.im) );
+}
+
+inline CvComplex32f operator * (CvComplex32f a, double b)
+{
+ return CvComplex32f( (float)(a.re*b), (float)(a.im*b) );
+}
+
+inline CvComplex32f::operator CvComplex64f() const
+{
+ return CvComplex64f(re,im);
+}
+
+
+inline CvComplex64f operator + (CvComplex64f a, CvComplex64f b)
+{
+ return CvComplex64f( a.re + b.re, a.im + b.im );
+}
+
+inline CvComplex64f& operator += (CvComplex64f& a, CvComplex64f b)
+{
+ a.re += b.re;
+ a.im += b.im;
+ return a;
+}
+
+inline CvComplex64f operator - (CvComplex64f a, CvComplex64f b)
+{
+ return CvComplex64f( a.re - b.re, a.im - b.im );
+}
+
+inline CvComplex64f& operator -= (CvComplex64f& a, CvComplex64f b)
+{
+ a.re -= b.re;
+ a.im -= b.im;
+ return a;
+}
+
+inline CvComplex64f operator - (CvComplex64f a)
+{
+ return CvComplex64f( -a.re, -a.im );
+}
+
+inline CvComplex64f operator * (CvComplex64f a, CvComplex64f b)
+{
+ return CvComplex64f( a.re*b.re - a.im*b.im, a.re*b.im + a.im*b.re );
+}
+
+inline double abs(CvComplex64f a)
+{
+ return sqrt( (double)a.re*a.re + (double)a.im*a.im );
+}
+
+inline CvComplex64f operator / (CvComplex64f a, CvComplex64f b)
+{
+ double t = 1./((double)b.re*b.re + (double)b.im*b.im);
+ return CvComplex64f( (a.re*b.re + a.im*b.im)*t,
+ (-a.re*b.im + a.im*b.re)*t );
+}
+
+inline CvComplex64f operator * (double a, CvComplex64f b)
+{
+ return CvComplex64f( a*b.re, a*b.im );
+}
+
+inline CvComplex64f operator * (CvComplex64f a, double b)
+{
+ return CvComplex64f( a.re*b, a.im*b );
+}
+
+inline CvComplex64f::operator CvComplex32f() const
+{
+ return CvComplex32f((float)re,(float)im);
+}
+
+inline CvComplex64f conj(CvComplex64f a)
+{
+ return CvComplex64f( a.re, -a.im );
+}
+
+inline CvComplex64f operator + (CvComplex64f a, CvComplex32f b)
+{
+ return CvComplex64f( a.re + b.re, a.im + b.im );
+}
+
+inline CvComplex64f operator + (CvComplex32f a, CvComplex64f b)
+{
+ return CvComplex64f( a.re + b.re, a.im + b.im );
+}
+
+inline CvComplex64f operator - (CvComplex64f a, CvComplex32f b)
+{
+ return CvComplex64f( a.re - b.re, a.im - b.im );
+}
+
+inline CvComplex64f operator - (CvComplex32f a, CvComplex64f b)
+{
+ return CvComplex64f( a.re - b.re, a.im - b.im );
+}
+
+inline CvComplex64f operator * (CvComplex64f a, CvComplex32f b)
+{
+ return CvComplex64f( a.re*b.re - a.im*b.im, a.re*b.im + a.im*b.re );
+}
+
+inline CvComplex64f operator * (CvComplex32f a, CvComplex64f b)
+{
+ return CvComplex64f( a.re*b.re - a.im*b.im, a.re*b.im + a.im*b.re );
+}
+
+
+typedef CvStatus (CV_STDCALL * CvCopyMaskFunc)(const void* src, int src_step,
+ void* dst, int dst_step, CvSize size,
+ const void* mask, int mask_step);
+
+CvCopyMaskFunc icvGetCopyMaskFunc( int elem_size );
+
+CvStatus CV_STDCALL icvSetZero_8u_C1R( uchar* dst, int dststep, CvSize size );
+
+CvStatus CV_STDCALL icvScale_32f( const float* src, float* dst, int len, float a, float b );
+CvStatus CV_STDCALL icvScale_64f( const double* src, double* dst, int len, double a, double b );
+
+CvStatus CV_STDCALL icvLUT_Transform8u_8u_C1R( const uchar* src, int srcstep, uchar* dst,
+ int dststep, CvSize size, const uchar* lut );
+CvStatus CV_STDCALL icvLUT_Transform8u_16u_C1R( const uchar* src, int srcstep, ushort* dst,
+ int dststep, CvSize size, const ushort* lut );
+CvStatus CV_STDCALL icvLUT_Transform8u_32s_C1R( const uchar* src, int srcstep, int* dst,
+ int dststep, CvSize size, const int* lut );
+CvStatus CV_STDCALL icvLUT_Transform8u_64f_C1R( const uchar* src, int srcstep, double* dst,
+ int dststep, CvSize size, const double* lut );
+
+CvStatus CV_STDCALL icvLUT_Transform8u_8u_C2R( const uchar* src, int srcstep, uchar* dst,
+ int dststep, CvSize size, const uchar* lut );
+CvStatus CV_STDCALL icvLUT_Transform8u_8u_C3R( const uchar* src, int srcstep, uchar* dst,
+ int dststep, CvSize size, const uchar* lut );
+CvStatus CV_STDCALL icvLUT_Transform8u_8u_C4R( const uchar* src, int srcstep, uchar* dst,
+ int dststep, CvSize size, const uchar* lut );
+
+typedef CvStatus (CV_STDCALL * CvLUT_TransformFunc)( const void* src, int srcstep, void* dst,
+ int dststep, CvSize size, const void* lut );
+
+CV_INLINE CvStatus
+icvLUT_Transform8u_8s_C1R( const uchar* src, int srcstep, schar* dst,
+ int dststep, CvSize size, const schar* lut )
+{
+ return icvLUT_Transform8u_8u_C1R( src, srcstep, (uchar*)dst,
+ dststep, size, (const uchar*)lut );
+}
+
+CV_INLINE CvStatus
+icvLUT_Transform8u_16s_C1R( const uchar* src, int srcstep, short* dst,
+ int dststep, CvSize size, const short* lut )
+{
+ return icvLUT_Transform8u_16u_C1R( src, srcstep, (ushort*)dst,
+ dststep, size, (const ushort*)lut );
+}
+
+CV_INLINE CvStatus
+icvLUT_Transform8u_32f_C1R( const uchar* src, int srcstep, float* dst,
+ int dststep, CvSize size, const float* lut )
+{
+ return icvLUT_Transform8u_32s_C1R( src, srcstep, (int*)dst,
+ dststep, size, (const int*)lut );
+}
+
+#endif /*_CXCORE_INTERNAL_H_*/
diff --git a/cxcore/src/_cxipp.h b/cxcore/src/_cxipp.h
new file mode 100644
index 0000000..1d30ef5
--- /dev/null
+++ b/cxcore/src/_cxipp.h
@@ -0,0 +1,646 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _CXCORE_IPP_H_
+#define _CXCORE_IPP_H_
+
+/****************************************************************************************\
+* Copy/Set *
+\****************************************************************************************/
+
+/* temporary disable ipp zero and copy functions as they affect subsequent functions' performance */
+IPCVAPI_EX( CvStatus, icvCopy_8u_C1R, "ippiCopy_8u_C1R", 0/*CV_PLUGINS1(CV_PLUGIN_IPPI)*/,
+ ( const uchar* src, int src_step,
+ uchar* dst, int dst_step, CvSize size ))
+
+IPCVAPI_EX( CvStatus, icvSetByte_8u_C1R, "ippiSet_8u_C1R", 0/*CV_PLUGINS1(CV_PLUGIN_IPPI)*/,
+ ( uchar value, uchar* dst, int dst_step, CvSize size ))
+
+IPCVAPI_EX( CvStatus, icvCvt_32f64f, "ippsConvert_32f64f",
+ CV_PLUGINS1(CV_PLUGIN_IPPS), ( const float* src, double* dst, int len ))
+IPCVAPI_EX( CvStatus, icvCvt_64f32f, "ippsConvert_64f32f",
+ CV_PLUGINS1(CV_PLUGIN_IPPS), ( const double* src, float* dst, int len ))
+
+#define IPCV_COPYSET( flavor, arrtype, scalartype ) \
+IPCVAPI_EX( CvStatus, icvCopy##flavor, "ippiCopy" #flavor, \
+ CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, CvSize size, \
+ const uchar* mask, int maskstep )) \
+IPCVAPI_EX( CvStatus, icvSet##flavor, "ippiSet" #flavor, \
+ 0/*CV_PLUGINS1(CV_PLUGIN_OPTCV)*/, \
+ ( arrtype* dst, int dststep, \
+ const uchar* mask, int maskstep, \
+ CvSize size, const arrtype* scalar ))
+
+IPCV_COPYSET( _8u_C1MR, uchar, int )
+IPCV_COPYSET( _16s_C1MR, ushort, int )
+IPCV_COPYSET( _8u_C3MR, uchar, int )
+IPCV_COPYSET( _8u_C4MR, int, int )
+IPCV_COPYSET( _16s_C3MR, ushort, int )
+IPCV_COPYSET( _16s_C4MR, int64, int64 )
+IPCV_COPYSET( _32f_C3MR, int, int )
+IPCV_COPYSET( _32f_C4MR, int, int )
+IPCV_COPYSET( _64s_C3MR, int64, int64 )
+IPCV_COPYSET( _64s_C4MR, int64, int64 )
+
+
+/****************************************************************************************\
+* Arithmetics *
+\****************************************************************************************/
+
+#define IPCV_BIN_ARITHM( name ) \
+IPCVAPI_EX( CvStatus, icv##name##_8u_C1R, \
+ "ippi" #name "_8u_C1RSfs", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+( const uchar* src1, int srcstep1, const uchar* src2, int srcstep2, \
+ uchar* dst, int dststep, CvSize size, int scalefactor )) \
+IPCVAPI_EX( CvStatus, icv##name##_16u_C1R, \
+ "ippi" #name "_16u_C1RSfs", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+( const ushort* src1, int srcstep1, const ushort* src2, int srcstep2,\
+ ushort* dst, int dststep, CvSize size, int scalefactor )) \
+IPCVAPI_EX( CvStatus, icv##name##_16s_C1R, \
+ "ippi" #name "_16s_C1RSfs", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+( const short* src1, int srcstep1, const short* src2, int srcstep2, \
+ short* dst, int dststep, CvSize size, int scalefactor )) \
+IPCVAPI_EX( CvStatus, icv##name##_32s_C1R, \
+ "ippi" #name "_32s_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+( const int* src1, int srcstep1, const int* src2, int srcstep2, \
+ int* dst, int dststep, CvSize size )) \
+IPCVAPI_EX( CvStatus, icv##name##_32f_C1R, \
+ "ippi" #name "_32f_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+( const float* src1, int srcstep1, const float* src2, int srcstep2, \
+ float* dst, int dststep, CvSize size )) \
+IPCVAPI_EX( CvStatus, icv##name##_64f_C1R, \
+ "ippi" #name "_64f_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+( const double* src1, int srcstep1, const double* src2, int srcstep2,\
+ double* dst, int dststep, CvSize size ))
+
+
+IPCV_BIN_ARITHM( Add )
+IPCV_BIN_ARITHM( Sub )
+
+#undef IPCV_BIN_ARITHM
+
+/****************************************************************************************\
+* Logical operations *
+\****************************************************************************************/
+
+#define IPCV_LOGIC( name ) \
+IPCVAPI_EX( CvStatus, icv##name##_8u_C1R, \
+ "ippi" #name "_8u_C1R", 0/*CV_PLUGINS1(CV_PLUGIN_IPPI)*/, \
+( const uchar* src1, int srcstep1, const uchar* src2, int srcstep2, \
+ uchar* dst, int dststep, CvSize size ))
+
+IPCV_LOGIC( And )
+IPCV_LOGIC( Or )
+IPCV_LOGIC( Xor )
+
+#undef IPCV_LOGIC
+
+IPCVAPI_EX( CvStatus, icvNot_8u_C1R, "ippiNot_8u_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI),
+( const uchar* src, int step1, uchar* dst, int step, CvSize size ))
+
+/****************************************************************************************\
+* Image Statistics *
+\****************************************************************************************/
+
+///////////////////////////////////////// Mean //////////////////////////////////////////
+
+#define IPCV_DEF_MEAN_MASK( flavor, srctype ) \
+IPCVAPI_EX( CvStatus, icvMean_##flavor##_C1MR, \
+"ippiMean_" #flavor "_C1MR", CV_PLUGINS1(CV_PLUGIN_IPPCV), \
+( const srctype* img, int imgstep, const uchar* mask, \
+ int maskStep, CvSize size, double* mean )) \
+IPCVAPI_EX( CvStatus, icvMean_##flavor##_C2MR, \
+"ippiMean_" #flavor "_C2MR", 0/*CV_PLUGINS1(CV_PLUGIN_OPTCV)*/, \
+( const srctype* img, int imgstep, const uchar* mask, \
+ int maskStep, CvSize size, double* mean )) \
+IPCVAPI_EX( CvStatus, icvMean_##flavor##_C3MR, \
+"ippiMean_" #flavor "_C3MR", 0/*CV_PLUGINS1(CV_PLUGIN_OPTCV)*/, \
+( const srctype* img, int imgstep, const uchar* mask, \
+ int maskStep, CvSize size, double* mean )) \
+IPCVAPI_EX( CvStatus, icvMean_##flavor##_C4MR, \
+"ippiMean_" #flavor "_C4MR", 0/*CV_PLUGINS1(CV_PLUGIN_OPTCV)*/, \
+( const srctype* img, int imgstep, const uchar* mask, \
+ int maskStep, CvSize size, double* mean ))
+
+IPCV_DEF_MEAN_MASK( 8u, uchar )
+IPCV_DEF_MEAN_MASK( 16u, ushort )
+IPCV_DEF_MEAN_MASK( 16s, short )
+IPCV_DEF_MEAN_MASK( 32s, int )
+IPCV_DEF_MEAN_MASK( 32f, float )
+IPCV_DEF_MEAN_MASK( 64f, double )
+
+#undef IPCV_DEF_MEAN_MASK
+
+//////////////////////////////////// Mean_StdDev ////////////////////////////////////////
+
+#undef IPCV_MEAN_SDV_PLUGIN
+#define ICV_MEAN_SDV_PLUGIN 0 /* CV_PLUGINS1(IPPCV) */
+
+#define IPCV_DEF_MEAN_SDV( flavor, srctype ) \
+IPCVAPI_EX( CvStatus, icvMean_StdDev_##flavor##_C1R, \
+"ippiMean_StdDev_" #flavor "_C1R", ICV_MEAN_SDV_PLUGIN, \
+( const srctype* img, int imgstep, CvSize size, double* mean, double* sdv ))\
+IPCVAPI_EX( CvStatus, icvMean_StdDev_##flavor##_C2R, \
+"ippiMean_StdDev_" #flavor "_C2R", ICV_MEAN_SDV_PLUGIN, \
+( const srctype* img, int imgstep, CvSize size, double* mean, double* sdv ))\
+IPCVAPI_EX( CvStatus, icvMean_StdDev_##flavor##_C3R, \
+"ippiMean_StdDev_" #flavor "_C3R", ICV_MEAN_SDV_PLUGIN, \
+( const srctype* img, int imgstep, CvSize size, double* mean, double* sdv ))\
+IPCVAPI_EX( CvStatus, icvMean_StdDev_##flavor##_C4R, \
+"ippiMean_StdDev_" #flavor "_C4R", ICV_MEAN_SDV_PLUGIN, \
+( const srctype* img, int imgstep, CvSize size, double* mean, double* sdv ))\
+ \
+IPCVAPI_EX( CvStatus, icvMean_StdDev_##flavor##_C1MR, \
+"ippiMean_StdDev_" #flavor "_C1MR", ICV_MEAN_SDV_PLUGIN, \
+( const srctype* img, int imgstep, \
+ const uchar* mask, int maskStep, \
+ CvSize size, double* mean, double* sdv )) \
+IPCVAPI_EX( CvStatus, icvMean_StdDev_##flavor##_C2MR, \
+"ippiMean_StdDev_" #flavor "_C2MR", ICV_MEAN_SDV_PLUGIN, \
+( const srctype* img, int imgstep, const uchar* mask, int maskStep, \
+ CvSize size, double* mean, double* sdv )) \
+IPCVAPI_EX( CvStatus, icvMean_StdDev_##flavor##_C3MR, \
+"ippiMean_StdDev_" #flavor "_C3MR", ICV_MEAN_SDV_PLUGIN, \
+( const srctype* img, int imgstep, \
+ const uchar* mask, int maskStep, \
+ CvSize size, double* mean, double* sdv )) \
+IPCVAPI_EX( CvStatus, icvMean_StdDev_##flavor##_C4MR, \
+"ippiMean_StdDev_" #flavor "_C4MR", ICV_MEAN_SDV_PLUGIN, \
+( const srctype* img, int imgstep, \
+ const uchar* mask, int maskStep, \
+ CvSize size, double* mean, double* sdv ))
+
+IPCV_DEF_MEAN_SDV( 8u, uchar )
+IPCV_DEF_MEAN_SDV( 16u, ushort )
+IPCV_DEF_MEAN_SDV( 16s, short )
+IPCV_DEF_MEAN_SDV( 32s, int )
+IPCV_DEF_MEAN_SDV( 32f, float )
+IPCV_DEF_MEAN_SDV( 64f, double )
+
+#undef IPCV_DEF_MEAN_SDV
+#undef IPCV_MEAN_SDV_PLUGIN
+
+//////////////////////////////////// MinMaxIndx /////////////////////////////////////////
+
+#define IPCV_DEF_MIN_MAX_LOC( flavor, srctype, extrtype, plugin ) \
+IPCVAPI_EX( CvStatus, icvMinMaxIndx_##flavor##_C1R, \
+"ippiMinMaxIndx_" #flavor "_C1R", plugin, \
+( const srctype* img, int imgstep, \
+ CvSize size, extrtype* minVal, extrtype* maxVal, \
+ CvPoint* minLoc, CvPoint* maxLoc )) \
+ \
+IPCVAPI_EX( CvStatus, icvMinMaxIndx_##flavor##_C1MR, \
+"ippiMinMaxIndx_" #flavor "_C1MR", plugin, \
+( const srctype* img, int imgstep, \
+ const uchar* mask, int maskStep, \
+ CvSize size, extrtype* minVal, extrtype* maxVal, \
+ CvPoint* minLoc, CvPoint* maxLoc ))
+
+IPCV_DEF_MIN_MAX_LOC( 8u, uchar, float, CV_PLUGINS1(CV_PLUGIN_IPPCV) )
+IPCV_DEF_MIN_MAX_LOC( 16u, ushort, float, 0 )
+IPCV_DEF_MIN_MAX_LOC( 16s, short, float, CV_PLUGINS1(CV_PLUGIN_IPPCV) )
+IPCV_DEF_MIN_MAX_LOC( 32s, int, double, 0 )
+#if !defined WIN64 && (defined WIN32 || defined __i386__)
+IPCV_DEF_MIN_MAX_LOC( 32f, int, float, CV_PLUGINS1(CV_PLUGIN_IPPCV) )
+#else
+IPCV_DEF_MIN_MAX_LOC( 32f, int, float, 0 )
+#endif
+IPCV_DEF_MIN_MAX_LOC( 64f, int64, double, 0 )
+
+#undef IPCV_DEF_MIN_MAX_LOC
+
+////////////////////////////////////////// Sum //////////////////////////////////////////
+
+#define IPCV_DEF_SUM_NOHINT( flavor, srctype, plugin ) \
+IPCVAPI_EX( CvStatus, icvSum_##flavor##_C1R, \
+ "ippiSum_" #flavor "_C1R", plugin, \
+ ( const srctype* img, int imgstep, CvSize size, double* sum )) \
+IPCVAPI_EX( CvStatus, icvSum_##flavor##_C2R, \
+ "ippiSum_" #flavor "_C2R", plugin, \
+ ( const srctype* img, int imgstep, CvSize size, double* sum )) \
+IPCVAPI_EX( CvStatus, icvSum_##flavor##_C3R, \
+ "ippiSum_" #flavor "_C3R", plugin, \
+ ( const srctype* img, int imgstep, CvSize size, double* sum )) \
+IPCVAPI_EX( CvStatus, icvSum_##flavor##_C4R, \
+ "ippiSum_" #flavor "_C4R", plugin, \
+ ( const srctype* img, int imgstep, CvSize size, double* sum ))
+
+#define IPCV_DEF_SUM_HINT( flavor, srctype ) \
+IPCVAPI_EX( CvStatus, icvSum_##flavor##_C1R, \
+ "ippiSum_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const srctype* img, int imgstep, \
+ CvSize size, double* sum, CvHintAlgorithm )) \
+IPCVAPI_EX( CvStatus, icvSum_##flavor##_C2R, \
+ "ippiSum_" #flavor "_C2R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const srctype* img, int imgstep, \
+ CvSize size, double* sum, CvHintAlgorithm )) \
+IPCVAPI_EX( CvStatus, icvSum_##flavor##_C3R, \
+ "ippiSum_" #flavor "_C3R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const srctype* img, int imgstep, \
+ CvSize size, double* sum, CvHintAlgorithm )) \
+IPCVAPI_EX( CvStatus, icvSum_##flavor##_C4R, \
+ "ippiSum_" #flavor "_C4R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const srctype* img, int imgstep, \
+ CvSize size, double* sum, CvHintAlgorithm ))
+
+IPCV_DEF_SUM_NOHINT( 8u, uchar, CV_PLUGINS1(CV_PLUGIN_IPPI) )
+IPCV_DEF_SUM_NOHINT( 16s, short, CV_PLUGINS1(CV_PLUGIN_IPPI) )
+IPCV_DEF_SUM_NOHINT( 16u, ushort, 0 )
+IPCV_DEF_SUM_NOHINT( 32s, int, 0 )
+IPCV_DEF_SUM_HINT( 32f, float )
+IPCV_DEF_SUM_NOHINT( 64f, double, 0 )
+
+#undef IPCV_DEF_SUM_NOHINT
+#undef IPCV_DEF_SUM_HINT
+
+////////////////////////////////////////// CountNonZero /////////////////////////////////
+
+#define IPCV_DEF_NON_ZERO( flavor, srctype ) \
+IPCVAPI_EX( CvStatus, icvCountNonZero_##flavor##_C1R, \
+ "ippiCountNonZero_" #flavor "_C1R", 0/*CV_PLUGINS1(CV_PLUGIN_OPTCV)*/, \
+ ( const srctype* img, int imgstep, CvSize size, int* nonzero ))
+
+IPCV_DEF_NON_ZERO( 8u, uchar )
+IPCV_DEF_NON_ZERO( 16s, ushort )
+IPCV_DEF_NON_ZERO( 32s, int )
+IPCV_DEF_NON_ZERO( 32f, int )
+IPCV_DEF_NON_ZERO( 64f, int64 )
+
+#undef IPCV_DEF_NON_ZERO
+
+////////////////////////////////////////// Norms /////////////////////////////////
+
+#define IPCV_DEF_NORM_NOHINT_C1( flavor, srctype, plugin ) \
+IPCVAPI_EX( CvStatus, icvNorm_Inf_##flavor##_C1R, \
+ "ippiNorm_Inf_" #flavor "_C1R", plugin, \
+ ( const srctype* img, int imgstep, CvSize size, double* norm )) \
+IPCVAPI_EX( CvStatus, icvNorm_L1_##flavor##_C1R, \
+ "ippiNorm_L1_" #flavor "_C1R", plugin, \
+ ( const srctype* img, int imgstep, CvSize size, double* norm )) \
+IPCVAPI_EX( CvStatus, icvNorm_L2_##flavor##_C1R, \
+ "ippiNorm_L2_" #flavor "_C1R", plugin, \
+ ( const srctype* img, int imgstep, CvSize size, double* norm )) \
+IPCVAPI_EX( CvStatus, icvNormDiff_Inf_##flavor##_C1R, \
+ "ippiNormDiff_Inf_" #flavor "_C1R", plugin, \
+ ( const srctype* img1, int imgstep1, \
+ const srctype* img2, int imgstep2, \
+ CvSize size, double* norm )) \
+IPCVAPI_EX( CvStatus, icvNormDiff_L1_##flavor##_C1R, \
+ "ippiNormDiff_L1_" #flavor "_C1R", plugin, \
+ ( const srctype* img1, int imgstep1, \
+ const srctype* img2, int imgstep2, \
+ CvSize size, double* norm )) \
+IPCVAPI_EX( CvStatus, icvNormDiff_L2_##flavor##_C1R, \
+ "ippiNormDiff_L2_" #flavor "_C1R", plugin, \
+ ( const srctype* img1, int imgstep1, \
+ const srctype* img2, int imgstep2, \
+ CvSize size, double* norm ))
+
+#define IPCV_DEF_NORM_HINT_C1( flavor, srctype ) \
+IPCVAPI_EX( CvStatus, icvNorm_Inf_##flavor##_C1R, \
+ "ippiNorm_Inf_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const srctype* img, int imgstep, \
+ CvSize size, double* norm )) \
+IPCVAPI_EX( CvStatus, icvNorm_L1_##flavor##_C1R, \
+ "ippiNorm_L1_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const srctype* img, int imgstep, \
+ CvSize size, double* norm, CvHintAlgorithm )) \
+IPCVAPI_EX( CvStatus, icvNorm_L2_##flavor##_C1R, \
+ "ippiNorm_L2_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const srctype* img, int imgstep, \
+ CvSize size, double* norm, CvHintAlgorithm )) \
+IPCVAPI_EX( CvStatus, icvNormDiff_Inf_##flavor##_C1R, \
+ "ippiNormDiff_Inf_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const srctype* img1, int imgstep1, \
+ const srctype* img2, int imgstep2, \
+ CvSize size, double* norm )) \
+IPCVAPI_EX( CvStatus, icvNormDiff_L1_##flavor##_C1R, \
+ "ippiNormDiff_L1_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const srctype* img1, int imgstep1, \
+ const srctype* img2, int imgstep2, \
+ CvSize size, double* norm, CvHintAlgorithm )) \
+IPCVAPI_EX( CvStatus, icvNormDiff_L2_##flavor##_C1R, \
+ "ippiNormDiff_L2_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const srctype* img1, int imgstep1, \
+ const srctype* img2, int imgstep2, \
+ CvSize size, double* norm, CvHintAlgorithm ))
+
+#define IPCV_DEF_NORM_MASK_C1( flavor, srctype, plugin ) \
+IPCVAPI_EX( CvStatus, icvNorm_Inf_##flavor##_C1MR, \
+ "ippiNorm_Inf_" #flavor "_C1MR", plugin, \
+ ( const srctype* img, int imgstep, \
+ const uchar* mask, int maskstep, \
+ CvSize size, double* norm )) \
+IPCVAPI_EX( CvStatus, icvNorm_L1_##flavor##_C1MR, \
+ "ippiNorm_L1_" #flavor "_C1MR", plugin, \
+ ( const srctype* img, int imgstep, \
+ const uchar* mask, int maskstep, \
+ CvSize size, double* norm )) \
+IPCVAPI_EX( CvStatus, icvNorm_L2_##flavor##_C1MR, \
+ "ippiNorm_L2_" #flavor "_C1MR", plugin, \
+ ( const srctype* img, int imgstep, \
+ const uchar* mask, int maskstep, \
+ CvSize size, double* norm )) \
+IPCVAPI_EX( CvStatus, icvNormDiff_Inf_##flavor##_C1MR, \
+ "ippiNormDiff_Inf_" #flavor "_C1MR", plugin, \
+ ( const srctype* img1, int imgstep1, \
+ const srctype* img2, int imgstep2, \
+ const uchar* mask, int maskstep, \
+ CvSize size, double* norm )) \
+IPCVAPI_EX( CvStatus, icvNormDiff_L1_##flavor##_C1MR, \
+ "ippiNormDiff_L1_" #flavor "_C1MR", plugin, \
+ ( const srctype* img1, int imgstep1, \
+ const srctype* img2, int imgstep2, \
+ const uchar* mask, int maskstep, \
+ CvSize size, double* norm )) \
+IPCVAPI_EX( CvStatus, icvNormDiff_L2_##flavor##_C1MR, \
+ "ippiNormDiff_L2_" #flavor "_C1MR", plugin, \
+ ( const srctype* img1, int imgstep1, \
+ const srctype* img2, int imgstep2, \
+ const uchar* mask, int maskstep, \
+ CvSize size, double* norm ))
+
+IPCV_DEF_NORM_NOHINT_C1( 8u, uchar, CV_PLUGINS1(CV_PLUGIN_IPPI) )
+IPCV_DEF_NORM_MASK_C1( 8u, uchar, CV_PLUGINS1(CV_PLUGIN_IPPCV) )
+
+IPCV_DEF_NORM_NOHINT_C1( 16u, ushort, 0 )
+IPCV_DEF_NORM_MASK_C1( 16u, ushort, 0 )
+
+IPCV_DEF_NORM_NOHINT_C1( 16s, short, CV_PLUGINS1(CV_PLUGIN_IPPI) )
+IPCV_DEF_NORM_MASK_C1( 16s, short, CV_PLUGINS1(CV_PLUGIN_IPPCV) )
+
+IPCV_DEF_NORM_NOHINT_C1( 32s, int, 0 )
+IPCV_DEF_NORM_MASK_C1( 32s, int, 0 )
+
+IPCV_DEF_NORM_HINT_C1( 32f, float )
+IPCV_DEF_NORM_MASK_C1( 32f, float, CV_PLUGINS1(CV_PLUGIN_IPPCV) )
+
+IPCV_DEF_NORM_NOHINT_C1( 64f, double, 0 )
+IPCV_DEF_NORM_MASK_C1( 64f, double, 0 )
+
+#undef IPCV_DEF_NORM_HONINT_C1
+#undef IPCV_DEF_NORM_HINT_C1
+#undef IPCV_DEF_NORM_MASK_C1
+
+
+////////////////////////////////////// AbsDiff ///////////////////////////////////////////
+
+#define IPCV_ABS_DIFF( flavor, arrtype ) \
+IPCVAPI_EX( CvStatus, icvAbsDiff_##flavor##_C1R, \
+"ippiAbsDiff_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPCV),\
+( const arrtype* src1, int srcstep1, \
+ const arrtype* src2, int srcstep2, \
+ arrtype* dst, int dststep, CvSize size ))
+
+IPCV_ABS_DIFF( 8u, uchar )
+IPCV_ABS_DIFF( 16u, ushort )
+IPCV_ABS_DIFF( 16s, short )
+IPCV_ABS_DIFF( 32s, int )
+IPCV_ABS_DIFF( 32f, float )
+IPCV_ABS_DIFF( 64f, double )
+
+#undef IPCV_ABS_DIFF
+
+////////////////////////////// Comparisons //////////////////////////////////////////
+
+#define IPCV_CMP( arrtype, flavor ) \
+IPCVAPI_EX( CvStatus, icvCompare_##flavor##_C1R, \
+ "ippiCompare_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const arrtype* src1, int srcstep1, const arrtype* src2, int srcstep2, \
+ arrtype* dst, int dststep, CvSize size, int cmp_op )) \
+IPCVAPI_EX( CvStatus, icvCompareC_##flavor##_C1R, \
+ "ippiCompareC_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const arrtype* src1, int srcstep1, arrtype scalar, \
+ arrtype* dst, int dststep, CvSize size, int cmp_op )) \
+IPCVAPI_EX( CvStatus, icvThreshold_GT_##flavor##_C1R, \
+ "ippiThreshold_GT_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const arrtype* pSrc, int srcstep, arrtype* pDst, int dststep, \
+ CvSize size, arrtype threshold )) \
+IPCVAPI_EX( CvStatus, icvThreshold_LT_##flavor##_C1R, \
+ "ippiThreshold_LT_" #flavor "_C1R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const arrtype* pSrc, int srcstep, arrtype* pDst, int dststep, \
+ CvSize size, arrtype threshold ))
+IPCV_CMP( uchar, 8u )
+IPCV_CMP( short, 16s )
+IPCV_CMP( float, 32f )
+#undef IPCV_CMP
+
+/****************************************************************************************\
+* Utilities *
+\****************************************************************************************/
+
+////////////////////////////// Copy Pixel <-> Plane /////////////////////////////////
+
+#define IPCV_PIX_PLANE( flavor, arrtype ) \
+IPCVAPI_EX( CvStatus, icvCopy_##flavor##_C2P2R, \
+ "ippiCopy_" #flavor "_C2P2R", 0/*CV_PLUGINS1(CV_PLUGIN_IPPI)*/, \
+ ( const arrtype* src, int srcstep, arrtype** dst, int dststep, CvSize size )) \
+IPCVAPI_EX( CvStatus, icvCopy_##flavor##_C3P3R, \
+ "ippiCopy_" #flavor "_C3P3R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const arrtype* src, int srcstep, arrtype** dst, int dststep, CvSize size )) \
+IPCVAPI_EX( CvStatus, icvCopy_##flavor##_C4P4R, \
+ "ippiCopy_" #flavor "_C4P4R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const arrtype* src, int srcstep, arrtype** dst, int dststep, CvSize size )) \
+IPCVAPI_EX( CvStatus, icvCopy_##flavor##_CnC1CR, \
+ "ippiCopy_" #flavor "_CnC1CR", 0/*CV_PLUGINS1(CV_PLUGIN_OPTCV)*/, \
+ ( const arrtype* src, int srcstep, arrtype* dst, int dststep, \
+ CvSize size, int cn, int coi )) \
+IPCVAPI_EX( CvStatus, icvCopy_##flavor##_C1CnCR, \
+ "ippiCopy_" #flavor "_CnC1CR", 0/*CV_PLUGINS1(CV_PLUGIN_OPTCV)*/, \
+ ( const arrtype* src, int srcstep, arrtype* dst, int dststep, \
+ CvSize size, int cn, int coi )) \
+IPCVAPI_EX( CvStatus, icvCopy_##flavor##_P2C2R, \
+ "ippiCopy_" #flavor "_P2C2R", 0/*CV_PLUGINS1(CV_PLUGIN_IPPI)*/, \
+ ( const arrtype** src, int srcstep, arrtype* dst, int dststep, CvSize size )) \
+IPCVAPI_EX( CvStatus, icvCopy_##flavor##_P3C3R, \
+ "ippiCopy_" #flavor "_P3C3R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const arrtype** src, int srcstep, arrtype* dst, int dststep, CvSize size )) \
+IPCVAPI_EX( CvStatus, icvCopy_##flavor##_P4C4R, \
+ "ippiCopy_" #flavor "_P4C4R", CV_PLUGINS1(CV_PLUGIN_IPPI), \
+ ( const arrtype** src, int srcstep, arrtype* dst, int dststep, CvSize size ))
+
+IPCV_PIX_PLANE( 8u, uchar )
+IPCV_PIX_PLANE( 16s, ushort )
+IPCV_PIX_PLANE( 32f, int )
+IPCV_PIX_PLANE( 64f, int64 )
+
+#undef IPCV_PIX_PLANE
+
+/****************************************************************************************/
+/* Math routines and RNGs */
+/****************************************************************************************/
+
+IPCVAPI_EX( CvStatus, icvInvSqrt_32f, "ippsInvSqrt_32f_A21",
+ CV_PLUGINS1(CV_PLUGIN_IPPVM),
+ ( const float* src, float* dst, int len ))
+IPCVAPI_EX( CvStatus, icvSqrt_32f, "ippsSqrt_32f_A21, ippsSqrt_32f",
+ CV_PLUGINS2(CV_PLUGIN_IPPVM,CV_PLUGIN_IPPS),
+ ( const float* src, float* dst, int len ))
+IPCVAPI_EX( CvStatus, icvInvSqrt_64f, "ippsInvSqrt_64f_A50",
+ CV_PLUGINS1(CV_PLUGIN_IPPVM),
+ ( const double* src, double* dst, int len ))
+IPCVAPI_EX( CvStatus, icvSqrt_64f, "ippsSqrt_64f_A50, ippsSqrt_64f",
+ CV_PLUGINS2(CV_PLUGIN_IPPVM,CV_PLUGIN_IPPS),
+ ( const double* src, double* dst, int len ))
+
+IPCVAPI_EX( CvStatus, icvLog_32f, "ippsLn_32f_A21, ippsLn_32f",
+ CV_PLUGINS2(CV_PLUGIN_IPPVM,CV_PLUGIN_IPPS),
+ ( const float *x, float *y, int n ) )
+IPCVAPI_EX( CvStatus, icvLog_64f, "ippsLn_64f_A50, ippsLn_64f",
+ CV_PLUGINS2(CV_PLUGIN_IPPVM,CV_PLUGIN_IPPS),
+ ( const double *x, double *y, int n ) )
+IPCVAPI_EX( CvStatus, icvExp_32f, "ippsExp_32f_A21, ippsExp_32f",
+ CV_PLUGINS2(CV_PLUGIN_IPPVM,CV_PLUGIN_IPPS),
+ ( const float *x, float *y, int n ) )
+IPCVAPI_EX( CvStatus, icvExp_64f, "ippsExp_64f_A50, ippsExp_64f",
+ CV_PLUGINS2(CV_PLUGIN_IPPVM,CV_PLUGIN_IPPS),
+ ( const double *x, double *y, int n ) )
+IPCVAPI_EX( CvStatus, icvFastArctan_32f, "ippibFastArctan_32f",
+ CV_PLUGINS1(CV_PLUGIN_IPPCV),
+ ( const float* y, const float* x, float* angle, int len ))
+
+/****************************************************************************************/
+/* Error handling functions */
+/****************************************************************************************/
+
+IPCVAPI_EX( CvStatus, icvCheckArray_32f_C1R,
+ "ippiCheckArray_32f_C1R", 0/*CV_PLUGINS1(CV_PLUGIN_OPTCV)*/,
+ ( const float* src, int srcstep,
+ CvSize size, int flags,
+ double min_val, double max_val ))
+
+IPCVAPI_EX( CvStatus, icvCheckArray_64f_C1R,
+ "ippiCheckArray_64f_C1R", 0/*CV_PLUGINS1(CV_PLUGIN_OPTCV)*/,
+ ( const double* src, int srcstep,
+ CvSize size, int flags,
+ double min_val, double max_val ))
+
+/****************************************************************************************/
+/* Affine transformations of matrix/image elements */
+/****************************************************************************************/
+
+#define IPCV_TRANSFORM( suffix, ipp_suffix, cn ) \
+IPCVAPI_EX( CvStatus, icvColorTwist##suffix##_C##cn##R, \
+ "ippiColorTwist" #ipp_suffix "_C" #cn \
+ "R,ippiColorTwist" #ipp_suffix "_C" #cn "R", \
+ CV_PLUGINS2(CV_PLUGIN_IPPI, CV_PLUGIN_IPPCC), \
+ ( const void* src, int srcstep, void* dst, int dststep, \
+ CvSize roisize, const float* twist_matrix ))
+
+IPCV_TRANSFORM( _8u, 32f_8u, 3 )
+IPCV_TRANSFORM( _16u, 32f_16u, 3 )
+IPCV_TRANSFORM( _16s, 32f_16s, 3 )
+IPCV_TRANSFORM( _32f, _32f, 3 )
+IPCV_TRANSFORM( _32f, _32f, 4 )
+
+#undef IPCV_TRANSFORM
+
+#define IPCV_TRANSFORM_N1( suffix ) \
+IPCVAPI_EX( CvStatus, icvColorToGray##suffix, \
+ "ippiColorToGray" #suffix ",ippiColorToGray" #suffix, \
+ CV_PLUGINS2(CV_PLUGIN_IPPI,CV_PLUGIN_IPPCC), \
+ ( const void* src, int srcstep, void* dst, int dststep, \
+ CvSize roisize, const float* coeffs ))
+
+IPCV_TRANSFORM_N1( _8u_C3C1R )
+IPCV_TRANSFORM_N1( _16u_C3C1R )
+IPCV_TRANSFORM_N1( _16s_C3C1R )
+IPCV_TRANSFORM_N1( _32f_C3C1R )
+IPCV_TRANSFORM_N1( _8u_AC4C1R )
+IPCV_TRANSFORM_N1( _16u_AC4C1R )
+IPCV_TRANSFORM_N1( _16s_AC4C1R )
+IPCV_TRANSFORM_N1( _32f_AC4C1R )
+
+#undef IPCV_TRANSFORM_N1
+
+/****************************************************************************************/
+/* Matrix routines from BLAS/LAPACK compatible libraries */
+/****************************************************************************************/
+
+IPCVAPI_C_EX( void, icvBLAS_GEMM_32f, "sgemm, mkl_sgemm", CV_PLUGINS2(CV_PLUGIN_MKL,CV_PLUGIN_MKL),
+ (const char *transa, const char *transb, int *n, int *m, int *k,
+ const void *alpha, const void *a, int *lda, const void *b, int *ldb,
+ const void *beta, void *c, int *ldc ))
+
+IPCVAPI_C_EX( void, icvBLAS_GEMM_64f, "dgemm, mkl_dgemm", CV_PLUGINS2(CV_PLUGIN_MKL,CV_PLUGIN_MKL),
+ (const char *transa, const char *transb, int *n, int *m, int *k,
+ const void *alpha, const void *a, int *lda, const void *b, int *ldb,
+ const void *beta, void *c, int *ldc ))
+
+IPCVAPI_C_EX( void, icvBLAS_GEMM_32fc, "cgemm, mkl_cgemm", CV_PLUGINS2(CV_PLUGIN_MKL,CV_PLUGIN_MKL),
+ (const char *transa, const char *transb, int *n, int *m, int *k,
+ const void *alpha, const void *a, int *lda, const void *b, int *ldb,
+ const void *beta, void *c, int *ldc ))
+
+IPCVAPI_C_EX( void, icvBLAS_GEMM_64fc, "zgemm, mkl_zgemm", CV_PLUGINS2(CV_PLUGIN_MKL,CV_PLUGIN_MKL),
+ (const char *transa, const char *transb, int *n, int *m, int *k,
+ const void *alpha, const void *a, int *lda, const void *b, int *ldb,
+ const void *beta, void *c, int *ldc ))
+
+
+#define IPCV_DFT( init_flavor, fwd_flavor, inv_flavor ) \
+IPCVAPI_EX( CvStatus, icvDFTInitAlloc_##init_flavor, "ippsDFTInitAlloc_" #init_flavor, \
+ CV_PLUGINS1(CV_PLUGIN_IPPS), ( void**, int, int, CvHintAlgorithm )) \
+ \
+IPCVAPI_EX( CvStatus, icvDFTFree_##init_flavor, "ippsDFTFree_" #init_flavor, \
+ CV_PLUGINS1(CV_PLUGIN_IPPS), ( void* )) \
+ \
+IPCVAPI_EX( CvStatus, icvDFTGetBufSize_##init_flavor, "ippsDFTGetBufSize_" #init_flavor,\
+ CV_PLUGINS1(CV_PLUGIN_IPPS), ( const void* spec, int* buf_size )) \
+ \
+IPCVAPI_EX( CvStatus, icvDFTFwd_##fwd_flavor, "ippsDFTFwd_" #fwd_flavor, \
+ CV_PLUGINS1(CV_PLUGIN_IPPS), ( const void* src, void* dst, \
+ const void* spec, void* buffer )) \
+ \
+IPCVAPI_EX( CvStatus, icvDFTInv_##inv_flavor, "ippsDFTInv_" #inv_flavor, \
+ CV_PLUGINS1(CV_PLUGIN_IPPS), ( const void* src, void* dst, \
+ const void* spec, void* buffer ))
+
+IPCV_DFT( C_32fc, CToC_32fc, CToC_32fc )
+IPCV_DFT( R_32f, RToPack_32f, PackToR_32f )
+IPCV_DFT( C_64fc, CToC_64fc, CToC_64fc )
+IPCV_DFT( R_64f, RToPack_64f, PackToR_64f )
+#undef IPCV_DFT
+
+#endif /*_CXCORE_IPP_H_*/
+
diff --git a/cxcore/src/cxalloc.cpp b/cxcore/src/cxalloc.cpp
new file mode 100644
index 0000000..8f60a6c
--- /dev/null
+++ b/cxcore/src/cxalloc.cpp
@@ -0,0 +1,135 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+
+// default <malloc>
+static void*
+icvDefaultAlloc( size_t size, void* )
+{
+ char *ptr, *ptr0 = (char*)malloc(
+ (size_t)(size + CV_MALLOC_ALIGN*((size >= 4096) + 1) + sizeof(char*)));
+
+ if( !ptr0 )
+ return 0;
+
+ // align the pointer
+ ptr = (char*)cvAlignPtr(ptr0 + sizeof(char*) + 1, CV_MALLOC_ALIGN);
+ *(char**)(ptr - sizeof(char*)) = ptr0;
+
+ return ptr;
+}
+
+
+// default <free>
+static int
+icvDefaultFree( void* ptr, void* )
+{
+ // Pointer must be aligned by CV_MALLOC_ALIGN
+ if( ((size_t)ptr & (CV_MALLOC_ALIGN-1)) != 0 )
+ return CV_BADARG_ERR;
+ free( *((char**)ptr - 1) );
+
+ return CV_OK;
+}
+
+
+// pointers to allocation functions, initially set to default
+static CvAllocFunc p_cvAlloc = icvDefaultAlloc;
+static CvFreeFunc p_cvFree = icvDefaultFree;
+static void* p_cvAllocUserData = 0;
+
+CV_IMPL void cvSetMemoryManager( CvAllocFunc alloc_func, CvFreeFunc free_func, void* userdata )
+{
+ CV_FUNCNAME( "cvSetMemoryManager" );
+
+ __BEGIN__;
+
+ if( (alloc_func == 0) ^ (free_func == 0) )
+ CV_ERROR( CV_StsNullPtr, "Either both pointers should be NULL or none of them");
+
+ p_cvAlloc = alloc_func ? alloc_func : icvDefaultAlloc;
+ p_cvFree = free_func ? free_func : icvDefaultFree;
+ p_cvAllocUserData = userdata;
+
+ __END__;
+}
+
+
+CV_IMPL void* cvAlloc( size_t size )
+{
+ void* ptr = 0;
+
+ CV_FUNCNAME( "cvAlloc" );
+
+ __BEGIN__;
+
+ if( (size_t)size > CV_MAX_ALLOC_SIZE )
+ CV_ERROR( CV_StsOutOfRange,
+ "Negative or too large argument of cvAlloc function" );
+
+ ptr = p_cvAlloc( size, p_cvAllocUserData );
+ if( !ptr )
+ CV_ERROR( CV_StsNoMem, "Out of memory" );
+
+ __END__;
+
+ return ptr;
+}
+
+
+CV_IMPL void cvFree_( void* ptr )
+{
+ CV_FUNCNAME( "cvFree_" );
+
+ __BEGIN__;
+
+ if( ptr )
+ {
+ CVStatus status = p_cvFree( ptr, p_cvAllocUserData );
+ if( status < 0 )
+ CV_ERROR( status, "Deallocation error" );
+ }
+
+ __END__;
+}
+
+/* End of file. */
diff --git a/cxcore/src/cxarithm.cpp b/cxcore/src/cxarithm.cpp
new file mode 100644
index 0000000..e314093
--- /dev/null
+++ b/cxcore/src/cxarithm.cpp
@@ -0,0 +1,2050 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/* ////////////////////////////////////////////////////////////////////
+//
+// CvMat arithmetic operations: +, - ...
+//
+// */
+
+#include "_cxcore.h"
+
+/****************************************************************************************\
+* Arithmetic operations (+, -) without mask *
+\****************************************************************************************/
+
+#define ICV_DEF_BIN_ARI_OP_CASE( __op__, worktype, cast_macro, len )\
+{ \
+ int i; \
+ \
+ for( i = 0; i <= (len) - 4; i += 4 ) \
+ { \
+ worktype t0 = __op__((src1)[i], (src2)[i]); \
+ worktype t1 = __op__((src1)[i+1], (src2)[i+1]); \
+ \
+ (dst)[i] = cast_macro( t0 ); \
+ (dst)[i+1] = cast_macro( t1 ); \
+ \
+ t0 = __op__((src1)[i+2],(src2)[i+2]); \
+ t1 = __op__((src1)[i+3],(src2)[i+3]); \
+ \
+ (dst)[i+2] = cast_macro( t0 ); \
+ (dst)[i+3] = cast_macro( t1 ); \
+ } \
+ \
+ for( ; i < (len); i++ ) \
+ { \
+ worktype t0 = __op__((src1)[i],(src2)[i]); \
+ (dst)[i] = cast_macro( t0 ); \
+ } \
+}
+
+#define ICV_DEF_BIN_ARI_OP_2D( __op__, name, type, worktype, cast_macro ) \
+IPCVAPI_IMPL( CvStatus, name, \
+ ( const type* src1, int step1, const type* src2, int step2, \
+ type* dst, int step, CvSize size ), \
+ (src1, step1, src2, step2, dst, step, size) ) \
+{ \
+ step1/=sizeof(src1[0]); step2/=sizeof(src2[0]); step/=sizeof(dst[0]); \
+ \
+ if( size.width == 1 ) \
+ { \
+ for( ; size.height--; src1 += step1, src2 += step2, dst += step ) \
+ { \
+ worktype t0 = __op__((src1)[0],(src2)[0]); \
+ (dst)[0] = cast_macro( t0 ); \
+ } \
+ } \
+ else \
+ { \
+ for( ; size.height--; src1 += step1, src2 += step2, dst += step ) \
+ { \
+ ICV_DEF_BIN_ARI_OP_CASE( __op__, worktype, \
+ cast_macro, size.width ); \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_BIN_ARI_OP_2D_SFS(__op__, name, type, worktype, cast_macro) \
+IPCVAPI_IMPL( CvStatus, name, \
+ ( const type* src1, int step1, const type* src2, int step2, \
+ type* dst, int step, CvSize size, int /*scalefactor*/ ), \
+ (src1, step1, src2, step2, dst, step, size, 0) ) \
+{ \
+ step1/=sizeof(src1[0]); step2/=sizeof(src2[0]); step/=sizeof(dst[0]); \
+ \
+ if( size.width == 1 ) \
+ { \
+ for( ; size.height--; src1 += step1, src2 += step2, dst += step ) \
+ { \
+ worktype t0 = __op__((src1)[0],(src2)[0]); \
+ (dst)[0] = cast_macro( t0 ); \
+ } \
+ } \
+ else \
+ { \
+ for( ; size.height--; src1 += step1, src2 += step2, dst += step ) \
+ { \
+ ICV_DEF_BIN_ARI_OP_CASE( __op__, worktype, \
+ cast_macro, size.width ); \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_UN_ARI_OP_CASE( __op__, worktype, cast_macro, \
+ src, scalar, dst, len ) \
+{ \
+ int i; \
+ \
+ for( ; ((len) -= 12) >= 0; (dst) += 12, (src) += 12 ) \
+ { \
+ worktype t0 = __op__((scalar)[0], (src)[0]); \
+ worktype t1 = __op__((scalar)[1], (src)[1]); \
+ \
+ (dst)[0] = cast_macro( t0 ); \
+ (dst)[1] = cast_macro( t1 ); \
+ \
+ t0 = __op__((scalar)[2], (src)[2]); \
+ t1 = __op__((scalar)[3], (src)[3]); \
+ \
+ (dst)[2] = cast_macro( t0 ); \
+ (dst)[3] = cast_macro( t1 ); \
+ \
+ t0 = __op__((scalar)[4], (src)[4]); \
+ t1 = __op__((scalar)[5], (src)[5]); \
+ \
+ (dst)[4] = cast_macro( t0 ); \
+ (dst)[5] = cast_macro( t1 ); \
+ \
+ t0 = __op__((scalar)[6], (src)[6]); \
+ t1 = __op__((scalar)[7], (src)[7]); \
+ \
+ (dst)[6] = cast_macro( t0 ); \
+ (dst)[7] = cast_macro( t1 ); \
+ \
+ t0 = __op__((scalar)[8], (src)[8]); \
+ t1 = __op__((scalar)[9], (src)[9]); \
+ \
+ (dst)[8] = cast_macro( t0 ); \
+ (dst)[9] = cast_macro( t1 ); \
+ \
+ t0 = __op__((scalar)[10], (src)[10]); \
+ t1 = __op__((scalar)[11], (src)[11]); \
+ \
+ (dst)[10] = cast_macro( t0 ); \
+ (dst)[11] = cast_macro( t1 ); \
+ } \
+ \
+ for( (len) += 12, i = 0; i < (len); i++ ) \
+ { \
+ worktype t0 = __op__((scalar)[i],(src)[i]); \
+ (dst)[i] = cast_macro( t0 ); \
+ } \
+}
+
+
+#define ICV_DEF_UN_ARI_OP_2D( __op__, name, type, worktype, cast_macro ) \
+static CvStatus CV_STDCALL name \
+ ( const type* src, int step1, type* dst, int step, \
+ CvSize size, const worktype* scalar ) \
+{ \
+ step1 /= sizeof(src[0]); step /= sizeof(dst[0]); \
+ \
+ if( size.width == 1 ) \
+ { \
+ for( ; size.height--; src += step1, dst += step ) \
+ { \
+ worktype t0 = __op__(*(scalar),*(src)); \
+ *(dst) = cast_macro( t0 ); \
+ } \
+ } \
+ else \
+ { \
+ for( ; size.height--; src += step1, dst += step ) \
+ { \
+ const type *tsrc = src; \
+ type *tdst = dst; \
+ int width = size.width; \
+ \
+ ICV_DEF_UN_ARI_OP_CASE( __op__, worktype, cast_macro, \
+ tsrc, scalar, tdst, width ); \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_BIN_ARI_ALL( __op__, name, cast_8u ) \
+ICV_DEF_BIN_ARI_OP_2D_SFS( __op__, icv##name##_8u_C1R, uchar, int, cast_8u ) \
+ICV_DEF_BIN_ARI_OP_2D_SFS( __op__, icv##name##_16u_C1R, ushort, int, CV_CAST_16U ) \
+ICV_DEF_BIN_ARI_OP_2D_SFS( __op__, icv##name##_16s_C1R, short, int, CV_CAST_16S ) \
+ICV_DEF_BIN_ARI_OP_2D( __op__, icv##name##_32s_C1R, int, int, CV_CAST_32S ) \
+ICV_DEF_BIN_ARI_OP_2D( __op__, icv##name##_32f_C1R, float, float, CV_CAST_32F ) \
+ICV_DEF_BIN_ARI_OP_2D( __op__, icv##name##_64f_C1R, double, double, CV_CAST_64F )
+
+#define ICV_DEF_UN_ARI_ALL( __op__, name ) \
+ICV_DEF_UN_ARI_OP_2D( __op__, icv##name##_8u_C1R, uchar, int, CV_CAST_8U ) \
+ICV_DEF_UN_ARI_OP_2D( __op__, icv##name##_16u_C1R, ushort, int, CV_CAST_16U ) \
+ICV_DEF_UN_ARI_OP_2D( __op__, icv##name##_16s_C1R, short, int, CV_CAST_16S ) \
+ICV_DEF_UN_ARI_OP_2D( __op__, icv##name##_32s_C1R, int, int, CV_CAST_32S ) \
+ICV_DEF_UN_ARI_OP_2D( __op__, icv##name##_32f_C1R, float, float, CV_CAST_32F ) \
+ICV_DEF_UN_ARI_OP_2D( __op__, icv##name##_64f_C1R, double, double, CV_CAST_64F )
+
+#undef CV_SUB_R
+#define CV_SUB_R(a,b) ((b) - (a))
+
+ICV_DEF_BIN_ARI_ALL( CV_ADD, Add, CV_FAST_CAST_8U )
+ICV_DEF_BIN_ARI_ALL( CV_SUB_R, Sub, CV_FAST_CAST_8U )
+
+ICV_DEF_UN_ARI_ALL( CV_ADD, AddC )
+ICV_DEF_UN_ARI_ALL( CV_SUB, SubRC )
+
+#define ICV_DEF_INIT_ARITHM_FUNC_TAB( FUNCNAME, FLAG ) \
+static void icvInit##FUNCNAME##FLAG##Table( CvFuncTable* tab )\
+{ \
+ tab->fn_2d[CV_8U] = (void*)icv##FUNCNAME##_8u_##FLAG; \
+ tab->fn_2d[CV_8S] = 0; \
+ tab->fn_2d[CV_16U] = (void*)icv##FUNCNAME##_16u_##FLAG; \
+ tab->fn_2d[CV_16S] = (void*)icv##FUNCNAME##_16s_##FLAG; \
+ tab->fn_2d[CV_32S] = (void*)icv##FUNCNAME##_32s_##FLAG; \
+ tab->fn_2d[CV_32F] = (void*)icv##FUNCNAME##_32f_##FLAG; \
+ tab->fn_2d[CV_64F] = (void*)icv##FUNCNAME##_64f_##FLAG; \
+}
+
+ICV_DEF_INIT_ARITHM_FUNC_TAB( Sub, C1R )
+ICV_DEF_INIT_ARITHM_FUNC_TAB( SubRC, C1R )
+ICV_DEF_INIT_ARITHM_FUNC_TAB( Add, C1R )
+ICV_DEF_INIT_ARITHM_FUNC_TAB( AddC, C1R )
+
+/****************************************************************************************\
+* External Functions for Arithmetic Operations *
+\****************************************************************************************/
+
+/*************************************** S U B ******************************************/
+
+CV_IMPL void
+cvSub( const void* srcarr1, const void* srcarr2,
+ void* dstarr, const void* maskarr )
+{
+ static CvFuncTable sub_tab;
+ static int inittab = 0;
+ int local_alloc = 1;
+ uchar* buffer = 0;
+
+ CV_FUNCNAME( "cvSub" );
+
+ __BEGIN__;
+
+ const CvArr* tmp;
+ int y, dy, type, depth, cn, cont_flag = 0;
+ int src1_step, src2_step, dst_step, tdst_step, mask_step;
+ CvMat srcstub1, srcstub2, *src1, *src2;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvMat maskstub, *mask = (CvMat*)maskarr;
+ CvMat dstbuf, *tdst;
+ CvFunc2D_3A func;
+ CvFunc2D_3A1I func_sfs;
+ CvCopyMaskFunc copym_func;
+ CvSize size, tsize;
+
+ CV_SWAP( srcarr1, srcarr2, tmp ); // to comply with IPP
+ src1 = (CvMat*)srcarr1;
+ src2 = (CvMat*)srcarr2;
+
+ if( !CV_IS_MAT(src1) || !CV_IS_MAT(src2) || !CV_IS_MAT(dst))
+ {
+ if( CV_IS_MATND(src1) || CV_IS_MATND(src2) || CV_IS_MATND(dst))
+ {
+ CvArr* arrs[] = { src1, src2, dst };
+ CvMatND stubs[3];
+ CvNArrayIterator iterator;
+
+ if( maskarr )
+ CV_ERROR( CV_StsBadMask,
+ "This operation on multi-dimensional arrays does not support mask" );
+
+ CV_CALL( cvInitNArrayIterator( 3, arrs, 0, stubs, &iterator ));
+
+ type = iterator.hdr[0]->type;
+ iterator.size.width *= CV_MAT_CN(type);
+
+ if( !inittab )
+ {
+ icvInitSubC1RTable( &sub_tab );
+ inittab = 1;
+ }
+
+ depth = CV_MAT_DEPTH(type);
+ if( depth <= CV_16S )
+ {
+ func_sfs = (CvFunc2D_3A1I)(sub_tab.fn_2d[depth]);
+ if( !func_sfs )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ do
+ {
+ IPPI_CALL( func_sfs( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.ptr[2], CV_STUB_STEP,
+ iterator.size, 0 ));
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ else
+ {
+ func = (CvFunc2D_3A)(sub_tab.fn_2d[depth]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ do
+ {
+ IPPI_CALL( func( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.ptr[2], CV_STUB_STEP,
+ iterator.size ));
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ EXIT;
+ }
+ else
+ {
+ int coi1 = 0, coi2 = 0, coi3 = 0;
+
+ CV_CALL( src1 = cvGetMat( src1, &srcstub1, &coi1 ));
+ CV_CALL( src2 = cvGetMat( src2, &srcstub2, &coi2 ));
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi3 ));
+ if( coi1 + coi2 + coi3 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+ }
+
+ if( !CV_ARE_TYPES_EQ( src1, src2 ) || !CV_ARE_TYPES_EQ( src1, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( src1, src2 ) || !CV_ARE_SIZES_EQ( src1, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ type = CV_MAT_TYPE(src1->type);
+ size = cvGetMatSize( src1 );
+ depth = CV_MAT_DEPTH(type);
+ cn = CV_MAT_CN(type);
+
+ if( !mask )
+ {
+ if( CV_IS_MAT_CONT( src1->type & src2->type & dst->type ))
+ {
+ int len = size.width*size.height*cn;
+
+ if( len <= CV_MAX_INLINE_MAT_OP_SIZE*CV_MAX_INLINE_MAT_OP_SIZE )
+ {
+ if( depth == CV_32F )
+ {
+ const float* src1data = (const float*)(src1->data.ptr);
+ const float* src2data = (const float*)(src2->data.ptr);
+ float* dstdata = (float*)(dst->data.ptr);
+
+ do
+ {
+ dstdata[len-1] = (float)(src2data[len-1] - src1data[len-1]);
+ }
+ while( --len );
+
+ EXIT;
+ }
+
+ if( depth == CV_64F )
+ {
+ const double* src1data = (const double*)(src1->data.ptr);
+ const double* src2data = (const double*)(src2->data.ptr);
+ double* dstdata = (double*)(dst->data.ptr);
+
+ do
+ {
+ dstdata[len-1] = src2data[len-1] - src1data[len-1];
+ }
+ while( --len );
+
+ EXIT;
+ }
+ }
+ cont_flag = 1;
+ }
+
+ dy = size.height;
+ copym_func = 0;
+ tdst = dst;
+ }
+ else
+ {
+ int buf_size, elem_size;
+
+ if( !CV_IS_MAT(mask) )
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+
+ if( !CV_IS_MASK_ARR(mask))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !CV_ARE_SIZES_EQ( mask, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ cont_flag = CV_IS_MAT_CONT( src1->type & src2->type & dst->type & mask->type );
+ elem_size = CV_ELEM_SIZE(type);
+
+ dy = CV_MAX_LOCAL_SIZE/(elem_size*size.height);
+ dy = MAX(dy,1);
+ dy = MIN(dy,size.height);
+ dstbuf = cvMat( dy, size.width, type );
+ if( !cont_flag )
+ dstbuf.step = cvAlign( dstbuf.step, 8 );
+ buf_size = dstbuf.step ? dstbuf.step*dy : size.width*elem_size;
+ if( buf_size > CV_MAX_LOCAL_SIZE )
+ {
+ CV_CALL( buffer = (uchar*)cvAlloc( buf_size ));
+ local_alloc = 0;
+ }
+ else
+ buffer = (uchar*)cvStackAlloc( buf_size );
+ dstbuf.data.ptr = buffer;
+ tdst = &dstbuf;
+
+ copym_func = icvGetCopyMaskFunc( elem_size );
+ }
+
+ if( !inittab )
+ {
+ icvInitSubC1RTable( &sub_tab );
+ inittab = 1;
+ }
+
+ if( depth <= CV_16S )
+ {
+ func = 0;
+ func_sfs = (CvFunc2D_3A1I)(sub_tab.fn_2d[depth]);
+ if( !func_sfs )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+ }
+ else
+ {
+ func_sfs = 0;
+ func = (CvFunc2D_3A)(sub_tab.fn_2d[depth]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+ }
+
+ src1_step = src1->step;
+ src2_step = src2->step;
+ dst_step = dst->step;
+ tdst_step = tdst->step;
+ mask_step = mask ? mask->step : 0;
+
+ for( y = 0; y < size.height; y += dy )
+ {
+ tsize.width = size.width;
+ tsize.height = dy;
+ if( y + dy > size.height )
+ tsize.height = size.height - y;
+ if( cont_flag || tsize.height == 1 )
+ {
+ tsize.width *= tsize.height;
+ tsize.height = 1;
+ src1_step = src2_step = tdst_step = dst_step = mask_step = CV_STUB_STEP;
+ }
+
+ IPPI_CALL( depth <= CV_16S ?
+ func_sfs( src1->data.ptr + y*src1->step, src1_step,
+ src2->data.ptr + y*src2->step, src2_step,
+ tdst->data.ptr, tdst_step,
+ cvSize( tsize.width*cn, tsize.height ), 0 ) :
+ func( src1->data.ptr + y*src1->step, src1_step,
+ src2->data.ptr + y*src2->step, src2_step,
+ tdst->data.ptr, tdst_step,
+ cvSize( tsize.width*cn, tsize.height )));
+
+ if( mask )
+ {
+ IPPI_CALL( copym_func( tdst->data.ptr, tdst_step, dst->data.ptr + y*dst->step,
+ dst_step, tsize, mask->data.ptr + y*mask->step, mask_step ));
+ }
+ }
+
+ __END__;
+
+ if( !local_alloc )
+ cvFree( &buffer );
+}
+
+
+CV_IMPL void
+cvSubRS( const void* srcarr, CvScalar scalar, void* dstarr, const void* maskarr )
+{
+ static CvFuncTable subr_tab;
+ static int inittab = 0;
+ int local_alloc = 1;
+ uchar* buffer = 0;
+
+ CV_FUNCNAME( "cvSubRS" );
+
+ __BEGIN__;
+
+ int sctype, y, dy, type, depth, cn, coi = 0, cont_flag = 0;
+ int src_step, dst_step, tdst_step, mask_step;
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvMat maskstub, *mask = (CvMat*)maskarr;
+ CvMat dstbuf, *tdst;
+ CvFunc2D_2A1P func;
+ CvCopyMaskFunc copym_func;
+ double buf[12];
+ int is_nd = 0;
+ CvSize size, tsize;
+
+ if( !inittab )
+ {
+ icvInitSubRCC1RTable( &subr_tab );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(src) )
+ {
+ if( CV_IS_MATND(src) )
+ is_nd = 1;
+ else
+ {
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+ }
+
+ if( !CV_IS_MAT(dst) )
+ {
+ if( CV_IS_MATND(dst) )
+ is_nd = 1;
+ else
+ {
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+ }
+
+ if( is_nd )
+ {
+ CvArr* arrs[] = { src, dst };
+ CvMatND stubs[2];
+ CvNArrayIterator iterator;
+
+ if( maskarr )
+ CV_ERROR( CV_StsBadMask,
+ "This operation on multi-dimensional arrays does not support mask" );
+
+ CV_CALL( cvInitNArrayIterator( 2, arrs, 0, stubs, &iterator ));
+
+ sctype = type = CV_MAT_TYPE(iterator.hdr[0]->type);
+ if( CV_MAT_DEPTH(sctype) < CV_32S )
+ sctype = (type & CV_MAT_CN_MASK) | CV_32SC1;
+ iterator.size.width *= CV_MAT_CN(type);
+
+ func = (CvFunc2D_2A1P)(subr_tab.fn_2d[CV_MAT_DEPTH(type)]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ CV_CALL( cvScalarToRawData( &scalar, buf, sctype, 1 ));
+
+ do
+ {
+ IPPI_CALL( func( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.size, buf ));
+ }
+ while( cvNextNArraySlice( &iterator ));
+ EXIT;
+ }
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ sctype = type = CV_MAT_TYPE(src->type);
+ depth = CV_MAT_DEPTH(type);
+ cn = CV_MAT_CN(type);
+ if( depth < CV_32S )
+ sctype = (type & CV_MAT_CN_MASK) | CV_32SC1;
+
+ size = cvGetMatSize( src );
+
+ if( !maskarr )
+ {
+ if( CV_IS_MAT_CONT( src->type & dst->type ))
+ {
+ if( size.width <= CV_MAX_INLINE_MAT_OP_SIZE )
+ {
+ int len = size.width * size.height;
+
+ if( type == CV_32FC1 )
+ {
+ const float* srcdata = (const float*)(src->data.ptr);
+ float* dstdata = (float*)(dst->data.ptr);
+
+ do
+ {
+ dstdata[len-1] = (float)(scalar.val[0] - srcdata[len-1]);
+ }
+ while( --len );
+
+ EXIT;
+ }
+
+ if( type == CV_64FC1 )
+ {
+ const double* srcdata = (const double*)(src->data.ptr);
+ double* dstdata = (double*)(dst->data.ptr);
+
+ do
+ {
+ dstdata[len-1] = scalar.val[0] - srcdata[len-1];
+ }
+ while( --len );
+
+ EXIT;
+ }
+ }
+ cont_flag = 1;
+ }
+
+ dy = size.height;
+ copym_func = 0;
+ tdst = dst;
+ }
+ else
+ {
+ int buf_size, elem_size;
+
+ if( !CV_IS_MAT(mask) )
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+
+ if( !CV_IS_MASK_ARR(mask))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !CV_ARE_SIZES_EQ( mask, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ cont_flag = CV_IS_MAT_CONT( src->type & dst->type & mask->type );
+ elem_size = CV_ELEM_SIZE(type);
+
+ dy = CV_MAX_LOCAL_SIZE/(elem_size*size.height);
+ dy = MAX(dy,1);
+ dy = MIN(dy,size.height);
+ dstbuf = cvMat( dy, size.width, type );
+ if( !cont_flag )
+ dstbuf.step = cvAlign( dstbuf.step, 8 );
+ buf_size = dstbuf.step ? dstbuf.step*dy : size.width*elem_size;
+ if( buf_size > CV_MAX_LOCAL_SIZE )
+ {
+ CV_CALL( buffer = (uchar*)cvAlloc( buf_size ));
+ local_alloc = 0;
+ }
+ else
+ buffer = (uchar*)cvStackAlloc( buf_size );
+ dstbuf.data.ptr = buffer;
+ tdst = &dstbuf;
+
+ copym_func = icvGetCopyMaskFunc( elem_size );
+ }
+
+ func = (CvFunc2D_2A1P)(subr_tab.fn_2d[depth]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ src_step = src->step;
+ dst_step = dst->step;
+ tdst_step = tdst->step;
+ mask_step = mask ? mask->step : 0;
+
+ CV_CALL( cvScalarToRawData( &scalar, buf, sctype, 1 ));
+
+ for( y = 0; y < size.height; y += dy )
+ {
+ tsize.width = size.width;
+ tsize.height = dy;
+ if( y + dy > size.height )
+ tsize.height = size.height - y;
+ if( cont_flag || tsize.height == 1 )
+ {
+ tsize.width *= tsize.height;
+ tsize.height = 1;
+ src_step = tdst_step = dst_step = mask_step = CV_STUB_STEP;
+ }
+
+ IPPI_CALL( func( src->data.ptr + y*src->step, src_step,
+ tdst->data.ptr, tdst_step,
+ cvSize( tsize.width*cn, tsize.height ), buf ));
+ if( mask )
+ {
+ IPPI_CALL( copym_func( tdst->data.ptr, tdst_step, dst->data.ptr + y*dst->step,
+ dst_step, tsize, mask->data.ptr + y*mask->step, mask_step ));
+ }
+ }
+
+ __END__;
+
+ if( !local_alloc )
+ cvFree( &buffer );
+}
+
+
+/******************************* A D D ********************************/
+
+CV_IMPL void
+cvAdd( const void* srcarr1, const void* srcarr2,
+ void* dstarr, const void* maskarr )
+{
+ static CvFuncTable add_tab;
+ static int inittab = 0;
+ int local_alloc = 1;
+ uchar* buffer = 0;
+
+ CV_FUNCNAME( "cvAdd" );
+
+ __BEGIN__;
+
+ int y, dy, type, depth, cn, cont_flag = 0;
+ int src1_step, src2_step, dst_step, tdst_step, mask_step;
+ CvMat srcstub1, *src1 = (CvMat*)srcarr1;
+ CvMat srcstub2, *src2 = (CvMat*)srcarr2;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvMat maskstub, *mask = (CvMat*)maskarr;
+ CvMat dstbuf, *tdst;
+ CvFunc2D_3A func;
+ CvFunc2D_3A1I func_sfs;
+ CvCopyMaskFunc copym_func;
+ CvSize size, tsize;
+
+ if( !CV_IS_MAT(src1) || !CV_IS_MAT(src2) || !CV_IS_MAT(dst))
+ {
+ if( CV_IS_MATND(src1) || CV_IS_MATND(src2) || CV_IS_MATND(dst))
+ {
+ CvArr* arrs[] = { src1, src2, dst };
+ CvMatND stubs[3];
+ CvNArrayIterator iterator;
+
+ if( maskarr )
+ CV_ERROR( CV_StsBadMask,
+ "This operation on multi-dimensional arrays does not support mask" );
+
+ CV_CALL( cvInitNArrayIterator( 3, arrs, 0, stubs, &iterator ));
+
+ type = iterator.hdr[0]->type;
+ iterator.size.width *= CV_MAT_CN(type);
+
+ if( !inittab )
+ {
+ icvInitAddC1RTable( &add_tab );
+ inittab = 1;
+ }
+
+ depth = CV_MAT_DEPTH(type);
+ if( depth <= CV_16S )
+ {
+ func_sfs = (CvFunc2D_3A1I)(add_tab.fn_2d[depth]);
+ if( !func_sfs )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ do
+ {
+ IPPI_CALL( func_sfs( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.ptr[2], CV_STUB_STEP,
+ iterator.size, 0 ));
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ else
+ {
+ func = (CvFunc2D_3A)(add_tab.fn_2d[depth]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ do
+ {
+ IPPI_CALL( func( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.ptr[2], CV_STUB_STEP,
+ iterator.size ));
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ EXIT;
+ }
+ else
+ {
+ int coi1 = 0, coi2 = 0, coi3 = 0;
+
+ CV_CALL( src1 = cvGetMat( src1, &srcstub1, &coi1 ));
+ CV_CALL( src2 = cvGetMat( src2, &srcstub2, &coi2 ));
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi3 ));
+ if( coi1 + coi2 + coi3 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+ }
+
+ if( !CV_ARE_TYPES_EQ( src1, src2 ) || !CV_ARE_TYPES_EQ( src1, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( src1, src2 ) || !CV_ARE_SIZES_EQ( src1, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ type = CV_MAT_TYPE(src1->type);
+ size = cvGetMatSize( src1 );
+ depth = CV_MAT_DEPTH(type);
+ cn = CV_MAT_CN(type);
+
+ if( !mask )
+ {
+ if( CV_IS_MAT_CONT( src1->type & src2->type & dst->type ))
+ {
+ int len = size.width*size.height*cn;
+
+ if( len <= CV_MAX_INLINE_MAT_OP_SIZE*CV_MAX_INLINE_MAT_OP_SIZE )
+ {
+ if( depth == CV_32F )
+ {
+ const float* src1data = (const float*)(src1->data.ptr);
+ const float* src2data = (const float*)(src2->data.ptr);
+ float* dstdata = (float*)(dst->data.ptr);
+
+ do
+ {
+ dstdata[len-1] = (float)(src1data[len-1] + src2data[len-1]);
+ }
+ while( --len );
+
+ EXIT;
+ }
+
+ if( depth == CV_64F )
+ {
+ const double* src1data = (const double*)(src1->data.ptr);
+ const double* src2data = (const double*)(src2->data.ptr);
+ double* dstdata = (double*)(dst->data.ptr);
+
+ do
+ {
+ dstdata[len-1] = src1data[len-1] + src2data[len-1];
+ }
+ while( --len );
+
+ EXIT;
+ }
+ }
+ cont_flag = 1;
+ }
+
+ dy = size.height;
+ copym_func = 0;
+ tdst = dst;
+ }
+ else
+ {
+ int buf_size, elem_size;
+
+ if( !CV_IS_MAT(mask) )
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+
+ if( !CV_IS_MASK_ARR(mask))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !CV_ARE_SIZES_EQ( mask, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ cont_flag = CV_IS_MAT_CONT( src1->type & src2->type & dst->type & mask->type );
+ elem_size = CV_ELEM_SIZE(type);
+
+ dy = CV_MAX_LOCAL_SIZE/(elem_size*size.height);
+ dy = MAX(dy,1);
+ dy = MIN(dy,size.height);
+ dstbuf = cvMat( dy, size.width, type );
+ if( !cont_flag )
+ dstbuf.step = cvAlign( dstbuf.step, 8 );
+ buf_size = dstbuf.step ? dstbuf.step*dy : size.width*elem_size;
+ if( buf_size > CV_MAX_LOCAL_SIZE )
+ {
+ CV_CALL( buffer = (uchar*)cvAlloc( buf_size ));
+ local_alloc = 0;
+ }
+ else
+ buffer = (uchar*)cvStackAlloc( buf_size );
+ dstbuf.data.ptr = buffer;
+ tdst = &dstbuf;
+
+ copym_func = icvGetCopyMaskFunc( elem_size );
+ }
+
+ if( !inittab )
+ {
+ icvInitAddC1RTable( &add_tab );
+ inittab = 1;
+ }
+
+ if( depth <= CV_16S )
+ {
+ func = 0;
+ func_sfs = (CvFunc2D_3A1I)(add_tab.fn_2d[depth]);
+ if( !func_sfs )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+ }
+ else
+ {
+ func_sfs = 0;
+ func = (CvFunc2D_3A)(add_tab.fn_2d[depth]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+ }
+
+ src1_step = src1->step;
+ src2_step = src2->step;
+ dst_step = dst->step;
+ tdst_step = tdst->step;
+ mask_step = mask ? mask->step : 0;
+
+ for( y = 0; y < size.height; y += dy )
+ {
+ tsize.width = size.width;
+ tsize.height = dy;
+ if( y + dy > size.height )
+ tsize.height = size.height - y;
+ if( cont_flag || tsize.height == 1 )
+ {
+ tsize.width *= tsize.height;
+ tsize.height = 1;
+ src1_step = src2_step = tdst_step = dst_step = mask_step = CV_STUB_STEP;
+ }
+
+ IPPI_CALL( depth <= CV_16S ?
+ func_sfs( src1->data.ptr + y*src1->step, src1_step,
+ src2->data.ptr + y*src2->step, src2_step,
+ tdst->data.ptr, tdst_step,
+ cvSize( tsize.width*cn, tsize.height ), 0 ) :
+ func( src1->data.ptr + y*src1->step, src1_step,
+ src2->data.ptr + y*src2->step, src2_step,
+ tdst->data.ptr, tdst_step,
+ cvSize( tsize.width*cn, tsize.height )));
+
+ if( mask )
+ {
+ IPPI_CALL( copym_func( tdst->data.ptr, tdst_step, dst->data.ptr + y*dst->step,
+ dst_step, tsize, mask->data.ptr + y*mask->step, mask_step ));
+ }
+ }
+
+ __END__;
+
+ if( !local_alloc )
+ cvFree( &buffer );
+}
+
+
+CV_IMPL void
+cvAddS( const void* srcarr, CvScalar scalar, void* dstarr, const void* maskarr )
+{
+ static CvFuncTable add_tab;
+ static int inittab = 0;
+ int local_alloc = 1;
+ uchar* buffer = 0;
+
+ CV_FUNCNAME( "cvAddS" );
+
+ __BEGIN__;
+
+ int sctype, y, dy, type, depth, cn, coi = 0, cont_flag = 0;
+ int src_step, dst_step, tdst_step, mask_step;
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvMat maskstub, *mask = (CvMat*)maskarr;
+ CvMat dstbuf, *tdst;
+ CvFunc2D_2A1P func;
+ CvCopyMaskFunc copym_func;
+ double buf[12];
+ int is_nd = 0;
+ CvSize size, tsize;
+
+ if( !inittab )
+ {
+ icvInitAddCC1RTable( &add_tab );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(src) )
+ {
+ if( CV_IS_MATND(src) )
+ is_nd = 1;
+ else
+ {
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+ }
+
+ if( !CV_IS_MAT(dst) )
+ {
+ if( CV_IS_MATND(dst) )
+ is_nd = 1;
+ else
+ {
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+ }
+
+ if( is_nd )
+ {
+ CvArr* arrs[] = { src, dst };
+ CvMatND stubs[2];
+ CvNArrayIterator iterator;
+
+ if( maskarr )
+ CV_ERROR( CV_StsBadMask,
+ "This operation on multi-dimensional arrays does not support mask" );
+
+ CV_CALL( cvInitNArrayIterator( 2, arrs, 0, stubs, &iterator ));
+
+ sctype = type = CV_MAT_TYPE(iterator.hdr[0]->type);
+ if( CV_MAT_DEPTH(sctype) < CV_32S )
+ sctype = (type & CV_MAT_CN_MASK) | CV_32SC1;
+ iterator.size.width *= CV_MAT_CN(type);
+
+ func = (CvFunc2D_2A1P)(add_tab.fn_2d[CV_MAT_DEPTH(type)]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ CV_CALL( cvScalarToRawData( &scalar, buf, sctype, 1 ));
+
+ do
+ {
+ IPPI_CALL( func( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.size, buf ));
+ }
+ while( cvNextNArraySlice( &iterator ));
+ EXIT;
+ }
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ sctype = type = CV_MAT_TYPE(src->type);
+ depth = CV_MAT_DEPTH(type);
+ cn = CV_MAT_CN(type);
+ if( depth < CV_32S )
+ sctype = (type & CV_MAT_CN_MASK) | CV_32SC1;
+
+ size = cvGetMatSize( src );
+
+ if( !maskarr )
+ {
+ if( CV_IS_MAT_CONT( src->type & dst->type ))
+ {
+ if( size.width <= CV_MAX_INLINE_MAT_OP_SIZE )
+ {
+ int len = size.width * size.height;
+
+ if( type == CV_32FC1 )
+ {
+ const float* srcdata = (const float*)(src->data.ptr);
+ float* dstdata = (float*)(dst->data.ptr);
+
+ do
+ {
+ dstdata[len-1] = (float)(scalar.val[0] + srcdata[len-1]);
+ }
+ while( --len );
+
+ EXIT;
+ }
+
+ if( type == CV_64FC1 )
+ {
+ const double* srcdata = (const double*)(src->data.ptr);
+ double* dstdata = (double*)(dst->data.ptr);
+
+ do
+ {
+ dstdata[len-1] = scalar.val[0] + srcdata[len-1];
+ }
+ while( --len );
+
+ EXIT;
+ }
+ }
+ cont_flag = 1;
+ }
+
+ dy = size.height;
+ copym_func = 0;
+ tdst = dst;
+ }
+ else
+ {
+ int buf_size, elem_size;
+
+ if( !CV_IS_MAT(mask) )
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+
+ if( !CV_IS_MASK_ARR(mask))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !CV_ARE_SIZES_EQ( mask, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ cont_flag = CV_IS_MAT_CONT( src->type & dst->type & mask->type );
+ elem_size = CV_ELEM_SIZE(type);
+
+ dy = CV_MAX_LOCAL_SIZE/(elem_size*size.height);
+ dy = MAX(dy,1);
+ dy = MIN(dy,size.height);
+ dstbuf = cvMat( dy, size.width, type );
+ if( !cont_flag )
+ dstbuf.step = cvAlign( dstbuf.step, 8 );
+ buf_size = dstbuf.step ? dstbuf.step*dy : size.width*elem_size;
+ if( buf_size > CV_MAX_LOCAL_SIZE )
+ {
+ CV_CALL( buffer = (uchar*)cvAlloc( buf_size ));
+ local_alloc = 0;
+ }
+ else
+ buffer = (uchar*)cvStackAlloc( buf_size );
+ dstbuf.data.ptr = buffer;
+ tdst = &dstbuf;
+
+ copym_func = icvGetCopyMaskFunc( elem_size );
+ }
+
+ func = (CvFunc2D_2A1P)(add_tab.fn_2d[depth]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ src_step = src->step;
+ dst_step = dst->step;
+ tdst_step = tdst->step;
+ mask_step = mask ? mask->step : 0;
+
+ CV_CALL( cvScalarToRawData( &scalar, buf, sctype, 1 ));
+
+ for( y = 0; y < size.height; y += dy )
+ {
+ tsize.width = size.width;
+ tsize.height = dy;
+ if( y + dy > size.height )
+ tsize.height = size.height - y;
+ if( cont_flag || tsize.height == 1 )
+ {
+ tsize.width *= tsize.height;
+ tsize.height = 1;
+ src_step = tdst_step = dst_step = mask_step = CV_STUB_STEP;
+ }
+
+ IPPI_CALL( func( src->data.ptr + y*src->step, src_step,
+ tdst->data.ptr, tdst_step,
+ cvSize( tsize.width*cn, tsize.height ), buf ));
+ if( mask )
+ {
+ IPPI_CALL( copym_func( tdst->data.ptr, tdst_step, dst->data.ptr + y*dst->step,
+ dst_step, tsize, mask->data.ptr + y*mask->step, mask_step ));
+ }
+ }
+
+ __END__;
+
+ if( !local_alloc )
+ cvFree( &buffer );
+}
+
+
+/***************************************** M U L ****************************************/
+
+#define ICV_DEF_MUL_OP_CASE( flavor, arrtype, worktype, _cast_macro1_, \
+ _cast_macro2_, _cvt_macro_ ) \
+static CvStatus CV_STDCALL \
+ icvMul_##flavor##_C1R( const arrtype* src1, int step1, \
+ const arrtype* src2, int step2, \
+ arrtype* dst, int step, \
+ CvSize size, double scale ) \
+{ \
+ step1 /= sizeof(src1[0]); step2 /= sizeof(src2[0]); step /= sizeof(dst[0]); \
+ \
+ if( fabs(scale - 1.) < DBL_EPSILON ) \
+ { \
+ for( ; size.height--; src1+=step1, src2+=step2, dst+=step ) \
+ { \
+ int i; \
+ for( i = 0; i <= size.width - 4; i += 4 ) \
+ { \
+ worktype t0 = src1[i] * src2[i]; \
+ worktype t1 = src1[i+1] * src2[i+1]; \
+ \
+ dst[i] = _cast_macro2_(t0); \
+ dst[i+1] = _cast_macro2_(t1); \
+ \
+ t0 = src1[i+2] * src2[i+2]; \
+ t1 = src1[i+3] * src2[i+3]; \
+ \
+ dst[i+2] = _cast_macro2_(t0); \
+ dst[i+3] = _cast_macro2_(t1); \
+ } \
+ \
+ for( ; i < size.width; i++ ) \
+ { \
+ worktype t0 = src1[i] * src2[i]; \
+ dst[i] = _cast_macro2_(t0); \
+ } \
+ } \
+ } \
+ else \
+ { \
+ for( ; size.height--; src1+=step1, src2+=step2, dst+=step ) \
+ { \
+ int i; \
+ for( i = 0; i <= size.width - 4; i += 4 ) \
+ { \
+ double ft0 = scale*_cvt_macro_(src1[i])*_cvt_macro_(src2[i]); \
+ double ft1 = scale*_cvt_macro_(src1[i+1])*_cvt_macro_(src2[i+1]); \
+ worktype t0 = _cast_macro1_(ft0); \
+ worktype t1 = _cast_macro1_(ft1); \
+ \
+ dst[i] = _cast_macro2_(t0); \
+ dst[i+1] = _cast_macro2_(t1); \
+ \
+ ft0 = scale*_cvt_macro_(src1[i+2])*_cvt_macro_(src2[i+2]); \
+ ft1 = scale*_cvt_macro_(src1[i+3])*_cvt_macro_(src2[i+3]); \
+ t0 = _cast_macro1_(ft0); \
+ t1 = _cast_macro1_(ft1); \
+ \
+ dst[i+2] = _cast_macro2_(t0); \
+ dst[i+3] = _cast_macro2_(t1); \
+ } \
+ \
+ for( ; i < size.width; i++ ) \
+ { \
+ worktype t0; \
+ t0 = _cast_macro1_(scale*_cvt_macro_(src1[i])*_cvt_macro_(src2[i])); \
+ dst[i] = _cast_macro2_(t0); \
+ } \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_MUL_OP_CASE( 8u, uchar, int, cvRound, CV_CAST_8U, CV_8TO32F )
+ICV_DEF_MUL_OP_CASE( 16u, ushort, int, cvRound, CV_CAST_16U, CV_NOP )
+ICV_DEF_MUL_OP_CASE( 16s, short, int, cvRound, CV_CAST_16S, CV_NOP )
+ICV_DEF_MUL_OP_CASE( 32s, int, int, cvRound, CV_CAST_32S, CV_NOP )
+ICV_DEF_MUL_OP_CASE( 32f, float, double, CV_NOP, CV_CAST_32F, CV_NOP )
+ICV_DEF_MUL_OP_CASE( 64f, double, double, CV_NOP, CV_CAST_64F, CV_NOP )
+
+
+ICV_DEF_INIT_ARITHM_FUNC_TAB( Mul, C1R )
+
+
+typedef CvStatus (CV_STDCALL * CvScaledElWiseFunc)( const void* src1, int step1,
+ const void* src2, int step2,
+ void* dst, int step,
+ CvSize size, double scale );
+
+CV_IMPL void
+cvMul( const void* srcarr1, const void* srcarr2, void* dstarr, double scale )
+{
+ static CvFuncTable mul_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvMul" );
+
+ __BEGIN__;
+
+ int type, depth, coi = 0;
+ int src1_step, src2_step, dst_step;
+ int is_nd = 0;
+ CvMat srcstub1, *src1 = (CvMat*)srcarr1;
+ CvMat srcstub2, *src2 = (CvMat*)srcarr2;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize size;
+ CvScaledElWiseFunc func;
+
+ if( !inittab )
+ {
+ icvInitMulC1RTable( &mul_tab );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(src1) )
+ {
+ if( CV_IS_MATND(src1) )
+ is_nd = 1;
+ else
+ {
+ CV_CALL( src1 = cvGetMat( src1, &srcstub1, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+ }
+
+ if( !CV_IS_MAT(src2) )
+ {
+ if( CV_IS_MATND(src2) )
+ is_nd = 1;
+ else
+ {
+ CV_CALL( src2 = cvGetMat( src2, &srcstub2, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+ }
+
+ if( !CV_IS_MAT(dst) )
+ {
+ if( CV_IS_MATND(dst) )
+ is_nd = 1;
+ else
+ {
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+ }
+
+ if( is_nd )
+ {
+ CvArr* arrs[] = { src1, src2, dst };
+ CvMatND stubs[3];
+ CvNArrayIterator iterator;
+
+ CV_CALL( cvInitNArrayIterator( 3, arrs, 0, stubs, &iterator ));
+
+ type = iterator.hdr[0]->type;
+ iterator.size.width *= CV_MAT_CN(type);
+
+ func = (CvScaledElWiseFunc)(mul_tab.fn_2d[CV_MAT_DEPTH(type)]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ do
+ {
+ IPPI_CALL( func( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.ptr[2], CV_STUB_STEP,
+ iterator.size, scale ));
+ }
+ while( cvNextNArraySlice( &iterator ));
+ EXIT;
+ }
+
+ if( !CV_ARE_TYPES_EQ( src1, src2 ) || !CV_ARE_TYPES_EQ( src1, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( src1, src2 ) || !CV_ARE_SIZES_EQ( src1, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ type = CV_MAT_TYPE(src1->type);
+ size = cvGetMatSize( src1 );
+
+ depth = CV_MAT_DEPTH(type);
+ size.width *= CV_MAT_CN( type );
+
+ if( CV_IS_MAT_CONT( src1->type & src2->type & dst->type ))
+ {
+ size.width *= size.height;
+
+ if( size.width <= CV_MAX_INLINE_MAT_OP_SIZE && scale == 1 )
+ {
+ if( depth == CV_32F )
+ {
+ const float* src1data = (const float*)(src1->data.ptr);
+ const float* src2data = (const float*)(src2->data.ptr);
+ float* dstdata = (float*)(dst->data.ptr);
+
+ do
+ {
+ dstdata[size.width-1] = (float)
+ (src1data[size.width-1] * src2data[size.width-1]);
+ }
+ while( --size.width );
+
+ EXIT;
+ }
+
+ if( depth == CV_64F )
+ {
+ const double* src1data = (const double*)(src1->data.ptr);
+ const double* src2data = (const double*)(src2->data.ptr);
+ double* dstdata = (double*)(dst->data.ptr);
+
+ do
+ {
+ dstdata[size.width-1] =
+ src1data[size.width-1] * src2data[size.width-1];
+ }
+ while( --size.width );
+
+ EXIT;
+ }
+ }
+
+ src1_step = src2_step = dst_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+ else
+ {
+ src1_step = src1->step;
+ src2_step = src2->step;
+ dst_step = dst->step;
+ }
+
+ func = (CvScaledElWiseFunc)(mul_tab.fn_2d[CV_MAT_DEPTH(type)]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src1->data.ptr, src1_step, src2->data.ptr, src2_step,
+ dst->data.ptr, dst_step, size, scale ));
+
+ __END__;
+}
+
+
+/***************************************** D I V ****************************************/
+
+#define ICV_DEF_DIV_OP_CASE( flavor, arrtype, worktype, checktype, _start_row_macro_, \
+ _cast_macro1_, _cast_macro2_, _cvt_macro_, _check_macro_, isrc ) \
+ \
+static CvStatus CV_STDCALL \
+icvDiv_##flavor##_C1R( const arrtype* src1, int step1, \
+ const arrtype* src2, int step2, \
+ arrtype* dst, int step, \
+ CvSize size, double scale ) \
+{ \
+ step1 /= sizeof(src1[0]); step2 /= sizeof(src2[0]); step /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src1+=step1, src2+=step2, dst+=step ) \
+ { \
+ _start_row_macro_(checktype, src2); \
+ for( i = 0; i <= size.width - 4; i += 4 ) \
+ { \
+ if( _check_macro_(isrc[i]) && _check_macro_(isrc[i+1]) && \
+ _check_macro_(isrc[i+2]) && _check_macro_(isrc[i+3])) \
+ { \
+ double a = (double)_cvt_macro_(src2[i]) * _cvt_macro_(src2[i+1]); \
+ double b = (double)_cvt_macro_(src2[i+2]) * _cvt_macro_(src2[i+3]); \
+ double d = scale/(a * b); \
+ \
+ b *= d; \
+ a *= d; \
+ \
+ worktype z0 = _cast_macro1_(src2[i+1] * _cvt_macro_(src1[i]) * b); \
+ worktype z1 = _cast_macro1_(src2[i] * _cvt_macro_(src1[i+1]) * b); \
+ worktype z2 = _cast_macro1_(src2[i+3] * _cvt_macro_(src1[i+2]) * a); \
+ worktype z3 = _cast_macro1_(src2[i+2] * _cvt_macro_(src1[i+3]) * a); \
+ \
+ dst[i] = _cast_macro2_(z0); \
+ dst[i+1] = _cast_macro2_(z1); \
+ dst[i+2] = _cast_macro2_(z2); \
+ dst[i+3] = _cast_macro2_(z3); \
+ } \
+ else \
+ { \
+ worktype z0 = _check_macro_(isrc[i]) ? \
+ _cast_macro1_(_cvt_macro_(src1[i])*scale/_cvt_macro_(src2[i])) : 0; \
+ worktype z1 = _check_macro_(isrc[i+1]) ? \
+ _cast_macro1_(_cvt_macro_(src1[i+1])*scale/_cvt_macro_(src2[i+1])):0;\
+ worktype z2 = _check_macro_(isrc[i+2]) ? \
+ _cast_macro1_(_cvt_macro_(src1[i+2])*scale/_cvt_macro_(src2[i+2])):0;\
+ worktype z3 = _check_macro_(isrc[i+3]) ? \
+ _cast_macro1_(_cvt_macro_(src1[i+3])*scale/_cvt_macro_(src2[i+3])):0;\
+ \
+ dst[i] = _cast_macro2_(z0); \
+ dst[i+1] = _cast_macro2_(z1); \
+ dst[i+2] = _cast_macro2_(z2); \
+ dst[i+3] = _cast_macro2_(z3); \
+ } \
+ } \
+ \
+ for( ; i < size.width; i++ ) \
+ { \
+ worktype z0 = _check_macro_(isrc[i]) ? \
+ _cast_macro1_(_cvt_macro_(src1[i])*scale/_cvt_macro_(src2[i])) : 0; \
+ dst[i] = _cast_macro2_(z0); \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_RECIP_OP_CASE( flavor, arrtype, worktype, checktype, \
+ _start_row_macro_, _cast_macro1_, _cast_macro2_, \
+ _cvt_macro_, _check_macro_, isrc ) \
+ \
+static CvStatus CV_STDCALL \
+icvRecip_##flavor##_C1R( const arrtype* src, int step1, \
+ arrtype* dst, int step, \
+ CvSize size, double scale ) \
+{ \
+ step1 /= sizeof(src[0]); step /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src+=step1, dst+=step ) \
+ { \
+ _start_row_macro_(checktype, src); \
+ for( i = 0; i <= size.width - 4; i += 4 ) \
+ { \
+ if( _check_macro_(isrc[i]) && _check_macro_(isrc[i+1]) && \
+ _check_macro_(isrc[i+2]) && _check_macro_(isrc[i+3])) \
+ { \
+ double a = (double)_cvt_macro_(src[i]) * _cvt_macro_(src[i+1]); \
+ double b = (double)_cvt_macro_(src[i+2]) * _cvt_macro_(src[i+3]);\
+ double d = scale/(a * b); \
+ \
+ b *= d; \
+ a *= d; \
+ \
+ worktype z0 = _cast_macro1_(src[i+1] * b); \
+ worktype z1 = _cast_macro1_(src[i] * b); \
+ worktype z2 = _cast_macro1_(src[i+3] * a); \
+ worktype z3 = _cast_macro1_(src[i+2] * a); \
+ \
+ dst[i] = _cast_macro2_(z0); \
+ dst[i+1] = _cast_macro2_(z1); \
+ dst[i+2] = _cast_macro2_(z2); \
+ dst[i+3] = _cast_macro2_(z3); \
+ } \
+ else \
+ { \
+ worktype z0 = _check_macro_(isrc[i]) ? \
+ _cast_macro1_(scale/_cvt_macro_(src[i])) : 0; \
+ worktype z1 = _check_macro_(isrc[i+1]) ? \
+ _cast_macro1_(scale/_cvt_macro_(src[i+1])):0; \
+ worktype z2 = _check_macro_(isrc[i+2]) ? \
+ _cast_macro1_(scale/_cvt_macro_(src[i+2])):0; \
+ worktype z3 = _check_macro_(isrc[i+3]) ? \
+ _cast_macro1_(scale/_cvt_macro_(src[i+3])):0; \
+ \
+ dst[i] = _cast_macro2_(z0); \
+ dst[i+1] = _cast_macro2_(z1); \
+ dst[i+2] = _cast_macro2_(z2); \
+ dst[i+3] = _cast_macro2_(z3); \
+ } \
+ } \
+ \
+ for( ; i < size.width; i++ ) \
+ { \
+ worktype z0 = _check_macro_(isrc[i]) ? \
+ _cast_macro1_(scale/_cvt_macro_(src[i])) : 0; \
+ dst[i] = _cast_macro2_(z0); \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define div_start_row_int(checktype, divisor) \
+ int i
+
+#define div_start_row_flt(checktype, divisor) \
+ const checktype* isrc = (const checktype*)divisor; int i
+
+#define div_check_zero_flt(x) (((x) & 0x7fffffff) != 0)
+#define div_check_zero_dbl(x) (((x) & CV_BIG_INT(0x7fffffffffffffff)) != 0)
+
+#if defined WIN64 && defined EM64T && defined _MSC_VER && !defined CV_ICC
+#pragma optimize("",off)
+#endif
+
+ICV_DEF_DIV_OP_CASE( 8u, uchar, int, uchar, div_start_row_int,
+ cvRound, CV_CAST_8U, CV_8TO32F, CV_NONZERO, src2 )
+
+#if defined WIN64 && defined EM64T && defined _MSC_VER && !defined CV_ICC
+#pragma optimize("",on)
+#endif
+
+
+ICV_DEF_DIV_OP_CASE( 16u, ushort, int, ushort, div_start_row_int,
+ cvRound, CV_CAST_16U, CV_CAST_64F, CV_NONZERO, src2 )
+ICV_DEF_DIV_OP_CASE( 16s, short, int, short, div_start_row_int,
+ cvRound, CV_CAST_16S, CV_NOP, CV_NONZERO, src2 )
+ICV_DEF_DIV_OP_CASE( 32s, int, int, int, div_start_row_int,
+ cvRound, CV_CAST_32S, CV_CAST_64F, CV_NONZERO, src2 )
+ICV_DEF_DIV_OP_CASE( 32f, float, double, int, div_start_row_flt,
+ CV_NOP, CV_CAST_32F, CV_NOP, div_check_zero_flt, isrc )
+ICV_DEF_DIV_OP_CASE( 64f, double, double, int64, div_start_row_flt,
+ CV_NOP, CV_CAST_64F, CV_NOP, div_check_zero_dbl, isrc )
+
+ICV_DEF_RECIP_OP_CASE( 8u, uchar, int, uchar, div_start_row_int,
+ cvRound, CV_CAST_8U, CV_8TO32F, CV_NONZERO, src )
+ICV_DEF_RECIP_OP_CASE( 16u, ushort, int, ushort, div_start_row_int,
+ cvRound, CV_CAST_16U, CV_CAST_64F, CV_NONZERO, src )
+ICV_DEF_RECIP_OP_CASE( 16s, short, int, short, div_start_row_int,
+ cvRound, CV_CAST_16S, CV_NOP, CV_NONZERO, src )
+ICV_DEF_RECIP_OP_CASE( 32s, int, int, int, div_start_row_int,
+ cvRound, CV_CAST_32S, CV_CAST_64F, CV_NONZERO, src )
+ICV_DEF_RECIP_OP_CASE( 32f, float, double, int, div_start_row_flt,
+ CV_NOP, CV_CAST_32F, CV_NOP, div_check_zero_flt, isrc )
+ICV_DEF_RECIP_OP_CASE( 64f, double, double, int64, div_start_row_flt,
+ CV_NOP, CV_CAST_64F, CV_NOP, div_check_zero_dbl, isrc )
+
+ICV_DEF_INIT_ARITHM_FUNC_TAB( Div, C1R )
+ICV_DEF_INIT_ARITHM_FUNC_TAB( Recip, C1R )
+
+typedef CvStatus (CV_STDCALL * CvRecipFunc)( const void* src, int step1,
+ void* dst, int step,
+ CvSize size, double scale );
+
+CV_IMPL void
+cvDiv( const void* srcarr1, const void* srcarr2, void* dstarr, double scale )
+{
+ static CvFuncTable div_tab;
+ static CvFuncTable recip_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvDiv" );
+
+ __BEGIN__;
+
+ int type, coi = 0;
+ int is_nd = 0;
+ int src1_step, src2_step, dst_step;
+ int src1_cont_flag = CV_MAT_CONT_FLAG;
+ CvMat srcstub1, *src1 = (CvMat*)srcarr1;
+ CvMat srcstub2, *src2 = (CvMat*)srcarr2;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize size;
+
+ if( !inittab )
+ {
+ icvInitDivC1RTable( &div_tab );
+ icvInitRecipC1RTable( &recip_tab );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(src2) )
+ {
+ if( CV_IS_MATND(src2))
+ is_nd = 1;
+ else
+ {
+ CV_CALL( src2 = cvGetMat( src2, &srcstub2, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+ }
+
+ if( src1 )
+ {
+ if( CV_IS_MATND(src1))
+ is_nd = 1;
+ else
+ {
+ if( !CV_IS_MAT(src1) )
+ {
+ CV_CALL( src1 = cvGetMat( src1, &srcstub1, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_ARE_TYPES_EQ( src1, src2 ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( src1, src2 ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+ src1_cont_flag = src1->type;
+ }
+ }
+
+ if( !CV_IS_MAT(dst) )
+ {
+ if( CV_IS_MATND(dst))
+ is_nd = 1;
+ else
+ {
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+ }
+
+ if( is_nd )
+ {
+ CvArr* arrs[] = { dst, src2, src1 };
+ CvMatND stubs[3];
+ CvNArrayIterator iterator;
+
+ CV_CALL( cvInitNArrayIterator( 2 + (src1 != 0), arrs, 0, stubs, &iterator ));
+
+ type = iterator.hdr[0]->type;
+ iterator.size.width *= CV_MAT_CN(type);
+
+ if( src1 )
+ {
+ CvScaledElWiseFunc func =
+ (CvScaledElWiseFunc)(div_tab.fn_2d[CV_MAT_DEPTH(type)]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ do
+ {
+ IPPI_CALL( func( iterator.ptr[2], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.ptr[0], CV_STUB_STEP,
+ iterator.size, scale ));
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ else
+ {
+ CvRecipFunc func = (CvRecipFunc)(recip_tab.fn_2d[CV_MAT_DEPTH(type)]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ do
+ {
+ IPPI_CALL( func( iterator.ptr[1], CV_STUB_STEP,
+ iterator.ptr[0], CV_STUB_STEP,
+ iterator.size, scale ));
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ EXIT;
+ }
+
+ if( !CV_ARE_TYPES_EQ( src2, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( src2, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ type = CV_MAT_TYPE(src2->type);
+ size = cvGetMatSize( src2 );
+ size.width *= CV_MAT_CN( type );
+
+ if( CV_IS_MAT_CONT( src1_cont_flag & src2->type & dst->type ))
+ {
+ size.width *= size.height;
+ src1_step = src2_step = dst_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+ else
+ {
+ src1_step = src1 ? src1->step : 0;
+ src2_step = src2->step;
+ dst_step = dst->step;
+ }
+
+ if( src1 )
+ {
+ CvScaledElWiseFunc func = (CvScaledElWiseFunc)(div_tab.fn_2d[CV_MAT_DEPTH(type)]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src1->data.ptr, src1_step, src2->data.ptr, src2_step,
+ dst->data.ptr, dst_step, size, scale ));
+ }
+ else
+ {
+ CvRecipFunc func = (CvRecipFunc)(recip_tab.fn_2d[CV_MAT_DEPTH(type)]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src2->data.ptr, src2_step,
+ dst->data.ptr, dst_step, size, scale ));
+ }
+
+ __END__;
+}
+
+/******************************* A D D W E I G T E D ******************************/
+
+#define ICV_DEF_ADD_WEIGHTED_OP(flavor, arrtype, worktype, load_macro, \
+ cast_macro1, cast_macro2) \
+static CvStatus CV_STDCALL \
+icvAddWeighted_##flavor##_C1R( const arrtype* src1, int step1, double alpha, \
+ const arrtype* src2, int step2, double beta, \
+ double gamma, arrtype* dst, int step, CvSize size )\
+{ \
+ step1 /= sizeof(src1[0]); step2 /= sizeof(src2[0]); step /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2, dst += step ) \
+ { \
+ int i; \
+ \
+ for( i = 0; i <= size.width - 4; i += 4 ) \
+ { \
+ worktype t0 = cast_macro1(load_macro((src1)[i])*alpha + \
+ load_macro((src2)[i])*beta + gamma); \
+ worktype t1 = cast_macro1(load_macro((src1)[i+1])*alpha + \
+ load_macro((src2)[i+1])*beta + gamma); \
+ \
+ (dst)[i] = cast_macro2( t0 ); \
+ (dst)[i+1] = cast_macro2( t1 ); \
+ \
+ t0 = cast_macro1(load_macro((src1)[i+2])*alpha + \
+ load_macro((src2)[i+2])*beta + gamma); \
+ t1 = cast_macro1(load_macro((src1)[i+3])*alpha + \
+ load_macro((src2)[i+3])*beta + gamma); \
+ \
+ (dst)[i+2] = cast_macro2( t0 ); \
+ (dst)[i+3] = cast_macro2( t1 ); \
+ } \
+ \
+ for( ; i < size.width; i++ ) \
+ { \
+ worktype t0 = cast_macro1(load_macro((src1)[i])*alpha + \
+ load_macro((src2)[i])*beta + gamma); \
+ (dst)[i] = cast_macro2( t0 ); \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#undef shift
+#define shift 14
+
+static CvStatus CV_STDCALL
+icvAddWeighted_8u_fast_C1R( const uchar* src1, int step1, double alpha,
+ const uchar* src2, int step2, double beta,
+ double gamma, uchar* dst, int step, CvSize size )
+{
+ int tab1[256], tab2[256];
+ double t = 0;
+ int j, t0, t1, t2, t3;
+
+ alpha *= 1 << shift;
+ gamma = gamma*(1 << shift) + (1 << (shift - 1));
+ beta *= 1 << shift;
+
+ for( j = 0; j < 256; j++ )
+ {
+ tab1[j] = cvRound(t);
+ tab2[j] = cvRound(gamma);
+ t += alpha;
+ gamma += beta;
+ }
+
+ t0 = (tab1[0] + tab2[0]) >> shift;
+ t1 = (tab1[0] + tab2[255]) >> shift;
+ t2 = (tab1[255] + tab2[0]) >> shift;
+ t3 = (tab1[255] + tab2[255]) >> shift;
+
+ if( (unsigned)(t0+256) < 768 && (unsigned)(t1+256) < 768 &&
+ (unsigned)(t2+256) < 768 && (unsigned)(t3+256) < 768 )
+ {
+ // use faster table-based convertion back to 8u
+ for( ; size.height--; src1 += step1, src2 += step2, dst += step )
+ {
+ int i;
+
+ for( i = 0; i <= size.width - 4; i += 4 )
+ {
+ t0 = CV_FAST_CAST_8U((tab1[src1[i]] + tab2[src2[i]]) >> shift);
+ t1 = CV_FAST_CAST_8U((tab1[src1[i+1]] + tab2[src2[i+1]]) >> shift);
+
+ dst[i] = (uchar)t0;
+ dst[i+1] = (uchar)t1;
+
+ t0 = CV_FAST_CAST_8U((tab1[src1[i+2]] + tab2[src2[i+2]]) >> shift);
+ t1 = CV_FAST_CAST_8U((tab1[src1[i+3]] + tab2[src2[i+3]]) >> shift);
+
+ dst[i+2] = (uchar)t0;
+ dst[i+3] = (uchar)t1;
+ }
+
+ for( ; i < size.width; i++ )
+ {
+ t0 = CV_FAST_CAST_8U((tab1[src1[i]] + tab2[src2[i]]) >> shift);
+ dst[i] = (uchar)t0;
+ }
+ }
+ }
+ else
+ {
+ // use universal macro for convertion back to 8u
+ for( ; size.height--; src1 += step1, src2 += step2, dst += step )
+ {
+ int i;
+
+ for( i = 0; i <= size.width - 4; i += 4 )
+ {
+ t0 = (tab1[src1[i]] + tab2[src2[i]]) >> shift;
+ t1 = (tab1[src1[i+1]] + tab2[src2[i+1]]) >> shift;
+
+ dst[i] = CV_CAST_8U( t0 );
+ dst[i+1] = CV_CAST_8U( t1 );
+
+ t0 = (tab1[src1[i+2]] + tab2[src2[i+2]]) >> shift;
+ t1 = (tab1[src1[i+3]] + tab2[src2[i+3]]) >> shift;
+
+ dst[i+2] = CV_CAST_8U( t0 );
+ dst[i+3] = CV_CAST_8U( t1 );
+ }
+
+ for( ; i < size.width; i++ )
+ {
+ t0 = (tab1[src1[i]] + tab2[src2[i]]) >> shift;
+ dst[i] = CV_CAST_8U( t0 );
+ }
+ }
+ }
+
+ return CV_OK;
+}
+
+
+ICV_DEF_ADD_WEIGHTED_OP( 8u, uchar, int, CV_8TO32F, cvRound, CV_CAST_8U )
+ICV_DEF_ADD_WEIGHTED_OP( 16u, ushort, int, CV_NOP, cvRound, CV_CAST_16U )
+ICV_DEF_ADD_WEIGHTED_OP( 16s, short, int, CV_NOP, cvRound, CV_CAST_16S )
+ICV_DEF_ADD_WEIGHTED_OP( 32s, int, int, CV_NOP, cvRound, CV_CAST_32S )
+ICV_DEF_ADD_WEIGHTED_OP( 32f, float, double, CV_NOP, CV_NOP, CV_CAST_32F )
+ICV_DEF_ADD_WEIGHTED_OP( 64f, double, double, CV_NOP, CV_NOP, CV_CAST_64F )
+
+
+ICV_DEF_INIT_ARITHM_FUNC_TAB( AddWeighted, C1R )
+
+typedef CvStatus (CV_STDCALL *CvAddWeightedFunc)( const void* src1, int step1, double alpha,
+ const void* src2, int step2, double beta,
+ double gamma, void* dst,
+ int step, CvSize size );
+
+CV_IMPL void
+cvAddWeighted( const CvArr* srcAarr, double alpha,
+ const CvArr* srcBarr, double beta,
+ double gamma, CvArr* dstarr )
+{
+ static CvFuncTable addw_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvAddWeighted" );
+
+ __BEGIN__;
+
+ CvMat srcA_stub, *srcA = (CvMat*)srcAarr;
+ CvMat srcB_stub, *srcB = (CvMat*)srcBarr;
+ CvMat dst_stub, *dst = (CvMat*)dstarr;
+ int coi1, coi2, coi;
+ int srcA_step, srcB_step, dst_step;
+ int type;
+ CvAddWeightedFunc func;
+ CvSize size;
+
+ if( !inittab )
+ {
+ icvInitAddWeightedC1RTable( &addw_tab );
+ inittab = 1;
+ }
+
+ CV_CALL( srcA = cvGetMat( srcA, &srcA_stub, &coi1 ));
+ CV_CALL( srcB = cvGetMat( srcB, &srcB_stub, &coi2 ));
+ CV_CALL( dst = cvGetMat( dst, &dst_stub, &coi ));
+
+ if( coi1 || coi2 || coi )
+ CV_ERROR( CV_BadCOI, "COI must not be set" );
+
+ if( !CV_ARE_TYPES_EQ( srcA, srcB ) ||
+ !CV_ARE_TYPES_EQ( srcA, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats,
+ "All input/output arrays should have the same type");
+
+ if( !CV_ARE_SIZES_EQ( srcA, srcB ) ||
+ !CV_ARE_SIZES_EQ( srcA, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "All input/output arrays should have the same sizes");
+
+ size = cvGetMatSize( srcA );
+ type = CV_MAT_TYPE( srcA->type );
+ size.width *= CV_MAT_CN( type );
+ srcA_step = srcA->step;
+ srcB_step = srcB->step;
+ dst_step = dst->step;
+
+ if( CV_IS_MAT_CONT( type & srcB->type & dst->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ srcA_step = srcB_step = dst_step = CV_AUTOSTEP;
+ }
+
+ if( type == CV_8UC1 && size.width * size.height >= 1024 &&
+ fabs(alpha) < 256 && fabs(beta) < 256 && fabs(gamma) < 256*256 )
+ {
+ func = (CvAddWeightedFunc)icvAddWeighted_8u_fast_C1R;
+ }
+ else
+ {
+ func = (CvAddWeightedFunc)addw_tab.fn_2d[CV_MAT_DEPTH(type)];
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "This array type is not supported" );
+ }
+
+ IPPI_CALL( func( srcA->data.ptr, srcA_step, alpha, srcB->data.ptr, srcB_step,
+ beta, gamma, dst->data.ptr, dst_step, size ));
+
+ __END__;
+}
+
+
+/* End of file. */
diff --git a/cxcore/src/cxarray.cpp b/cxcore/src/cxarray.cpp
new file mode 100644
index 0000000..03f6dac
--- /dev/null
+++ b/cxcore/src/cxarray.cpp
@@ -0,0 +1,3701 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/* ////////////////////////////////////////////////////////////////////
+//
+// CvMat, CvMatND, CvSparceMat and IplImage support functions
+// (creation, deletion, copying, retrieving and setting elements etc.)
+//
+// */
+
+#include "_cxcore.h"
+
+static struct
+{
+ Cv_iplCreateImageHeader createHeader;
+ Cv_iplAllocateImageData allocateData;
+ Cv_iplDeallocate deallocate;
+ Cv_iplCreateROI createROI;
+ Cv_iplCloneImage cloneImage;
+}
+CvIPL;
+
+// Makes the library use native IPL image allocators
+CV_IMPL void
+cvSetIPLAllocators( Cv_iplCreateImageHeader createHeader,
+ Cv_iplAllocateImageData allocateData,
+ Cv_iplDeallocate deallocate,
+ Cv_iplCreateROI createROI,
+ Cv_iplCloneImage cloneImage )
+{
+ CV_FUNCNAME( "cvSetIPLAllocators" );
+
+ __BEGIN__;
+
+ if( !createHeader || !allocateData || !deallocate || !createROI || !cloneImage )
+ {
+ if( createHeader || allocateData || deallocate || createROI || cloneImage )
+ CV_ERROR( CV_StsBadArg, "Either all the pointers should be null or "
+ "they all should be non-null" );
+ }
+
+ CvIPL.createHeader = createHeader;
+ CvIPL.allocateData = allocateData;
+ CvIPL.deallocate = deallocate;
+ CvIPL.createROI = createROI;
+ CvIPL.cloneImage = cloneImage;
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* CvMat creation and basic operations *
+\****************************************************************************************/
+
+// Creates CvMat and underlying data
+CV_IMPL CvMat*
+cvCreateMat( int height, int width, int type )
+{
+ CvMat* arr = 0;
+
+ CV_FUNCNAME( "cvCreateMat" );
+
+ __BEGIN__;
+
+ CV_CALL( arr = cvCreateMatHeader( height, width, type ));
+ CV_CALL( cvCreateData( arr ));
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvReleaseMat( &arr );
+
+ return arr;
+}
+
+
+static void icvCheckHuge( CvMat* arr )
+{
+ if( (int64)arr->step*arr->rows > INT_MAX )
+ arr->type &= ~CV_MAT_CONT_FLAG;
+}
+
+// Creates CvMat header only
+CV_IMPL CvMat*
+cvCreateMatHeader( int rows, int cols, int type )
+{
+ CvMat* arr = 0;
+
+ CV_FUNCNAME( "cvCreateMatHeader" );
+
+ __BEGIN__;
+
+ int min_step;
+ type = CV_MAT_TYPE(type);
+
+ if( rows <= 0 || cols <= 0 )
+ CV_ERROR( CV_StsBadSize, "Non-positive width or height" );
+
+ min_step = CV_ELEM_SIZE(type)*cols;
+ if( min_step <= 0 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Invalid matrix type" );
+
+ CV_CALL( arr = (CvMat*)cvAlloc( sizeof(*arr)));
+
+ arr->step = rows == 1 ? 0 : cvAlign(min_step, CV_DEFAULT_MAT_ROW_ALIGN);
+ arr->type = CV_MAT_MAGIC_VAL | type |
+ (arr->step == 0 || arr->step == min_step ? CV_MAT_CONT_FLAG : 0);
+ arr->rows = rows;
+ arr->cols = cols;
+ arr->data.ptr = 0;
+ arr->refcount = 0;
+ arr->hdr_refcount = 1;
+
+ icvCheckHuge( arr );
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvReleaseMat( &arr );
+
+ return arr;
+}
+
+
+// Initializes CvMat header, allocated by the user
+CV_IMPL CvMat*
+cvInitMatHeader( CvMat* arr, int rows, int cols,
+ int type, void* data, int step )
+{
+ CV_FUNCNAME( "cvInitMatHeader" );
+
+ __BEGIN__;
+
+ int mask, pix_size, min_step;
+
+ if( !arr )
+ CV_ERROR_FROM_CODE( CV_StsNullPtr );
+
+ if( (unsigned)CV_MAT_DEPTH(type) > CV_DEPTH_MAX )
+ CV_ERROR_FROM_CODE( CV_BadNumChannels );
+
+ if( rows <= 0 || cols <= 0 )
+ CV_ERROR( CV_StsBadSize, "Non-positive cols or rows" );
+
+ type = CV_MAT_TYPE( type );
+ arr->type = type | CV_MAT_MAGIC_VAL;
+ arr->rows = rows;
+ arr->cols = cols;
+ arr->data.ptr = (uchar*)data;
+ arr->refcount = 0;
+ arr->hdr_refcount = 0;
+
+ mask = (arr->rows <= 1) - 1;
+ pix_size = CV_ELEM_SIZE(type);
+ min_step = arr->cols*pix_size & mask;
+
+ if( step != CV_AUTOSTEP && step != 0 )
+ {
+ if( step < min_step )
+ CV_ERROR_FROM_CODE( CV_BadStep );
+ arr->step = step & mask;
+ }
+ else
+ {
+ arr->step = min_step;
+ }
+
+ arr->type = CV_MAT_MAGIC_VAL | type |
+ (arr->step == min_step ? CV_MAT_CONT_FLAG : 0);
+
+ icvCheckHuge( arr );
+
+ __END__;
+
+ return arr;
+}
+
+
+// Deallocates the CvMat structure and underlying data
+CV_IMPL void
+cvReleaseMat( CvMat** array )
+{
+ CV_FUNCNAME( "cvReleaseMat" );
+
+ __BEGIN__;
+
+ if( !array )
+ CV_ERROR_FROM_CODE( CV_HeaderIsNull );
+
+ if( *array )
+ {
+ CvMat* arr = *array;
+
+ if( !CV_IS_MAT_HDR(arr) && !CV_IS_MATND_HDR(arr) )
+ CV_ERROR_FROM_CODE( CV_StsBadFlag );
+
+ *array = 0;
+
+ cvDecRefData( arr );
+ cvFree( &arr );
+ }
+
+ __END__;
+}
+
+
+// Creates a copy of matrix
+CV_IMPL CvMat*
+cvCloneMat( const CvMat* src )
+{
+ CvMat* dst = 0;
+ CV_FUNCNAME( "cvCloneMat" );
+
+ __BEGIN__;
+
+ if( !CV_IS_MAT_HDR( src ))
+ CV_ERROR( CV_StsBadArg, "Bad CvMat header" );
+
+ CV_CALL( dst = cvCreateMatHeader( src->rows, src->cols, src->type ));
+
+ if( src->data.ptr )
+ {
+ CV_CALL( cvCreateData( dst ));
+ CV_CALL( cvCopy( src, dst ));
+ }
+
+ __END__;
+
+ return dst;
+}
+
+
+/****************************************************************************************\
+* CvMatND creation and basic operations *
+\****************************************************************************************/
+
+CV_IMPL CvMatND*
+cvInitMatNDHeader( CvMatND* mat, int dims, const int* sizes,
+ int type, void* data )
+{
+ CvMatND* result = 0;
+
+ CV_FUNCNAME( "cvInitMatNDHeader" );
+
+ __BEGIN__;
+
+ type = CV_MAT_TYPE(type);
+ int i;
+ int64 step = CV_ELEM_SIZE(type);
+
+ if( !mat )
+ CV_ERROR( CV_StsNullPtr, "NULL matrix header pointer" );
+
+ if( step == 0 )
+ CV_ERROR( CV_StsUnsupportedFormat, "invalid array data type" );
+
+ if( !sizes )
+ CV_ERROR( CV_StsNullPtr, "NULL <sizes> pointer" );
+
+ if( dims <= 0 || dims > CV_MAX_DIM )
+ CV_ERROR( CV_StsOutOfRange,
+ "non-positive or too large number of dimensions" );
+
+ for( i = dims - 1; i >= 0; i-- )
+ {
+ if( sizes[i] <= 0 )
+ CV_ERROR( CV_StsBadSize, "one of dimesion sizes is non-positive" );
+ mat->dim[i].size = sizes[i];
+ if( step > INT_MAX )
+ CV_ERROR( CV_StsOutOfRange, "The array is too big" );
+ mat->dim[i].step = (int)step;
+ step *= sizes[i];
+ }
+
+ mat->type = CV_MATND_MAGIC_VAL | (step <= INT_MAX ? CV_MAT_CONT_FLAG : 0) | type;
+ mat->dims = dims;
+ mat->data.ptr = (uchar*)data;
+ mat->refcount = 0;
+ mat->hdr_refcount = 0;
+ result = mat;
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 && mat )
+ {
+ mat->type = 0;
+ mat->data.ptr = 0;
+ }
+
+ return result;
+}
+
+
+// Creates CvMatND and underlying data
+CV_IMPL CvMatND*
+cvCreateMatND( int dims, const int* sizes, int type )
+{
+ CvMatND* arr = 0;
+
+ CV_FUNCNAME( "cvCreateMatND" );
+
+ __BEGIN__;
+
+ CV_CALL( arr = cvCreateMatNDHeader( dims, sizes, type ));
+ CV_CALL( cvCreateData( arr ));
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvReleaseMatND( &arr );
+
+ return arr;
+}
+
+
+// Creates CvMatND header only
+CV_IMPL CvMatND*
+cvCreateMatNDHeader( int dims, const int* sizes, int type )
+{
+ CvMatND* arr = 0;
+
+ CV_FUNCNAME( "cvCreateMatNDHeader" );
+
+ __BEGIN__;
+
+ if( dims <= 0 || dims > CV_MAX_DIM )
+ CV_ERROR( CV_StsOutOfRange,
+ "non-positive or too large number of dimensions" );
+
+ CV_CALL( arr = (CvMatND*)cvAlloc( sizeof(*arr) ));
+
+ CV_CALL( cvInitMatNDHeader( arr, dims, sizes, type, 0 ));
+ arr->hdr_refcount = 1;
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvReleaseMatND( &arr );
+
+ return arr;
+}
+
+
+// Creates a copy of nD array
+CV_IMPL CvMatND*
+cvCloneMatND( const CvMatND* src )
+{
+ CvMatND* dst = 0;
+ CV_FUNCNAME( "cvCloneMatND" );
+
+ __BEGIN__;
+
+ int i, *sizes;
+
+ if( !CV_IS_MATND_HDR( src ))
+ CV_ERROR( CV_StsBadArg, "Bad CvMatND header" );
+
+ sizes = (int*)alloca( src->dims*sizeof(sizes[0]) );
+
+ for( i = 0; i < src->dims; i++ )
+ sizes[i] = src->dim[i].size;
+
+ CV_CALL( dst = cvCreateMatNDHeader( src->dims, sizes, src->type ));
+
+ if( src->data.ptr )
+ {
+ CV_CALL( cvCreateData( dst ));
+ CV_CALL( cvCopy( src, dst ));
+ }
+
+ __END__;
+
+ return dst;
+}
+
+
+static CvMatND*
+cvGetMatND( const CvArr* arr, CvMatND* matnd, int* coi )
+{
+ CvMatND* result = 0;
+
+ CV_FUNCNAME( "cvGetMatND" );
+
+ __BEGIN__;
+
+ if( coi )
+ *coi = 0;
+
+ if( !matnd || !arr )
+ CV_ERROR( CV_StsNullPtr, "NULL array pointer is passed" );
+
+ if( CV_IS_MATND_HDR(arr))
+ {
+ if( !((CvMatND*)arr)->data.ptr )
+ CV_ERROR( CV_StsNullPtr, "The matrix has NULL data pointer" );
+
+ result = (CvMatND*)arr;
+ }
+ else
+ {
+ CvMat stub, *mat = (CvMat*)arr;
+
+ if( CV_IS_IMAGE_HDR( mat ))
+ CV_CALL( mat = cvGetMat( mat, &stub, coi ));
+
+ if( !CV_IS_MAT_HDR( mat ))
+ CV_ERROR( CV_StsBadArg, "Unrecognized or unsupported array type" );
+
+ if( !mat->data.ptr )
+ CV_ERROR( CV_StsNullPtr, "Input array has NULL data pointer" );
+
+ matnd->data.ptr = mat->data.ptr;
+ matnd->refcount = 0;
+ matnd->hdr_refcount = 0;
+ matnd->type = mat->type;
+ matnd->dims = 2;
+ matnd->dim[0].size = mat->rows;
+ matnd->dim[0].step = mat->step;
+ matnd->dim[1].size = mat->cols;
+ matnd->dim[1].step = CV_ELEM_SIZE(mat->type);
+ result = matnd;
+ }
+
+ __END__;
+
+ return result;
+}
+
+
+// returns number of dimensions to iterate.
+/*
+Checks whether <count> arrays have equal type, sizes (mask is optional array
+that needs to have the same size, but 8uC1 or 8sC1 type).
+Returns number of dimensions to iterate through:
+0 means that all arrays are continuous,
+1 means that all arrays are vectors of continuous arrays etc.
+and the size of largest common continuous part of the arrays
+*/
+CV_IMPL int
+cvInitNArrayIterator( int count, CvArr** arrs,
+ const CvArr* mask, CvMatND* stubs,
+ CvNArrayIterator* iterator, int flags )
+{
+ int dims = -1;
+
+ CV_FUNCNAME( "cvInitArrayOp" );
+
+ __BEGIN__;
+
+ int i, j, size, dim0 = -1;
+ int64 step;
+ CvMatND* hdr0 = 0;
+
+ if( count < 1 || count > CV_MAX_ARR )
+ CV_ERROR( CV_StsOutOfRange, "Incorrect number of arrays" );
+
+ if( !arrs || !stubs )
+ CV_ERROR( CV_StsNullPtr, "Some of required array pointers is NULL" );
+
+ if( !iterator )
+ CV_ERROR( CV_StsNullPtr, "Iterator pointer is NULL" );
+
+ for( i = 0; i <= count; i++ )
+ {
+ const CvArr* arr = i < count ? arrs[i] : mask;
+ CvMatND* hdr;
+
+ if( !arr )
+ {
+ if( i < count )
+ CV_ERROR( CV_StsNullPtr, "Some of required array pointers is NULL" );
+ break;
+ }
+
+ if( CV_IS_MATND( arr ))
+ hdr = (CvMatND*)arr;
+ else
+ {
+ int coi = 0;
+ CV_CALL( hdr = cvGetMatND( arr, stubs + i, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "COI set is not allowed here" );
+ }
+
+ iterator->hdr[i] = hdr;
+
+ if( i > 0 )
+ {
+ if( hdr->dims != hdr0->dims )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Number of dimensions is the same for all arrays" );
+
+ if( i < count )
+ {
+ switch( flags & (CV_NO_DEPTH_CHECK|CV_NO_CN_CHECK))
+ {
+ case 0:
+ if( !CV_ARE_TYPES_EQ( hdr, hdr0 ))
+ CV_ERROR( CV_StsUnmatchedFormats,
+ "Data type is not the same for all arrays" );
+ break;
+ case CV_NO_DEPTH_CHECK:
+ if( !CV_ARE_CNS_EQ( hdr, hdr0 ))
+ CV_ERROR( CV_StsUnmatchedFormats,
+ "Number of channels is not the same for all arrays" );
+ break;
+ case CV_NO_CN_CHECK:
+ if( !CV_ARE_CNS_EQ( hdr, hdr0 ))
+ CV_ERROR( CV_StsUnmatchedFormats,
+ "Depth is not the same for all arrays" );
+ break;
+ }
+ }
+ else
+ {
+ if( !CV_IS_MASK_ARR( hdr ))
+ CV_ERROR( CV_StsBadMask, "Mask should have 8uC1 or 8sC1 data type" );
+ }
+
+ if( !(flags & CV_NO_SIZE_CHECK) )
+ {
+ for( j = 0; j < hdr->dims; j++ )
+ if( hdr->dim[j].size != hdr0->dim[j].size )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Dimension sizes are the same for all arrays" );
+ }
+ }
+ else
+ hdr0 = hdr;
+
+ step = CV_ELEM_SIZE(hdr->type);
+ for( j = hdr->dims - 1; j > dim0; j-- )
+ {
+ if( step != hdr->dim[j].step )
+ break;
+ step *= hdr->dim[j].size;
+ }
+
+ if( j == dim0 && step > INT_MAX )
+ j++;
+
+ if( j > dim0 )
+ dim0 = j;
+
+ iterator->hdr[i] = (CvMatND*)hdr;
+ iterator->ptr[i] = (uchar*)hdr->data.ptr;
+ }
+
+ size = 1;
+ for( j = hdr0->dims - 1; j > dim0; j-- )
+ size *= hdr0->dim[j].size;
+
+ dims = dim0 + 1;
+ iterator->dims = dims;
+ iterator->count = count;
+ iterator->size = cvSize(size,1);
+
+ for( i = 0; i < dims; i++ )
+ iterator->stack[i] = hdr0->dim[i].size;
+
+ __END__;
+
+ return dims;
+}
+
+
+// returns zero value if iteration is finished, non-zero otherwise
+CV_IMPL int cvNextNArraySlice( CvNArrayIterator* iterator )
+{
+ assert( iterator != 0 );
+ int i, dims, size = 0;
+
+ for( dims = iterator->dims; dims > 0; dims-- )
+ {
+ for( i = 0; i < iterator->count; i++ )
+ iterator->ptr[i] += iterator->hdr[i]->dim[dims-1].step;
+
+ if( --iterator->stack[dims-1] > 0 )
+ break;
+
+ size = iterator->hdr[0]->dim[dims-1].size;
+
+ for( i = 0; i < iterator->count; i++ )
+ iterator->ptr[i] -= (size_t)size*iterator->hdr[i]->dim[dims-1].step;
+
+ iterator->stack[dims-1] = size;
+ }
+
+ return dims > 0;
+}
+
+
+/****************************************************************************************\
+* CvSparseMat creation and basic operations *
+\****************************************************************************************/
+
+
+// Creates CvMatND and underlying data
+CV_IMPL CvSparseMat*
+cvCreateSparseMat( int dims, const int* sizes, int type )
+{
+ CvSparseMat* arr = 0;
+
+ CV_FUNCNAME( "cvCreateSparseMat" );
+
+ __BEGIN__;
+
+ type = CV_MAT_TYPE( type );
+ int pix_size1 = CV_ELEM_SIZE1(type);
+ int pix_size = pix_size1*CV_MAT_CN(type);
+ int i, size;
+ CvMemStorage* storage;
+
+ if( pix_size == 0 )
+ CV_ERROR( CV_StsUnsupportedFormat, "invalid array data type" );
+
+ if( dims <= 0 || dims > CV_MAX_DIM_HEAP )
+ CV_ERROR( CV_StsOutOfRange, "bad number of dimensions" );
+
+ if( !sizes )
+ CV_ERROR( CV_StsNullPtr, "NULL <sizes> pointer" );
+
+ for( i = 0; i < dims; i++ )
+ {
+ if( sizes[i] <= 0 )
+ CV_ERROR( CV_StsBadSize, "one of dimesion sizes is non-positive" );
+ }
+
+ CV_CALL( arr = (CvSparseMat*)cvAlloc(sizeof(*arr)+MAX(0,dims-CV_MAX_DIM)*sizeof(arr->size[0])));
+
+ arr->type = CV_SPARSE_MAT_MAGIC_VAL | type;
+ arr->dims = dims;
+ arr->refcount = 0;
+ arr->hdr_refcount = 1;
+ memcpy( arr->size, sizes, dims*sizeof(sizes[0]));
+
+ arr->valoffset = (int)cvAlign(sizeof(CvSparseNode), pix_size1);
+ arr->idxoffset = (int)cvAlign(arr->valoffset + pix_size, sizeof(int));
+ size = (int)cvAlign(arr->idxoffset + dims*sizeof(int), sizeof(CvSetElem));
+
+ CV_CALL( storage = cvCreateMemStorage( CV_SPARSE_MAT_BLOCK ));
+ CV_CALL( arr->heap = cvCreateSet( 0, sizeof(CvSet), size, storage ));
+
+ arr->hashsize = CV_SPARSE_HASH_SIZE0;
+ size = arr->hashsize*sizeof(arr->hashtable[0]);
+
+ CV_CALL( arr->hashtable = (void**)cvAlloc( size ));
+ memset( arr->hashtable, 0, size );
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvReleaseSparseMat( &arr );
+
+ return arr;
+}
+
+
+// Creates CvMatND and underlying data
+CV_IMPL void
+cvReleaseSparseMat( CvSparseMat** array )
+{
+ CV_FUNCNAME( "cvReleaseSparseMat" );
+
+ __BEGIN__;
+
+ if( !array )
+ CV_ERROR_FROM_CODE( CV_HeaderIsNull );
+
+ if( *array )
+ {
+ CvSparseMat* arr = *array;
+
+ if( !CV_IS_SPARSE_MAT_HDR(arr) )
+ CV_ERROR_FROM_CODE( CV_StsBadFlag );
+
+ *array = 0;
+
+ cvReleaseMemStorage( &arr->heap->storage );
+ cvFree( &arr->hashtable );
+ cvFree( &arr );
+ }
+
+ __END__;
+}
+
+
+// Creates CvMatND and underlying data
+CV_IMPL CvSparseMat*
+cvCloneSparseMat( const CvSparseMat* src )
+{
+ CvSparseMat* dst = 0;
+
+ CV_FUNCNAME( "cvCloneSparseMat" );
+
+ __BEGIN__;
+
+ if( !CV_IS_SPARSE_MAT_HDR(src) )
+ CV_ERROR( CV_StsBadArg, "Invalid sparse array header" );
+
+ CV_CALL( dst = cvCreateSparseMat( src->dims, src->size, src->type ));
+ CV_CALL( cvCopy( src, dst ));
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvReleaseSparseMat( &dst );
+
+ return dst;
+}
+
+
+CvSparseNode*
+cvInitSparseMatIterator( const CvSparseMat* mat, CvSparseMatIterator* iterator )
+{
+ CvSparseNode* node = 0;
+
+ CV_FUNCNAME( "cvInitSparseMatIterator" );
+
+ __BEGIN__;
+
+ int idx;
+
+ if( !CV_IS_SPARSE_MAT( mat ))
+ CV_ERROR( CV_StsBadArg, "Invalid sparse matrix header" );
+
+ if( !iterator )
+ CV_ERROR( CV_StsNullPtr, "NULL iterator pointer" );
+
+ iterator->mat = (CvSparseMat*)mat;
+ iterator->node = 0;
+
+ for( idx = 0; idx < mat->hashsize; idx++ )
+ if( mat->hashtable[idx] )
+ {
+ node = iterator->node = (CvSparseNode*)mat->hashtable[idx];
+ break;
+ }
+
+ iterator->curidx = idx;
+
+ __END__;
+
+ return node;
+}
+
+#define ICV_SPARSE_MAT_HASH_MULTIPLIER 33
+
+static uchar*
+icvGetNodePtr( CvSparseMat* mat, const int* idx, int* _type,
+ int create_node, unsigned* precalc_hashval )
+{
+ uchar* ptr = 0;
+
+ CV_FUNCNAME( "icvGetNodePtr" );
+
+ __BEGIN__;
+
+ int i, tabidx;
+ unsigned hashval = 0;
+ CvSparseNode *node;
+ assert( CV_IS_SPARSE_MAT( mat ));
+
+ if( !precalc_hashval )
+ {
+ for( i = 0; i < mat->dims; i++ )
+ {
+ int t = idx[i];
+ if( (unsigned)t >= (unsigned)mat->size[i] )
+ CV_ERROR( CV_StsOutOfRange, "One of indices is out of range" );
+ hashval = hashval*ICV_SPARSE_MAT_HASH_MULTIPLIER + t;
+ }
+ }
+ else
+ {
+ hashval = *precalc_hashval;
+ }
+
+ tabidx = hashval & (mat->hashsize - 1);
+ hashval &= INT_MAX;
+
+ for( node = (CvSparseNode*)mat->hashtable[tabidx];
+ node != 0; node = node->next )
+ {
+ if( node->hashval == hashval )
+ {
+ int* nodeidx = CV_NODE_IDX(mat,node);
+ for( i = 0; i < mat->dims; i++ )
+ if( idx[i] != nodeidx[i] )
+ break;
+ if( i == mat->dims )
+ {
+ ptr = (uchar*)CV_NODE_VAL(mat,node);
+ break;
+ }
+ }
+ }
+
+ if( !ptr && create_node )
+ {
+ if( mat->heap->active_count >= mat->hashsize*CV_SPARSE_HASH_RATIO )
+ {
+ void** newtable;
+ int newsize = MAX( mat->hashsize*2, CV_SPARSE_HASH_SIZE0);
+ int newrawsize = newsize*sizeof(newtable[0]);
+
+ CvSparseMatIterator iterator;
+ assert( (newsize & (newsize - 1)) == 0 );
+
+ // resize hash table
+ CV_CALL( newtable = (void**)cvAlloc( newrawsize ));
+ memset( newtable, 0, newrawsize );
+
+ node = cvInitSparseMatIterator( mat, &iterator );
+ while( node )
+ {
+ CvSparseNode* next = cvGetNextSparseNode( &iterator );
+ int newidx = node->hashval & (newsize - 1);
+ node->next = (CvSparseNode*)newtable[newidx];
+ newtable[newidx] = node;
+ node = next;
+ }
+
+ cvFree( &mat->hashtable );
+ mat->hashtable = newtable;
+ mat->hashsize = newsize;
+ tabidx = hashval & (newsize - 1);
+ }
+
+ node = (CvSparseNode*)cvSetNew( mat->heap );
+ node->hashval = hashval;
+ node->next = (CvSparseNode*)mat->hashtable[tabidx];
+ mat->hashtable[tabidx] = node;
+ CV_MEMCPY_INT( CV_NODE_IDX(mat,node), idx, mat->dims );
+ ptr = (uchar*)CV_NODE_VAL(mat,node);
+ if( create_node > 0 )
+ CV_ZERO_CHAR( ptr, CV_ELEM_SIZE(mat->type));
+ }
+
+ if( _type )
+ *_type = CV_MAT_TYPE(mat->type);
+
+ __END__;
+
+ return ptr;
+}
+
+
+static void
+icvDeleteNode( CvSparseMat* mat, const int* idx, unsigned* precalc_hashval )
+{
+ CV_FUNCNAME( "icvDeleteNode" );
+
+ __BEGIN__;
+
+ int i, tabidx;
+ unsigned hashval = 0;
+ CvSparseNode *node, *prev = 0;
+ assert( CV_IS_SPARSE_MAT( mat ));
+
+ if( !precalc_hashval )
+ {
+ for( i = 0; i < mat->dims; i++ )
+ {
+ int t = idx[i];
+ if( (unsigned)t >= (unsigned)mat->size[i] )
+ CV_ERROR( CV_StsOutOfRange, "One of indices is out of range" );
+ hashval = hashval*ICV_SPARSE_MAT_HASH_MULTIPLIER + t;
+ }
+ }
+ else
+ {
+ hashval = *precalc_hashval;
+ }
+
+ tabidx = hashval & (mat->hashsize - 1);
+ hashval &= INT_MAX;
+
+ for( node = (CvSparseNode*)mat->hashtable[tabidx];
+ node != 0; prev = node, node = node->next )
+ {
+ if( node->hashval == hashval )
+ {
+ int* nodeidx = CV_NODE_IDX(mat,node);
+ for( i = 0; i < mat->dims; i++ )
+ if( idx[i] != nodeidx[i] )
+ break;
+ if( i == mat->dims )
+ break;
+ }
+ }
+
+ if( node )
+ {
+ if( prev )
+ prev->next = node->next;
+ else
+ mat->hashtable[tabidx] = node->next;
+ cvSetRemoveByPtr( mat->heap, node );
+ }
+
+ __END__;
+}
+
+
+
+/****************************************************************************************\
+* Common for multiple array types operations *
+\****************************************************************************************/
+
+// Allocates underlying array data
+CV_IMPL void
+cvCreateData( CvArr* arr )
+{
+ CV_FUNCNAME( "cvCreateData" );
+
+ __BEGIN__;
+
+ if( CV_IS_MAT_HDR( arr ))
+ {
+ size_t step, total_size;
+ CvMat* mat = (CvMat*)arr;
+ step = mat->step;
+
+ if( mat->data.ptr != 0 )
+ CV_ERROR( CV_StsError, "Data is already allocated" );
+
+ if( step == 0 )
+ step = CV_ELEM_SIZE(mat->type)*mat->cols;
+
+ total_size = step*mat->rows + sizeof(int) + CV_MALLOC_ALIGN;
+ CV_CALL( mat->refcount = (int*)cvAlloc( (size_t)total_size ));
+ mat->data.ptr = (uchar*)cvAlignPtr( mat->refcount + 1, CV_MALLOC_ALIGN );
+ *mat->refcount = 1;
+ }
+ else if( CV_IS_IMAGE_HDR(arr))
+ {
+ IplImage* img = (IplImage*)arr;
+
+ if( img->imageData != 0 )
+ CV_ERROR( CV_StsError, "Data is already allocated" );
+
+ if( !CvIPL.allocateData )
+ {
+ CV_CALL( img->imageData = img->imageDataOrigin =
+ (char*)cvAlloc( (size_t)img->imageSize ));
+ }
+ else
+ {
+ int depth = img->depth;
+ int width = img->width;
+
+ if( img->depth == IPL_DEPTH_32F || img->nChannels == 64 )
+ {
+ img->width *= img->depth == IPL_DEPTH_32F ? sizeof(float) : sizeof(double);
+ img->depth = IPL_DEPTH_8U;
+ }
+
+ CvIPL.allocateData( img, 0, 0 );
+
+ img->width = width;
+ img->depth = depth;
+ }
+ }
+ else if( CV_IS_MATND_HDR( arr ))
+ {
+ CvMatND* mat = (CvMatND*)arr;
+ int i;
+ size_t total_size = CV_ELEM_SIZE(mat->type);
+
+ if( mat->data.ptr != 0 )
+ CV_ERROR( CV_StsError, "Data is already allocated" );
+
+ if( CV_IS_MAT_CONT( mat->type ))
+ {
+ total_size = (size_t)mat->dim[0].size*(mat->dim[0].step != 0 ?
+ mat->dim[0].step : total_size);
+ }
+ else
+ {
+ for( i = mat->dims - 1; i >= 0; i-- )
+ {
+ size_t size = (size_t)mat->dim[i].step*mat->dim[i].size;
+
+ if( total_size < size )
+ total_size = size;
+ }
+ }
+
+ CV_CALL( mat->refcount = (int*)cvAlloc( total_size +
+ sizeof(int) + CV_MALLOC_ALIGN ));
+ mat->data.ptr = (uchar*)cvAlignPtr( mat->refcount + 1, CV_MALLOC_ALIGN );
+ *mat->refcount = 1;
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg, "unrecognized or unsupported array type" );
+ }
+
+ __END__;
+}
+
+
+// Assigns external data to array
+CV_IMPL void
+cvSetData( CvArr* arr, void* data, int step )
+{
+ CV_FUNCNAME( "cvSetData" );
+
+ __BEGIN__;
+
+ int pix_size, min_step;
+
+ if( CV_IS_MAT_HDR(arr) || CV_IS_MATND_HDR(arr) )
+ cvReleaseData( arr );
+
+ if( CV_IS_MAT_HDR( arr ))
+ {
+ CvMat* mat = (CvMat*)arr;
+
+ int type = CV_MAT_TYPE(mat->type);
+ pix_size = CV_ELEM_SIZE(type);
+ min_step = mat->cols*pix_size & ((mat->rows <= 1) - 1);
+
+ if( step != CV_AUTOSTEP )
+ {
+ if( step < min_step && data != 0 )
+ CV_ERROR_FROM_CODE( CV_BadStep );
+ mat->step = step & ((mat->rows <= 1) - 1);
+ }
+ else
+ {
+ mat->step = min_step;
+ }
+
+ mat->data.ptr = (uchar*)data;
+ mat->type = CV_MAT_MAGIC_VAL | type |
+ (mat->step==min_step ? CV_MAT_CONT_FLAG : 0);
+ icvCheckHuge( mat );
+ }
+ else if( CV_IS_IMAGE_HDR( arr ))
+ {
+ IplImage* img = (IplImage*)arr;
+
+ pix_size = ((img->depth & 255) >> 3)*img->nChannels;
+ min_step = img->width*pix_size;
+
+ if( step != CV_AUTOSTEP && img->height > 1 )
+ {
+ if( step < min_step && data != 0 )
+ CV_ERROR_FROM_CODE( CV_BadStep );
+ img->widthStep = step;
+ }
+ else
+ {
+ img->widthStep = min_step;
+ }
+
+ img->imageSize = img->widthStep * img->height;
+ img->imageData = img->imageDataOrigin = (char*)data;
+
+ if( (((int)(size_t)data | step) & 7) == 0 &&
+ cvAlign(img->width * pix_size, 8) == step )
+ {
+ img->align = 8;
+ }
+ else
+ {
+ img->align = 4;
+ }
+ }
+ else if( CV_IS_MATND_HDR( arr ))
+ {
+ CvMatND* mat = (CvMatND*)arr;
+ int i;
+ int64 cur_step;
+
+ if( step != CV_AUTOSTEP )
+ CV_ERROR( CV_BadStep,
+ "For multidimensional array only CV_AUTOSTEP is allowed here" );
+
+ mat->data.ptr = (uchar*)data;
+ cur_step = CV_ELEM_SIZE(mat->type);
+
+ for( i = mat->dims - 1; i >= 0; i-- )
+ {
+ if( cur_step > INT_MAX )
+ CV_ERROR( CV_StsOutOfRange, "The array is too big" );
+ mat->dim[i].step = (int)cur_step;
+ cur_step *= mat->dim[i].size;
+ }
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg, "unrecognized or unsupported array type" );
+ }
+
+ __END__;
+}
+
+
+// Deallocates array's data
+CV_IMPL void
+cvReleaseData( CvArr* arr )
+{
+ CV_FUNCNAME( "cvReleaseData" );
+
+ __BEGIN__;
+
+ if( CV_IS_MAT_HDR( arr ) || CV_IS_MATND_HDR( arr ))
+ {
+ CvMat* mat = (CvMat*)arr;
+ cvDecRefData( mat );
+ }
+ else if( CV_IS_IMAGE_HDR( arr ))
+ {
+ IplImage* img = (IplImage*)arr;
+
+ if( !CvIPL.deallocate )
+ {
+ char* ptr = img->imageDataOrigin;
+ img->imageData = img->imageDataOrigin = 0;
+ cvFree( &ptr );
+ }
+ else
+ {
+ CvIPL.deallocate( img, IPL_IMAGE_DATA );
+ }
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg, "unrecognized or unsupported array type" );
+ }
+
+ __END__;
+}
+
+
+// Retrieves essential information about image ROI or CvMat data
+CV_IMPL void
+cvGetRawData( const CvArr* arr, uchar** data, int* step, CvSize* roi_size )
+{
+ CV_FUNCNAME( "cvGetRawData" );
+
+ __BEGIN__;
+
+ if( CV_IS_MAT( arr ))
+ {
+ CvMat *mat = (CvMat*)arr;
+
+ if( step )
+ *step = mat->step;
+
+ if( data )
+ *data = mat->data.ptr;
+
+ if( roi_size )
+ *roi_size = cvGetMatSize( mat );
+ }
+ else if( CV_IS_IMAGE( arr ))
+ {
+ IplImage* img = (IplImage*)arr;
+
+ if( step )
+ *step = img->widthStep;
+
+ if( data )
+ CV_CALL( *data = cvPtr2D( img, 0, 0 ));
+
+ if( roi_size )
+ {
+ if( img->roi )
+ {
+ *roi_size = cvSize( img->roi->width, img->roi->height );
+ }
+ else
+ {
+ *roi_size = cvSize( img->width, img->height );
+ }
+ }
+ }
+ else if( CV_IS_MATND( arr ))
+ {
+ CvMatND* mat = (CvMatND*)arr;
+
+ if( !CV_IS_MAT_CONT( mat->type ))
+ CV_ERROR( CV_StsBadArg, "Only continuous nD arrays are supported here" );
+
+ if( data )
+ *data = mat->data.ptr;
+
+ if( roi_size || step )
+ {
+ int i, size1 = mat->dim[0].size, size2 = 1;
+
+ if( mat->dims > 2 )
+ for( i = 1; i < mat->dims; i++ )
+ size1 *= mat->dim[i].size;
+ else
+ size2 = mat->dim[1].size;
+
+ if( roi_size )
+ {
+ roi_size->width = size2;
+ roi_size->height = size1;
+ }
+
+ if( step )
+ *step = size1 == 1 ? 0 : mat->dim[0].step;
+ }
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg, "unrecognized or unsupported array type" );
+ }
+
+ __END__;
+}
+
+
+CV_IMPL int
+cvGetElemType( const CvArr* arr )
+{
+ int type = -1;
+
+ CV_FUNCNAME( "cvGetElemType" );
+
+ __BEGIN__;
+
+ if( CV_IS_MAT_HDR(arr) || CV_IS_MATND_HDR(arr) || CV_IS_SPARSE_MAT_HDR(arr))
+ {
+ type = CV_MAT_TYPE( ((CvMat*)arr)->type );
+ }
+ else if( CV_IS_IMAGE(arr))
+ {
+ IplImage* img = (IplImage*)arr;
+ type = CV_MAKETYPE( icvIplToCvDepth(img->depth), img->nChannels );
+ }
+ else
+ CV_ERROR( CV_StsBadArg, "unrecognized or unsupported array type" );
+
+ __END__;
+
+ return type;
+}
+
+
+// Returns a number of array dimensions
+CV_IMPL int
+cvGetDims( const CvArr* arr, int* sizes )
+{
+ int dims = -1;
+ CV_FUNCNAME( "cvGetDims" );
+
+ __BEGIN__;
+
+ if( CV_IS_MAT_HDR( arr ))
+ {
+ CvMat* mat = (CvMat*)arr;
+
+ dims = 2;
+ if( sizes )
+ {
+ sizes[0] = mat->rows;
+ sizes[1] = mat->cols;
+ }
+ }
+ else if( CV_IS_IMAGE( arr ))
+ {
+ IplImage* img = (IplImage*)arr;
+ dims = 2;
+
+ if( sizes )
+ {
+ sizes[0] = img->height;
+ sizes[1] = img->width;
+ }
+ }
+ else if( CV_IS_MATND_HDR( arr ))
+ {
+ CvMatND* mat = (CvMatND*)arr;
+ dims = mat->dims;
+
+ if( sizes )
+ {
+ int i;
+ for( i = 0; i < dims; i++ )
+ sizes[i] = mat->dim[i].size;
+ }
+ }
+ else if( CV_IS_SPARSE_MAT_HDR( arr ))
+ {
+ CvSparseMat* mat = (CvSparseMat*)arr;
+ dims = mat->dims;
+
+ if( sizes )
+ memcpy( sizes, mat->size, dims*sizeof(sizes[0]));
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg, "unrecognized or unsupported array type" );
+ }
+
+ __END__;
+
+ return dims;
+}
+
+
+// Returns the size of particular array dimension
+CV_IMPL int
+cvGetDimSize( const CvArr* arr, int index )
+{
+ int size = -1;
+ CV_FUNCNAME( "cvGetDimSize" );
+
+ __BEGIN__;
+
+ if( CV_IS_MAT( arr ))
+ {
+ CvMat *mat = (CvMat*)arr;
+
+ switch( index )
+ {
+ case 0:
+ size = mat->rows;
+ break;
+ case 1:
+ size = mat->cols;
+ break;
+ default:
+ CV_ERROR( CV_StsOutOfRange, "bad dimension index" );
+ }
+ }
+ else if( CV_IS_IMAGE( arr ))
+ {
+ IplImage* img = (IplImage*)arr;
+
+ switch( index )
+ {
+ case 0:
+ size = !img->roi ? img->height : img->roi->height;
+ break;
+ case 1:
+ size = !img->roi ? img->width : img->roi->width;
+ break;
+ default:
+ CV_ERROR( CV_StsOutOfRange, "bad dimension index" );
+ }
+ }
+ else if( CV_IS_MATND_HDR( arr ))
+ {
+ CvMatND* mat = (CvMatND*)arr;
+
+ if( (unsigned)index >= (unsigned)mat->dims )
+ CV_ERROR( CV_StsOutOfRange, "bad dimension index" );
+
+ size = mat->dim[index].size;
+ }
+ else if( CV_IS_SPARSE_MAT_HDR( arr ))
+ {
+ CvSparseMat* mat = (CvSparseMat*)arr;
+
+ if( (unsigned)index >= (unsigned)mat->dims )
+ CV_ERROR( CV_StsOutOfRange, "bad dimension index" );
+
+ size = mat->size[index];
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg, "unrecognized or unsupported array type" );
+ }
+
+ __END__;
+
+ return size;
+}
+
+
+// Returns the size of CvMat or IplImage
+CV_IMPL CvSize
+cvGetSize( const CvArr* arr )
+{
+ CvSize size = { 0, 0 };
+
+ CV_FUNCNAME( "cvGetSize" );
+
+ __BEGIN__;
+
+ if( CV_IS_MAT_HDR( arr ))
+ {
+ CvMat *mat = (CvMat*)arr;
+
+ size.width = mat->cols;
+ size.height = mat->rows;
+ }
+ else if( CV_IS_IMAGE_HDR( arr ))
+ {
+ IplImage* img = (IplImage*)arr;
+
+ if( img->roi )
+ {
+ size.width = img->roi->width;
+ size.height = img->roi->height;
+ }
+ else
+ {
+ size.width = img->width;
+ size.height = img->height;
+ }
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg, "Array should be CvMat or IplImage" );
+ }
+
+ __END__;
+
+ return size;
+}
+
+
+// Selects sub-array (no data is copied)
+CV_IMPL CvMat*
+cvGetSubRect( const CvArr* arr, CvMat* submat, CvRect rect )
+{
+ CvMat* res = 0;
+
+ CV_FUNCNAME( "cvGetRect" );
+
+ __BEGIN__;
+
+ CvMat stub, *mat = (CvMat*)arr;
+
+ if( !CV_IS_MAT( mat ))
+ CV_CALL( mat = cvGetMat( mat, &stub ));
+
+ if( !submat )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( (rect.x|rect.y|rect.width|rect.height) < 0 )
+ CV_ERROR( CV_StsBadSize, "" );
+
+ if( rect.x + rect.width > mat->cols ||
+ rect.y + rect.height > mat->rows )
+ CV_ERROR( CV_StsBadSize, "" );
+
+ {
+ /*
+ int* refcount = mat->refcount;
+
+ if( refcount )
+ ++*refcount;
+
+ cvDecRefData( submat );
+ */
+ submat->data.ptr = mat->data.ptr + (size_t)rect.y*mat->step +
+ rect.x*CV_ELEM_SIZE(mat->type);
+ submat->step = mat->step & (rect.height > 1 ? -1 : 0);
+ submat->type = (mat->type & (rect.width < mat->cols ? ~CV_MAT_CONT_FLAG : -1)) |
+ (submat->step == 0 ? CV_MAT_CONT_FLAG : 0);
+ submat->rows = rect.height;
+ submat->cols = rect.width;
+ submat->refcount = 0;
+ res = submat;
+ }
+
+ __END__;
+
+ return res;
+}
+
+
+// Selects array's row span.
+CV_IMPL CvMat*
+cvGetRows( const CvArr* arr, CvMat* submat,
+ int start_row, int end_row, int delta_row )
+{
+ CvMat* res = 0;
+
+ CV_FUNCNAME( "cvGetRows" );
+
+ __BEGIN__;
+
+ CvMat stub, *mat = (CvMat*)arr;
+
+ if( !CV_IS_MAT( mat ))
+ CV_CALL( mat = cvGetMat( mat, &stub ));
+
+ if( !submat )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( (unsigned)start_row >= (unsigned)mat->rows ||
+ (unsigned)end_row > (unsigned)mat->rows || delta_row <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ {
+ /*
+ int* refcount = mat->refcount;
+
+ if( refcount )
+ ++*refcount;
+
+ cvDecRefData( submat );
+ */
+ if( delta_row == 1 )
+ {
+ submat->rows = end_row - start_row;
+ submat->step = mat->step & (submat->rows > 1 ? -1 : 0);
+ }
+ else
+ {
+ submat->rows = (end_row - start_row + delta_row - 1)/delta_row;
+ submat->step = mat->step * delta_row;
+ }
+
+ submat->cols = mat->cols;
+ submat->step &= submat->rows > 1 ? -1 : 0;
+ submat->data.ptr = mat->data.ptr + (size_t)start_row*mat->step;
+ submat->type = (mat->type | (submat->step == 0 ? CV_MAT_CONT_FLAG : 0)) &
+ (delta_row != 1 ? ~CV_MAT_CONT_FLAG : -1);
+ submat->refcount = 0;
+ submat->hdr_refcount = 0;
+ res = submat;
+ }
+
+ __END__;
+
+ return res;
+}
+
+
+// Selects array's column span.
+CV_IMPL CvMat*
+cvGetCols( const CvArr* arr, CvMat* submat, int start_col, int end_col )
+{
+ CvMat* res = 0;
+
+ CV_FUNCNAME( "cvGetCols" );
+
+ __BEGIN__;
+
+ CvMat stub, *mat = (CvMat*)arr;
+ int cols;
+
+ if( !CV_IS_MAT( mat ))
+ CV_CALL( mat = cvGetMat( mat, &stub ));
+
+ if( !submat )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ cols = mat->cols;
+ if( (unsigned)start_col >= (unsigned)cols ||
+ (unsigned)end_col > (unsigned)cols )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ {
+ /*
+ int* refcount = mat->refcount;
+
+ if( refcount )
+ ++*refcount;
+
+ cvDecRefData( submat );
+ */
+ submat->rows = mat->rows;
+ submat->cols = end_col - start_col;
+ submat->step = mat->step & (submat->rows > 1 ? -1 : 0);
+ submat->data.ptr = mat->data.ptr + (size_t)start_col*CV_ELEM_SIZE(mat->type);
+ submat->type = mat->type & (submat->step && submat->cols < cols ? ~CV_MAT_CONT_FLAG : -1);
+ submat->refcount = 0;
+ submat->hdr_refcount = 0;
+ res = submat;
+ }
+
+ __END__;
+
+ return res;
+}
+
+
+// Selects array diagonal
+CV_IMPL CvMat*
+cvGetDiag( const CvArr* arr, CvMat* submat, int diag )
+{
+ CvMat* res = 0;
+
+ CV_FUNCNAME( "cvGetDiag" );
+
+ __BEGIN__;
+
+ CvMat stub, *mat = (CvMat*)arr;
+ int len, pix_size;
+
+ if( !CV_IS_MAT( mat ))
+ CV_CALL( mat = cvGetMat( mat, &stub ));
+
+ if( !submat )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ pix_size = CV_ELEM_SIZE(mat->type);
+
+ /*{
+ int* refcount = mat->refcount;
+
+ if( refcount )
+ ++*refcount;
+
+ cvDecRefData( submat );
+ }*/
+
+ if( diag >= 0 )
+ {
+ len = mat->cols - diag;
+
+ if( len <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ len = CV_IMIN( len, mat->rows );
+ submat->data.ptr = mat->data.ptr + diag*pix_size;
+ }
+ else
+ {
+ len = mat->rows + diag;
+
+ if( len <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ len = CV_IMIN( len, mat->cols );
+ submat->data.ptr = mat->data.ptr - diag*mat->step;
+ }
+
+ submat->rows = len;
+ submat->cols = 1;
+ submat->step = (mat->step + pix_size) & (submat->rows > 1 ? -1 : 0);
+ submat->type = mat->type;
+ if( submat->step )
+ submat->type &= ~CV_MAT_CONT_FLAG;
+ else
+ submat->type |= CV_MAT_CONT_FLAG;
+ submat->refcount = 0;
+ submat->hdr_refcount = 0;
+ res = submat;
+
+ __END__;
+
+ return res;
+}
+
+
+/****************************************************************************************\
+* Operations on CvScalar and accessing array elements *
+\****************************************************************************************/
+
+// Converts CvScalar to specified type
+CV_IMPL void
+cvScalarToRawData( const CvScalar* scalar, void* data, int type, int extend_to_12 )
+{
+ CV_FUNCNAME( "cvScalarToRawData" );
+
+ type = CV_MAT_TYPE(type);
+
+ __BEGIN__;
+
+ int cn = CV_MAT_CN( type );
+ int depth = type & CV_MAT_DEPTH_MASK;
+
+ assert( scalar && data );
+ if( (unsigned)(cn - 1) >= 4 )
+ CV_ERROR( CV_StsOutOfRange, "The number of channels must be 1, 2, 3 or 4" );
+
+ switch( depth )
+ {
+ case CV_8UC1:
+ while( cn-- )
+ {
+ int t = cvRound( scalar->val[cn] );
+ ((uchar*)data)[cn] = CV_CAST_8U(t);
+ }
+ break;
+ case CV_8SC1:
+ while( cn-- )
+ {
+ int t = cvRound( scalar->val[cn] );
+ ((char*)data)[cn] = CV_CAST_8S(t);
+ }
+ break;
+ case CV_16UC1:
+ while( cn-- )
+ {
+ int t = cvRound( scalar->val[cn] );
+ ((ushort*)data)[cn] = CV_CAST_16U(t);
+ }
+ break;
+ case CV_16SC1:
+ while( cn-- )
+ {
+ int t = cvRound( scalar->val[cn] );
+ ((short*)data)[cn] = CV_CAST_16S(t);
+ }
+ break;
+ case CV_32SC1:
+ while( cn-- )
+ ((int*)data)[cn] = cvRound( scalar->val[cn] );
+ break;
+ case CV_32FC1:
+ while( cn-- )
+ ((float*)data)[cn] = (float)(scalar->val[cn]);
+ break;
+ case CV_64FC1:
+ while( cn-- )
+ ((double*)data)[cn] = (double)(scalar->val[cn]);
+ break;
+ default:
+ assert(0);
+ CV_ERROR_FROM_CODE( CV_BadDepth );
+ }
+
+ if( extend_to_12 )
+ {
+ int pix_size = CV_ELEM_SIZE(type);
+ int offset = CV_ELEM_SIZE1(depth)*12;
+
+ do
+ {
+ offset -= pix_size;
+ CV_MEMCPY_AUTO( (char*)data + offset, data, pix_size );
+ }
+ while( offset > pix_size );
+ }
+
+ __END__;
+}
+
+
+// Converts data of specified type to CvScalar
+CV_IMPL void
+cvRawDataToScalar( const void* data, int flags, CvScalar* scalar )
+{
+ CV_FUNCNAME( "cvRawDataToScalar" );
+
+ __BEGIN__;
+
+ int cn = CV_MAT_CN( flags );
+
+ assert( scalar && data );
+
+ if( (unsigned)(cn - 1) >= 4 )
+ CV_ERROR( CV_StsOutOfRange, "The number of channels must be 1, 2, 3 or 4" );
+
+ memset( scalar->val, 0, sizeof(scalar->val));
+
+ switch( CV_MAT_DEPTH( flags ))
+ {
+ case CV_8U:
+ while( cn-- )
+ scalar->val[cn] = CV_8TO32F(((uchar*)data)[cn]);
+ break;
+ case CV_8S:
+ while( cn-- )
+ scalar->val[cn] = CV_8TO32F(((char*)data)[cn]);
+ break;
+ case CV_16U:
+ while( cn-- )
+ scalar->val[cn] = ((ushort*)data)[cn];
+ break;
+ case CV_16S:
+ while( cn-- )
+ scalar->val[cn] = ((short*)data)[cn];
+ break;
+ case CV_32S:
+ while( cn-- )
+ scalar->val[cn] = ((int*)data)[cn];
+ break;
+ case CV_32F:
+ while( cn-- )
+ scalar->val[cn] = ((float*)data)[cn];
+ break;
+ case CV_64F:
+ while( cn-- )
+ scalar->val[cn] = ((double*)data)[cn];
+ break;
+ default:
+ assert(0);
+ CV_ERROR_FROM_CODE( CV_BadDepth );
+ }
+
+ __END__;
+}
+
+
+static double icvGetReal( const void* data, int type )
+{
+ switch( type )
+ {
+ case CV_8U:
+ return *(uchar*)data;
+ case CV_8S:
+ return *(char*)data;
+ case CV_16U:
+ return *(ushort*)data;
+ case CV_16S:
+ return *(short*)data;
+ case CV_32S:
+ return *(int*)data;
+ case CV_32F:
+ return *(float*)data;
+ case CV_64F:
+ return *(double*)data;
+ }
+
+ return 0;
+}
+
+
+static void icvSetReal( double value, const void* data, int type )
+{
+ if( type < CV_32F )
+ {
+ int ivalue = cvRound(value);
+ switch( type )
+ {
+ case CV_8U:
+ *(uchar*)data = CV_CAST_8U(ivalue);
+ break;
+ case CV_8S:
+ *(char*)data = CV_CAST_8S(ivalue);
+ break;
+ case CV_16U:
+ *(ushort*)data = CV_CAST_16U(ivalue);
+ break;
+ case CV_16S:
+ *(short*)data = CV_CAST_16S(ivalue);
+ break;
+ case CV_32S:
+ *(int*)data = CV_CAST_32S(ivalue);
+ break;
+ }
+ }
+ else
+ {
+ switch( type )
+ {
+ case CV_32F:
+ *(float*)data = (float)value;
+ break;
+ case CV_64F:
+ *(double*)data = value;
+ break;
+ }
+ }
+}
+
+
+// Returns pointer to specified element of array (linear index is used)
+CV_IMPL uchar*
+cvPtr1D( const CvArr* arr, int idx, int* _type )
+{
+ uchar* ptr = 0;
+
+ CV_FUNCNAME( "cvPtr1D" );
+
+ __BEGIN__;
+
+ if( CV_IS_MAT( arr ))
+ {
+ CvMat* mat = (CvMat*)arr;
+
+ int type = CV_MAT_TYPE(mat->type);
+ int pix_size = CV_ELEM_SIZE(type);
+
+ if( _type )
+ *_type = type;
+
+ // the first part is mul-free sufficient check
+ // that the index is within the matrix
+ if( (unsigned)idx >= (unsigned)(mat->rows + mat->cols - 1) &&
+ (unsigned)idx >= (unsigned)(mat->rows*mat->cols))
+ CV_ERROR( CV_StsOutOfRange, "index is out of range" );
+
+ if( CV_IS_MAT_CONT(mat->type))
+ {
+ ptr = mat->data.ptr + (size_t)idx*pix_size;
+ }
+ else
+ {
+ int row, col;
+ if( mat->cols == 1 )
+ row = idx, col = 0;
+ else
+ row = idx/mat->cols, col = idx - row*mat->cols;
+ ptr = mat->data.ptr + (size_t)row*mat->step + col*pix_size;
+ }
+ }
+ else if( CV_IS_IMAGE_HDR( arr ))
+ {
+ IplImage* img = (IplImage*)arr;
+ int width = !img->roi ? img->width : img->roi->width;
+ int y = idx/width, x = idx - y*width;
+
+ ptr = cvPtr2D( arr, y, x, _type );
+ }
+ else if( CV_IS_MATND( arr ))
+ {
+ CvMatND* mat = (CvMatND*)arr;
+ int j, type = CV_MAT_TYPE(mat->type);
+ size_t size = mat->dim[0].size;
+
+ if( _type )
+ *_type = type;
+
+ for( j = 1; j < mat->dims; j++ )
+ size *= mat->dim[j].size;
+
+ if((unsigned)idx >= (unsigned)size )
+ CV_ERROR( CV_StsOutOfRange, "index is out of range" );
+
+ if( CV_IS_MAT_CONT(mat->type))
+ {
+ int pix_size = CV_ELEM_SIZE(type);
+ ptr = mat->data.ptr + (size_t)idx*pix_size;
+ }
+ else
+ {
+ ptr = mat->data.ptr;
+ for( j = mat->dims - 1; j >= 0; j-- )
+ {
+ int sz = mat->dim[j].size;
+ if( sz )
+ {
+ int t = idx/sz;
+ ptr += (idx - t*sz)*mat->dim[j].step;
+ idx = t;
+ }
+ }
+ }
+ }
+ else if( CV_IS_SPARSE_MAT( arr ))
+ {
+ CvSparseMat* m = (CvSparseMat*)arr;
+ if( m->dims == 1 )
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, &idx, _type, 1, 0 );
+ else
+ {
+ int i, n = m->dims;
+ int* _idx = (int*)cvStackAlloc(n*sizeof(_idx[0]));
+
+ for( i = n - 1; i >= 0; i-- )
+ {
+ int t = idx / m->size[i];
+ _idx[i] = idx - t*m->size[i];
+ idx = t;
+ }
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, _idx, _type, 1, 0 );
+ }
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg, "unrecognized or unsupported array type" );
+ }
+
+ __END__;
+
+ return ptr;
+}
+
+
+// Returns pointer to specified element of 2d array
+CV_IMPL uchar*
+cvPtr2D( const CvArr* arr, int y, int x, int* _type )
+{
+ uchar* ptr = 0;
+
+ CV_FUNCNAME( "cvPtr2D" );
+
+ __BEGIN__;
+
+ if( CV_IS_MAT( arr ))
+ {
+ CvMat* mat = (CvMat*)arr;
+ int type;
+
+ if( (unsigned)y >= (unsigned)(mat->rows) ||
+ (unsigned)x >= (unsigned)(mat->cols) )
+ CV_ERROR( CV_StsOutOfRange, "index is out of range" );
+
+ type = CV_MAT_TYPE(mat->type);
+ if( _type )
+ *_type = type;
+
+ ptr = mat->data.ptr + (size_t)y*mat->step + x*CV_ELEM_SIZE(type);
+ }
+ else if( CV_IS_IMAGE( arr ))
+ {
+ IplImage* img = (IplImage*)arr;
+ int pix_size = (img->depth & 255) >> 3;
+ int width, height;
+ ptr = (uchar*)img->imageData;
+
+ if( img->dataOrder == 0 )
+ pix_size *= img->nChannels;
+
+ if( img->roi )
+ {
+ width = img->roi->width;
+ height = img->roi->height;
+
+ ptr += img->roi->yOffset*img->widthStep +
+ img->roi->xOffset*pix_size;
+
+ if( img->dataOrder )
+ {
+ int coi = img->roi->coi;
+ if( !coi )
+ CV_ERROR( CV_BadCOI,
+ "COI must be non-null in case of planar images" );
+ ptr += (coi - 1)*img->imageSize;
+ }
+ }
+ else
+ {
+ width = img->width;
+ height = img->height;
+ }
+
+ if( (unsigned)y >= (unsigned)height ||
+ (unsigned)x >= (unsigned)width )
+ CV_ERROR( CV_StsOutOfRange, "index is out of range" );
+
+ ptr += y*img->widthStep + x*pix_size;
+
+ if( _type )
+ {
+ int type = icvIplToCvDepth(img->depth);
+ if( type < 0 || (unsigned)(img->nChannels - 1) > 3 )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ *_type = CV_MAKETYPE( type, img->nChannels );
+ }
+ }
+ else if( CV_IS_MATND( arr ))
+ {
+ CvMatND* mat = (CvMatND*)arr;
+
+ if( mat->dims != 2 ||
+ (unsigned)y >= (unsigned)(mat->dim[0].size) ||
+ (unsigned)x >= (unsigned)(mat->dim[1].size) )
+ CV_ERROR( CV_StsOutOfRange, "index is out of range" );
+
+ ptr = mat->data.ptr + (size_t)y*mat->dim[0].step + x*mat->dim[1].step;
+ if( _type )
+ *_type = CV_MAT_TYPE(mat->type);
+ }
+ else if( CV_IS_SPARSE_MAT( arr ))
+ {
+ int idx[] = { y, x };
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, _type, 1, 0 );
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg, "unrecognized or unsupported array type" );
+ }
+
+ __END__;
+
+ return ptr;
+}
+
+
+// Returns pointer to specified element of 3d array
+CV_IMPL uchar*
+cvPtr3D( const CvArr* arr, int z, int y, int x, int* _type )
+{
+ uchar* ptr = 0;
+
+ CV_FUNCNAME( "cvPtr3D" );
+
+ __BEGIN__;
+
+ if( CV_IS_MATND( arr ))
+ {
+ CvMatND* mat = (CvMatND*)arr;
+
+ if( mat->dims != 3 ||
+ (unsigned)z >= (unsigned)(mat->dim[0].size) ||
+ (unsigned)y >= (unsigned)(mat->dim[1].size) ||
+ (unsigned)x >= (unsigned)(mat->dim[2].size) )
+ CV_ERROR( CV_StsOutOfRange, "index is out of range" );
+
+ ptr = mat->data.ptr + (size_t)z*mat->dim[0].step +
+ (size_t)y*mat->dim[1].step + x*mat->dim[2].step;
+
+ if( _type )
+ *_type = CV_MAT_TYPE(mat->type);
+ }
+ else if( CV_IS_SPARSE_MAT( arr ))
+ {
+ int idx[] = { z, y, x };
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, _type, 1, 0 );
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg, "unrecognized or unsupported array type" );
+ }
+
+ __END__;
+
+ return ptr;
+}
+
+
+// Returns pointer to specified element of n-d array
+CV_IMPL uchar*
+cvPtrND( const CvArr* arr, const int* idx, int* _type,
+ int create_node, unsigned* precalc_hashval )
+{
+ uchar* ptr = 0;
+ CV_FUNCNAME( "cvPtrND" );
+
+ __BEGIN__;
+
+ if( !idx )
+ CV_ERROR( CV_StsNullPtr, "NULL pointer to indices" );
+
+ if( CV_IS_SPARSE_MAT( arr ))
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, idx,
+ _type, create_node, precalc_hashval );
+ else if( CV_IS_MATND( arr ))
+ {
+ CvMatND* mat = (CvMatND*)arr;
+ int i;
+ ptr = mat->data.ptr;
+
+ for( i = 0; i < mat->dims; i++ )
+ {
+ if( (unsigned)idx[i] >= (unsigned)(mat->dim[i].size) )
+ CV_ERROR( CV_StsOutOfRange, "index is out of range" );
+ ptr += (size_t)idx[i]*mat->dim[i].step;
+ }
+
+ if( _type )
+ *_type = CV_MAT_TYPE(mat->type);
+ }
+ else if( CV_IS_MAT_HDR(arr) || CV_IS_IMAGE_HDR(arr) )
+ ptr = cvPtr2D( arr, idx[0], idx[1], _type );
+ else
+ CV_ERROR( CV_StsBadArg, "unrecognized or unsupported array type" );
+
+ __END__;
+
+ return ptr;
+}
+
+
+// Returns specifed element of n-D array given linear index
+CV_IMPL CvScalar
+cvGet1D( const CvArr* arr, int idx )
+{
+ CvScalar scalar = {{0,0,0,0}};
+
+ CV_FUNCNAME( "cvGet1D" );
+
+ __BEGIN__;
+
+ int type = 0;
+ uchar* ptr;
+
+ if( CV_IS_MAT( arr ) && CV_IS_MAT_CONT( ((CvMat*)arr)->type ))
+ {
+ CvMat* mat = (CvMat*)arr;
+
+ type = CV_MAT_TYPE(mat->type);
+ int pix_size = CV_ELEM_SIZE(type);
+
+ // the first part is mul-free sufficient check
+ // that the index is within the matrix
+ if( (unsigned)idx >= (unsigned)(mat->rows + mat->cols - 1) &&
+ (unsigned)idx >= (unsigned)(mat->rows*mat->cols))
+ CV_ERROR( CV_StsOutOfRange, "index is out of range" );
+
+ ptr = mat->data.ptr + (size_t)idx*pix_size;
+ }
+ else if( !CV_IS_SPARSE_MAT( arr ) || ((CvSparseMat*)arr)->dims > 1 )
+ ptr = cvPtr1D( arr, idx, &type );
+ else
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, &idx, &type, 0, 0 );
+
+ cvRawDataToScalar( ptr, type, &scalar );
+
+ __END__;
+
+ return scalar;
+}
+
+
+// Returns specifed element of 2D array
+CV_IMPL CvScalar
+cvGet2D( const CvArr* arr, int y, int x )
+{
+ CvScalar scalar = {{0,0,0,0}};
+
+ CV_FUNCNAME( "cvGet2D" );
+
+ __BEGIN__;
+
+ int type = 0;
+ uchar* ptr;
+
+ if( CV_IS_MAT( arr ))
+ {
+ CvMat* mat = (CvMat*)arr;
+
+ if( (unsigned)y >= (unsigned)(mat->rows) ||
+ (unsigned)x >= (unsigned)(mat->cols) )
+ CV_ERROR( CV_StsOutOfRange, "index is out of range" );
+
+ type = CV_MAT_TYPE(mat->type);
+ ptr = mat->data.ptr + (size_t)y*mat->step + x*CV_ELEM_SIZE(type);
+ }
+ else if( !CV_IS_SPARSE_MAT( arr ))
+ ptr = cvPtr2D( arr, y, x, &type );
+ else
+ {
+ int idx[] = { y, x };
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 );
+ }
+
+ cvRawDataToScalar( ptr, type, &scalar );
+
+ __END__;
+
+ return scalar;
+}
+
+
+// Returns specifed element of 3D array
+CV_IMPL CvScalar
+cvGet3D( const CvArr* arr, int z, int y, int x )
+{
+ CvScalar scalar = {{0,0,0,0}};
+
+ /*CV_FUNCNAME( "cvGet3D" );*/
+
+ __BEGIN__;
+
+ int type = 0;
+ uchar* ptr;
+
+ if( !CV_IS_SPARSE_MAT( arr ))
+ ptr = cvPtr3D( arr, z, y, x, &type );
+ else
+ {
+ int idx[] = { z, y, x };
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 );
+ }
+
+ cvRawDataToScalar( ptr, type, &scalar );
+
+ __END__;
+
+ return scalar;
+}
+
+
+// Returns specifed element of nD array
+CV_IMPL CvScalar
+cvGetND( const CvArr* arr, const int* idx )
+{
+ CvScalar scalar = {{0,0,0,0}};
+
+ /*CV_FUNCNAME( "cvGetND" );*/
+
+ __BEGIN__;
+
+ int type = 0;
+ uchar* ptr;
+
+ if( !CV_IS_SPARSE_MAT( arr ))
+ ptr = cvPtrND( arr, idx, &type );
+ else
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 );
+
+ cvRawDataToScalar( ptr, type, &scalar );
+
+ __END__;
+
+ return scalar;
+}
+
+
+// Returns specifed element of n-D array given linear index
+CV_IMPL double
+cvGetReal1D( const CvArr* arr, int idx )
+{
+ double value = 0;
+
+ CV_FUNCNAME( "cvGetReal1D" );
+
+ __BEGIN__;
+
+ int type = 0;
+ uchar* ptr;
+
+ if( CV_IS_MAT( arr ) && CV_IS_MAT_CONT( ((CvMat*)arr)->type ))
+ {
+ CvMat* mat = (CvMat*)arr;
+
+ type = CV_MAT_TYPE(mat->type);
+ int pix_size = CV_ELEM_SIZE(type);
+
+ // the first part is mul-free sufficient check
+ // that the index is within the matrix
+ if( (unsigned)idx >= (unsigned)(mat->rows + mat->cols - 1) &&
+ (unsigned)idx >= (unsigned)(mat->rows*mat->cols))
+ CV_ERROR( CV_StsOutOfRange, "index is out of range" );
+
+ ptr = mat->data.ptr + (size_t)idx*pix_size;
+ }
+ else if( !CV_IS_SPARSE_MAT( arr ) || ((CvSparseMat*)arr)->dims > 1 )
+ ptr = cvPtr1D( arr, idx, &type );
+ else
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, &idx, &type, 0, 0 );
+
+ if( ptr )
+ {
+ if( CV_MAT_CN( type ) > 1 )
+ CV_ERROR( CV_BadNumChannels, "cvGetReal* support only single-channel arrays" );
+
+ value = icvGetReal( ptr, type );
+ }
+
+ __END__;
+
+ return value;
+}
+
+
+// Returns specifed element of 2D array
+CV_IMPL double
+cvGetReal2D( const CvArr* arr, int y, int x )
+{
+ double value = 0;
+
+ CV_FUNCNAME( "cvGetReal2D" );
+
+ __BEGIN__;
+
+ int type = 0;
+ uchar* ptr;
+
+ if( CV_IS_MAT( arr ))
+ {
+ CvMat* mat = (CvMat*)arr;
+
+ if( (unsigned)y >= (unsigned)(mat->rows) ||
+ (unsigned)x >= (unsigned)(mat->cols) )
+ CV_ERROR( CV_StsOutOfRange, "index is out of range" );
+
+ type = CV_MAT_TYPE(mat->type);
+ ptr = mat->data.ptr + (size_t)y*mat->step + x*CV_ELEM_SIZE(type);
+ }
+ else if( !CV_IS_SPARSE_MAT( arr ))
+ ptr = cvPtr2D( arr, y, x, &type );
+ else
+ {
+ int idx[] = { y, x };
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 );
+ }
+
+ if( ptr )
+ {
+ if( CV_MAT_CN( type ) > 1 )
+ CV_ERROR( CV_BadNumChannels, "cvGetReal* support only single-channel arrays" );
+
+ value = icvGetReal( ptr, type );
+ }
+
+ __END__;
+
+ return value;
+}
+
+
+// Returns specifed element of 3D array
+CV_IMPL double
+cvGetReal3D( const CvArr* arr, int z, int y, int x )
+{
+ double value = 0;
+
+ CV_FUNCNAME( "cvGetReal3D" );
+
+ __BEGIN__;
+
+ int type = 0;
+ uchar* ptr;
+
+ if( !CV_IS_SPARSE_MAT( arr ))
+ ptr = cvPtr3D( arr, z, y, x, &type );
+ else
+ {
+ int idx[] = { z, y, x };
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 );
+ }
+
+ if( ptr )
+ {
+ if( CV_MAT_CN( type ) > 1 )
+ CV_ERROR( CV_BadNumChannels, "cvGetReal* support only single-channel arrays" );
+
+ value = icvGetReal( ptr, type );
+ }
+
+ __END__;
+
+ return value;
+}
+
+
+// Returns specifed element of nD array
+CV_IMPL double
+cvGetRealND( const CvArr* arr, const int* idx )
+{
+ double value = 0;
+
+ CV_FUNCNAME( "cvGetRealND" );
+
+ __BEGIN__;
+
+ int type = 0;
+ uchar* ptr;
+
+ if( !CV_IS_SPARSE_MAT( arr ))
+ ptr = cvPtrND( arr, idx, &type );
+ else
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, 0, 0 );
+
+ if( ptr )
+ {
+ if( CV_MAT_CN( type ) > 1 )
+ CV_ERROR( CV_BadNumChannels, "cvGetReal* support only single-channel arrays" );
+
+ value = icvGetReal( ptr, type );
+ }
+
+ __END__;
+
+ return value;
+}
+
+
+// Assigns new value to specifed element of nD array given linear index
+CV_IMPL void
+cvSet1D( CvArr* arr, int idx, CvScalar scalar )
+{
+ CV_FUNCNAME( "cvSet1D" );
+
+ __BEGIN__;
+
+ int type = 0;
+ uchar* ptr;
+
+ if( CV_IS_MAT( arr ) && CV_IS_MAT_CONT( ((CvMat*)arr)->type ))
+ {
+ CvMat* mat = (CvMat*)arr;
+
+ type = CV_MAT_TYPE(mat->type);
+ int pix_size = CV_ELEM_SIZE(type);
+
+ // the first part is mul-free sufficient check
+ // that the index is within the matrix
+ if( (unsigned)idx >= (unsigned)(mat->rows + mat->cols - 1) &&
+ (unsigned)idx >= (unsigned)(mat->rows*mat->cols))
+ CV_ERROR( CV_StsOutOfRange, "index is out of range" );
+
+ ptr = mat->data.ptr + (size_t)idx*pix_size;
+ }
+ else if( !CV_IS_SPARSE_MAT( arr ) || ((CvSparseMat*)arr)->dims > 1 )
+ ptr = cvPtr1D( arr, idx, &type );
+ else
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, &idx, &type, -1, 0 );
+
+ cvScalarToRawData( &scalar, ptr, type );
+
+ __END__;
+}
+
+
+// Assigns new value to specifed element of 2D array
+CV_IMPL void
+cvSet2D( CvArr* arr, int y, int x, CvScalar scalar )
+{
+ CV_FUNCNAME( "cvSet2D" );
+
+ __BEGIN__;
+
+ int type = 0;
+ uchar* ptr;
+
+ if( CV_IS_MAT( arr ))
+ {
+ CvMat* mat = (CvMat*)arr;
+
+ if( (unsigned)y >= (unsigned)(mat->rows) ||
+ (unsigned)x >= (unsigned)(mat->cols) )
+ CV_ERROR( CV_StsOutOfRange, "index is out of range" );
+
+ type = CV_MAT_TYPE(mat->type);
+ ptr = mat->data.ptr + (size_t)y*mat->step + x*CV_ELEM_SIZE(type);
+ }
+ else if( !CV_IS_SPARSE_MAT( arr ))
+ ptr = cvPtr2D( arr, y, x, &type );
+ else
+ {
+ int idx[] = { y, x };
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 );
+ }
+ cvScalarToRawData( &scalar, ptr, type );
+
+ __END__;
+}
+
+
+// Assigns new value to specifed element of 3D array
+CV_IMPL void
+cvSet3D( CvArr* arr, int z, int y, int x, CvScalar scalar )
+{
+ /*CV_FUNCNAME( "cvSet3D" );*/
+
+ __BEGIN__;
+
+ int type = 0;
+ uchar* ptr;
+
+ if( !CV_IS_SPARSE_MAT( arr ))
+ ptr = cvPtr3D( arr, z, y, x, &type );
+ else
+ {
+ int idx[] = { z, y, x };
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 );
+ }
+ cvScalarToRawData( &scalar, ptr, type );
+
+ __END__;
+}
+
+
+// Assigns new value to specifed element of nD array
+CV_IMPL void
+cvSetND( CvArr* arr, const int* idx, CvScalar scalar )
+{
+ /*CV_FUNCNAME( "cvSetND" );*/
+
+ __BEGIN__;
+
+ int type = 0;
+ uchar* ptr;
+
+ if( !CV_IS_SPARSE_MAT( arr ))
+ ptr = cvPtrND( arr, idx, &type );
+ else
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 );
+ cvScalarToRawData( &scalar, ptr, type );
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvSetReal1D( CvArr* arr, int idx, double value )
+{
+ CV_FUNCNAME( "cvSetReal1D" );
+
+ __BEGIN__;
+
+ int type = 0;
+ uchar* ptr;
+
+ if( CV_IS_MAT( arr ) && CV_IS_MAT_CONT( ((CvMat*)arr)->type ))
+ {
+ CvMat* mat = (CvMat*)arr;
+
+ type = CV_MAT_TYPE(mat->type);
+ int pix_size = CV_ELEM_SIZE(type);
+
+ // the first part is mul-free sufficient check
+ // that the index is within the matrix
+ if( (unsigned)idx >= (unsigned)(mat->rows + mat->cols - 1) &&
+ (unsigned)idx >= (unsigned)(mat->rows*mat->cols))
+ CV_ERROR( CV_StsOutOfRange, "index is out of range" );
+
+ ptr = mat->data.ptr + (size_t)idx*pix_size;
+ }
+ else if( !CV_IS_SPARSE_MAT( arr ) || ((CvSparseMat*)arr)->dims > 1 )
+ ptr = cvPtr1D( arr, idx, &type );
+ else
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, &idx, &type, -1, 0 );
+
+ if( CV_MAT_CN( type ) > 1 )
+ CV_ERROR( CV_BadNumChannels, "cvSetReal* support only single-channel arrays" );
+
+ if( ptr )
+ icvSetReal( value, ptr, type );
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvSetReal2D( CvArr* arr, int y, int x, double value )
+{
+ CV_FUNCNAME( "cvSetReal2D" );
+
+ __BEGIN__;
+
+ int type = 0;
+ uchar* ptr;
+
+ if( CV_IS_MAT( arr ))
+ {
+ CvMat* mat = (CvMat*)arr;
+
+ if( (unsigned)y >= (unsigned)(mat->rows) ||
+ (unsigned)x >= (unsigned)(mat->cols) )
+ CV_ERROR( CV_StsOutOfRange, "index is out of range" );
+
+ type = CV_MAT_TYPE(mat->type);
+ ptr = mat->data.ptr + (size_t)y*mat->step + x*CV_ELEM_SIZE(type);
+ }
+ else if( !CV_IS_SPARSE_MAT( arr ))
+ {
+ ptr = cvPtr2D( arr, y, x, &type );
+ }
+ else
+ {
+ int idx[] = { y, x };
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 );
+ }
+ if( CV_MAT_CN( type ) > 1 )
+ CV_ERROR( CV_BadNumChannels, "cvSetReal* support only single-channel arrays" );
+
+ if( ptr )
+ icvSetReal( value, ptr, type );
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvSetReal3D( CvArr* arr, int z, int y, int x, double value )
+{
+ CV_FUNCNAME( "cvSetReal3D" );
+
+ __BEGIN__;
+
+ int type = 0;
+ uchar* ptr;
+
+ if( !CV_IS_SPARSE_MAT( arr ))
+ ptr = cvPtr3D( arr, z, y, x, &type );
+ else
+ {
+ int idx[] = { z, y, x };
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 );
+ }
+ if( CV_MAT_CN( type ) > 1 )
+ CV_ERROR( CV_BadNumChannels, "cvSetReal* support only single-channel arrays" );
+
+ if( ptr )
+ icvSetReal( value, ptr, type );
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvSetRealND( CvArr* arr, const int* idx, double value )
+{
+ CV_FUNCNAME( "cvSetRealND" );
+
+ __BEGIN__;
+
+ int type = 0;
+ uchar* ptr;
+
+ if( !CV_IS_SPARSE_MAT( arr ))
+ ptr = cvPtrND( arr, idx, &type );
+ else
+ ptr = icvGetNodePtr( (CvSparseMat*)arr, idx, &type, -1, 0 );
+
+ if( CV_MAT_CN( type ) > 1 )
+ CV_ERROR( CV_BadNumChannels, "cvSetReal* support only single-channel arrays" );
+
+ if( ptr )
+ icvSetReal( value, ptr, type );
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvClearND( CvArr* arr, const int* idx )
+{
+ /*CV_FUNCNAME( "cvClearND" );*/
+
+ __BEGIN__;
+
+ if( !CV_IS_SPARSE_MAT( arr ))
+ {
+ int type;
+ uchar* ptr;
+ ptr = cvPtrND( arr, idx, &type );
+ if( ptr )
+ CV_ZERO_CHAR( ptr, CV_ELEM_SIZE(type) );
+ }
+ else
+ {
+ icvDeleteNode( (CvSparseMat*)arr, idx, 0 );
+ }
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* Conversion to CvMat or IplImage *
+\****************************************************************************************/
+
+// convert array (CvMat or IplImage) to CvMat
+CV_IMPL CvMat*
+cvGetMat( const CvArr* array, CvMat* mat,
+ int* pCOI, int allowND )
+{
+ CvMat* result = 0;
+ CvMat* src = (CvMat*)array;
+ int coi = 0;
+
+ CV_FUNCNAME( "cvGetMat" );
+
+ __BEGIN__;
+
+ if( !mat || !src )
+ CV_ERROR( CV_StsNullPtr, "NULL array pointer is passed" );
+
+ if( CV_IS_MAT_HDR(src))
+ {
+ if( !src->data.ptr )
+ CV_ERROR( CV_StsNullPtr, "The matrix has NULL data pointer" );
+
+ result = (CvMat*)src;
+ }
+ else if( CV_IS_IMAGE_HDR(src) )
+ {
+ const IplImage* img = (const IplImage*)src;
+ int depth, order;
+
+ if( img->imageData == 0 )
+ CV_ERROR( CV_StsNullPtr, "The image has NULL data pointer" );
+
+ depth = icvIplToCvDepth( img->depth );
+ if( depth < 0 )
+ CV_ERROR_FROM_CODE( CV_BadDepth );
+
+ order = img->dataOrder & (img->nChannels > 1 ? -1 : 0);
+
+ if( img->roi )
+ {
+ if( order == IPL_DATA_ORDER_PLANE )
+ {
+ int type = depth;
+
+ if( img->roi->coi == 0 )
+ CV_ERROR( CV_StsBadFlag,
+ "Images with planar data layout should be used with COI selected" );
+
+ CV_CALL( cvInitMatHeader( mat, img->roi->height,
+ img->roi->width, type,
+ img->imageData + (img->roi->coi-1)*img->imageSize +
+ img->roi->yOffset*img->widthStep +
+ img->roi->xOffset*CV_ELEM_SIZE(type),
+ img->widthStep ));
+ }
+ else /* pixel order */
+ {
+ int type = CV_MAKETYPE( depth, img->nChannels );
+ coi = img->roi->coi;
+
+ if( img->nChannels > CV_CN_MAX )
+ CV_ERROR( CV_BadNumChannels,
+ "The image is interleaved and has over CV_CN_MAX channels" );
+
+ CV_CALL( cvInitMatHeader( mat, img->roi->height, img->roi->width,
+ type, img->imageData +
+ img->roi->yOffset*img->widthStep +
+ img->roi->xOffset*CV_ELEM_SIZE(type),
+ img->widthStep ));
+ }
+ }
+ else
+ {
+ int type = CV_MAKETYPE( depth, img->nChannels );
+
+ if( order != IPL_DATA_ORDER_PIXEL )
+ CV_ERROR( CV_StsBadFlag, "Pixel order should be used with coi == 0" );
+
+ CV_CALL( cvInitMatHeader( mat, img->height, img->width, type,
+ img->imageData, img->widthStep ));
+ }
+
+ result = mat;
+ }
+ else if( allowND && CV_IS_MATND_HDR(src) )
+ {
+ CvMatND* matnd = (CvMatND*)src;
+ int i;
+ int size1 = matnd->dim[0].size, size2 = 1;
+
+ if( !src->data.ptr )
+ CV_ERROR( CV_StsNullPtr, "Input array has NULL data pointer" );
+
+ if( !CV_IS_MAT_CONT( matnd->type ))
+ CV_ERROR( CV_StsBadArg, "Only continuous nD arrays are supported here" );
+
+ if( matnd->dims > 2 )
+ for( i = 1; i < matnd->dims; i++ )
+ size2 *= matnd->dim[i].size;
+ else
+ size2 = matnd->dims == 1 ? 1 : matnd->dim[1].size;
+
+ mat->refcount = 0;
+ mat->hdr_refcount = 0;
+ mat->data.ptr = matnd->data.ptr;
+ mat->rows = size1;
+ mat->cols = size2;
+ mat->type = CV_MAT_TYPE(matnd->type) | CV_MAT_MAGIC_VAL | CV_MAT_CONT_FLAG;
+ mat->step = size2*CV_ELEM_SIZE(matnd->type);
+ mat->step &= size1 > 1 ? -1 : 0;
+
+ icvCheckHuge( mat );
+ result = mat;
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadFlag, "Unrecognized or unsupported array type" );
+ }
+
+ __END__;
+
+ if( pCOI )
+ *pCOI = coi;
+
+ return result;
+}
+
+
+CV_IMPL CvArr*
+cvReshapeMatND( const CvArr* arr,
+ int sizeof_header, CvArr* _header,
+ int new_cn, int new_dims, int* new_sizes )
+{
+ CvArr* result = 0;
+ CV_FUNCNAME( "cvReshapeMatND" );
+
+ __BEGIN__;
+
+ int dims, coi = 0;
+
+ if( !arr || !_header )
+ CV_ERROR( CV_StsNullPtr, "NULL pointer to array or destination header" );
+
+ if( new_cn == 0 && new_dims == 0 )
+ CV_ERROR( CV_StsBadArg, "None of array parameters is changed: dummy call?" );
+
+ CV_CALL( dims = cvGetDims( arr ));
+
+ if( new_dims == 0 )
+ {
+ new_sizes = 0;
+ new_dims = dims;
+ }
+ else if( new_dims == 1 )
+ {
+ new_sizes = 0;
+ }
+ else
+ {
+ if( new_dims <= 0 || new_dims > CV_MAX_DIM )
+ CV_ERROR( CV_StsOutOfRange, "Non-positive or too large number of dimensions" );
+ if( !new_sizes )
+ CV_ERROR( CV_StsNullPtr, "New dimension sizes are not specified" );
+ }
+
+ if( new_dims <= 2 )
+ {
+ CvMat* mat = (CvMat*)arr;
+ CvMat* header = (CvMat*)_header;
+ int* refcount = 0;
+ int hdr_refcount = 0;
+ int total_width, new_rows, cn;
+
+ if( sizeof_header != sizeof(CvMat))
+ CV_ERROR( CV_StsBadArg, "The header should be CvMat" );
+
+ if( mat == header )
+ {
+ refcount = mat->refcount;
+ hdr_refcount = mat->hdr_refcount;
+ }
+ else if( !CV_IS_MAT( mat ))
+ CV_CALL( mat = cvGetMat( mat, header, &coi, 1 ));
+
+ cn = CV_MAT_CN( mat->type );
+ total_width = mat->cols * cn;
+
+ if( new_cn == 0 )
+ new_cn = cn;
+
+ if( new_sizes )
+ new_rows = new_sizes[0];
+ else if( new_dims == 1 )
+ new_rows = total_width*mat->rows/new_cn;
+ else
+ {
+ new_rows = mat->rows;
+ if( new_cn > total_width )
+ new_rows = mat->rows * total_width / new_cn;
+ }
+
+ if( new_rows != mat->rows )
+ {
+ int total_size = total_width * mat->rows;
+
+ if( !CV_IS_MAT_CONT( mat->type ))
+ CV_ERROR( CV_BadStep,
+ "The matrix is not continuous so the number of rows can not be changed" );
+
+ total_width = total_size / new_rows;
+
+ if( total_width * new_rows != total_size )
+ CV_ERROR( CV_StsBadArg, "The total number of matrix elements "
+ "is not divisible by the new number of rows" );
+ }
+
+ header->rows = new_rows;
+ header->cols = total_width / new_cn;
+
+ if( header->cols * new_cn != total_width ||
+ (new_sizes && header->cols != new_sizes[1]) )
+ CV_ERROR( CV_StsBadArg, "The total matrix width is not "
+ "divisible by the new number of columns" );
+
+ header->type = CV_MAKETYPE( mat->type & ~CV_MAT_CN_MASK, new_cn );
+ header->step = header->cols * CV_ELEM_SIZE(mat->type);
+ header->step &= new_rows > 1 ? -1 : 0;
+ header->refcount = refcount;
+ header->hdr_refcount = hdr_refcount;
+ }
+ else
+ {
+ CvMatND* header = (CvMatND*)_header;
+
+ if( sizeof_header != sizeof(CvMatND))
+ CV_ERROR( CV_StsBadSize, "The header should be CvMatND" );
+
+ if( !new_sizes )
+ {
+ if( !CV_IS_MATND( arr ))
+ CV_ERROR( CV_StsBadArg, "The source array must be CvMatND" );
+
+ {
+ CvMatND* mat = (CvMatND*)arr;
+ assert( new_cn > 0 );
+ int last_dim_size = mat->dim[mat->dims-1].size*CV_MAT_CN(mat->type);
+ int new_size = last_dim_size/new_cn;
+
+ if( new_size*new_cn != last_dim_size )
+ CV_ERROR( CV_StsBadArg,
+ "The last dimension full size is not divisible by new number of channels");
+
+ if( mat != header )
+ {
+ memcpy( header, mat, sizeof(*header));
+ header->refcount = 0;
+ header->hdr_refcount = 0;
+ }
+
+ header->dim[header->dims-1].size = new_size;
+ header->type = CV_MAKETYPE( header->type & ~CV_MAT_CN_MASK, new_cn );
+ }
+ }
+ else
+ {
+ CvMatND stub;
+ CvMatND* mat = (CvMatND*)arr;
+ int i, size1, size2;
+ int step;
+
+ if( new_cn != 0 )
+ CV_ERROR( CV_StsBadArg,
+ "Simultaneous change of shape and number of channels is not supported. "
+ "Do it by 2 separate calls" );
+
+ if( !CV_IS_MATND( mat ))
+ {
+ CV_CALL( cvGetMatND( mat, &stub, &coi ));
+ mat = &stub;
+ }
+
+ if( CV_IS_MAT_CONT( mat->type ))
+ CV_ERROR( CV_StsBadArg, "Non-continuous nD arrays are not supported" );
+
+ size1 = mat->dim[0].size;
+ for( i = 1; i < dims; i++ )
+ size1 *= mat->dim[i].size;
+
+ size2 = 1;
+ for( i = 0; i < new_dims; i++ )
+ {
+ if( new_sizes[i] <= 0 )
+ CV_ERROR( CV_StsBadSize,
+ "One of new dimension sizes is non-positive" );
+ size2 *= new_sizes[i];
+ }
+
+ if( size1 != size2 )
+ CV_ERROR( CV_StsBadSize,
+ "Number of elements in the original and reshaped array is different" );
+
+ if( header != mat )
+ {
+ header->refcount = 0;
+ header->hdr_refcount = 0;
+ }
+
+ header->dims = new_dims;
+ header->type = mat->type;
+ header->data.ptr = mat->data.ptr;
+ step = CV_ELEM_SIZE(header->type);
+
+ for( i = new_dims - 1; i >= 0; i-- )
+ {
+ header->dim[i].size = new_sizes[i];
+ header->dim[i].step = step;
+ step *= new_sizes[i];
+ }
+ }
+ }
+
+ if( !coi )
+ CV_ERROR( CV_BadCOI, "COI is not supported by this operation" );
+
+ result = _header;
+
+ __END__;
+
+ return result;
+}
+
+
+CV_IMPL CvMat*
+cvReshape( const CvArr* array, CvMat* header,
+ int new_cn, int new_rows )
+{
+ CvMat* result = 0;
+ CV_FUNCNAME( "cvReshape" );
+
+ __BEGIN__;
+
+ CvMat *mat = (CvMat*)array;
+ int total_width, new_width;
+
+ if( !header )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !CV_IS_MAT( mat ))
+ {
+ int coi = 0;
+ CV_CALL( mat = cvGetMat( mat, header, &coi, 1 ));
+ if( coi )
+ CV_ERROR( CV_BadCOI, "COI is not supported" );
+ }
+
+ if( new_cn == 0 )
+ new_cn = CV_MAT_CN(mat->type);
+ else if( (unsigned)(new_cn - 1) > 3 )
+ CV_ERROR( CV_BadNumChannels, "" );
+
+ if( mat != header )
+ {
+ int hdr_refcount = header->hdr_refcount;
+ *header = *mat;
+ header->refcount = 0;
+ header->hdr_refcount = hdr_refcount;
+ }
+
+ total_width = mat->cols * CV_MAT_CN( mat->type );
+
+ if( (new_cn > total_width || total_width % new_cn != 0) && new_rows == 0 )
+ new_rows = mat->rows * total_width / new_cn;
+
+ if( new_rows == 0 || new_rows == mat->rows )
+ {
+ header->rows = mat->rows;
+ header->step = mat->step;
+ }
+ else
+ {
+ int total_size = total_width * mat->rows;
+ if( !CV_IS_MAT_CONT( mat->type ))
+ CV_ERROR( CV_BadStep,
+ "The matrix is not continuous, thus its number of rows can not be changed" );
+
+ if( (unsigned)new_rows > (unsigned)total_size )
+ CV_ERROR( CV_StsOutOfRange, "Bad new number of rows" );
+
+ total_width = total_size / new_rows;
+
+ if( total_width * new_rows != total_size )
+ CV_ERROR( CV_StsBadArg, "The total number of matrix elements "
+ "is not divisible by the new number of rows" );
+
+ header->rows = new_rows;
+ header->step = total_width * CV_ELEM_SIZE1(mat->type);
+ }
+
+ new_width = total_width / new_cn;
+
+ if( new_width * new_cn != total_width )
+ CV_ERROR( CV_BadNumChannels,
+ "The total width is not divisible by the new number of channels" );
+
+ header->cols = new_width;
+ header->type = CV_MAKETYPE( mat->type & ~CV_MAT_CN_MASK, new_cn );
+
+ result = header;
+
+ __END__;
+
+ return result;
+}
+
+
+// convert array (CvMat or IplImage) to IplImage
+CV_IMPL IplImage*
+cvGetImage( const CvArr* array, IplImage* img )
+{
+ IplImage* result = 0;
+ const IplImage* src = (const IplImage*)array;
+
+ CV_FUNCNAME( "cvGetImage" );
+
+ __BEGIN__;
+
+ int depth;
+
+ if( !img )
+ CV_ERROR_FROM_CODE( CV_StsNullPtr );
+
+ if( !CV_IS_IMAGE_HDR(src) )
+ {
+ const CvMat* mat = (const CvMat*)src;
+
+ if( !CV_IS_MAT_HDR(mat))
+ CV_ERROR_FROM_CODE( CV_StsBadFlag );
+
+ if( mat->data.ptr == 0 )
+ CV_ERROR_FROM_CODE( CV_StsNullPtr );
+
+ depth = cvCvToIplDepth(mat->type);
+
+ cvInitImageHeader( img, cvSize(mat->cols, mat->rows),
+ depth, CV_MAT_CN(mat->type) );
+ cvSetData( img, mat->data.ptr, mat->step );
+
+ result = img;
+ }
+ else
+ {
+ result = (IplImage*)src;
+ }
+
+ __END__;
+
+ return result;
+}
+
+
+/****************************************************************************************\
+* IplImage-specific functions *
+\****************************************************************************************/
+
+static IplROI* icvCreateROI( int coi, int xOffset, int yOffset, int width, int height )
+{
+ IplROI *roi = 0;
+
+ CV_FUNCNAME( "icvCreateROI" );
+
+ __BEGIN__;
+
+ if( !CvIPL.createROI )
+ {
+ CV_CALL( roi = (IplROI*)cvAlloc( sizeof(*roi)));
+
+ roi->coi = coi;
+ roi->xOffset = xOffset;
+ roi->yOffset = yOffset;
+ roi->width = width;
+ roi->height = height;
+ }
+ else
+ {
+ roi = CvIPL.createROI( coi, xOffset, yOffset, width, height );
+ }
+
+ __END__;
+
+ return roi;
+}
+
+static void
+icvGetColorModel( int nchannels, const char** colorModel, const char** channelSeq )
+{
+ static const char* tab[][2] =
+ {
+ {"GRAY", "GRAY"},
+ {"",""},
+ {"RGB","BGR"},
+ {"RGB","BGRA"}
+ };
+
+ nchannels--;
+ *colorModel = *channelSeq = "";
+
+ if( (unsigned)nchannels <= 3 )
+ {
+ *colorModel = tab[nchannels][0];
+ *channelSeq = tab[nchannels][1];
+ }
+}
+
+
+// create IplImage header
+CV_IMPL IplImage *
+cvCreateImageHeader( CvSize size, int depth, int channels )
+{
+ IplImage *img = 0;
+
+ CV_FUNCNAME( "cvCreateImageHeader" );
+
+ __BEGIN__;
+
+ if( !CvIPL.createHeader )
+ {
+ CV_CALL( img = (IplImage *)cvAlloc( sizeof( *img )));
+ CV_CALL( cvInitImageHeader( img, size, depth, channels, IPL_ORIGIN_TL,
+ CV_DEFAULT_IMAGE_ROW_ALIGN ));
+ }
+ else
+ {
+ const char *colorModel, *channelSeq;
+
+ icvGetColorModel( channels, &colorModel, &channelSeq );
+
+ img = CvIPL.createHeader( channels, 0, depth, (char*)colorModel, (char*)channelSeq,
+ IPL_DATA_ORDER_PIXEL, IPL_ORIGIN_TL,
+ CV_DEFAULT_IMAGE_ROW_ALIGN,
+ size.width, size.height, 0, 0, 0, 0 );
+ }
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 && img )
+ cvReleaseImageHeader( &img );
+
+ return img;
+}
+
+
+// create IplImage header and allocate underlying data
+CV_IMPL IplImage *
+cvCreateImage( CvSize size, int depth, int channels )
+{
+ IplImage *img = 0;
+
+ CV_FUNCNAME( "cvCreateImage" );
+
+ __BEGIN__;
+
+ CV_CALL( img = cvCreateImageHeader( size, depth, channels ));
+ assert( img );
+ CV_CALL( cvCreateData( img ));
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvReleaseImage( &img );
+
+ return img;
+}
+
+
+// initalize IplImage header, allocated by the user
+CV_IMPL IplImage*
+cvInitImageHeader( IplImage * image, CvSize size, int depth,
+ int channels, int origin, int align )
+{
+ IplImage* result = 0;
+
+ CV_FUNCNAME( "cvInitImageHeader" );
+
+ __BEGIN__;
+
+ const char *colorModel, *channelSeq;
+
+ if( !image )
+ CV_ERROR( CV_HeaderIsNull, "null pointer to header" );
+
+ memset( image, 0, sizeof( *image ));
+ image->nSize = sizeof( *image );
+
+ CV_CALL( icvGetColorModel( channels, &colorModel, &channelSeq ));
+ strncpy( image->colorModel, colorModel, 4 );
+ strncpy( image->channelSeq, channelSeq, 4 );
+
+ if( size.width < 0 || size.height < 0 )
+ CV_ERROR( CV_BadROISize, "Bad input roi" );
+
+ if( (depth != (int)IPL_DEPTH_1U && depth != (int)IPL_DEPTH_8U &&
+ depth != (int)IPL_DEPTH_8S && depth != (int)IPL_DEPTH_16U &&
+ depth != (int)IPL_DEPTH_16S && depth != (int)IPL_DEPTH_32S &&
+ depth != (int)IPL_DEPTH_32F && depth != (int)IPL_DEPTH_64F) ||
+ channels < 0 )
+ CV_ERROR( CV_BadDepth, "Unsupported format" );
+ if( origin != CV_ORIGIN_BL && origin != CV_ORIGIN_TL )
+ CV_ERROR( CV_BadOrigin, "Bad input origin" );
+
+ if( align != 4 && align != 8 )
+ CV_ERROR( CV_BadAlign, "Bad input align" );
+
+ image->width = size.width;
+ image->height = size.height;
+
+ if( image->roi )
+ {
+ image->roi->coi = 0;
+ image->roi->xOffset = image->roi->yOffset = 0;
+ image->roi->width = size.width;
+ image->roi->height = size.height;
+ }
+
+ image->nChannels = MAX( channels, 1 );
+ image->depth = depth;
+ image->align = align;
+ image->widthStep = (((image->width * image->nChannels *
+ (image->depth & ~IPL_DEPTH_SIGN) + 7)/8)+ align - 1) & (~(align - 1));
+ image->origin = origin;
+ image->imageSize = image->widthStep * image->height;
+
+ result = image;
+
+ __END__;
+
+ return result;
+}
+
+
+CV_IMPL void
+cvReleaseImageHeader( IplImage** image )
+{
+ CV_FUNCNAME( "cvReleaseImageHeader" );
+
+ __BEGIN__;
+
+ if( !image )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( *image )
+ {
+ IplImage* img = *image;
+ *image = 0;
+
+ if( !CvIPL.deallocate )
+ {
+ cvFree( &img->roi );
+ cvFree( &img );
+ }
+ else
+ {
+ CvIPL.deallocate( img, IPL_IMAGE_HEADER | IPL_IMAGE_ROI );
+ }
+ }
+ __END__;
+}
+
+
+CV_IMPL void
+cvReleaseImage( IplImage ** image )
+{
+ CV_FUNCNAME( "cvReleaseImage" );
+
+ __BEGIN__
+
+ if( !image )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( *image )
+ {
+ IplImage* img = *image;
+ *image = 0;
+
+ cvReleaseData( img );
+ cvReleaseImageHeader( &img );
+ }
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvSetImageROI( IplImage* image, CvRect rect )
+{
+ CV_FUNCNAME( "cvSetImageROI" );
+
+ __BEGIN__;
+
+ if( !image )
+ CV_ERROR( CV_HeaderIsNull, "" );
+
+ if( rect.x > image->width || rect.y > image->height )
+ CV_ERROR( CV_BadROISize, "" );
+
+ if( rect.x + rect.width < 0 || rect.y + rect.height < 0 )
+ CV_ERROR( CV_BadROISize, "" );
+
+ if( rect.x < 0 )
+ {
+ rect.width += rect.x;
+ rect.x = 0;
+ }
+
+ if( rect.y < 0 )
+ {
+ rect.height += rect.y;
+ rect.y = 0;
+ }
+
+ if( rect.x + rect.width > image->width )
+ rect.width = image->width - rect.x;
+
+ if( rect.y + rect.height > image->height )
+ rect.height = image->height - rect.y;
+
+ if( image->roi )
+ {
+ image->roi->xOffset = rect.x;
+ image->roi->yOffset = rect.y;
+ image->roi->width = rect.width;
+ image->roi->height = rect.height;
+ }
+ else
+ {
+ CV_CALL( image->roi = icvCreateROI( 0, rect.x, rect.y, rect.width, rect.height ));
+ }
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvResetImageROI( IplImage* image )
+{
+ CV_FUNCNAME( "cvResetImageROI" );
+
+ __BEGIN__;
+
+ if( !image )
+ CV_ERROR( CV_HeaderIsNull, "" );
+
+ if( image->roi )
+ {
+ if( !CvIPL.deallocate )
+ {
+ cvFree( &image->roi );
+ }
+ else
+ {
+ CvIPL.deallocate( image, IPL_IMAGE_ROI );
+ image->roi = 0;
+ }
+ }
+
+ __END__;
+}
+
+
+CV_IMPL CvRect
+cvGetImageROI( const IplImage* img )
+{
+ CvRect rect = { 0, 0, 0, 0 };
+
+ CV_FUNCNAME( "cvGetImageROI" );
+
+ __BEGIN__;
+
+ if( !img )
+ CV_ERROR( CV_StsNullPtr, "Null pointer to image" );
+
+ if( img->roi )
+ rect = cvRect( img->roi->xOffset, img->roi->yOffset,
+ img->roi->width, img->roi->height );
+ else
+ rect = cvRect( 0, 0, img->width, img->height );
+
+ __END__;
+
+ return rect;
+}
+
+
+CV_IMPL void
+cvSetImageCOI( IplImage* image, int coi )
+{
+ CV_FUNCNAME( "cvSetImageCOI" );
+
+ __BEGIN__;
+
+ if( !image )
+ CV_ERROR( CV_HeaderIsNull, "" );
+
+ if( (unsigned)coi > (unsigned)(image->nChannels) )
+ CV_ERROR( CV_BadCOI, "" );
+
+ if( image->roi || coi != 0 )
+ {
+ if( image->roi )
+ {
+ image->roi->coi = coi;
+ }
+ else
+ {
+ CV_CALL( image->roi = icvCreateROI( coi, 0, 0, image->width, image->height ));
+ }
+ }
+
+ __END__;
+}
+
+
+CV_IMPL int
+cvGetImageCOI( const IplImage* image )
+{
+ int coi = -1;
+ CV_FUNCNAME( "cvGetImageCOI" );
+
+ __BEGIN__;
+
+ if( !image )
+ CV_ERROR( CV_HeaderIsNull, "" );
+
+ coi = image->roi ? image->roi->coi : 0;
+
+ __END__;
+
+ return coi;
+}
+
+
+CV_IMPL IplImage*
+cvCloneImage( const IplImage* src )
+{
+ IplImage* dst = 0;
+ CV_FUNCNAME( "cvCloneImage" );
+
+ __BEGIN__;
+
+ if( !CV_IS_IMAGE_HDR( src ))
+ CV_ERROR( CV_StsBadArg, "Bad image header" );
+
+ if( !CvIPL.cloneImage )
+ {
+ CV_CALL( dst = (IplImage*)cvAlloc( sizeof(*dst)));
+
+ memcpy( dst, src, sizeof(*src));
+ dst->imageData = dst->imageDataOrigin = 0;
+ dst->roi = 0;
+
+ if( src->roi )
+ {
+ dst->roi = icvCreateROI( src->roi->coi, src->roi->xOffset,
+ src->roi->yOffset, src->roi->width, src->roi->height );
+ }
+
+ if( src->imageData )
+ {
+ int size = src->imageSize;
+ cvCreateData( dst );
+ memcpy( dst->imageData, src->imageData, size );
+ }
+ }
+ else
+ {
+ dst = CvIPL.cloneImage( src );
+ }
+
+ __END__;
+
+ return dst;
+}
+
+
+/****************************************************************************************\
+* Additional operations on CvTermCriteria *
+\****************************************************************************************/
+
+CV_IMPL CvTermCriteria
+cvCheckTermCriteria( CvTermCriteria criteria, double default_eps,
+ int default_max_iters )
+{
+ CV_FUNCNAME( "cvCheckTermCriteria" );
+
+ CvTermCriteria crit;
+
+ crit.type = CV_TERMCRIT_ITER|CV_TERMCRIT_EPS;
+ crit.max_iter = default_max_iters;
+ crit.epsilon = (float)default_eps;
+
+ __BEGIN__;
+
+ if( (criteria.type & ~(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER)) != 0 )
+ CV_ERROR( CV_StsBadArg,
+ "Unknown type of term criteria" );
+
+ if( (criteria.type & CV_TERMCRIT_ITER) != 0 )
+ {
+ if( criteria.max_iter <= 0 )
+ CV_ERROR( CV_StsBadArg,
+ "Iterations flag is set and maximum number of iterations is <= 0" );
+ crit.max_iter = criteria.max_iter;
+ }
+
+ if( (criteria.type & CV_TERMCRIT_EPS) != 0 )
+ {
+ if( criteria.epsilon < 0 )
+ CV_ERROR( CV_StsBadArg, "Accuracy flag is set and epsilon is < 0" );
+
+ crit.epsilon = criteria.epsilon;
+ }
+
+ if( (criteria.type & (CV_TERMCRIT_EPS | CV_TERMCRIT_ITER)) == 0 )
+ CV_ERROR( CV_StsBadArg,
+ "Neither accuracy nor maximum iterations "
+ "number flags are set in criteria type" );
+
+ __END__;
+
+ crit.epsilon = (float)MAX( 0, crit.epsilon );
+ crit.max_iter = MAX( 1, crit.max_iter );
+
+ return crit;
+}
+
+
+/* End of file. */
diff --git a/cxcore/src/cxcmp.cpp b/cxcore/src/cxcmp.cpp
new file mode 100644
index 0000000..e9ca9c2
--- /dev/null
+++ b/cxcore/src/cxcmp.cpp
@@ -0,0 +1,1557 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/* ////////////////////////////////////////////////////////////////////
+//
+// CvMat comparison functions: range checking, min, max
+//
+// */
+
+#include "_cxcore.h"
+
+/****************************************************************************************\
+* InRange[S] *
+\****************************************************************************************/
+
+#define ICV_DEF_IN_RANGE_CASE_C1( worktype, _toggle_macro_ ) \
+for( x = 0; x < size.width; x++ ) \
+{ \
+ worktype a1 = _toggle_macro_(src1[x]), \
+ a2 = src2[x], a3 = src3[x]; \
+ dst[x] = (uchar)-(_toggle_macro_(a2) <= a1 && \
+ a1 < _toggle_macro_(a3)); \
+}
+
+
+#define ICV_DEF_IN_RANGE_CASE_C2( worktype, _toggle_macro_ ) \
+for( x = 0; x < size.width; x++ ) \
+{ \
+ worktype a1 = _toggle_macro_(src1[x*2]), \
+ a2 = src2[x*2], a3 = src3[x*2]; \
+ int f = _toggle_macro_(a2) <= a1 && a1 < _toggle_macro_(a3); \
+ a1 = _toggle_macro_(src1[x*2+1]); \
+ a2 = src2[x*2+1]; \
+ a3 = src3[x*2+1]; \
+ f &= _toggle_macro_(a2) <= a1 && a1 < _toggle_macro_(a3); \
+ dst[x] = (uchar)-f; \
+}
+
+
+#define ICV_DEF_IN_RANGE_CASE_C3( worktype, _toggle_macro_ ) \
+for( x = 0; x < size.width; x++ ) \
+{ \
+ worktype a1 = _toggle_macro_(src1[x*3]), \
+ a2 = src2[x*3], a3 = src3[x*3]; \
+ int f = _toggle_macro_(a2) <= a1 && a1 < _toggle_macro_(a3); \
+ a1 = _toggle_macro_(src1[x*3+1]); \
+ a2 = src2[x*3+1]; \
+ a3 = src3[x*3+1]; \
+ f &= _toggle_macro_(a2) <= a1 && a1 < _toggle_macro_(a3); \
+ a1 = _toggle_macro_(src1[x*3+2]); \
+ a2 = src2[x*3+2]; \
+ a3 = src3[x*3+2]; \
+ f &= _toggle_macro_(a2) <= a1 && a1 < _toggle_macro_(a3); \
+ dst[x] = (uchar)-f; \
+}
+
+
+#define ICV_DEF_IN_RANGE_CASE_C4( worktype, _toggle_macro_ ) \
+for( x = 0; x < size.width; x++ ) \
+{ \
+ worktype a1 = _toggle_macro_(src1[x*4]), \
+ a2 = src2[x*4], a3 = src3[x*4]; \
+ int f = _toggle_macro_(a2) <= a1 && a1 < _toggle_macro_(a3); \
+ a1 = _toggle_macro_(src1[x*4+1]); \
+ a2 = src2[x*4+1]; \
+ a3 = src3[x*4+1]; \
+ f &= _toggle_macro_(a2) <= a1 && a1 < _toggle_macro_(a3); \
+ a1 = _toggle_macro_(src1[x*4+2]); \
+ a2 = src2[x*4+2]; \
+ a3 = src3[x*4+2]; \
+ f &= _toggle_macro_(a2) <= a1 && a1 < _toggle_macro_(a3); \
+ a1 = _toggle_macro_(src1[x*4+3]); \
+ a2 = src2[x*4+3]; \
+ a3 = src3[x*4+3]; \
+ f &= _toggle_macro_(a2) <= a1 && a1 < _toggle_macro_(a3); \
+ dst[x] = (uchar)-f; \
+}
+
+
+#define ICV_DEF_IN_RANGE_FUNC( flavor, arrtype, worktype, \
+ _toggle_macro_, cn ) \
+static CvStatus CV_STDCALL \
+icvInRange_##flavor##_C##cn##R( const arrtype* src1, int step1, \
+ const arrtype* src2, int step2, \
+ const arrtype* src3, int step3, \
+ uchar* dst, int step, CvSize size ) \
+{ \
+ step1 /= sizeof(src1[0]); step2 /= sizeof(src2[0]); \
+ step3 /= sizeof(src3[0]); step /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2, \
+ src3 += step3, dst += step ) \
+ { \
+ int x; \
+ ICV_DEF_IN_RANGE_CASE_C##cn( worktype, _toggle_macro_ ) \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_IN_RANGE_CASE_CONST_C1( worktype, _toggle_macro_ ) \
+for( x = 0; x < size.width; x++ ) \
+{ \
+ worktype a1 = _toggle_macro_(src1[x]); \
+ dst[x] = (uchar)-(scalar[0] <= a1 && a1 < scalar[1]); \
+}
+
+
+#define ICV_DEF_IN_RANGE_CASE_CONST_C2( worktype, _toggle_macro_ ) \
+for( x = 0; x < size.width; x++ ) \
+{ \
+ worktype a1 = _toggle_macro_(src1[x*2]); \
+ int f = scalar[0] <= a1 && a1 < scalar[2]; \
+ a1 = _toggle_macro_(src1[x*2+1]); \
+ f &= scalar[1] <= a1 && a1 < scalar[3]; \
+ dst[x] = (uchar)-f; \
+}
+
+
+#define ICV_DEF_IN_RANGE_CASE_CONST_C3( worktype, _toggle_macro_ ) \
+for( x = 0; x < size.width; x++ ) \
+{ \
+ worktype a1 = _toggle_macro_(src1[x*3]); \
+ int f = scalar[0] <= a1 && a1 < scalar[3]; \
+ a1 = _toggle_macro_(src1[x*3+1]); \
+ f &= scalar[1] <= a1 && a1 < scalar[4]; \
+ a1 = _toggle_macro_(src1[x*3+2]); \
+ f &= scalar[2] <= a1 && a1 < scalar[5]; \
+ dst[x] = (uchar)-f; \
+}
+
+
+#define ICV_DEF_IN_RANGE_CASE_CONST_C4( worktype, _toggle_macro_ ) \
+for( x = 0; x < size.width; x++ ) \
+{ \
+ worktype a1 = _toggle_macro_(src1[x*4]); \
+ int f = scalar[0] <= a1 && a1 < scalar[4]; \
+ a1 = _toggle_macro_(src1[x*4+1]); \
+ f &= scalar[1] <= a1 && a1 < scalar[5]; \
+ a1 = _toggle_macro_(src1[x*4+2]); \
+ f &= scalar[2] <= a1 && a1 < scalar[6]; \
+ a1 = _toggle_macro_(src1[x*4+3]); \
+ f &= scalar[3] <= a1 && a1 < scalar[7]; \
+ dst[x] = (uchar)-f; \
+}
+
+
+#define ICV_DEF_IN_RANGE_CONST_FUNC( flavor, arrtype, worktype, \
+ _toggle_macro_, cn ) \
+static CvStatus CV_STDCALL \
+icvInRangeC_##flavor##_C##cn##R( const arrtype* src1, int step1, \
+ uchar* dst, int step, CvSize size, \
+ const worktype* scalar ) \
+{ \
+ step1 /= sizeof(src1[0]); step /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src1 += step1, dst += step ) \
+ { \
+ int x; \
+ ICV_DEF_IN_RANGE_CASE_CONST_C##cn( worktype, _toggle_macro_)\
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_IN_RANGE_ALL( flavor, arrtype, worktype, _toggle_macro_ ) \
+ICV_DEF_IN_RANGE_FUNC( flavor, arrtype, worktype, _toggle_macro_, 1 ) \
+ICV_DEF_IN_RANGE_FUNC( flavor, arrtype, worktype, _toggle_macro_, 2 ) \
+ICV_DEF_IN_RANGE_FUNC( flavor, arrtype, worktype, _toggle_macro_, 3 ) \
+ICV_DEF_IN_RANGE_FUNC( flavor, arrtype, worktype, _toggle_macro_, 4 ) \
+ \
+ICV_DEF_IN_RANGE_CONST_FUNC( flavor, arrtype, worktype, _toggle_macro_, 1 ) \
+ICV_DEF_IN_RANGE_CONST_FUNC( flavor, arrtype, worktype, _toggle_macro_, 2 ) \
+ICV_DEF_IN_RANGE_CONST_FUNC( flavor, arrtype, worktype, _toggle_macro_, 3 ) \
+ICV_DEF_IN_RANGE_CONST_FUNC( flavor, arrtype, worktype, _toggle_macro_, 4 )
+
+ICV_DEF_IN_RANGE_ALL( 8u, uchar, int, CV_NOP )
+ICV_DEF_IN_RANGE_ALL( 16u, ushort, int, CV_NOP )
+ICV_DEF_IN_RANGE_ALL( 16s, short, int, CV_NOP )
+ICV_DEF_IN_RANGE_ALL( 32s, int, int, CV_NOP )
+ICV_DEF_IN_RANGE_ALL( 32f, float, float, CV_NOP )
+ICV_DEF_IN_RANGE_ALL( 64f, double, double, CV_NOP )
+
+#define icvInRange_8s_C1R 0
+#define icvInRange_8s_C2R 0
+#define icvInRange_8s_C3R 0
+#define icvInRange_8s_C4R 0
+
+#define icvInRangeC_8s_C1R 0
+#define icvInRangeC_8s_C2R 0
+#define icvInRangeC_8s_C3R 0
+#define icvInRangeC_8s_C4R 0
+
+CV_DEF_INIT_BIG_FUNC_TAB_2D( InRange, R )
+CV_DEF_INIT_BIG_FUNC_TAB_2D( InRangeC, R )
+
+typedef CvStatus (CV_STDCALL * CvInRangeCFunc)( const void* src, int srcstep,
+ uchar* dst, int dststep,
+ CvSize size, const void* scalar );
+
+/*************************************** InRange ****************************************/
+
+CV_IMPL void
+cvInRange( const void* srcarr1, const void* srcarr2,
+ const void* srcarr3, void* dstarr )
+{
+ static CvBigFuncTable inrange_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvInRange" );
+
+ __BEGIN__;
+
+ int type, coi = 0;
+ int src1_step, src2_step, src3_step, dst_step;
+ CvMat srcstub1, *src1 = (CvMat*)srcarr1;
+ CvMat srcstub2, *src2 = (CvMat*)srcarr2;
+ CvMat srcstub3, *src3 = (CvMat*)srcarr3;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize size;
+ CvFunc2D_4A func;
+
+ if( !inittab )
+ {
+ icvInitInRangeRTable( &inrange_tab );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(src1) )
+ {
+ CV_CALL( src1 = cvGetMat( src1, &srcstub1, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_IS_MAT(src2) )
+ {
+ CV_CALL( src2 = cvGetMat( src2, &srcstub2, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_IS_MAT(src3) )
+ {
+ CV_CALL( src3 = cvGetMat( src3, &srcstub3, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_IS_MAT(dst) )
+ {
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_ARE_TYPES_EQ( src1, src2 ) ||
+ !CV_ARE_TYPES_EQ( src1, src3 ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_IS_MASK_ARR( dst ))
+ CV_ERROR( CV_StsUnsupportedFormat, "Destination image should be 8uC1 or 8sC1");
+
+ if( !CV_ARE_SIZES_EQ( src1, src2 ) ||
+ !CV_ARE_SIZES_EQ( src1, src3 ) ||
+ !CV_ARE_SIZES_EQ( src1, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ type = CV_MAT_TYPE(src1->type);
+ size = cvGetMatSize( src1 );
+
+ if( CV_IS_MAT_CONT( src1->type & src2->type & src3->type & dst->type ))
+ {
+ size.width *= size.height;
+ src1_step = src2_step = src3_step = dst_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+ else
+ {
+ src1_step = src1->step;
+ src2_step = src2->step;
+ src3_step = src3->step;
+ dst_step = dst->step;
+ }
+
+ if( CV_MAT_CN(type) > 4 )
+ CV_ERROR( CV_StsOutOfRange, "The number of channels must be 1, 2, 3 or 4" );
+
+ func = (CvFunc2D_4A)(inrange_tab.fn_2d[type]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src1->data.ptr, src1_step, src2->data.ptr, src2_step,
+ src3->data.ptr, src3_step, dst->data.ptr, dst_step, size ));
+
+ __END__;
+}
+
+
+/************************************** InRangeS ****************************************/
+
+CV_IMPL void
+cvInRangeS( const void* srcarr, CvScalar lower, CvScalar upper, void* dstarr )
+{
+ static CvBigFuncTable inrange_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvInRangeS" );
+
+ __BEGIN__;
+
+ int sctype, type, coi = 0;
+ int src1_step, dst_step;
+ CvMat srcstub1, *src1 = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize size;
+ CvInRangeCFunc func;
+ double buf[8];
+
+ if( !inittab )
+ {
+ icvInitInRangeCRTable( &inrange_tab );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(src1) )
+ {
+ CV_CALL( src1 = cvGetMat( src1, &srcstub1, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_IS_MAT(dst) )
+ {
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_IS_MASK_ARR( dst ))
+ CV_ERROR( CV_StsUnsupportedFormat, "Destination image should be 8uC1 or 8sC1");
+
+ if( !CV_ARE_SIZES_EQ( src1, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ sctype = type = CV_MAT_TYPE(src1->type);
+ if( CV_MAT_DEPTH(sctype) < CV_32S )
+ sctype = (type & CV_MAT_CN_MASK) | CV_32SC1;
+
+ size = cvGetMatSize( src1 );
+
+ if( CV_IS_MAT_CONT( src1->type & dst->type ))
+ {
+ size.width *= size.height;
+ src1_step = dst_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+ else
+ {
+ src1_step = src1->step;
+ dst_step = dst->step;
+ }
+
+ if( CV_MAT_CN(type) > 4 )
+ CV_ERROR( CV_StsOutOfRange, "The number of channels must be 1, 2, 3 or 4" );
+
+ func = (CvInRangeCFunc)(inrange_tab.fn_2d[type]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ cvScalarToRawData( &lower, buf, sctype, 0 );
+ cvScalarToRawData( &upper, (char*)buf + CV_ELEM_SIZE(sctype), sctype, 0 );
+
+ IPPI_CALL( func( src1->data.ptr, src1_step, dst->data.ptr,
+ dst_step, size, buf ));
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* Cmp *
+\****************************************************************************************/
+
+#define ICV_DEF_CMP_CASE_C1( __op__, _toggle_macro_ ) \
+for( x = 0; x <= size.width - 4; x += 4 ) \
+{ \
+ int f0 = __op__( _toggle_macro_(src1[x]), _toggle_macro_(src2[x])); \
+ int f1 = __op__( _toggle_macro_(src1[x+1]), _toggle_macro_(src2[x+1])); \
+ dst[x] = (uchar)-f0; \
+ dst[x+1] = (uchar)-f1; \
+ f0 = __op__( _toggle_macro_(src1[x+2]), _toggle_macro_(src2[x+2])); \
+ f1 = __op__( _toggle_macro_(src1[x+3]), _toggle_macro_(src2[x+3])); \
+ dst[x+2] = (uchar)-f0; \
+ dst[x+3] = (uchar)-f1; \
+} \
+ \
+for( ; x < size.width; x++ ) \
+{ \
+ int f0 = __op__( _toggle_macro_(src1[x]), _toggle_macro_(src2[x])); \
+ dst[x] = (uchar)-f0; \
+}
+
+
+#define ICV_DEF_CMP_FUNC( __op__, name, flavor, arrtype, \
+ worktype, _toggle_macro_ ) \
+static CvStatus CV_STDCALL \
+icv##name##_##flavor##_C1R( const arrtype* src1, int step1, \
+ const arrtype* src2, int step2, \
+ uchar* dst, int step, CvSize size ) \
+{ \
+ step1 /= sizeof(src1[0]); step2 /= sizeof(src2[0]); \
+ step /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2, \
+ dst += step ) \
+ { \
+ int x; \
+ ICV_DEF_CMP_CASE_C1( __op__, _toggle_macro_ ) \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_CMP_CONST_CASE_C1( __op__, _toggle_macro_ ) \
+for( x = 0; x <= size.width - 4; x += 4 ) \
+{ \
+ int f0 = __op__( _toggle_macro_(src1[x]), scalar ); \
+ int f1 = __op__( _toggle_macro_(src1[x+1]), scalar ); \
+ dst[x] = (uchar)-f0; \
+ dst[x+1] = (uchar)-f1; \
+ f0 = __op__( _toggle_macro_(src1[x+2]), scalar ); \
+ f1 = __op__( _toggle_macro_(src1[x+3]), scalar ); \
+ dst[x+2] = (uchar)-f0; \
+ dst[x+3] = (uchar)-f1; \
+} \
+ \
+for( ; x < size.width; x++ ) \
+{ \
+ int f0 = __op__( _toggle_macro_(src1[x]), scalar ); \
+ dst[x] = (uchar)-f0; \
+}
+
+
+#define ICV_DEF_CMP_CONST_FUNC( __op__, name, flavor, arrtype, \
+ worktype, _toggle_macro_) \
+static CvStatus CV_STDCALL \
+icv##name##C_##flavor##_C1R( const arrtype* src1, int step1, \
+ uchar* dst, int step, \
+ CvSize size, worktype* pScalar ) \
+{ \
+ worktype scalar = *pScalar; \
+ step1 /= sizeof(src1[0]); step /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src1 += step1, dst += step ) \
+ { \
+ int x; \
+ ICV_DEF_CMP_CONST_CASE_C1( __op__, _toggle_macro_ ) \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_CMP_ALL( flavor, arrtype, worktype, _toggle_macro_ ) \
+ICV_DEF_CMP_FUNC( CV_GT, CmpGT, flavor, arrtype, worktype, _toggle_macro_ ) \
+ICV_DEF_CMP_FUNC( CV_EQ, CmpEQ, flavor, arrtype, worktype, _toggle_macro_ ) \
+ICV_DEF_CMP_CONST_FUNC( CV_GT, CmpGT, flavor, arrtype, worktype, _toggle_macro_)\
+ICV_DEF_CMP_CONST_FUNC( CV_GE, CmpGE, flavor, arrtype, worktype, _toggle_macro_)\
+ICV_DEF_CMP_CONST_FUNC( CV_EQ, CmpEQ, flavor, arrtype, worktype, _toggle_macro_)
+
+ICV_DEF_CMP_ALL( 8u, uchar, int, CV_NOP )
+ICV_DEF_CMP_ALL( 16u, ushort, int, CV_NOP )
+ICV_DEF_CMP_ALL( 16s, short, int, CV_NOP )
+ICV_DEF_CMP_ALL( 32s, int, int, CV_NOP )
+ICV_DEF_CMP_ALL( 32f, float, double, CV_NOP )
+ICV_DEF_CMP_ALL( 64f, double, double, CV_NOP )
+
+#define icvCmpGT_8s_C1R 0
+#define icvCmpEQ_8s_C1R 0
+#define icvCmpGTC_8s_C1R 0
+#define icvCmpGEC_8s_C1R 0
+#define icvCmpEQC_8s_C1R 0
+
+CV_DEF_INIT_FUNC_TAB_2D( CmpGT, C1R )
+CV_DEF_INIT_FUNC_TAB_2D( CmpEQ, C1R )
+CV_DEF_INIT_FUNC_TAB_2D( CmpGTC, C1R )
+CV_DEF_INIT_FUNC_TAB_2D( CmpGEC, C1R )
+CV_DEF_INIT_FUNC_TAB_2D( CmpEQC, C1R )
+
+icvCompare_8u_C1R_t icvCompare_8u_C1R_p = 0;
+icvCompare_16s_C1R_t icvCompare_16s_C1R_p = 0;
+icvCompare_32f_C1R_t icvCompare_32f_C1R_p = 0;
+
+icvCompareC_8u_C1R_t icvCompareC_8u_C1R_p = 0;
+icvCompareC_16s_C1R_t icvCompareC_16s_C1R_p = 0;
+icvCompareC_32f_C1R_t icvCompareC_32f_C1R_p = 0;
+
+icvThreshold_GT_8u_C1R_t icvThreshold_GT_8u_C1R_p = 0;
+icvThreshold_GT_16s_C1R_t icvThreshold_GT_16s_C1R_p = 0;
+icvThreshold_GT_32f_C1R_t icvThreshold_GT_32f_C1R_p = 0;
+
+icvThreshold_LT_8u_C1R_t icvThreshold_LT_8u_C1R_p = 0;
+icvThreshold_LT_16s_C1R_t icvThreshold_LT_16s_C1R_p = 0;
+icvThreshold_LT_32f_C1R_t icvThreshold_LT_32f_C1R_p = 0;
+
+/***************************************** cvCmp ****************************************/
+
+CV_IMPL void
+cvCmp( const void* srcarr1, const void* srcarr2,
+ void* dstarr, int cmp_op )
+{
+ static CvFuncTable cmp_tab[2];
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvCmp" );
+
+ __BEGIN__;
+
+ int type, coi = 0;
+ int invflag = 0;
+ CvCmpOp ipp_cmp_op;
+ int src1_step, src2_step, dst_step;
+ CvMat srcstub1, *src1 = (CvMat*)srcarr1;
+ CvMat srcstub2, *src2 = (CvMat*)srcarr2;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvMat *temp;
+ CvSize size;
+ CvFunc2D_3A func;
+
+ if( !inittab )
+ {
+ icvInitCmpGTC1RTable( &cmp_tab[0] );
+ icvInitCmpEQC1RTable( &cmp_tab[1] );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(src1) )
+ {
+ CV_CALL( src1 = cvGetMat( src1, &srcstub1, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_IS_MAT(src2) )
+ {
+ CV_CALL( src2 = cvGetMat( src2, &srcstub2, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_IS_MAT(dst) )
+ {
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ switch( cmp_op )
+ {
+ case CV_CMP_GT:
+ case CV_CMP_EQ:
+ break;
+ case CV_CMP_GE:
+ CV_SWAP( src1, src2, temp );
+ invflag = 1;
+ break;
+ case CV_CMP_LT:
+ CV_SWAP( src1, src2, temp );
+ break;
+ case CV_CMP_LE:
+ invflag = 1;
+ break;
+ case CV_CMP_NE:
+ cmp_op = CV_CMP_EQ;
+ invflag = 1;
+ break;
+ default:
+ CV_ERROR( CV_StsBadArg, "Unknown comparison operation" );
+ }
+
+ if( !CV_ARE_TYPES_EQ( src1, src2 ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( CV_MAT_CN( src1->type ) != 1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Input arrays must be single-channel");
+
+ if( !CV_IS_MASK_ARR( dst ))
+ CV_ERROR( CV_StsUnsupportedFormat, "Destination array should be 8uC1 or 8sC1");
+
+ if( !CV_ARE_SIZES_EQ( src1, src2 ) ||
+ !CV_ARE_SIZES_EQ( src1, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ type = CV_MAT_TYPE(src1->type);
+ size = cvGetMatSize( src1 );
+
+ if( CV_IS_MAT_CONT( src1->type & src2->type & dst->type ))
+ {
+ size.width *= size.height;
+ src1_step = src2_step = dst_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+ else
+ {
+ src1_step = src1->step;
+ src2_step = src2->step;
+ dst_step = dst->step;
+ }
+
+ func = (CvFunc2D_3A)(cmp_tab[cmp_op == CV_CMP_EQ].fn_2d[type]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ ipp_cmp_op = cmp_op == CV_CMP_EQ ? cvCmpEq : cvCmpGreater;
+
+ if( type == CV_8U && icvCompare_8u_C1R_p )
+ {
+ IPPI_CALL( icvCompare_8u_C1R_p( src1->data.ptr, src1_step, src2->data.ptr,
+ src2_step, dst->data.ptr, dst_step, size, ipp_cmp_op ));
+ }
+ else if( type == CV_16S && icvCompare_16s_C1R_p )
+ {
+ IPPI_CALL( icvCompare_16s_C1R_p( src1->data.s, src1_step, src2->data.s,
+ src2_step, dst->data.s, dst_step, size, ipp_cmp_op ));
+ }
+ else if( type == CV_32F && icvCompare_32f_C1R_p )
+ {
+ IPPI_CALL( icvCompare_32f_C1R_p( src1->data.fl, src1_step, src2->data.fl,
+ src2_step, dst->data.fl, dst_step, size, ipp_cmp_op ));
+ }
+ else
+ {
+ IPPI_CALL( func( src1->data.ptr, src1_step, src2->data.ptr, src2_step,
+ dst->data.ptr, dst_step, size ));
+ }
+
+ if( invflag )
+ IPPI_CALL( icvNot_8u_C1R( dst->data.ptr, dst_step,
+ dst->data.ptr, dst_step, size ));
+
+ __END__;
+}
+
+
+/*************************************** cvCmpS *****************************************/
+
+CV_IMPL void
+cvCmpS( const void* srcarr, double value, void* dstarr, int cmp_op )
+{
+ static CvFuncTable cmps_tab[3];
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvCmpS" );
+
+ __BEGIN__;
+
+ int y, type, coi = 0;
+ int invflag = 0, ipp_cmp_op;
+ int src1_step, dst_step;
+ CvMat srcstub1, *src1 = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize size;
+ int ival = 0;
+
+ if( !inittab )
+ {
+ icvInitCmpEQCC1RTable( &cmps_tab[CV_CMP_EQ] );
+ icvInitCmpGTCC1RTable( &cmps_tab[CV_CMP_GT] );
+ icvInitCmpGECC1RTable( &cmps_tab[CV_CMP_GE] );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(src1) )
+ {
+ CV_CALL( src1 = cvGetMat( src1, &srcstub1, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_IS_MAT(dst) )
+ {
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ switch( cmp_op )
+ {
+ case CV_CMP_GT:
+ case CV_CMP_EQ:
+ case CV_CMP_GE:
+ break;
+ case CV_CMP_LT:
+ invflag = 1;
+ cmp_op = CV_CMP_GE;
+ break;
+ case CV_CMP_LE:
+ invflag = 1;
+ cmp_op = CV_CMP_GT;
+ break;
+ case CV_CMP_NE:
+ invflag = 1;
+ cmp_op = CV_CMP_EQ;
+ break;
+ default:
+ CV_ERROR( CV_StsBadArg, "Unknown comparison operation" );
+ }
+
+ if( !CV_IS_MASK_ARR( dst ))
+ CV_ERROR( CV_StsUnsupportedFormat, "Destination array should be 8uC1 or 8sC1");
+
+ if( CV_MAT_CN( src1->type ) != 1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Input array must be single-channel");
+
+ if( !CV_ARE_SIZES_EQ( src1, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ type = CV_MAT_TYPE(src1->type);
+ size = cvGetMatSize( src1 );
+
+ if( CV_IS_MAT_CONT( src1->type & dst->type ))
+ {
+ size.width *= size.height;
+ src1_step = dst_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+ else
+ {
+ src1_step = src1->step;
+ dst_step = dst->step;
+ }
+
+ if( CV_MAT_DEPTH(type) <= CV_32S )
+ {
+ ival = cvRound(value);
+ if( type == CV_8U || type == CV_16S )
+ {
+ int minval = type == CV_8U ? 0 : -32768;
+ int maxval = type == CV_8U ? 255 : 32767;
+ int fillval = -1;
+ if( ival < minval )
+ fillval = cmp_op == CV_CMP_NE || cmp_op == CV_CMP_GE || cmp_op == CV_CMP_GT ? 255 : 0;
+ else if( ival > maxval )
+ fillval = cmp_op == CV_CMP_NE || cmp_op == CV_CMP_LE || cmp_op == CV_CMP_LT ? 255 : 0;
+ if( fillval >= 0 )
+ {
+ fillval ^= invflag ? 255 : 0;
+ for( y = 0; y < size.height; y++ )
+ memset( dst->data.ptr + y*dst_step, fillval, size.width );
+ EXIT;
+ }
+ }
+ }
+
+ ipp_cmp_op = cmp_op == CV_CMP_EQ ? cvCmpEq :
+ cmp_op == CV_CMP_GE ? cvCmpGreaterEq : cvCmpGreater;
+ if( type == CV_8U && icvCompare_8u_C1R_p )
+ {
+ IPPI_CALL( icvCompareC_8u_C1R_p( src1->data.ptr, src1_step, (uchar)ival,
+ dst->data.ptr, dst_step, size, ipp_cmp_op ));
+ }
+ else if( type == CV_16S && icvCompare_16s_C1R_p )
+ {
+ IPPI_CALL( icvCompareC_16s_C1R_p( src1->data.s, src1_step, (short)ival,
+ dst->data.s, dst_step, size, ipp_cmp_op ));
+ }
+ else if( type == CV_32F && icvCompare_32f_C1R_p )
+ {
+ IPPI_CALL( icvCompareC_32f_C1R_p( src1->data.fl, src1_step, (float)value,
+ dst->data.fl, dst_step, size, ipp_cmp_op ));
+ }
+ else
+ {
+ CvFunc2D_2A1P func = (CvFunc2D_2A1P)(cmps_tab[cmp_op].fn_2d[type]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( type <= CV_32S )
+ {
+ IPPI_CALL( func( src1->data.ptr, src1_step, dst->data.ptr,
+ dst_step, size, &ival ));
+ }
+ else
+ {
+ IPPI_CALL( func( src1->data.ptr, src1_step, dst->data.ptr,
+ dst_step, size, &value ));
+ }
+ }
+
+ if( invflag )
+ IPPI_CALL( icvNot_8u_C1R( dst->data.ptr, dst_step,
+ dst->data.ptr, dst_step, size ));
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* Min/Max *
+\****************************************************************************************/
+
+
+#define ICV_DEF_MINMAX_FUNC( __op__, name, flavor, arrtype, \
+ worktype, _toggle_macro_ ) \
+static CvStatus CV_STDCALL \
+icv##name##_##flavor##_C1R( const arrtype* src1, int step1, \
+ const arrtype* src2, int step2, \
+ arrtype* dst, int step, CvSize size ) \
+{ \
+ step1 /= sizeof(src1[0]); step2 /= sizeof(src2[0]); \
+ step /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src1 += step1, \
+ src2 += step2, dst += step ) \
+ { \
+ int x; \
+ for( x = 0; x <= size.width - 4; x += 4 ) \
+ { \
+ worktype a0 = _toggle_macro_(src1[x]); \
+ worktype b0 = _toggle_macro_(src2[x]); \
+ worktype a1 = _toggle_macro_(src1[x+1]); \
+ worktype b1 = _toggle_macro_(src2[x+1]); \
+ a0 = __op__( a0, b0 ); \
+ a1 = __op__( a1, b1 ); \
+ dst[x] = (arrtype)_toggle_macro_(a0); \
+ dst[x+1] = (arrtype)_toggle_macro_(a1); \
+ a0 = _toggle_macro_(src1[x+2]); \
+ b0 = _toggle_macro_(src2[x+2]); \
+ a1 = _toggle_macro_(src1[x+3]); \
+ b1 = _toggle_macro_(src2[x+3]); \
+ a0 = __op__( a0, b0 ); \
+ a1 = __op__( a1, b1 ); \
+ dst[x+2] = (arrtype)_toggle_macro_(a0); \
+ dst[x+3] = (arrtype)_toggle_macro_(a1); \
+ } \
+ \
+ for( ; x < size.width; x++ ) \
+ { \
+ worktype a0 = _toggle_macro_(src1[x]); \
+ worktype b0 = _toggle_macro_(src2[x]); \
+ a0 = __op__( a0, b0 ); \
+ dst[x] = (arrtype)_toggle_macro_(a0); \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_MINMAX_CONST_FUNC( __op__, name, \
+ flavor, arrtype, worktype, _toggle_macro_) \
+static CvStatus CV_STDCALL \
+icv##name##C_##flavor##_C1R( const arrtype* src1, int step1,\
+ arrtype* dst, int step, \
+ CvSize size, worktype* pScalar)\
+{ \
+ worktype scalar = _toggle_macro_(*pScalar); \
+ step1 /= sizeof(src1[0]); step /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src1 += step1, dst += step ) \
+ { \
+ int x; \
+ for( x = 0; x <= size.width - 4; x += 4 ) \
+ { \
+ worktype a0 = _toggle_macro_(src1[x]); \
+ worktype a1 = _toggle_macro_(src1[x+1]); \
+ a0 = __op__( a0, scalar ); \
+ a1 = __op__( a1, scalar ); \
+ dst[x] = (arrtype)_toggle_macro_(a0); \
+ dst[x+1] = (arrtype)_toggle_macro_(a1); \
+ a0 = _toggle_macro_(src1[x+2]); \
+ a1 = _toggle_macro_(src1[x+3]); \
+ a0 = __op__( a0, scalar ); \
+ a1 = __op__( a1, scalar ); \
+ dst[x+2] = (arrtype)_toggle_macro_(a0); \
+ dst[x+3] = (arrtype)_toggle_macro_(a1); \
+ } \
+ \
+ for( ; x < size.width; x++ ) \
+ { \
+ worktype a0 = _toggle_macro_(src1[x]); \
+ a0 = __op__( a0, scalar ); \
+ dst[x] = (arrtype)_toggle_macro_(a0); \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_MINMAX_ALL( flavor, arrtype, worktype, \
+ _toggle_macro_, _min_op_, _max_op_ ) \
+ICV_DEF_MINMAX_FUNC( _min_op_, Min, flavor, arrtype, worktype, _toggle_macro_ ) \
+ICV_DEF_MINMAX_FUNC( _max_op_, Max, flavor, arrtype, worktype, _toggle_macro_ ) \
+ICV_DEF_MINMAX_CONST_FUNC(_min_op_, Min, flavor, arrtype, worktype, _toggle_macro_)\
+ICV_DEF_MINMAX_CONST_FUNC(_max_op_, Max, flavor, arrtype, worktype, _toggle_macro_)
+
+ICV_DEF_MINMAX_ALL( 8u, uchar, int, CV_NOP, CV_MIN_8U, CV_MAX_8U )
+ICV_DEF_MINMAX_ALL( 16u, ushort, int, CV_NOP, CV_IMIN, CV_IMAX )
+ICV_DEF_MINMAX_ALL( 16s, short, int, CV_NOP, CV_IMIN, CV_IMAX )
+ICV_DEF_MINMAX_ALL( 32s, int, int, CV_NOP, CV_IMIN, CV_IMAX )
+ICV_DEF_MINMAX_ALL( 32f, int, int, CV_TOGGLE_FLT, CV_IMIN, CV_IMAX )
+ICV_DEF_MINMAX_ALL( 64f, double, double, CV_NOP, MIN, MAX )
+
+#define icvMin_8s_C1R 0
+#define icvMax_8s_C1R 0
+#define icvMinC_8s_C1R 0
+#define icvMaxC_8s_C1R 0
+
+CV_DEF_INIT_FUNC_TAB_2D( Min, C1R )
+CV_DEF_INIT_FUNC_TAB_2D( Max, C1R )
+CV_DEF_INIT_FUNC_TAB_2D( MinC, C1R )
+CV_DEF_INIT_FUNC_TAB_2D( MaxC, C1R )
+
+/*********************************** cvMin & cvMax **************************************/
+
+static void
+icvMinMax( const void* srcarr1, const void* srcarr2,
+ void* dstarr, int is_max )
+{
+ static CvFuncTable minmax_tab[2];
+ static int inittab = 0;
+
+ CV_FUNCNAME( "icvMinMax" );
+
+ __BEGIN__;
+
+ int type, coi = 0;
+ int src1_step, src2_step, dst_step;
+ CvMat srcstub1, *src1 = (CvMat*)srcarr1;
+ CvMat srcstub2, *src2 = (CvMat*)srcarr2;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize size;
+ CvFunc2D_3A func;
+
+ if( !inittab )
+ {
+ icvInitMinC1RTable( &minmax_tab[0] );
+ icvInitMaxC1RTable( &minmax_tab[1] );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(src1) )
+ {
+ CV_CALL( src1 = cvGetMat( src1, &srcstub1, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_IS_MAT(src2) )
+ {
+ CV_CALL( src2 = cvGetMat( src2, &srcstub2, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_IS_MAT(dst) )
+ {
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_ARE_TYPES_EQ( src1, src2 ) ||
+ !CV_ARE_TYPES_EQ( src1, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( CV_MAT_CN( src1->type ) != 1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Input arrays must be single-channel");
+
+ if( !CV_ARE_SIZES_EQ( src1, src2 ) ||
+ !CV_ARE_SIZES_EQ( src1, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ type = CV_MAT_TYPE(src1->type);
+ size = cvGetMatSize( src1 );
+
+ if( CV_IS_MAT_CONT( src1->type & src2->type & dst->type ))
+ {
+ size.width *= size.height;
+ src1_step = src2_step = dst_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+ else
+ {
+ src1_step = src1->step;
+ src2_step = src2->step;
+ dst_step = dst->step;
+ }
+
+ func = (CvFunc2D_3A)(minmax_tab[is_max != 0].fn_2d[type]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src1->data.ptr, src1_step, src2->data.ptr, src2_step,
+ dst->data.ptr, dst_step, size ));
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvMin( const void* srcarr1, const void* srcarr2, void* dstarr )
+{
+ icvMinMax( srcarr1, srcarr2, dstarr, 0 );
+}
+
+
+CV_IMPL void
+cvMax( const void* srcarr1, const void* srcarr2, void* dstarr )
+{
+ icvMinMax( srcarr1, srcarr2, dstarr, 1 );
+}
+
+
+/********************************* cvMinS / cvMaxS **************************************/
+
+static void
+icvMinMaxS( const void* srcarr, double value, void* dstarr, int is_max )
+{
+ static CvFuncTable minmaxs_tab[2];
+ static int inittab = 0;
+
+ CV_FUNCNAME( "icvMinMaxS" );
+
+ __BEGIN__;
+
+ int type, coi = 0;
+ int src1_step, dst_step;
+ CvMat srcstub1, *src1 = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize size;
+ CvFunc2D_2A1P func;
+ union
+ {
+ int i;
+ float f;
+ double d;
+ }
+ buf;
+
+ if( !inittab )
+ {
+ icvInitMinCC1RTable( &minmaxs_tab[0] );
+ icvInitMaxCC1RTable( &minmaxs_tab[1] );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(src1) )
+ {
+ CV_CALL( src1 = cvGetMat( src1, &srcstub1, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_IS_MAT(dst) )
+ {
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_ARE_TYPES_EQ( src1, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( CV_MAT_CN( src1->type ) != 1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Input array must be single-channel");
+
+ if( !CV_ARE_SIZES_EQ( src1, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ type = CV_MAT_TYPE(src1->type);
+
+ if( CV_MAT_DEPTH(type) <= CV_32S )
+ {
+ buf.i = cvRound(value);
+ if( CV_MAT_DEPTH(type) == CV_8U )
+ buf.i = CV_CAST_8U(buf.i);
+ else if( CV_MAT_DEPTH(type) == CV_8S )
+ buf.i = CV_CAST_8S(buf.i);
+ else if( CV_MAT_DEPTH(type) == CV_16U )
+ buf.i = CV_CAST_16U(buf.i);
+ else if( CV_MAT_DEPTH(type) == CV_16S )
+ buf.i = CV_CAST_16S(buf.i);
+ }
+ else if( CV_MAT_DEPTH(type) == CV_32F )
+ buf.f = (float)value;
+ else
+ buf.d = value;
+
+ size = cvGetMatSize( src1 );
+
+ if( CV_IS_MAT_CONT( src1->type & dst->type ))
+ {
+ size.width *= size.height;
+ src1_step = dst_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+ else
+ {
+ src1_step = src1->step;
+ dst_step = dst->step;
+ }
+
+ func = (CvFunc2D_2A1P)(minmaxs_tab[is_max].fn_2d[type]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( is_max )
+ {
+ if( type == CV_8U && icvThreshold_LT_8u_C1R_p )
+ {
+ IPPI_CALL( icvThreshold_LT_8u_C1R_p( src1->data.ptr, src1_step, dst->data.ptr,
+ dst_step, size, (uchar)buf.i ));
+ EXIT;
+ }
+ else if( type == CV_16S && icvThreshold_LT_16s_C1R_p )
+ {
+ IPPI_CALL( icvThreshold_LT_16s_C1R_p( src1->data.s, src1_step, dst->data.s,
+ dst_step, size, (short)buf.i ));
+ EXIT;
+ }
+ else if( type == CV_32F && icvThreshold_LT_32f_C1R_p )
+ {
+ IPPI_CALL( icvThreshold_LT_32f_C1R_p( src1->data.fl, src1_step, dst->data.fl,
+ dst_step, size, buf.f ));
+ EXIT;
+ }
+ }
+ else
+ {
+ if( type == CV_8U && icvThreshold_GT_8u_C1R_p )
+ {
+ IPPI_CALL( icvThreshold_GT_8u_C1R_p( src1->data.ptr, src1_step, dst->data.ptr,
+ dst_step, size, (uchar)buf.i ));
+ EXIT;
+ }
+ else if( type == CV_16S && icvThreshold_GT_16s_C1R_p )
+ {
+ IPPI_CALL( icvThreshold_GT_16s_C1R_p( src1->data.s, src1_step, dst->data.s,
+ dst_step, size, (short)buf.i ));
+ EXIT;
+ }
+ else if( type == CV_32F && icvThreshold_GT_32f_C1R_p )
+ {
+ IPPI_CALL( icvThreshold_GT_32f_C1R_p( src1->data.fl, src1_step, dst->data.fl,
+ dst_step, size, buf.f ));
+ EXIT;
+ }
+ }
+
+ if( type == CV_8U && size.width*size.height >= 1024 )
+ {
+ int i;
+ uchar tab[256];
+ CvMat _tab = cvMat( 1, 256, CV_8U, tab );
+
+ if( is_max )
+ {
+ for( i = 0; i < buf.i; i++ )
+ tab[i] = (uchar)buf.i;
+ for( ; i < 256; i++ )
+ tab[i] = (uchar)i;
+ }
+ else
+ {
+ for( i = 0; i < buf.i; i++ )
+ tab[i] = (uchar)i;
+ for( ; i < 256; i++ )
+ tab[i] = (uchar)buf.i;
+ }
+
+ cvLUT( src1, dst, &_tab );
+ EXIT;
+ }
+
+ IPPI_CALL( func( src1->data.ptr, src1_step, dst->data.ptr,
+ dst_step, size, &buf ));
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvMinS( const void* srcarr, double value, void* dstarr )
+{
+ icvMinMaxS( srcarr, value, dstarr, 0 );
+}
+
+
+CV_IMPL void
+cvMaxS( const void* srcarr, double value, void* dstarr )
+{
+ icvMinMaxS( srcarr, value, dstarr, 1 );
+}
+
+
+/****************************************************************************************\
+* Absolute Difference *
+\****************************************************************************************/
+
+#define ICV_DEF_BIN_ABS_DIFF_2D(name, arrtype, temptype, abs_macro, cast_macro)\
+IPCVAPI_IMPL( CvStatus, \
+name,( const arrtype* src1, int step1, \
+ const arrtype* src2, int step2, \
+ arrtype* dst, int step, CvSize size ), \
+ (src1, step1, src2, step2, dst, step, size)) \
+{ \
+ step1 /= sizeof(src1[0]); step2 /= sizeof(src2[0]); \
+ step /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2, \
+ dst += step ) \
+ { \
+ int i; \
+ \
+ for( i = 0; i <= size.width - 4; i += 4 ) \
+ { \
+ temptype t0 = src1[i] - src2[i]; \
+ temptype t1 = src1[i+1] - src2[i+1]; \
+ \
+ t0 = (temptype)abs_macro(t0); \
+ t1 = (temptype)abs_macro(t1); \
+ \
+ dst[i] = cast_macro(t0); \
+ dst[i+1] = cast_macro(t1); \
+ \
+ t0 = src1[i+2] - src2[i+2]; \
+ t1 = src1[i+3] - src2[i+3]; \
+ \
+ t0 = (temptype)abs_macro(t0); \
+ t1 = (temptype)abs_macro(t1); \
+ \
+ dst[i+2] = cast_macro(t0); \
+ dst[i+3] = cast_macro(t1); \
+ } \
+ \
+ for( ; i < size.width; i++ ) \
+ { \
+ temptype t0 = src1[i] - src2[i]; \
+ t0 = (temptype)abs_macro(t0); \
+ dst[i] = cast_macro(t0); \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_UN_ABS_DIFF_2D( name, arrtype, temptype, abs_macro, cast_macro)\
+static CvStatus CV_STDCALL \
+name( const arrtype* src0, int step1, \
+ arrtype* dst0, int step, \
+ CvSize size, const temptype* scalar ) \
+{ \
+ step1 /= sizeof(src0[0]); step /= sizeof(dst0[0]); \
+ \
+ for( ; size.height--; src0 += step1, dst0 += step ) \
+ { \
+ int i, len = size.width; \
+ const arrtype* src = src0; \
+ arrtype* dst = dst0; \
+ \
+ for( ; (len -= 12) >= 0; dst += 12, src += 12 ) \
+ { \
+ temptype t0 = src[0] - scalar[0]; \
+ temptype t1 = src[1] - scalar[1]; \
+ \
+ t0 = (temptype)abs_macro(t0); \
+ t1 = (temptype)abs_macro(t1); \
+ \
+ dst[0] = cast_macro( t0 ); \
+ dst[1] = cast_macro( t1 ); \
+ \
+ t0 = src[2] - scalar[2]; \
+ t1 = src[3] - scalar[3]; \
+ \
+ t0 = (temptype)abs_macro(t0); \
+ t1 = (temptype)abs_macro(t1); \
+ \
+ dst[2] = cast_macro( t0 ); \
+ dst[3] = cast_macro( t1 ); \
+ \
+ t0 = src[4] - scalar[4]; \
+ t1 = src[5] - scalar[5]; \
+ \
+ t0 = (temptype)abs_macro(t0); \
+ t1 = (temptype)abs_macro(t1); \
+ \
+ dst[4] = cast_macro( t0 ); \
+ dst[5] = cast_macro( t1 ); \
+ \
+ t0 = src[6] - scalar[6]; \
+ t1 = src[7] - scalar[7]; \
+ \
+ t0 = (temptype)abs_macro(t0); \
+ t1 = (temptype)abs_macro(t1); \
+ \
+ dst[6] = cast_macro( t0 ); \
+ dst[7] = cast_macro( t1 ); \
+ \
+ t0 = src[8] - scalar[8]; \
+ t1 = src[9] - scalar[9]; \
+ \
+ t0 = (temptype)abs_macro(t0); \
+ t1 = (temptype)abs_macro(t1); \
+ \
+ dst[8] = cast_macro( t0 ); \
+ dst[9] = cast_macro( t1 ); \
+ \
+ t0 = src[10] - scalar[10]; \
+ t1 = src[11] - scalar[11]; \
+ \
+ t0 = (temptype)abs_macro(t0); \
+ t1 = (temptype)abs_macro(t1); \
+ \
+ dst[10] = cast_macro( t0 ); \
+ dst[11] = cast_macro( t1 ); \
+ } \
+ \
+ for( (len) += 12, i = 0; i < (len); i++ ) \
+ { \
+ temptype t0 = src[i] - scalar[i]; \
+ t0 = (temptype)abs_macro(t0); \
+ dst[i] = cast_macro( t0 ); \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_TO_8U(x) ((uchar)(x))
+#define ICV_TO_16U(x) ((ushort)(x))
+
+ICV_DEF_BIN_ABS_DIFF_2D( icvAbsDiff_8u_C1R, uchar, int, CV_IABS, ICV_TO_8U )
+ICV_DEF_BIN_ABS_DIFF_2D( icvAbsDiff_16u_C1R, ushort, int, CV_IABS, ICV_TO_16U )
+ICV_DEF_BIN_ABS_DIFF_2D( icvAbsDiff_16s_C1R, short, int, CV_IABS, CV_CAST_16S )
+ICV_DEF_BIN_ABS_DIFF_2D( icvAbsDiff_32s_C1R, int, int, CV_IABS, CV_CAST_32S )
+ICV_DEF_BIN_ABS_DIFF_2D( icvAbsDiff_32f_C1R, float, float, fabs, CV_CAST_32F )
+ICV_DEF_BIN_ABS_DIFF_2D( icvAbsDiff_64f_C1R, double, double, fabs, CV_CAST_64F )
+
+ICV_DEF_UN_ABS_DIFF_2D( icvAbsDiffC_8u_CnR, uchar, int, CV_IABS, CV_CAST_8U )
+ICV_DEF_UN_ABS_DIFF_2D( icvAbsDiffC_16u_CnR, ushort, int, CV_IABS, CV_CAST_16U )
+ICV_DEF_UN_ABS_DIFF_2D( icvAbsDiffC_16s_CnR, short, int, CV_IABS, CV_CAST_16S )
+ICV_DEF_UN_ABS_DIFF_2D( icvAbsDiffC_32s_CnR, int, int, CV_IABS, CV_CAST_32S )
+ICV_DEF_UN_ABS_DIFF_2D( icvAbsDiffC_32f_CnR, float, float, fabs, CV_CAST_32F )
+ICV_DEF_UN_ABS_DIFF_2D( icvAbsDiffC_64f_CnR, double, double, fabs, CV_CAST_64F )
+
+
+#define ICV_INIT_MINI_FUNC_TAB_2D( FUNCNAME, suffix ) \
+static void icvInit##FUNCNAME##Table( CvFuncTable* tab ) \
+{ \
+ tab->fn_2d[CV_8U] = (void*)icv##FUNCNAME##_8u_##suffix; \
+ tab->fn_2d[CV_16U] = (void*)icv##FUNCNAME##_16u_##suffix; \
+ tab->fn_2d[CV_16S] = (void*)icv##FUNCNAME##_16s_##suffix; \
+ tab->fn_2d[CV_32S] = (void*)icv##FUNCNAME##_32s_##suffix; \
+ tab->fn_2d[CV_32F] = (void*)icv##FUNCNAME##_32f_##suffix; \
+ tab->fn_2d[CV_64F] = (void*)icv##FUNCNAME##_64f_##suffix; \
+}
+
+
+ICV_INIT_MINI_FUNC_TAB_2D( AbsDiff, C1R )
+ICV_INIT_MINI_FUNC_TAB_2D( AbsDiffC, CnR )
+
+
+CV_IMPL void
+cvAbsDiff( const void* srcarr1, const void* srcarr2, void* dstarr )
+{
+ static CvFuncTable adiff_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvAbsDiff" );
+
+ __BEGIN__;
+
+ int coi1 = 0, coi2 = 0, coi3 = 0;
+ CvMat srcstub1, *src1 = (CvMat*)srcarr1;
+ CvMat srcstub2, *src2 = (CvMat*)srcarr2;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ int src1_step, src2_step, dst_step;
+ CvSize size;
+ int type;
+
+ if( !inittab )
+ {
+ icvInitAbsDiffTable( &adiff_tab );
+ inittab = 1;
+ }
+
+ CV_CALL( src1 = cvGetMat( src1, &srcstub1, &coi1 ));
+ CV_CALL( src2 = cvGetMat( src2, &srcstub2, &coi2 ));
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi3 ));
+
+ if( coi1 != 0 || coi2 != 0 || coi3 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ if( !CV_ARE_SIZES_EQ( src1, src2 ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ size = cvGetMatSize( src1 );
+ type = CV_MAT_TYPE(src1->type);
+
+ if( !CV_ARE_SIZES_EQ( src1, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ if( !CV_ARE_TYPES_EQ( src1, src2 ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_TYPES_EQ( src1, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ size.width *= CV_MAT_CN( type );
+
+ src1_step = src1->step;
+ src2_step = src2->step;
+ dst_step = dst->step;
+
+ if( CV_IS_MAT_CONT( src1->type & src2->type & dst->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ src1_step = src2_step = dst_step = CV_STUB_STEP;
+ }
+
+ {
+ CvFunc2D_3A func = (CvFunc2D_3A)
+ (adiff_tab.fn_2d[CV_MAT_DEPTH(type)]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src1->data.ptr, src1_step, src2->data.ptr, src2_step,
+ dst->data.ptr, dst_step, size ));
+ }
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvAbsDiffS( const void* srcarr, void* dstarr, CvScalar scalar )
+{
+ static CvFuncTable adiffs_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvAbsDiffS" );
+
+ __BEGIN__;
+
+ int coi1 = 0, coi2 = 0;
+ int type, sctype;
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ int src_step, dst_step;
+ double buf[12];
+ CvSize size;
+
+ if( !inittab )
+ {
+ icvInitAbsDiffCTable( &adiffs_tab );
+ inittab = 1;
+ }
+
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ if( !CV_ARE_TYPES_EQ(src, dst) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ(src, dst) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ sctype = type = CV_MAT_TYPE( src->type );
+ if( CV_MAT_DEPTH(type) < CV_32S )
+ sctype = (type & CV_MAT_CN_MASK) | CV_32SC1;
+
+ size = cvGetMatSize( src );
+ size.width *= CV_MAT_CN( type );
+
+ src_step = src->step;
+ dst_step = dst->step;
+
+ if( CV_IS_MAT_CONT( src->type & dst->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ src_step = dst_step = CV_STUB_STEP;
+ }
+
+ CV_CALL( cvScalarToRawData( &scalar, buf, sctype, 1 ));
+
+ {
+ CvFunc2D_2A1P func = (CvFunc2D_2A1P)
+ (adiffs_tab.fn_2d[CV_MAT_DEPTH(type)]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src->data.ptr, src_step, dst->data.ptr,
+ dst_step, size, buf ));
+ }
+
+ __END__;
+}
+
+/* End of file. */
diff --git a/cxcore/src/cxconvert.cpp b/cxcore/src/cxconvert.cpp
new file mode 100644
index 0000000..1c29f0e
--- /dev/null
+++ b/cxcore/src/cxconvert.cpp
@@ -0,0 +1,1788 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+
+/****************************************************************************************\
+* Splitting/extracting array channels *
+\****************************************************************************************/
+
+#define ICV_DEF_PX2PL2PX_ENTRY_C2( arrtype_ptr, ptr ) \
+ arrtype_ptr plane0 = ptr[0]; \
+ arrtype_ptr plane1 = ptr[1];
+
+#define ICV_DEF_PX2PL2PX_ENTRY_C3( arrtype_ptr, ptr ) \
+ arrtype_ptr plane0 = ptr[0]; \
+ arrtype_ptr plane1 = ptr[1]; \
+ arrtype_ptr plane2 = ptr[2];
+
+#define ICV_DEF_PX2PL2PX_ENTRY_C4( arrtype_ptr, ptr ) \
+ arrtype_ptr plane0 = ptr[0]; \
+ arrtype_ptr plane1 = ptr[1]; \
+ arrtype_ptr plane2 = ptr[2]; \
+ arrtype_ptr plane3 = ptr[3];
+
+
+#define ICV_DEF_PX2PL_C2( arrtype, len ) \
+{ \
+ int j; \
+ \
+ for( j = 0; j < (len); j++, (src) += 2 ) \
+ { \
+ arrtype t0 = (src)[0]; \
+ arrtype t1 = (src)[1]; \
+ \
+ plane0[j] = t0; \
+ plane1[j] = t1; \
+ } \
+ plane0 += dststep; \
+ plane1 += dststep; \
+}
+
+
+#define ICV_DEF_PX2PL_C3( arrtype, len ) \
+{ \
+ int j; \
+ \
+ for( j = 0; j < (len); j++, (src) += 3 ) \
+ { \
+ arrtype t0 = (src)[0]; \
+ arrtype t1 = (src)[1]; \
+ arrtype t2 = (src)[2]; \
+ \
+ plane0[j] = t0; \
+ plane1[j] = t1; \
+ plane2[j] = t2; \
+ } \
+ plane0 += dststep; \
+ plane1 += dststep; \
+ plane2 += dststep; \
+}
+
+
+#define ICV_DEF_PX2PL_C4( arrtype, len ) \
+{ \
+ int j; \
+ \
+ for( j = 0; j < (len); j++, (src) += 4 ) \
+ { \
+ arrtype t0 = (src)[0]; \
+ arrtype t1 = (src)[1]; \
+ \
+ plane0[j] = t0; \
+ plane1[j] = t1; \
+ \
+ t0 = (src)[2]; \
+ t1 = (src)[3]; \
+ \
+ plane2[j] = t0; \
+ plane3[j] = t1; \
+ } \
+ plane0 += dststep; \
+ plane1 += dststep; \
+ plane2 += dststep; \
+ plane3 += dststep; \
+}
+
+
+#define ICV_DEF_PX2PL_COI( arrtype, len, cn ) \
+{ \
+ int j; \
+ \
+ for( j = 0; j <= (len) - 4; j += 4, (src) += 4*(cn))\
+ { \
+ arrtype t0 = (src)[0]; \
+ arrtype t1 = (src)[(cn)]; \
+ \
+ (dst)[j] = t0; \
+ (dst)[j+1] = t1; \
+ \
+ t0 = (src)[(cn)*2]; \
+ t1 = (src)[(cn)*3]; \
+ \
+ (dst)[j+2] = t0; \
+ (dst)[j+3] = t1; \
+ } \
+ \
+ for( ; j < (len); j++, (src) += (cn)) \
+ { \
+ (dst)[j] = (src)[0]; \
+ } \
+}
+
+
+#define ICV_DEF_COPY_PX2PL_FUNC_2D( arrtype, flavor, \
+ cn, entry_macro ) \
+IPCVAPI_IMPL( CvStatus, icvCopy_##flavor##_C##cn##P##cn##R,\
+( const arrtype* src, int srcstep, \
+ arrtype** dst, int dststep, CvSize size ), \
+ (src, srcstep, dst, dststep, size)) \
+{ \
+ entry_macro(arrtype*, dst); \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0][0]); \
+ \
+ for( ; size.height--; src += srcstep ) \
+ { \
+ ICV_DEF_PX2PL_C##cn( arrtype, size.width ); \
+ src -= size.width*(cn); \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_COPY_PX2PL_FUNC_2D_COI( arrtype, flavor )\
+IPCVAPI_IMPL( CvStatus, icvCopy_##flavor##_CnC1CR, \
+( const arrtype* src, int srcstep, arrtype* dst, int dststep,\
+ CvSize size, int cn, int coi ), \
+ (src, srcstep, dst, dststep, size, cn, coi)) \
+{ \
+ src += coi - 1; \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep )\
+ { \
+ ICV_DEF_PX2PL_COI( arrtype, size.width, cn ); \
+ src -= size.width*(cn); \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_COPY_PX2PL_FUNC_2D( uchar, 8u, 2, ICV_DEF_PX2PL2PX_ENTRY_C2 )
+ICV_DEF_COPY_PX2PL_FUNC_2D( uchar, 8u, 3, ICV_DEF_PX2PL2PX_ENTRY_C3 )
+ICV_DEF_COPY_PX2PL_FUNC_2D( uchar, 8u, 4, ICV_DEF_PX2PL2PX_ENTRY_C4 )
+ICV_DEF_COPY_PX2PL_FUNC_2D( ushort, 16s, 2, ICV_DEF_PX2PL2PX_ENTRY_C2 )
+ICV_DEF_COPY_PX2PL_FUNC_2D( ushort, 16s, 3, ICV_DEF_PX2PL2PX_ENTRY_C3 )
+ICV_DEF_COPY_PX2PL_FUNC_2D( ushort, 16s, 4, ICV_DEF_PX2PL2PX_ENTRY_C4 )
+ICV_DEF_COPY_PX2PL_FUNC_2D( int, 32f, 2, ICV_DEF_PX2PL2PX_ENTRY_C2 )
+ICV_DEF_COPY_PX2PL_FUNC_2D( int, 32f, 3, ICV_DEF_PX2PL2PX_ENTRY_C3 )
+ICV_DEF_COPY_PX2PL_FUNC_2D( int, 32f, 4, ICV_DEF_PX2PL2PX_ENTRY_C4 )
+ICV_DEF_COPY_PX2PL_FUNC_2D( int64, 64f, 2, ICV_DEF_PX2PL2PX_ENTRY_C2 )
+ICV_DEF_COPY_PX2PL_FUNC_2D( int64, 64f, 3, ICV_DEF_PX2PL2PX_ENTRY_C3 )
+ICV_DEF_COPY_PX2PL_FUNC_2D( int64, 64f, 4, ICV_DEF_PX2PL2PX_ENTRY_C4 )
+
+
+ICV_DEF_COPY_PX2PL_FUNC_2D_COI( uchar, 8u )
+ICV_DEF_COPY_PX2PL_FUNC_2D_COI( ushort, 16s )
+ICV_DEF_COPY_PX2PL_FUNC_2D_COI( int, 32f )
+ICV_DEF_COPY_PX2PL_FUNC_2D_COI( int64, 64f )
+
+
+/****************************************************************************************\
+* Merging/inserting array channels *
+\****************************************************************************************/
+
+
+#define ICV_DEF_PL2PX_C2( arrtype, len ) \
+{ \
+ int j; \
+ \
+ for( j = 0; j < (len); j++, (dst) += 2 )\
+ { \
+ arrtype t0 = plane0[j]; \
+ arrtype t1 = plane1[j]; \
+ \
+ dst[0] = t0; \
+ dst[1] = t1; \
+ } \
+ plane0 += srcstep; \
+ plane1 += srcstep; \
+}
+
+
+#define ICV_DEF_PL2PX_C3( arrtype, len ) \
+{ \
+ int j; \
+ \
+ for( j = 0; j < (len); j++, (dst) += 3 )\
+ { \
+ arrtype t0 = plane0[j]; \
+ arrtype t1 = plane1[j]; \
+ arrtype t2 = plane2[j]; \
+ \
+ dst[0] = t0; \
+ dst[1] = t1; \
+ dst[2] = t2; \
+ } \
+ plane0 += srcstep; \
+ plane1 += srcstep; \
+ plane2 += srcstep; \
+}
+
+
+#define ICV_DEF_PL2PX_C4( arrtype, len ) \
+{ \
+ int j; \
+ \
+ for( j = 0; j < (len); j++, (dst) += 4 )\
+ { \
+ arrtype t0 = plane0[j]; \
+ arrtype t1 = plane1[j]; \
+ \
+ dst[0] = t0; \
+ dst[1] = t1; \
+ \
+ t0 = plane2[j]; \
+ t1 = plane3[j]; \
+ \
+ dst[2] = t0; \
+ dst[3] = t1; \
+ } \
+ plane0 += srcstep; \
+ plane1 += srcstep; \
+ plane2 += srcstep; \
+ plane3 += srcstep; \
+}
+
+
+#define ICV_DEF_PL2PX_COI( arrtype, len, cn ) \
+{ \
+ int j; \
+ \
+ for( j = 0; j <= (len) - 4; j += 4, (dst) += 4*(cn))\
+ { \
+ arrtype t0 = (src)[j]; \
+ arrtype t1 = (src)[j+1]; \
+ \
+ (dst)[0] = t0; \
+ (dst)[(cn)] = t1; \
+ \
+ t0 = (src)[j+2]; \
+ t1 = (src)[j+3]; \
+ \
+ (dst)[(cn)*2] = t0; \
+ (dst)[(cn)*3] = t1; \
+ } \
+ \
+ for( ; j < (len); j++, (dst) += (cn)) \
+ { \
+ (dst)[0] = (src)[j]; \
+ } \
+}
+
+
+#define ICV_DEF_COPY_PL2PX_FUNC_2D( arrtype, flavor, cn, entry_macro ) \
+IPCVAPI_IMPL( CvStatus, icvCopy_##flavor##_P##cn##C##cn##R, \
+( const arrtype** src, int srcstep, \
+ arrtype* dst, int dststep, CvSize size ), \
+ (src, srcstep, dst, dststep, size)) \
+{ \
+ entry_macro(const arrtype*, src); \
+ srcstep /= sizeof(src[0][0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; dst += dststep ) \
+ { \
+ ICV_DEF_PL2PX_C##cn( arrtype, size.width ); \
+ dst -= size.width*(cn); \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_COPY_PL2PX_FUNC_2D_COI( arrtype, flavor ) \
+IPCVAPI_IMPL( CvStatus, icvCopy_##flavor##_C1CnCR, \
+( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, \
+ CvSize size, int cn, int coi ), \
+ (src, srcstep, dst, dststep, size, cn, coi)) \
+{ \
+ dst += coi - 1; \
+ srcstep /= sizeof(src[0]); dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ ICV_DEF_PL2PX_COI( arrtype, size.width, cn ); \
+ dst -= size.width*(cn); \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_COPY_PL2PX_FUNC_2D( uchar, 8u, 2, ICV_DEF_PX2PL2PX_ENTRY_C2 )
+ICV_DEF_COPY_PL2PX_FUNC_2D( uchar, 8u, 3, ICV_DEF_PX2PL2PX_ENTRY_C3 )
+ICV_DEF_COPY_PL2PX_FUNC_2D( uchar, 8u, 4, ICV_DEF_PX2PL2PX_ENTRY_C4 )
+ICV_DEF_COPY_PL2PX_FUNC_2D( ushort, 16s, 2, ICV_DEF_PX2PL2PX_ENTRY_C2 )
+ICV_DEF_COPY_PL2PX_FUNC_2D( ushort, 16s, 3, ICV_DEF_PX2PL2PX_ENTRY_C3 )
+ICV_DEF_COPY_PL2PX_FUNC_2D( ushort, 16s, 4, ICV_DEF_PX2PL2PX_ENTRY_C4 )
+ICV_DEF_COPY_PL2PX_FUNC_2D( int, 32f, 2, ICV_DEF_PX2PL2PX_ENTRY_C2 )
+ICV_DEF_COPY_PL2PX_FUNC_2D( int, 32f, 3, ICV_DEF_PX2PL2PX_ENTRY_C3 )
+ICV_DEF_COPY_PL2PX_FUNC_2D( int, 32f, 4, ICV_DEF_PX2PL2PX_ENTRY_C4 )
+ICV_DEF_COPY_PL2PX_FUNC_2D( int64, 64f, 2, ICV_DEF_PX2PL2PX_ENTRY_C2 )
+ICV_DEF_COPY_PL2PX_FUNC_2D( int64, 64f, 3, ICV_DEF_PX2PL2PX_ENTRY_C3 )
+ICV_DEF_COPY_PL2PX_FUNC_2D( int64, 64f, 4, ICV_DEF_PX2PL2PX_ENTRY_C4 )
+
+ICV_DEF_COPY_PL2PX_FUNC_2D_COI( uchar, 8u )
+ICV_DEF_COPY_PL2PX_FUNC_2D_COI( ushort, 16s )
+ICV_DEF_COPY_PL2PX_FUNC_2D_COI( int, 32f )
+ICV_DEF_COPY_PL2PX_FUNC_2D_COI( int64, 64f )
+
+
+#define ICV_DEF_PXPLPX_TAB( name, FROM, TO ) \
+static void \
+name( CvBigFuncTable* tab ) \
+{ \
+ tab->fn_2d[CV_8UC2] = (void*)icvCopy##_8u_##FROM##2##TO##2R; \
+ tab->fn_2d[CV_8UC3] = (void*)icvCopy##_8u_##FROM##3##TO##3R; \
+ tab->fn_2d[CV_8UC4] = (void*)icvCopy##_8u_##FROM##4##TO##4R; \
+ \
+ tab->fn_2d[CV_8SC2] = (void*)icvCopy##_8u_##FROM##2##TO##2R; \
+ tab->fn_2d[CV_8SC3] = (void*)icvCopy##_8u_##FROM##3##TO##3R; \
+ tab->fn_2d[CV_8SC4] = (void*)icvCopy##_8u_##FROM##4##TO##4R; \
+ \
+ tab->fn_2d[CV_16UC2] = (void*)icvCopy##_16s_##FROM##2##TO##2R; \
+ tab->fn_2d[CV_16UC3] = (void*)icvCopy##_16s_##FROM##3##TO##3R; \
+ tab->fn_2d[CV_16UC4] = (void*)icvCopy##_16s_##FROM##4##TO##4R; \
+ \
+ tab->fn_2d[CV_16SC2] = (void*)icvCopy##_16s_##FROM##2##TO##2R; \
+ tab->fn_2d[CV_16SC3] = (void*)icvCopy##_16s_##FROM##3##TO##3R; \
+ tab->fn_2d[CV_16SC4] = (void*)icvCopy##_16s_##FROM##4##TO##4R; \
+ \
+ tab->fn_2d[CV_32SC2] = (void*)icvCopy##_32f_##FROM##2##TO##2R; \
+ tab->fn_2d[CV_32SC3] = (void*)icvCopy##_32f_##FROM##3##TO##3R; \
+ tab->fn_2d[CV_32SC4] = (void*)icvCopy##_32f_##FROM##4##TO##4R; \
+ \
+ tab->fn_2d[CV_32FC2] = (void*)icvCopy##_32f_##FROM##2##TO##2R; \
+ tab->fn_2d[CV_32FC3] = (void*)icvCopy##_32f_##FROM##3##TO##3R; \
+ tab->fn_2d[CV_32FC4] = (void*)icvCopy##_32f_##FROM##4##TO##4R; \
+ \
+ tab->fn_2d[CV_64FC2] = (void*)icvCopy##_64f_##FROM##2##TO##2R; \
+ tab->fn_2d[CV_64FC3] = (void*)icvCopy##_64f_##FROM##3##TO##3R; \
+ tab->fn_2d[CV_64FC4] = (void*)icvCopy##_64f_##FROM##4##TO##4R; \
+}
+
+
+
+#define ICV_DEF_PXPLCOI_TAB( name, FROM, TO ) \
+static void \
+name( CvFuncTable* tab ) \
+{ \
+ tab->fn_2d[CV_8U] = (void*)icvCopy##_8u_##FROM##TO##CR; \
+ tab->fn_2d[CV_8S] = (void*)icvCopy##_8u_##FROM##TO##CR; \
+ tab->fn_2d[CV_16U] = (void*)icvCopy##_16s_##FROM##TO##CR; \
+ tab->fn_2d[CV_16S] = (void*)icvCopy##_16s_##FROM##TO##CR; \
+ tab->fn_2d[CV_32S] = (void*)icvCopy##_32f_##FROM##TO##CR; \
+ tab->fn_2d[CV_32F] = (void*)icvCopy##_32f_##FROM##TO##CR; \
+ tab->fn_2d[CV_64F] = (void*)icvCopy##_64f_##FROM##TO##CR; \
+}
+
+
+ICV_DEF_PXPLPX_TAB( icvInitSplitRTable, C, P )
+ICV_DEF_PXPLCOI_TAB( icvInitSplitRCoiTable, Cn, C1 )
+ICV_DEF_PXPLPX_TAB( icvInitCvtPlaneToPixRTable, P, C )
+ICV_DEF_PXPLCOI_TAB( icvInitCvtPlaneToPixRCoiTable, C1, Cn )
+
+typedef CvStatus (CV_STDCALL *CvSplitFunc)( const void* src, int srcstep,
+ void** dst, int dststep, CvSize size);
+
+typedef CvStatus (CV_STDCALL *CvExtractPlaneFunc)( const void* src, int srcstep,
+ void* dst, int dststep,
+ CvSize size, int cn, int coi );
+
+typedef CvStatus (CV_STDCALL *CvMergeFunc)( const void** src, int srcstep,
+ void* dst, int dststep, CvSize size);
+
+typedef CvStatus (CV_STDCALL *CvInsertPlaneFunc)( const void* src, int srcstep,
+ void* dst, int dststep,
+ CvSize size, int cn, int coi );
+
+CV_IMPL void
+cvSplit( const void* srcarr, void* dstarr0, void* dstarr1, void* dstarr2, void* dstarr3 )
+{
+ static CvBigFuncTable pxpl_tab;
+ static CvFuncTable pxplcoi_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvSplit" );
+
+ __BEGIN__;
+
+ CvMat stub[5], *dst[4], *src = (CvMat*)srcarr;
+ CvSize size;
+ void* dstptr[4] = { 0, 0, 0, 0 };
+ int type, cn, coi = 0;
+ int i, nzplanes = 0, nzidx = -1;
+ int cont_flag;
+ int src_step, dst_step = 0;
+
+ if( !inittab )
+ {
+ icvInitSplitRTable( &pxpl_tab );
+ icvInitSplitRCoiTable( &pxplcoi_tab );
+ inittab = 1;
+ }
+
+ dst[0] = (CvMat*)dstarr0;
+ dst[1] = (CvMat*)dstarr1;
+ dst[2] = (CvMat*)dstarr2;
+ dst[3] = (CvMat*)dstarr3;
+
+ CV_CALL( src = cvGetMat( src, stub + 4, &coi ));
+
+ //if( coi != 0 )
+ // CV_ERROR( CV_BadCOI, "" );
+
+ type = CV_MAT_TYPE( src->type );
+ cn = CV_MAT_CN( type );
+
+ cont_flag = src->type;
+
+ if( cn == 1 )
+ CV_ERROR( CV_BadNumChannels, "" );
+
+ for( i = 0; i < 4; i++ )
+ {
+ if( dst[i] )
+ {
+ nzplanes++;
+ nzidx = i;
+ CV_CALL( dst[i] = cvGetMat( dst[i], stub + i ));
+ if( CV_MAT_CN( dst[i]->type ) != 1 )
+ CV_ERROR( CV_BadNumChannels, "" );
+ if( !CV_ARE_DEPTHS_EQ( dst[i], src ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+ if( !CV_ARE_SIZES_EQ( dst[i], src ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+ if( nzplanes > i && i > 0 && dst[i]->step != dst[i-1]->step )
+ CV_ERROR( CV_BadStep, "" );
+ dst_step = dst[i]->step;
+ dstptr[nzplanes-1] = dst[i]->data.ptr;
+
+ cont_flag &= dst[i]->type;
+ }
+ }
+
+ src_step = src->step;
+ size = cvGetMatSize( src );
+
+ if( CV_IS_MAT_CONT( cont_flag ))
+ {
+ size.width *= size.height;
+ src_step = dst_step = CV_STUB_STEP;
+
+ size.height = 1;
+ }
+
+ if( nzplanes == cn )
+ {
+ CvSplitFunc func = (CvSplitFunc)pxpl_tab.fn_2d[type];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src->data.ptr, src_step, dstptr, dst_step, size ));
+ }
+ else if( nzplanes == 1 )
+ {
+ CvExtractPlaneFunc func = (CvExtractPlaneFunc)pxplcoi_tab.fn_2d[CV_MAT_DEPTH(type)];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src->data.ptr, src_step,
+ dst[nzidx]->data.ptr, dst_step,
+ size, cn, nzidx + 1 ));
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg,
+ "Either all output planes or only one output plane should be non zero" );
+ }
+
+ __END__;
+}
+
+
+
+CV_IMPL void
+cvMerge( const void* srcarr0, const void* srcarr1, const void* srcarr2,
+ const void* srcarr3, void* dstarr )
+{
+ static CvBigFuncTable plpx_tab;
+ static CvFuncTable plpxcoi_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvMerge" );
+
+ __BEGIN__;
+
+ int src_step = 0, dst_step;
+ CvMat stub[5], *src[4], *dst = (CvMat*)dstarr;
+ CvSize size;
+ const void* srcptr[4] = { 0, 0, 0, 0 };
+ int type, cn, coi = 0;
+ int i, nzplanes = 0, nzidx = -1;
+ int cont_flag;
+
+ if( !inittab )
+ {
+ icvInitCvtPlaneToPixRTable( &plpx_tab );
+ icvInitCvtPlaneToPixRCoiTable( &plpxcoi_tab );
+ inittab = 1;
+ }
+
+ src[0] = (CvMat*)srcarr0;
+ src[1] = (CvMat*)srcarr1;
+ src[2] = (CvMat*)srcarr2;
+ src[3] = (CvMat*)srcarr3;
+
+ CV_CALL( dst = cvGetMat( dst, stub + 4, &coi ));
+
+ type = CV_MAT_TYPE( dst->type );
+ cn = CV_MAT_CN( type );
+
+ cont_flag = dst->type;
+
+ if( cn == 1 )
+ CV_ERROR( CV_BadNumChannels, "" );
+
+ for( i = 0; i < 4; i++ )
+ {
+ if( src[i] )
+ {
+ nzplanes++;
+ nzidx = i;
+ CV_CALL( src[i] = cvGetMat( src[i], stub + i ));
+ if( CV_MAT_CN( src[i]->type ) != 1 )
+ CV_ERROR( CV_BadNumChannels, "" );
+ if( !CV_ARE_DEPTHS_EQ( src[i], dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+ if( !CV_ARE_SIZES_EQ( src[i], dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+ if( nzplanes > i && i > 0 && src[i]->step != src[i-1]->step )
+ CV_ERROR( CV_BadStep, "" );
+ src_step = src[i]->step;
+ srcptr[nzplanes-1] = (const void*)(src[i]->data.ptr);
+
+ cont_flag &= src[i]->type;
+ }
+ }
+
+ size = cvGetMatSize( dst );
+ dst_step = dst->step;
+
+ if( CV_IS_MAT_CONT( cont_flag ))
+ {
+ size.width *= size.height;
+ src_step = dst_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+
+ if( nzplanes == cn )
+ {
+ CvMergeFunc func = (CvMergeFunc)plpx_tab.fn_2d[type];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( srcptr, src_step, dst->data.ptr, dst_step, size ));
+ }
+ else if( nzplanes == 1 )
+ {
+ CvInsertPlaneFunc func = (CvInsertPlaneFunc)plpxcoi_tab.fn_2d[CV_MAT_DEPTH(type)];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src[nzidx]->data.ptr, src_step,
+ dst->data.ptr, dst_step,
+ size, cn, nzidx + 1 ));
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg,
+ "Either all input planes or only one input plane should be non zero" );
+ }
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* Generalized split/merge: mixing channels *
+\****************************************************************************************/
+
+#define ICV_DEF_MIX_CH_FUNC_2D( arrtype, flavor ) \
+static CvStatus CV_STDCALL \
+icvMixChannels_##flavor( const arrtype** src, int* sdelta0, \
+ int* sdelta1, arrtype** dst, \
+ int* ddelta0, int* ddelta1, \
+ int n, CvSize size ) \
+{ \
+ int i, k; \
+ int block_size0 = n == 1 ? size.width : 1024; \
+ \
+ for( ; size.height--; ) \
+ { \
+ int remaining = size.width; \
+ for( ; remaining > 0; ) \
+ { \
+ int block_size = MIN( remaining, block_size0 ); \
+ for( k = 0; k < n; k++ ) \
+ { \
+ const arrtype* s = src[k]; \
+ arrtype* d = dst[k]; \
+ int ds = sdelta1[k], dd = ddelta1[k]; \
+ if( s ) \
+ { \
+ for( i = 0; i <= block_size - 2; i += 2, \
+ s += ds*2, d += dd*2 ) \
+ { \
+ arrtype t0 = s[0], t1 = s[ds]; \
+ d[0] = t0; d[dd] = t1; \
+ } \
+ if( i < block_size ) \
+ d[0] = s[0], s += ds, d += dd; \
+ src[k] = s; \
+ } \
+ else \
+ { \
+ for( i=0; i <= block_size-2; i+=2, d+=dd*2 )\
+ d[0] = d[dd] = 0; \
+ if( i < block_size ) \
+ d[0] = 0, d += dd; \
+ } \
+ dst[k] = d; \
+ } \
+ remaining -= block_size; \
+ } \
+ for( k = 0; k < n; k++ ) \
+ src[k] += sdelta0[k], dst[k] += ddelta0[k]; \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_MIX_CH_FUNC_2D( uchar, 8u )
+ICV_DEF_MIX_CH_FUNC_2D( ushort, 16u )
+ICV_DEF_MIX_CH_FUNC_2D( int, 32s )
+ICV_DEF_MIX_CH_FUNC_2D( int64, 64s )
+
+static void
+icvInitMixChannelsTab( CvFuncTable* tab )
+{
+ tab->fn_2d[CV_8U] = (void*)icvMixChannels_8u;
+ tab->fn_2d[CV_8S] = (void*)icvMixChannels_8u;
+ tab->fn_2d[CV_16U] = (void*)icvMixChannels_16u;
+ tab->fn_2d[CV_16S] = (void*)icvMixChannels_16u;
+ tab->fn_2d[CV_32S] = (void*)icvMixChannels_32s;
+ tab->fn_2d[CV_32F] = (void*)icvMixChannels_32s;
+ tab->fn_2d[CV_64F] = (void*)icvMixChannels_64s;
+}
+
+typedef CvStatus (CV_STDCALL * CvMixChannelsFunc)( const void** src, int* sdelta0,
+ int* sdelta1, void** dst, int* ddelta0, int* ddelta1, int n, CvSize size );
+
+CV_IMPL void
+cvMixChannels( const CvArr** src, int src_count,
+ CvArr** dst, int dst_count,
+ const int* from_to, int pair_count )
+{
+ static CvFuncTable mixcn_tab;
+ static int inittab = 0;
+ uchar* buffer = 0;
+ int heap_alloc = 0;
+
+ CV_FUNCNAME( "cvMixChannels" );
+
+ __BEGIN__;
+
+ CvSize size = {0,0};
+ int depth = -1, elem_size = 1;
+ int *sdelta0 = 0, *sdelta1 = 0, *ddelta0 = 0, *ddelta1 = 0;
+ uchar **sptr = 0, **dptr = 0;
+ uchar **src0 = 0, **dst0 = 0;
+ int* src_cn = 0, *dst_cn = 0;
+ int* src_step = 0, *dst_step = 0;
+ int buf_size, i, k;
+ int cont_flag = CV_MAT_CONT_FLAG;
+ CvMixChannelsFunc func;
+
+ if( !inittab )
+ {
+ icvInitMixChannelsTab( &mixcn_tab );
+ inittab = 1;
+ }
+
+ src_count = MAX( src_count, 0 );
+
+ if( !src && src_count > 0 )
+ CV_ERROR( CV_StsNullPtr, "The input array of arrays is NULL" );
+
+ if( !dst )
+ CV_ERROR( CV_StsNullPtr, "The output array of arrays is NULL" );
+
+ if( dst_count <= 0 || pair_count <= 0 )
+ CV_ERROR( CV_StsOutOfRange,
+ "The number of output arrays and the number of copied channels must be positive" );
+
+ if( !from_to )
+ CV_ERROR( CV_StsNullPtr, "The array of copied channel indices is NULL" );
+
+ buf_size = (src_count + dst_count + 2)*
+ (sizeof(src0[0]) + sizeof(src_cn[0]) + sizeof(src_step[0])) +
+ pair_count*2*(sizeof(sptr[0]) + sizeof(sdelta0[0]) + sizeof(sdelta1[0]));
+
+ if( buf_size > CV_MAX_LOCAL_SIZE )
+ {
+ CV_CALL( buffer = (uchar*)cvAlloc( buf_size ) );
+ heap_alloc = 1;
+ }
+ else
+ buffer = (uchar*)cvStackAlloc( buf_size );
+
+ src0 = (uchar**)buffer;
+ dst0 = src0 + src_count;
+ src_cn = (int*)(dst0 + dst_count);
+ dst_cn = src_cn + src_count + 1;
+ src_step = dst_cn + dst_count + 1;
+ dst_step = src_step + src_count;
+
+ sptr = (uchar**)cvAlignPtr( dst_step + dst_count, (int)sizeof(void*) );
+ dptr = sptr + pair_count;
+ sdelta0 = (int*)(dptr + pair_count);
+ sdelta1 = sdelta0 + pair_count;
+ ddelta0 = sdelta1 + pair_count;
+ ddelta1 = ddelta0 + pair_count;
+
+ src_cn[0] = dst_cn[0] = 0;
+
+ for( k = 0; k < 2; k++ )
+ {
+ for( i = 0; i < (k == 0 ? src_count : dst_count); i++ )
+ {
+ CvMat stub, *mat = (CvMat*)(k == 0 ? src[i] : dst[i]);
+ int cn;
+
+ if( !CV_IS_MAT(mat) )
+ CV_CALL( mat = cvGetMat( mat, &stub ));
+
+ if( depth < 0 )
+ {
+ depth = CV_MAT_DEPTH(mat->type);
+ elem_size = CV_ELEM_SIZE1(depth);
+ size = cvGetMatSize(mat);
+ }
+
+ if( CV_MAT_DEPTH(mat->type) != depth )
+ CV_ERROR( CV_StsUnmatchedFormats, "All the arrays must have the same bit depth" );
+
+ if( mat->cols != size.width || mat->rows != size.height )
+ CV_ERROR( CV_StsUnmatchedSizes, "All the arrays must have the same size" );
+
+ if( k == 0 )
+ {
+ src0[i] = mat->data.ptr;
+ cn = CV_MAT_CN(mat->type);
+ src_cn[i+1] = src_cn[i] + cn;
+ src_step[i] = mat->step / elem_size - size.width * cn;
+ }
+ else
+ {
+ dst0[i] = mat->data.ptr;
+ cn = CV_MAT_CN(mat->type);
+ dst_cn[i+1] = dst_cn[i] + cn;
+ dst_step[i] = mat->step / elem_size - size.width * cn;
+ }
+
+ cont_flag &= mat->type;
+ }
+ }
+
+ if( cont_flag )
+ {
+ size.width *= size.height;
+ size.height = 1;
+ }
+
+ for( i = 0; i < pair_count; i++ )
+ {
+ for( k = 0; k < 2; k++ )
+ {
+ int cn = from_to[i*2 + k];
+ const int* cn_arr = k == 0 ? src_cn : dst_cn;
+ int a = 0, b = k == 0 ? src_count-1 : dst_count-1;
+
+ if( cn < 0 || cn >= cn_arr[b+1] )
+ {
+ if( k == 0 && cn < 0 )
+ {
+ sptr[i] = 0;
+ sdelta0[i] = sdelta1[i] = 0;
+ continue;
+ }
+ else
+ {
+ char err_str[100];
+ sprintf( err_str, "channel index #%d in the array of pairs is negative "
+ "or exceeds the total number of channels in all the %s arrays", i*2+k,
+ k == 0 ? "input" : "output" );
+ CV_ERROR( CV_StsOutOfRange, err_str );
+ }
+ }
+
+ for( ; cn >= cn_arr[a+1]; a++ )
+ ;
+
+ if( k == 0 )
+ {
+ sptr[i] = src0[a] + (cn - cn_arr[a])*elem_size;
+ sdelta1[i] = cn_arr[a+1] - cn_arr[a];
+ sdelta0[i] = src_step[a];
+ }
+ else
+ {
+ dptr[i] = dst0[a] + (cn - cn_arr[a])*elem_size;
+ ddelta1[i] = cn_arr[a+1] - cn_arr[a];
+ ddelta0[i] = dst_step[a];
+ }
+ }
+ }
+
+ func = (CvMixChannelsFunc)mixcn_tab.fn_2d[depth];
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "The data type is not supported by the function" );
+
+ IPPI_CALL( func( (const void**)sptr, sdelta0, sdelta1, (void**)dptr,
+ ddelta0, ddelta1, pair_count, size ));
+
+ __END__;
+
+ if( buffer && heap_alloc )
+ cvFree( &buffer );
+}
+
+
+/****************************************************************************************\
+* cvConvertScaleAbs *
+\****************************************************************************************/
+
+#define ICV_DEF_CVT_SCALE_ABS_CASE( srctype, worktype, \
+ scale_macro, abs_macro, cast_macro, a, b ) \
+ \
+{ \
+ const srctype* _src = (const srctype*)src; \
+ srcstep /= sizeof(_src[0]); /*dststep /= sizeof(_dst[0]);*/ \
+ \
+ for( ; size.height--; _src += srcstep, dst += dststep ) \
+ { \
+ int i; \
+ \
+ for( i = 0; i <= size.width - 4; i += 4 ) \
+ { \
+ worktype t0 = scale_macro((a)*_src[i] + (b)); \
+ worktype t1 = scale_macro((a)*_src[i+1] + (b)); \
+ \
+ t0 = (worktype)abs_macro(t0); \
+ t1 = (worktype)abs_macro(t1); \
+ \
+ dst[i] = cast_macro(t0); \
+ dst[i+1] = cast_macro(t1); \
+ \
+ t0 = scale_macro((a)*_src[i+2] + (b)); \
+ t1 = scale_macro((a)*_src[i+3] + (b)); \
+ \
+ t0 = (worktype)abs_macro(t0); \
+ t1 = (worktype)abs_macro(t1); \
+ \
+ dst[i+2] = cast_macro(t0); \
+ dst[i+3] = cast_macro(t1); \
+ } \
+ \
+ for( ; i < size.width; i++ ) \
+ { \
+ worktype t0 = scale_macro((a)*_src[i] + (b)); \
+ t0 = (worktype)abs_macro(t0); \
+ dst[i] = cast_macro(t0); \
+ } \
+ } \
+}
+
+
+#define ICV_FIX_SHIFT 15
+#define ICV_SCALE(x) (((x) + (1 << (ICV_FIX_SHIFT-1))) >> ICV_FIX_SHIFT)
+
+static CvStatus CV_STDCALL
+icvCvtScaleAbsTo_8u_C1R( const uchar* src, int srcstep,
+ uchar* dst, int dststep,
+ CvSize size, double scale, double shift,
+ int param )
+{
+ int srctype = param;
+ int srcdepth = CV_MAT_DEPTH(srctype);
+
+ size.width *= CV_MAT_CN(srctype);
+
+ switch( srcdepth )
+ {
+ case CV_8S:
+ case CV_8U:
+ {
+ uchar lut[256];
+ int i;
+ double val = shift;
+
+ for( i = 0; i < 128; i++, val += scale )
+ {
+ int t = cvRound(fabs(val));
+ lut[i] = CV_CAST_8U(t);
+ }
+
+ if( srcdepth == CV_8S )
+ val = -val;
+
+ for( ; i < 256; i++, val += scale )
+ {
+ int t = cvRound(fabs(val));
+ lut[i] = CV_CAST_8U(t);
+ }
+
+ icvLUT_Transform8u_8u_C1R( src, srcstep, dst,
+ dststep, size, lut );
+ }
+ break;
+ case CV_16U:
+ if( fabs( scale ) <= 1. && fabs(shift) < DBL_EPSILON )
+ {
+ int iscale = cvRound(scale*(1 << ICV_FIX_SHIFT));
+
+ if( iscale == ICV_FIX_SHIFT )
+ {
+ ICV_DEF_CVT_SCALE_ABS_CASE( ushort, int, CV_NOP, CV_IABS,
+ CV_CAST_8U, 1, 0 );
+ }
+ else
+ {
+ ICV_DEF_CVT_SCALE_ABS_CASE( ushort, int, ICV_SCALE, CV_IABS,
+ CV_CAST_8U, iscale, 0 );
+ }
+ }
+ else
+ {
+ ICV_DEF_CVT_SCALE_ABS_CASE( ushort, int, cvRound, CV_IABS,
+ CV_CAST_8U, scale, shift );
+ }
+ break;
+ case CV_16S:
+ if( fabs( scale ) <= 1. &&
+ fabs( shift ) <= (INT_MAX*0.5)/(1 << ICV_FIX_SHIFT))
+ {
+ int iscale = cvRound(scale*(1 << ICV_FIX_SHIFT));
+ int ishift = cvRound(shift*(1 << ICV_FIX_SHIFT));
+
+ if( iscale == ICV_FIX_SHIFT && ishift == 0 )
+ {
+ ICV_DEF_CVT_SCALE_ABS_CASE( short, int, CV_NOP, CV_IABS,
+ CV_CAST_8U, 1, 0 );
+ }
+ else
+ {
+ ICV_DEF_CVT_SCALE_ABS_CASE( short, int, ICV_SCALE, CV_IABS,
+ CV_CAST_8U, iscale, ishift );
+ }
+ }
+ else
+ {
+ ICV_DEF_CVT_SCALE_ABS_CASE( short, int, cvRound, CV_IABS,
+ CV_CAST_8U, scale, shift );
+ }
+ break;
+ case CV_32S:
+ ICV_DEF_CVT_SCALE_ABS_CASE( int, int, cvRound, CV_IABS,
+ CV_CAST_8U, scale, shift );
+ break;
+ case CV_32F:
+ ICV_DEF_CVT_SCALE_ABS_CASE( float, int, cvRound, CV_IABS,
+ CV_CAST_8U, scale, shift );
+ break;
+ case CV_64F:
+ ICV_DEF_CVT_SCALE_ABS_CASE( double, int, cvRound, CV_IABS,
+ CV_CAST_8U, scale, shift );
+ break;
+ default:
+ assert(0);
+ return CV_BADFLAG_ERR;
+ }
+
+ return CV_OK;
+}
+
+
+CV_IMPL void
+cvConvertScaleAbs( const void* srcarr, void* dstarr,
+ double scale, double shift )
+{
+ CV_FUNCNAME( "cvConvertScaleAbs" );
+
+ __BEGIN__;
+
+ int coi1 = 0, coi2 = 0;
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize size;
+ int src_step, dst_step;
+
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( !CV_ARE_CNS_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( CV_MAT_DEPTH( dst->type ) != CV_8U )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ size = cvGetMatSize( src );
+ src_step = src->step;
+ dst_step = dst->step;
+
+ if( CV_IS_MAT_CONT( src->type & dst->type ))
+ {
+ size.width *= size.height;
+ src_step = dst_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+
+ IPPI_CALL( icvCvtScaleAbsTo_8u_C1R( src->data.ptr, src_step,
+ (uchar*)(dst->data.ptr), dst_step,
+ size, scale, shift, CV_MAT_TYPE(src->type)));
+ __END__;
+}
+
+/****************************************************************************************\
+* cvConvertScale *
+\****************************************************************************************/
+
+#define ICV_DEF_CVT_SCALE_CASE( srctype, worktype, \
+ scale_macro, cast_macro, a, b ) \
+ \
+{ \
+ const srctype* _src = (const srctype*)src; \
+ srcstep /= sizeof(_src[0]); \
+ \
+ for( ; size.height--; _src += srcstep, dst += dststep ) \
+ { \
+ for( i = 0; i <= size.width - 4; i += 4 ) \
+ { \
+ worktype t0 = scale_macro((a)*_src[i]+(b)); \
+ worktype t1 = scale_macro((a)*_src[i+1]+(b)); \
+ \
+ dst[i] = cast_macro(t0); \
+ dst[i+1] = cast_macro(t1); \
+ \
+ t0 = scale_macro((a)*_src[i+2] + (b)); \
+ t1 = scale_macro((a)*_src[i+3] + (b)); \
+ \
+ dst[i+2] = cast_macro(t0); \
+ dst[i+3] = cast_macro(t1); \
+ } \
+ \
+ for( ; i < size.width; i++ ) \
+ { \
+ worktype t0 = scale_macro((a)*_src[i] + (b)); \
+ dst[i] = cast_macro(t0); \
+ } \
+ } \
+}
+
+
+#define ICV_DEF_CVT_SCALE_FUNC_INT( flavor, dsttype, cast_macro ) \
+static CvStatus CV_STDCALL \
+icvCvtScaleTo_##flavor##_C1R( const uchar* src, int srcstep, \
+ dsttype* dst, int dststep, CvSize size, \
+ double scale, double shift, int param ) \
+{ \
+ int i, srctype = param; \
+ dsttype lut[256]; \
+ dststep /= sizeof(dst[0]); \
+ \
+ switch( CV_MAT_DEPTH(srctype) ) \
+ { \
+ case CV_8U: \
+ if( size.width*size.height >= 256 ) \
+ { \
+ double val = shift; \
+ for( i = 0; i < 256; i++, val += scale ) \
+ { \
+ int t = cvRound(val); \
+ lut[i] = cast_macro(t); \
+ } \
+ \
+ icvLUT_Transform8u_##flavor##_C1R( src, srcstep, dst, \
+ dststep*sizeof(dst[0]), size, lut ); \
+ } \
+ else if( fabs( scale ) <= 128. && \
+ fabs( shift ) <= (INT_MAX*0.5)/(1 << ICV_FIX_SHIFT)) \
+ { \
+ int iscale = cvRound(scale*(1 << ICV_FIX_SHIFT)); \
+ int ishift = cvRound(shift*(1 << ICV_FIX_SHIFT)); \
+ \
+ ICV_DEF_CVT_SCALE_CASE( uchar, int, ICV_SCALE, \
+ cast_macro, iscale, ishift ); \
+ } \
+ else \
+ { \
+ ICV_DEF_CVT_SCALE_CASE( uchar, int, cvRound, \
+ cast_macro, scale, shift ); \
+ } \
+ break; \
+ case CV_8S: \
+ if( size.width*size.height >= 256 ) \
+ { \
+ for( i = 0; i < 256; i++ ) \
+ { \
+ int t = cvRound( (schar)i*scale + shift ); \
+ lut[i] = cast_macro(t); \
+ } \
+ \
+ icvLUT_Transform8u_##flavor##_C1R( src, srcstep, dst, \
+ dststep*sizeof(dst[0]), size, lut ); \
+ } \
+ else if( fabs( scale ) <= 128. && \
+ fabs( shift ) <= (INT_MAX*0.5)/(1 << ICV_FIX_SHIFT)) \
+ { \
+ int iscale = cvRound(scale*(1 << ICV_FIX_SHIFT)); \
+ int ishift = cvRound(shift*(1 << ICV_FIX_SHIFT)); \
+ \
+ ICV_DEF_CVT_SCALE_CASE( schar, int, ICV_SCALE, \
+ cast_macro, iscale, ishift ); \
+ } \
+ else \
+ { \
+ ICV_DEF_CVT_SCALE_CASE( schar, int, cvRound, \
+ cast_macro, scale, shift ); \
+ } \
+ break; \
+ case CV_16U: \
+ if( fabs( scale ) <= 1. && fabs(shift) < DBL_EPSILON ) \
+ { \
+ int iscale = cvRound(scale*(1 << ICV_FIX_SHIFT)); \
+ \
+ ICV_DEF_CVT_SCALE_CASE( ushort, int, ICV_SCALE, \
+ cast_macro, iscale, 0 ); \
+ } \
+ else \
+ { \
+ ICV_DEF_CVT_SCALE_CASE( ushort, int, cvRound, \
+ cast_macro, scale, shift ); \
+ } \
+ break; \
+ case CV_16S: \
+ if( fabs( scale ) <= 1. && \
+ fabs( shift ) <= (INT_MAX*0.5)/(1 << ICV_FIX_SHIFT)) \
+ { \
+ int iscale = cvRound(scale*(1 << ICV_FIX_SHIFT)); \
+ int ishift = cvRound(shift*(1 << ICV_FIX_SHIFT)); \
+ \
+ ICV_DEF_CVT_SCALE_CASE( short, int, ICV_SCALE, \
+ cast_macro, iscale, ishift ); \
+ } \
+ else \
+ { \
+ ICV_DEF_CVT_SCALE_CASE( short, int, cvRound, \
+ cast_macro, scale, shift ); \
+ } \
+ break; \
+ case CV_32S: \
+ ICV_DEF_CVT_SCALE_CASE( int, int, cvRound, \
+ cast_macro, scale, shift ); \
+ break; \
+ case CV_32F: \
+ ICV_DEF_CVT_SCALE_CASE( float, int, cvRound, \
+ cast_macro, scale, shift ); \
+ break; \
+ case CV_64F: \
+ ICV_DEF_CVT_SCALE_CASE( double, int, cvRound, \
+ cast_macro, scale, shift ); \
+ break; \
+ default: \
+ assert(0); \
+ return CV_BADFLAG_ERR; \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_CVT_SCALE_FUNC_FLT( flavor, dsttype, cast_macro ) \
+static CvStatus CV_STDCALL \
+icvCvtScaleTo_##flavor##_C1R( const uchar* src, int srcstep, \
+ dsttype* dst, int dststep, CvSize size, \
+ double scale, double shift, int param ) \
+{ \
+ int i, srctype = param; \
+ dsttype lut[256]; \
+ dststep /= sizeof(dst[0]); \
+ \
+ switch( CV_MAT_DEPTH(srctype) ) \
+ { \
+ case CV_8U: \
+ if( size.width*size.height >= 256 ) \
+ { \
+ double val = shift; \
+ for( i = 0; i < 256; i++, val += scale ) \
+ lut[i] = (dsttype)val; \
+ \
+ icvLUT_Transform8u_##flavor##_C1R( src, srcstep, dst, \
+ dststep*sizeof(dst[0]), size, lut ); \
+ } \
+ else \
+ { \
+ ICV_DEF_CVT_SCALE_CASE( uchar, double, CV_NOP, \
+ cast_macro, scale, shift ); \
+ } \
+ break; \
+ case CV_8S: \
+ if( size.width*size.height >= 256 ) \
+ { \
+ for( i = 0; i < 256; i++ ) \
+ lut[i] = (dsttype)((schar)i*scale + shift); \
+ \
+ icvLUT_Transform8u_##flavor##_C1R( src, srcstep, dst, \
+ dststep*sizeof(dst[0]), size, lut ); \
+ } \
+ else \
+ { \
+ ICV_DEF_CVT_SCALE_CASE( schar, double, CV_NOP, \
+ cast_macro, scale, shift ); \
+ } \
+ break; \
+ case CV_16U: \
+ ICV_DEF_CVT_SCALE_CASE( ushort, double, CV_NOP, \
+ cast_macro, scale, shift ); \
+ break; \
+ case CV_16S: \
+ ICV_DEF_CVT_SCALE_CASE( short, double, CV_NOP, \
+ cast_macro, scale, shift ); \
+ break; \
+ case CV_32S: \
+ ICV_DEF_CVT_SCALE_CASE( int, double, CV_NOP, \
+ cast_macro, scale, shift ); \
+ break; \
+ case CV_32F: \
+ ICV_DEF_CVT_SCALE_CASE( float, double, CV_NOP, \
+ cast_macro, scale, shift ); \
+ break; \
+ case CV_64F: \
+ ICV_DEF_CVT_SCALE_CASE( double, double, CV_NOP, \
+ cast_macro, scale, shift ); \
+ break; \
+ default: \
+ assert(0); \
+ return CV_BADFLAG_ERR; \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_CVT_SCALE_FUNC_INT( 8u, uchar, CV_CAST_8U )
+ICV_DEF_CVT_SCALE_FUNC_INT( 8s, schar, CV_CAST_8S )
+ICV_DEF_CVT_SCALE_FUNC_INT( 16s, short, CV_CAST_16S )
+ICV_DEF_CVT_SCALE_FUNC_INT( 16u, ushort, CV_CAST_16U )
+ICV_DEF_CVT_SCALE_FUNC_INT( 32s, int, CV_CAST_32S )
+
+ICV_DEF_CVT_SCALE_FUNC_FLT( 32f, float, CV_CAST_32F )
+ICV_DEF_CVT_SCALE_FUNC_FLT( 64f, double, CV_CAST_64F )
+
+CV_DEF_INIT_FUNC_TAB_2D( CvtScaleTo, C1R )
+
+
+/****************************************************************************************\
+* Conversion w/o scaling macros *
+\****************************************************************************************/
+
+#define ICV_DEF_CVT_CASE_2D( srctype, worktype, \
+ cast_macro1, cast_macro2 ) \
+{ \
+ const srctype* _src = (const srctype*)src; \
+ srcstep /= sizeof(_src[0]); \
+ \
+ for( ; size.height--; _src += srcstep, dst += dststep ) \
+ { \
+ int i; \
+ \
+ for( i = 0; i <= size.width - 4; i += 4 ) \
+ { \
+ worktype t0 = cast_macro1(_src[i]); \
+ worktype t1 = cast_macro1(_src[i+1]); \
+ \
+ dst[i] = cast_macro2(t0); \
+ dst[i+1] = cast_macro2(t1); \
+ \
+ t0 = cast_macro1(_src[i+2]); \
+ t1 = cast_macro1(_src[i+3]); \
+ \
+ dst[i+2] = cast_macro2(t0); \
+ dst[i+3] = cast_macro2(t1); \
+ } \
+ \
+ for( ; i < size.width; i++ ) \
+ { \
+ worktype t0 = cast_macro1(_src[i]); \
+ dst[i] = cast_macro2(t0); \
+ } \
+ } \
+}
+
+
+#define ICV_DEF_CVT_FUNC_2D( flavor, dsttype, worktype, cast_macro2, \
+ srcdepth1, srctype1, cast_macro11, \
+ srcdepth2, srctype2, cast_macro12, \
+ srcdepth3, srctype3, cast_macro13, \
+ srcdepth4, srctype4, cast_macro14, \
+ srcdepth5, srctype5, cast_macro15, \
+ srcdepth6, srctype6, cast_macro16 ) \
+static CvStatus CV_STDCALL \
+icvCvtTo_##flavor##_C1R( const uchar* src, int srcstep, \
+ dsttype* dst, int dststep, \
+ CvSize size, int param ) \
+{ \
+ int srctype = param; \
+ dststep /= sizeof(dst[0]); \
+ \
+ switch( CV_MAT_DEPTH(srctype) ) \
+ { \
+ case srcdepth1: \
+ ICV_DEF_CVT_CASE_2D( srctype1, worktype, \
+ cast_macro11, cast_macro2 ); \
+ break; \
+ case srcdepth2: \
+ ICV_DEF_CVT_CASE_2D( srctype2, worktype, \
+ cast_macro12, cast_macro2 ); \
+ break; \
+ case srcdepth3: \
+ ICV_DEF_CVT_CASE_2D( srctype3, worktype, \
+ cast_macro13, cast_macro2 ); \
+ break; \
+ case srcdepth4: \
+ ICV_DEF_CVT_CASE_2D( srctype4, worktype, \
+ cast_macro14, cast_macro2 ); \
+ break; \
+ case srcdepth5: \
+ ICV_DEF_CVT_CASE_2D( srctype5, worktype, \
+ cast_macro15, cast_macro2 ); \
+ break; \
+ case srcdepth6: \
+ ICV_DEF_CVT_CASE_2D( srctype6, worktype, \
+ cast_macro16, cast_macro2 ); \
+ break; \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_CVT_FUNC_2D( 8u, uchar, int, CV_CAST_8U,
+ CV_8S, schar, CV_NOP,
+ CV_16U, ushort, CV_NOP,
+ CV_16S, short, CV_NOP,
+ CV_32S, int, CV_NOP,
+ CV_32F, float, cvRound,
+ CV_64F, double, cvRound )
+
+ICV_DEF_CVT_FUNC_2D( 8s, schar, int, CV_CAST_8S,
+ CV_8U, uchar, CV_NOP,
+ CV_16U, ushort, CV_NOP,
+ CV_16S, short, CV_NOP,
+ CV_32S, int, CV_NOP,
+ CV_32F, float, cvRound,
+ CV_64F, double, cvRound )
+
+ICV_DEF_CVT_FUNC_2D( 16u, ushort, int, CV_CAST_16U,
+ CV_8U, uchar, CV_NOP,
+ CV_8S, schar, CV_NOP,
+ CV_16S, short, CV_NOP,
+ CV_32S, int, CV_NOP,
+ CV_32F, float, cvRound,
+ CV_64F, double, cvRound )
+
+ICV_DEF_CVT_FUNC_2D( 16s, short, int, CV_CAST_16S,
+ CV_8U, uchar, CV_NOP,
+ CV_8S, schar, CV_NOP,
+ CV_16U, ushort, CV_NOP,
+ CV_32S, int, CV_NOP,
+ CV_32F, float, cvRound,
+ CV_64F, double, cvRound )
+
+ICV_DEF_CVT_FUNC_2D( 32s, int, int, CV_NOP,
+ CV_8U, uchar, CV_NOP,
+ CV_8S, schar, CV_NOP,
+ CV_16U, ushort, CV_NOP,
+ CV_16S, short, CV_NOP,
+ CV_32F, float, cvRound,
+ CV_64F, double, cvRound )
+
+ICV_DEF_CVT_FUNC_2D( 32f, float, float, CV_NOP,
+ CV_8U, uchar, CV_8TO32F,
+ CV_8S, schar, CV_8TO32F,
+ CV_16U, ushort, CV_NOP,
+ CV_16S, short, CV_NOP,
+ CV_32S, int, CV_CAST_32F,
+ CV_64F, double, CV_CAST_32F )
+
+ICV_DEF_CVT_FUNC_2D( 64f, double, double, CV_NOP,
+ CV_8U, uchar, CV_8TO32F,
+ CV_8S, schar, CV_8TO32F,
+ CV_16U, ushort, CV_NOP,
+ CV_16S, short, CV_NOP,
+ CV_32S, int, CV_NOP,
+ CV_32F, float, CV_NOP )
+
+CV_DEF_INIT_FUNC_TAB_2D( CvtTo, C1R )
+
+
+typedef CvStatus (CV_STDCALL *CvCvtFunc)( const void* src, int srcstep,
+ void* dst, int dststep, CvSize size,
+ int param );
+
+typedef CvStatus (CV_STDCALL *CvCvtScaleFunc)( const void* src, int srcstep,
+ void* dst, int dststep, CvSize size,
+ double scale, double shift,
+ int param );
+
+CV_IMPL void
+cvConvertScale( const void* srcarr, void* dstarr,
+ double scale, double shift )
+{
+ static CvFuncTable cvt_tab, cvtscale_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvConvertScale" );
+
+ __BEGIN__;
+
+ int type;
+ int is_nd = 0;
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize size;
+ int src_step, dst_step;
+ int no_scale = scale == 1 && shift == 0;
+
+ if( !CV_IS_MAT(src) )
+ {
+ if( CV_IS_MATND(src) )
+ is_nd = 1;
+ else
+ {
+ int coi = 0;
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+ }
+
+ if( !CV_IS_MAT(dst) )
+ {
+ if( CV_IS_MATND(dst) )
+ is_nd = 1;
+ else
+ {
+ int coi = 0;
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+ }
+
+ if( is_nd )
+ {
+ CvArr* arrs[] = { src, dst };
+ CvMatND stubs[2];
+ CvNArrayIterator iterator;
+ int dsttype;
+
+ CV_CALL( cvInitNArrayIterator( 2, arrs, 0, stubs, &iterator, CV_NO_DEPTH_CHECK ));
+
+ type = iterator.hdr[0]->type;
+ dsttype = iterator.hdr[1]->type;
+ iterator.size.width *= CV_MAT_CN(type);
+
+ if( !inittab )
+ {
+ icvInitCvtToC1RTable( &cvt_tab );
+ icvInitCvtScaleToC1RTable( &cvtscale_tab );
+ inittab = 1;
+ }
+
+ if( no_scale )
+ {
+ CvCvtFunc func = (CvCvtFunc)(cvt_tab.fn_2d[CV_MAT_DEPTH(dsttype)]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ do
+ {
+ IPPI_CALL( func( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.size, type ));
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ else
+ {
+ CvCvtScaleFunc func =
+ (CvCvtScaleFunc)(cvtscale_tab.fn_2d[CV_MAT_DEPTH(dsttype)]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ do
+ {
+ IPPI_CALL( func( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.size, scale, shift, type ));
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ EXIT;
+ }
+
+ if( no_scale && CV_ARE_TYPES_EQ( src, dst ) )
+ {
+ if( src != dst )
+ cvCopy( src, dst );
+ EXIT;
+ }
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ size = cvGetMatSize( src );
+ type = CV_MAT_TYPE(src->type);
+ src_step = src->step;
+ dst_step = dst->step;
+
+ if( CV_IS_MAT_CONT( src->type & dst->type ))
+ {
+ size.width *= size.height;
+ src_step = dst_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+
+ size.width *= CV_MAT_CN( type );
+
+ if( CV_ARE_TYPES_EQ( src, dst ) && size.height == 1 &&
+ size.width <= CV_MAX_INLINE_MAT_OP_SIZE )
+ {
+ if( CV_MAT_DEPTH(type) == CV_32F )
+ {
+ const float* srcdata = (const float*)(src->data.ptr);
+ float* dstdata = (float*)(dst->data.ptr);
+
+ do
+ {
+ dstdata[size.width - 1] = (float)(srcdata[size.width-1]*scale + shift);
+ }
+ while( --size.width );
+
+ EXIT;
+ }
+
+ if( CV_MAT_DEPTH(type) == CV_64F )
+ {
+ const double* srcdata = (const double*)(src->data.ptr);
+ double* dstdata = (double*)(dst->data.ptr);
+
+ do
+ {
+ dstdata[size.width - 1] = srcdata[size.width-1]*scale + shift;
+ }
+ while( --size.width );
+
+ EXIT;
+ }
+ }
+
+ if( !inittab )
+ {
+ icvInitCvtToC1RTable( &cvt_tab );
+ icvInitCvtScaleToC1RTable( &cvtscale_tab );
+ inittab = 1;
+ }
+
+ if( !CV_ARE_CNS_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( no_scale )
+ {
+ CvCvtFunc func = (CvCvtFunc)(cvt_tab.fn_2d[CV_MAT_DEPTH(dst->type)]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src->data.ptr, src_step,
+ dst->data.ptr, dst_step, size, type ));
+ }
+ else
+ {
+ CvCvtScaleFunc func = (CvCvtScaleFunc)
+ (cvtscale_tab.fn_2d[CV_MAT_DEPTH(dst->type)]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src->data.ptr, src_step,
+ dst->data.ptr, dst_step, size,
+ scale, shift, type ));
+ }
+
+ __END__;
+}
+
+/********************* helper functions for converting 32f<->64f ************************/
+
+IPCVAPI_IMPL( CvStatus, icvCvt_32f64f,
+ ( const float* src, double* dst, int len ), (src, dst, len) )
+{
+ int i;
+ for( i = 0; i <= len - 4; i += 4 )
+ {
+ double t0 = src[i];
+ double t1 = src[i+1];
+
+ dst[i] = t0;
+ dst[i+1] = t1;
+
+ t0 = src[i+2];
+ t1 = src[i+3];
+
+ dst[i+2] = t0;
+ dst[i+3] = t1;
+ }
+
+ for( ; i < len; i++ )
+ dst[i] = src[i];
+
+ return CV_OK;
+}
+
+
+IPCVAPI_IMPL( CvStatus, icvCvt_64f32f,
+ ( const double* src, float* dst, int len ), (src, dst, len) )
+{
+ int i = 0;
+ for( ; i <= len - 4; i += 4 )
+ {
+ double t0 = src[i];
+ double t1 = src[i+1];
+
+ dst[i] = (float)t0;
+ dst[i+1] = (float)t1;
+
+ t0 = src[i+2];
+ t1 = src[i+3];
+
+ dst[i+2] = (float)t0;
+ dst[i+3] = (float)t1;
+ }
+
+ for( ; i < len; i++ )
+ dst[i] = (float)src[i];
+
+ return CV_OK;
+}
+
+
+CvStatus CV_STDCALL icvScale_32f( const float* src, float* dst, int len, float a, float b )
+{
+ int i;
+ for( i = 0; i <= len - 4; i += 4 )
+ {
+ double t0 = src[i]*a + b;
+ double t1 = src[i+1]*a + b;
+
+ dst[i] = (float)t0;
+ dst[i+1] = (float)t1;
+
+ t0 = src[i+2]*a + b;
+ t1 = src[i+3]*a + b;
+
+ dst[i+2] = (float)t0;
+ dst[i+3] = (float)t1;
+ }
+
+ for( ; i < len; i++ )
+ dst[i] = (float)(src[i]*a + b);
+
+ return CV_OK;
+}
+
+
+CvStatus CV_STDCALL icvScale_64f( const double* src, double* dst, int len, double a, double b )
+{
+ int i;
+ for( i = 0; i <= len - 4; i += 4 )
+ {
+ double t0 = src[i]*a + b;
+ double t1 = src[i+1]*a + b;
+
+ dst[i] = t0;
+ dst[i+1] = t1;
+
+ t0 = src[i+2]*a + b;
+ t1 = src[i+3]*a + b;
+
+ dst[i+2] = t0;
+ dst[i+3] = t1;
+ }
+
+ for( ; i < len; i++ )
+ dst[i] = src[i]*a + b;
+
+ return CV_OK;
+}
+
+/* End of file. */
diff --git a/cxcore/src/cxcopy.cpp b/cxcore/src/cxcopy.cpp
new file mode 100644
index 0000000..b27409e
--- /dev/null
+++ b/cxcore/src/cxcopy.cpp
@@ -0,0 +1,1042 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/* ////////////////////////////////////////////////////////////////////
+//
+// CvMat basic operations: cvCopy, cvSet
+//
+// */
+
+#include "_cxcore.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// //
+// L/L COPY & SET FUNCTIONS //
+// //
+/////////////////////////////////////////////////////////////////////////////////////////
+
+
+IPCVAPI_IMPL( CvStatus, icvCopy_8u_C1R, ( const uchar* src, int srcstep,
+ uchar* dst, int dststep, CvSize size ),
+ (src, srcstep, dst, dststep, size) )
+{
+ for( ; size.height--; src += srcstep, dst += dststep )
+ memcpy( dst, src, size.width );
+
+ return CV_OK;
+}
+
+
+static CvStatus CV_STDCALL
+icvSet_8u_C1R( uchar* dst, int dst_step, CvSize size,
+ const void* scalar, int pix_size )
+{
+ int copy_len = 12*pix_size;
+ uchar* dst_limit = dst + size.width;
+
+ if( size.height-- )
+ {
+ while( dst + copy_len <= dst_limit )
+ {
+ memcpy( dst, scalar, copy_len );
+ dst += copy_len;
+ }
+
+ memcpy( dst, scalar, dst_limit - dst );
+ }
+
+ if( size.height )
+ {
+ dst = dst_limit - size.width + dst_step;
+
+ for( ; size.height--; dst += dst_step )
+ memcpy( dst, dst - dst_step, size.width );
+ }
+
+ return CV_OK;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// //
+// L/L COPY WITH MASK FUNCTIONS //
+// //
+/////////////////////////////////////////////////////////////////////////////////////////
+
+
+#define ICV_DEF_COPY_MASK_C1_CASE( type ) \
+ for( i = 0; i <= size.width-2; i += 2 ) \
+ { \
+ if( mask[i] ) \
+ dst[i] = src[i]; \
+ if( mask[i+1] ) \
+ dst[i+1] = src[i+1]; \
+ } \
+ \
+ for( ; i < size.width; i++ ) \
+ { \
+ if( mask[i] ) \
+ dst[i] = src[i]; \
+ }
+
+#define ICV_DEF_COPY_MASK_C3_CASE( type ) \
+ for( i = 0; i < size.width; i++ ) \
+ if( mask[i] ) \
+ { \
+ type t0 = src[i*3]; \
+ type t1 = src[i*3+1]; \
+ type t2 = src[i*3+2]; \
+ \
+ dst[i*3] = t0; \
+ dst[i*3+1] = t1; \
+ dst[i*3+2] = t2; \
+ }
+
+
+
+#define ICV_DEF_COPY_MASK_C4_CASE( type ) \
+ for( i = 0; i < size.width; i++ ) \
+ if( mask[i] ) \
+ { \
+ type t0 = src[i*4]; \
+ type t1 = src[i*4+1]; \
+ dst[i*4] = t0; \
+ dst[i*4+1] = t1; \
+ \
+ t0 = src[i*4+2]; \
+ t1 = src[i*4+3]; \
+ dst[i*4+2] = t0; \
+ dst[i*4+3] = t1; \
+ }
+
+
+#define ICV_DEF_COPY_MASK_2D( name, type, cn ) \
+IPCVAPI_IMPL( CvStatus, \
+name,( const type* src, int srcstep, type* dst, int dststep,\
+ CvSize size, const uchar* mask, int maskstep ), \
+ (src, srcstep, dst, dststep, size, mask, maskstep)) \
+{ \
+ srcstep /= sizeof(src[0]); dststep /= sizeof(dst[0]); \
+ for( ; size.height--; src += srcstep, \
+ dst += dststep, mask += maskstep ) \
+ { \
+ int i; \
+ ICV_DEF_COPY_MASK_C##cn##_CASE( type ) \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_SET_MASK_C1_CASE( type ) \
+ for( i = 0; i <= size.width-2; i += 2 ) \
+ { \
+ if( mask[i] ) \
+ dst[i] = s0; \
+ if( mask[i+1] ) \
+ dst[i+1] = s0; \
+ } \
+ \
+ for( ; i < size.width; i++ ) \
+ { \
+ if( mask[i] ) \
+ dst[i] = s0; \
+ }
+
+
+#define ICV_DEF_SET_MASK_C3_CASE( type ) \
+ for( i = 0; i < size.width; i++ ) \
+ if( mask[i] ) \
+ { \
+ dst[i*3] = s0; \
+ dst[i*3+1] = s1; \
+ dst[i*3+2] = s2; \
+ }
+
+#define ICV_DEF_SET_MASK_C4_CASE( type ) \
+ for( i = 0; i < size.width; i++ ) \
+ if( mask[i] ) \
+ { \
+ dst[i*4] = s0; \
+ dst[i*4+1] = s1; \
+ dst[i*4+2] = s2; \
+ dst[i*4+3] = s3; \
+ }
+
+#define ICV_DEF_SET_MASK_2D( name, type, cn ) \
+IPCVAPI_IMPL( CvStatus, \
+name,( type* dst, int dststep, \
+ const uchar* mask, int maskstep, \
+ CvSize size, const type* scalar ), \
+ (dst, dststep, mask, maskstep, size, scalar))\
+{ \
+ CV_UN_ENTRY_C##cn( type ); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; mask += maskstep, \
+ dst += dststep ) \
+ { \
+ int i; \
+ ICV_DEF_SET_MASK_C##cn##_CASE( type ) \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_SET_MASK_2D( icvSet_8u_C1MR, uchar, 1 )
+ICV_DEF_SET_MASK_2D( icvSet_16s_C1MR, ushort, 1 )
+ICV_DEF_SET_MASK_2D( icvSet_8u_C3MR, uchar, 3 )
+ICV_DEF_SET_MASK_2D( icvSet_8u_C4MR, int, 1 )
+ICV_DEF_SET_MASK_2D( icvSet_16s_C3MR, ushort, 3 )
+ICV_DEF_SET_MASK_2D( icvSet_16s_C4MR, int64, 1 )
+ICV_DEF_SET_MASK_2D( icvSet_32f_C3MR, int, 3 )
+ICV_DEF_SET_MASK_2D( icvSet_32f_C4MR, int, 4 )
+ICV_DEF_SET_MASK_2D( icvSet_64s_C3MR, int64, 3 )
+ICV_DEF_SET_MASK_2D( icvSet_64s_C4MR, int64, 4 )
+
+ICV_DEF_COPY_MASK_2D( icvCopy_8u_C1MR, uchar, 1 )
+ICV_DEF_COPY_MASK_2D( icvCopy_16s_C1MR, ushort, 1 )
+ICV_DEF_COPY_MASK_2D( icvCopy_8u_C3MR, uchar, 3 )
+ICV_DEF_COPY_MASK_2D( icvCopy_8u_C4MR, int, 1 )
+ICV_DEF_COPY_MASK_2D( icvCopy_16s_C3MR, ushort, 3 )
+ICV_DEF_COPY_MASK_2D( icvCopy_16s_C4MR, int64, 1 )
+ICV_DEF_COPY_MASK_2D( icvCopy_32f_C3MR, int, 3 )
+ICV_DEF_COPY_MASK_2D( icvCopy_32f_C4MR, int, 4 )
+ICV_DEF_COPY_MASK_2D( icvCopy_64s_C3MR, int64, 3 )
+ICV_DEF_COPY_MASK_2D( icvCopy_64s_C4MR, int64, 4 )
+
+#define CV_DEF_INIT_COPYSET_TAB_2D( FUNCNAME, FLAG ) \
+static void icvInit##FUNCNAME##FLAG##Table( CvBtFuncTable* table ) \
+{ \
+ table->fn_2d[1] = (void*)icv##FUNCNAME##_8u_C1##FLAG; \
+ table->fn_2d[2] = (void*)icv##FUNCNAME##_16s_C1##FLAG; \
+ table->fn_2d[3] = (void*)icv##FUNCNAME##_8u_C3##FLAG; \
+ table->fn_2d[4] = (void*)icv##FUNCNAME##_8u_C4##FLAG; \
+ table->fn_2d[6] = (void*)icv##FUNCNAME##_16s_C3##FLAG; \
+ table->fn_2d[8] = (void*)icv##FUNCNAME##_16s_C4##FLAG; \
+ table->fn_2d[12] = (void*)icv##FUNCNAME##_32f_C3##FLAG; \
+ table->fn_2d[16] = (void*)icv##FUNCNAME##_32f_C4##FLAG; \
+ table->fn_2d[24] = (void*)icv##FUNCNAME##_64s_C3##FLAG; \
+ table->fn_2d[32] = (void*)icv##FUNCNAME##_64s_C4##FLAG; \
+}
+
+CV_DEF_INIT_COPYSET_TAB_2D( Set, MR )
+CV_DEF_INIT_COPYSET_TAB_2D( Copy, MR )
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// //
+// H/L COPY & SET FUNCTIONS //
+// //
+/////////////////////////////////////////////////////////////////////////////////////////
+
+
+CvCopyMaskFunc
+icvGetCopyMaskFunc( int elem_size )
+{
+ static CvBtFuncTable copym_tab;
+ static int inittab = 0;
+
+ if( !inittab )
+ {
+ icvInitCopyMRTable( &copym_tab );
+ inittab = 1;
+ }
+ return (CvCopyMaskFunc)copym_tab.fn_2d[elem_size];
+}
+
+
+/* dst = src */
+CV_IMPL void
+cvCopy( const void* srcarr, void* dstarr, const void* maskarr )
+{
+ CV_FUNCNAME( "cvCopy" );
+
+ __BEGIN__;
+
+ int pix_size;
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvSize size;
+
+ if( !CV_IS_MAT(src) || !CV_IS_MAT(dst) )
+ {
+ if( CV_IS_SPARSE_MAT(src) && CV_IS_SPARSE_MAT(dst))
+ {
+ CvSparseMat* src1 = (CvSparseMat*)src;
+ CvSparseMat* dst1 = (CvSparseMat*)dst;
+ CvSparseMatIterator iterator;
+ CvSparseNode* node;
+
+ dst1->dims = src1->dims;
+ memcpy( dst1->size, src1->size, src1->dims*sizeof(src1->size[0]));
+ dst1->valoffset = src1->valoffset;
+ dst1->idxoffset = src1->idxoffset;
+ cvClearSet( dst1->heap );
+
+ if( src1->heap->active_count >= dst1->hashsize*CV_SPARSE_HASH_RATIO )
+ {
+ CV_CALL( cvFree( &dst1->hashtable ));
+ dst1->hashsize = src1->hashsize;
+ CV_CALL( dst1->hashtable =
+ (void**)cvAlloc( dst1->hashsize*sizeof(dst1->hashtable[0])));
+ }
+
+ memset( dst1->hashtable, 0, dst1->hashsize*sizeof(dst1->hashtable[0]));
+
+ for( node = cvInitSparseMatIterator( src1, &iterator );
+ node != 0; node = cvGetNextSparseNode( &iterator ))
+ {
+ CvSparseNode* node_copy = (CvSparseNode*)cvSetNew( dst1->heap );
+ int tabidx = node->hashval & (dst1->hashsize - 1);
+ CV_MEMCPY_AUTO( node_copy, node, dst1->heap->elem_size );
+ node_copy->next = (CvSparseNode*)dst1->hashtable[tabidx];
+ dst1->hashtable[tabidx] = node_copy;
+ }
+ EXIT;
+ }
+ else if( CV_IS_MATND(src) || CV_IS_MATND(dst) )
+ {
+ CvArr* arrs[] = { src, dst };
+ CvMatND stubs[3];
+ CvNArrayIterator iterator;
+
+ CV_CALL( cvInitNArrayIterator( 2, arrs, maskarr, stubs, &iterator ));
+ pix_size = CV_ELEM_SIZE(iterator.hdr[0]->type);
+
+ if( !maskarr )
+ {
+ iterator.size.width *= pix_size;
+ if( iterator.size.width <= CV_MAX_INLINE_MAT_OP_SIZE*(int)sizeof(double))
+ {
+ do
+ {
+ memcpy( iterator.ptr[1], iterator.ptr[0], iterator.size.width );
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ else
+ {
+ do
+ {
+ icvCopy_8u_C1R( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP, iterator.size );
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ }
+ else
+ {
+ CvCopyMaskFunc func = icvGetCopyMaskFunc( pix_size );
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ do
+ {
+ func( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.size,
+ iterator.ptr[2], CV_STUB_STEP );
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ EXIT;
+ }
+ else
+ {
+ int coi1 = 0, coi2 = 0;
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
+
+ if( coi1 )
+ {
+ CvArr* planes[] = { 0, 0, 0, 0 };
+
+ if( maskarr )
+ CV_ERROR( CV_StsBadArg, "COI + mask are not supported" );
+
+ planes[coi1-1] = dst;
+ CV_CALL( cvSplit( src, planes[0], planes[1], planes[2], planes[3] ));
+ EXIT;
+ }
+ else if( coi2 )
+ {
+ CvArr* planes[] = { 0, 0, 0, 0 };
+
+ if( maskarr )
+ CV_ERROR( CV_StsBadArg, "COI + mask are not supported" );
+
+ planes[coi2-1] = src;
+ CV_CALL( cvMerge( planes[0], planes[1], planes[2], planes[3], dst ));
+ EXIT;
+ }
+ }
+ }
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ size = cvGetMatSize( src );
+ pix_size = CV_ELEM_SIZE(src->type);
+
+ if( !maskarr )
+ {
+ int src_step = src->step, dst_step = dst->step;
+ size.width *= pix_size;
+ if( CV_IS_MAT_CONT( src->type & dst->type ) && (src_step == dst_step) && (src_step == src->width * pix_size))
+ {
+ size.width *= size.height;
+
+ if( size.width <= CV_MAX_INLINE_MAT_OP_SIZE*
+ CV_MAX_INLINE_MAT_OP_SIZE*(int)sizeof(double))
+ {
+ memcpy( dst->data.ptr, src->data.ptr, size.width );
+ EXIT;
+ }
+
+ size.height = 1;
+ src_step = dst_step = CV_STUB_STEP;
+ }
+
+ if( src->data.ptr != dst->data.ptr )
+ icvCopy_8u_C1R( src->data.ptr, src_step,
+ dst->data.ptr, dst_step, size );
+ }
+ else
+ {
+ CvCopyMaskFunc func = icvGetCopyMaskFunc(pix_size);
+ CvMat maskstub, *mask = (CvMat*)maskarr;
+ int src_step = src->step;
+ int dst_step = dst->step;
+ int mask_step;
+
+ if( !CV_IS_MAT( mask ))
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+ if( !CV_IS_MASK_ARR( mask ))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !CV_ARE_SIZES_EQ( src, mask ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ mask_step = mask->step;
+
+ if( CV_IS_MAT_CONT( src->type & dst->type & mask->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ src_step = dst_step = mask_step = CV_STUB_STEP;
+ }
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src->data.ptr, src_step, dst->data.ptr, dst_step,
+ size, mask->data.ptr, mask_step ));
+ }
+
+ __END__;
+}
+
+
+/* dst(idx) = value */
+CV_IMPL void
+cvSet( void* arr, CvScalar value, const void* maskarr )
+{
+ static CvBtFuncTable setm_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvSet" );
+
+ __BEGIN__;
+
+ CvMat stub, *mat = (CvMat*)arr;
+ int pix_size, type;
+ double buf[12];
+ int mat_step;
+ CvSize size;
+
+ if( !value.val[0] && !value.val[1] &&
+ !value.val[2] && !value.val[3] && !maskarr )
+ {
+ cvZero( arr );
+ EXIT;
+ }
+
+ if( !CV_IS_MAT(mat))
+ {
+ if( CV_IS_MATND(mat))
+ {
+ CvMatND nstub;
+ CvNArrayIterator iterator;
+ int pix_size1;
+
+ CV_CALL( cvInitNArrayIterator( 1, &arr, maskarr, &nstub, &iterator ));
+
+ type = CV_MAT_TYPE(iterator.hdr[0]->type);
+ pix_size1 = CV_ELEM_SIZE1(type);
+ pix_size = pix_size1*CV_MAT_CN(type);
+
+ CV_CALL( cvScalarToRawData( &value, buf, type, maskarr == 0 ));
+
+ if( !maskarr )
+ {
+ iterator.size.width *= pix_size;
+ do
+ {
+ icvSet_8u_C1R( iterator.ptr[0], CV_STUB_STEP,
+ iterator.size, buf, pix_size1 );
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ else
+ {
+ CvFunc2D_2A1P func = (CvFunc2D_2A1P)(setm_tab.fn_2d[pix_size]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ do
+ {
+ func( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.size, buf );
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ EXIT;
+ }
+ else
+ {
+ int coi = 0;
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+ }
+
+ type = CV_MAT_TYPE( mat->type );
+ pix_size = CV_ELEM_SIZE(type);
+ size = cvGetMatSize( mat );
+ mat_step = mat->step;
+
+ if( !maskarr )
+ {
+ if( CV_IS_MAT_CONT( mat->type ))
+ {
+ size.width *= size.height;
+
+ if( size.width <= (int)(CV_MAX_INLINE_MAT_OP_SIZE*sizeof(double)))
+ {
+ if( type == CV_32FC1 )
+ {
+ float* dstdata = (float*)(mat->data.ptr);
+ float val = (float)value.val[0];
+
+ do
+ {
+ dstdata[size.width-1] = val;
+ }
+ while( --size.width );
+
+ EXIT;
+ }
+
+ if( type == CV_64FC1 )
+ {
+ double* dstdata = (double*)(mat->data.ptr);
+ double val = value.val[0];
+
+ do
+ {
+ dstdata[size.width-1] = val;
+ }
+ while( --size.width );
+
+ EXIT;
+ }
+ }
+
+ mat_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+
+ size.width *= pix_size;
+ CV_CALL( cvScalarToRawData( &value, buf, type, 1 ));
+
+ IPPI_CALL( icvSet_8u_C1R( mat->data.ptr, mat_step, size, buf,
+ CV_ELEM_SIZE1(type)));
+ }
+ else
+ {
+ CvFunc2D_2A1P func;
+ CvMat maskstub, *mask = (CvMat*)maskarr;
+ int mask_step;
+
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+
+ if( !CV_IS_MASK_ARR( mask ))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !inittab )
+ {
+ icvInitSetMRTable( &setm_tab );
+ inittab = 1;
+ }
+
+ if( !CV_ARE_SIZES_EQ( mat, mask ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ mask_step = mask->step;
+
+ if( CV_IS_MAT_CONT( mat->type & mask->type ))
+ {
+ size.width *= size.height;
+ mat_step = mask_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+
+ func = (CvFunc2D_2A1P)(setm_tab.fn_2d[pix_size]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ CV_CALL( cvScalarToRawData( &value, buf, type, 0 ));
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, mask->data.ptr,
+ mask_step, size, buf ));
+ }
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* Clearing *
+\****************************************************************************************/
+
+icvSetByte_8u_C1R_t icvSetByte_8u_C1R_p = 0;
+
+CvStatus CV_STDCALL
+icvSetZero_8u_C1R( uchar* dst, int dststep, CvSize size )
+{
+ if( size.width + size.height > 256 && icvSetByte_8u_C1R_p )
+ return icvSetByte_8u_C1R_p( 0, dst, dststep, size );
+
+ for( ; size.height--; dst += dststep )
+ memset( dst, 0, size.width );
+
+ return CV_OK;
+}
+
+CV_IMPL void
+cvSetZero( CvArr* arr )
+{
+ CV_FUNCNAME( "cvSetZero" );
+
+ __BEGIN__;
+
+ CvMat stub, *mat = (CvMat*)arr;
+ CvSize size;
+ int mat_step;
+
+ if( !CV_IS_MAT( mat ))
+ {
+ if( CV_IS_MATND(mat))
+ {
+ CvMatND nstub;
+ CvNArrayIterator iterator;
+
+ CV_CALL( cvInitNArrayIterator( 1, &arr, 0, &nstub, &iterator ));
+ iterator.size.width *= CV_ELEM_SIZE(iterator.hdr[0]->type);
+
+ if( iterator.size.width <= CV_MAX_INLINE_MAT_OP_SIZE*(int)sizeof(double) )
+ {
+ do
+ {
+ memset( iterator.ptr[0], 0, iterator.size.width );
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ else
+ {
+ do
+ {
+ icvSetZero_8u_C1R( iterator.ptr[0], CV_STUB_STEP, iterator.size );
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ EXIT;
+ }
+ else if( CV_IS_SPARSE_MAT(mat))
+ {
+ CvSparseMat* mat1 = (CvSparseMat*)mat;
+ cvClearSet( mat1->heap );
+ if( mat1->hashtable )
+ memset( mat1->hashtable, 0, mat1->hashsize*sizeof(mat1->hashtable[0]));
+ EXIT;
+ }
+ else
+ {
+ int coi = 0;
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "coi is not supported" );
+ }
+ }
+
+ size = cvGetMatSize( mat );
+ size.width *= CV_ELEM_SIZE(mat->type);
+ mat_step = mat->step;
+
+ if( CV_IS_MAT_CONT( mat->type ))
+ {
+ size.width *= size.height;
+
+ if( size.width <= CV_MAX_INLINE_MAT_OP_SIZE*(int)sizeof(double) )
+ {
+ memset( mat->data.ptr, 0, size.width );
+ EXIT;
+ }
+
+ mat_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+
+ IPPI_CALL( icvSetZero_8u_C1R( mat->data.ptr, mat_step, size ));
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* Flipping *
+\****************************************************************************************/
+
+#define ICV_DEF_FLIP_HZ_CASE_C1( type ) \
+ for( i = 0; i < (len+1)/2; i++ ) \
+ { \
+ type t0 = src[i]; \
+ type t1 = src[len - i - 1]; \
+ dst[i] = t1; \
+ dst[len - i - 1] = t0; \
+ }
+
+
+#define ICV_DEF_FLIP_HZ_CASE_C3( type ) \
+ for( i = 0; i < (len+1)/2; i++ ) \
+ { \
+ type t0 = src[i*3]; \
+ type t1 = src[(len - i)*3 - 3]; \
+ dst[i*3] = t1; \
+ dst[(len - i)*3 - 3] = t0; \
+ t0 = src[i*3 + 1]; \
+ t1 = src[(len - i)*3 - 2]; \
+ dst[i*3 + 1] = t1; \
+ dst[(len - i)*3 - 2] = t0; \
+ t0 = src[i*3 + 2]; \
+ t1 = src[(len - i)*3 - 1]; \
+ dst[i*3 + 2] = t1; \
+ dst[(len - i)*3 - 1] = t0; \
+ }
+
+
+#define ICV_DEF_FLIP_HZ_CASE_C4( type ) \
+ for( i = 0; i < (len+1)/2; i++ ) \
+ { \
+ type t0 = src[i*4]; \
+ type t1 = src[(len - i)*4 - 4]; \
+ dst[i*4] = t1; \
+ dst[(len - i)*4 - 4] = t0; \
+ t0 = src[i*4 + 1]; \
+ t1 = src[(len - i)*4 - 3]; \
+ dst[i*4 + 1] = t1; \
+ dst[(len - i)*4 - 3] = t0; \
+ t0 = src[i*4 + 2]; \
+ t1 = src[(len - i)*4 - 2]; \
+ dst[i*4 + 2] = t1; \
+ dst[(len - i)*4 - 2] = t0; \
+ t0 = src[i*4 + 3]; \
+ t1 = src[(len - i)*4 - 1]; \
+ dst[i*4 + 3] = t1; \
+ dst[(len - i)*4 - 1] = t0; \
+ }
+
+
+#define ICV_DEF_FLIP_HZ_FUNC( flavor, arrtype, cn ) \
+static CvStatus CV_STDCALL \
+icvFlipHorz_##flavor( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, CvSize size ) \
+{ \
+ int i, len = size.width; \
+ srcstep /= sizeof(src[0]); dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ ICV_DEF_FLIP_HZ_CASE_C##cn( arrtype ) \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_FLIP_HZ_FUNC( 8u_C1R, uchar, 1 )
+ICV_DEF_FLIP_HZ_FUNC( 8u_C2R, ushort, 1 )
+ICV_DEF_FLIP_HZ_FUNC( 8u_C3R, uchar, 3 )
+ICV_DEF_FLIP_HZ_FUNC( 16u_C2R, int, 1 )
+ICV_DEF_FLIP_HZ_FUNC( 16u_C3R, ushort, 3 )
+ICV_DEF_FLIP_HZ_FUNC( 32s_C2R, int64, 1 )
+ICV_DEF_FLIP_HZ_FUNC( 32s_C3R, int, 3 )
+ICV_DEF_FLIP_HZ_FUNC( 64s_C2R, int, 4 )
+ICV_DEF_FLIP_HZ_FUNC( 64s_C3R, int64, 3 )
+ICV_DEF_FLIP_HZ_FUNC( 64s_C4R, int64, 4 )
+
+CV_DEF_INIT_PIXSIZE_TAB_2D( FlipHorz, R )
+
+
+static CvStatus
+icvFlipVert_8u_C1R( const uchar* src, int srcstep,
+ uchar* dst, int dststep, CvSize size )
+{
+ int y, i;
+ const uchar* src1 = src + (size.height - 1)*srcstep;
+ uchar* dst1 = dst + (size.height - 1)*dststep;
+
+ for( y = 0; y < (size.height + 1)/2; y++, src += srcstep, src1 -= srcstep,
+ dst += dststep, dst1 -= dststep )
+ {
+ i = 0;
+ if( ((size_t)(src)|(size_t)(dst)|(size_t)src1|(size_t)dst1) % sizeof(int) == 0 )
+ {
+ for( ; i <= size.width - 16; i += 16 )
+ {
+ int t0 = ((int*)(src + i))[0];
+ int t1 = ((int*)(src1 + i))[0];
+
+ ((int*)(dst + i))[0] = t1;
+ ((int*)(dst1 + i))[0] = t0;
+
+ t0 = ((int*)(src + i))[1];
+ t1 = ((int*)(src1 + i))[1];
+
+ ((int*)(dst + i))[1] = t1;
+ ((int*)(dst1 + i))[1] = t0;
+
+ t0 = ((int*)(src + i))[2];
+ t1 = ((int*)(src1 + i))[2];
+
+ ((int*)(dst + i))[2] = t1;
+ ((int*)(dst1 + i))[2] = t0;
+
+ t0 = ((int*)(src + i))[3];
+ t1 = ((int*)(src1 + i))[3];
+
+ ((int*)(dst + i))[3] = t1;
+ ((int*)(dst1 + i))[3] = t0;
+ }
+
+ for( ; i <= size.width - 4; i += 4 )
+ {
+ int t0 = ((int*)(src + i))[0];
+ int t1 = ((int*)(src1 + i))[0];
+
+ ((int*)(dst + i))[0] = t1;
+ ((int*)(dst1 + i))[0] = t0;
+ }
+ }
+
+ for( ; i < size.width; i++ )
+ {
+ uchar t0 = src[i];
+ uchar t1 = src1[i];
+
+ dst[i] = t1;
+ dst1[i] = t0;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+CV_IMPL void
+cvFlip( const CvArr* srcarr, CvArr* dstarr, int flip_mode )
+{
+ static CvBtFuncTable tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvFlip" );
+
+ __BEGIN__;
+
+ CvMat sstub, *src = (CvMat*)srcarr;
+ CvMat dstub, *dst = (CvMat*)dstarr;
+ CvSize size;
+ CvFunc2D_2A func = 0;
+ int pix_size;
+
+ if( !inittab )
+ {
+ icvInitFlipHorzRTable( &tab );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT( src ))
+ {
+ int coi = 0;
+ CV_CALL( src = cvGetMat( src, &sstub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "coi is not supported" );
+ }
+
+ if( !dst )
+ dst = src;
+ else if( !CV_IS_MAT( dst ))
+ {
+ int coi = 0;
+ CV_CALL( dst = cvGetMat( dst, &dstub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "coi is not supported" );
+ }
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ size = cvGetMatSize( src );
+ pix_size = CV_ELEM_SIZE( src->type );
+
+ if( flip_mode == 0 )
+ {
+ size.width *= pix_size;
+
+ IPPI_CALL( icvFlipVert_8u_C1R( src->data.ptr, src->step,
+ dst->data.ptr, dst->step, size ));
+ }
+ else
+ {
+ int inplace = src->data.ptr == dst->data.ptr;
+ uchar* dst_data = dst->data.ptr;
+ int dst_step = dst->step;
+
+ func = (CvFunc2D_2A)(tab.fn_2d[pix_size]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( flip_mode < 0 && !inplace )
+ {
+ dst_data += dst_step * (dst->height - 1);
+ dst_step = -dst_step;
+ }
+
+ IPPI_CALL( func( src->data.ptr, src->step, dst_data, dst_step, size ));
+
+ if( flip_mode < 0 && inplace )
+ {
+ size.width *= pix_size;
+ IPPI_CALL( icvFlipVert_8u_C1R( dst->data.ptr, dst->step,
+ dst->data.ptr, dst->step, size ));
+ }
+ }
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvRepeat( const CvArr* srcarr, CvArr* dstarr )
+{
+ CV_FUNCNAME( "cvRepeat" );
+
+ __BEGIN__;
+
+ CvMat sstub, *src = (CvMat*)srcarr;
+ CvMat dstub, *dst = (CvMat*)dstarr;
+ CvSize srcsize, dstsize;
+ int pix_size;
+ int x, y, k, l;
+
+ if( !CV_IS_MAT( src ))
+ {
+ int coi = 0;
+ CV_CALL( src = cvGetMat( src, &sstub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "coi is not supported" );
+ }
+
+ if( !CV_IS_MAT( dst ))
+ {
+ int coi = 0;
+ CV_CALL( dst = cvGetMat( dst, &dstub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "coi is not supported" );
+ }
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ srcsize = cvGetMatSize( src );
+ dstsize = cvGetMatSize( dst );
+ pix_size = CV_ELEM_SIZE( src->type );
+
+ for( y = 0, k = 0; y < dstsize.height; y++ )
+ {
+ for( x = 0; x < dstsize.width; x += srcsize.width )
+ {
+ l = srcsize.width;
+ if( l > dstsize.width - x )
+ l = dstsize.width - x;
+ memcpy( dst->data.ptr + y*dst->step + x*pix_size,
+ src->data.ptr + k*src->step, l*pix_size );
+ }
+ if( ++k == srcsize.height )
+ k = 0;
+ }
+
+ __END__;
+}
+
+/* End of file. */
+
diff --git a/cxcore/src/cxdatastructs.cpp b/cxcore/src/cxdatastructs.cpp
new file mode 100644
index 0000000..b31b06f
--- /dev/null
+++ b/cxcore/src/cxdatastructs.cpp
@@ -0,0 +1,4009 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cxcore.h"
+
+#define ICV_FREE_PTR(storage) \
+ ((schar*)(storage)->top + (storage)->block_size - (storage)->free_space)
+
+#define ICV_ALIGNED_SEQ_BLOCK_SIZE \
+ (int)cvAlign(sizeof(CvSeqBlock), CV_STRUCT_ALIGN)
+
+CV_INLINE int
+cvAlignLeft( int size, int align )
+{
+ return size & -align;
+}
+
+#define CV_GET_LAST_ELEM( seq, block ) \
+ ((block)->data + ((block)->count - 1)*((seq)->elem_size))
+
+#define CV_SWAP_ELEMS(a,b,elem_size) \
+{ \
+ int k; \
+ for( k = 0; k < elem_size; k++ ) \
+ { \
+ char t0 = (a)[k]; \
+ char t1 = (b)[k]; \
+ (a)[k] = t1; \
+ (b)[k] = t0; \
+ } \
+}
+
+#define ICV_SHIFT_TAB_MAX 32
+static const schar icvPower2ShiftTab[] =
+{
+ 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5
+};
+
+/****************************************************************************************\
+* Functions for manipulating memory storage - list of memory blocks *
+\****************************************************************************************/
+
+/* Initialize allocated storage: */
+static void
+icvInitMemStorage( CvMemStorage* storage, int block_size )
+{
+ CV_FUNCNAME( "icvInitMemStorage " );
+
+ __BEGIN__;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( block_size <= 0 )
+ block_size = CV_STORAGE_BLOCK_SIZE;
+
+ block_size = cvAlign( block_size, CV_STRUCT_ALIGN );
+ assert( sizeof(CvMemBlock) % CV_STRUCT_ALIGN == 0 );
+
+ memset( storage, 0, sizeof( *storage ));
+ storage->signature = CV_STORAGE_MAGIC_VAL;
+ storage->block_size = block_size;
+
+ __END__;
+}
+
+
+/* Create root memory storage: */
+CV_IMPL CvMemStorage*
+cvCreateMemStorage( int block_size )
+{
+ CvMemStorage *storage = 0;
+
+ CV_FUNCNAME( "cvCreateMemStorage" );
+
+ __BEGIN__;
+
+ CV_CALL( storage = (CvMemStorage *)cvAlloc( sizeof( CvMemStorage )));
+ CV_CALL( icvInitMemStorage( storage, block_size ));
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvFree( &storage );
+
+ return storage;
+}
+
+
+/* Create child memory storage: */
+CV_IMPL CvMemStorage *
+cvCreateChildMemStorage( CvMemStorage * parent )
+{
+ CvMemStorage *storage = 0;
+ CV_FUNCNAME( "cvCreateChildMemStorage" );
+
+ __BEGIN__;
+
+ if( !parent )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ CV_CALL( storage = cvCreateMemStorage(parent->block_size));
+ storage->parent = parent;
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvFree( &storage );
+
+ return storage;
+}
+
+
+/* Release all blocks of the storage (or return them to parent, if any): */
+static void
+icvDestroyMemStorage( CvMemStorage* storage )
+{
+ CV_FUNCNAME( "icvDestroyMemStorage" );
+
+ __BEGIN__;
+
+ int k = 0;
+
+ CvMemBlock *block;
+ CvMemBlock *dst_top = 0;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( storage->parent )
+ dst_top = storage->parent->top;
+
+ for( block = storage->bottom; block != 0; k++ )
+ {
+ CvMemBlock *temp = block;
+
+ block = block->next;
+ if( storage->parent )
+ {
+ if( dst_top )
+ {
+ temp->prev = dst_top;
+ temp->next = dst_top->next;
+ if( temp->next )
+ temp->next->prev = temp;
+ dst_top = dst_top->next = temp;
+ }
+ else
+ {
+ dst_top = storage->parent->bottom = storage->parent->top = temp;
+ temp->prev = temp->next = 0;
+ storage->free_space = storage->block_size - sizeof( *temp );
+ }
+ }
+ else
+ {
+ cvFree( &temp );
+ }
+ }
+
+ storage->top = storage->bottom = 0;
+ storage->free_space = 0;
+
+ __END__;
+}
+
+
+/* Release memory storage: */
+CV_IMPL void
+cvReleaseMemStorage( CvMemStorage** storage )
+{
+ CvMemStorage *st;
+ CV_FUNCNAME( "cvReleaseMemStorage" );
+
+ __BEGIN__;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ st = *storage;
+ *storage = 0;
+
+ if( st )
+ {
+ CV_CALL( icvDestroyMemStorage( st ));
+ cvFree( &st );
+ }
+
+ __END__;
+}
+
+
+/* Clears memory storage (return blocks to the parent, if any): */
+CV_IMPL void
+cvClearMemStorage( CvMemStorage * storage )
+{
+ CV_FUNCNAME( "cvClearMemStorage" );
+
+ __BEGIN__;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( storage->parent )
+ {
+ icvDestroyMemStorage( storage );
+ }
+ else
+ {
+ storage->top = storage->bottom;
+ storage->free_space = storage->bottom ? storage->block_size - sizeof(CvMemBlock) : 0;
+ }
+
+ __END__;
+}
+
+
+/* Moves stack pointer to next block.
+ If no blocks, allocate new one and link it to the storage: */
+static void
+icvGoNextMemBlock( CvMemStorage * storage )
+{
+ CV_FUNCNAME( "icvGoNextMemBlock" );
+
+ __BEGIN__;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !storage->top || !storage->top->next )
+ {
+ CvMemBlock *block;
+
+ if( !(storage->parent) )
+ {
+ CV_CALL( block = (CvMemBlock *)cvAlloc( storage->block_size ));
+ }
+ else
+ {
+ CvMemStorage *parent = storage->parent;
+ CvMemStoragePos parent_pos;
+
+ cvSaveMemStoragePos( parent, &parent_pos );
+ CV_CALL( icvGoNextMemBlock( parent ));
+
+ block = parent->top;
+ cvRestoreMemStoragePos( parent, &parent_pos );
+
+ if( block == parent->top ) /* the single allocated block */
+ {
+ assert( parent->bottom == block );
+ parent->top = parent->bottom = 0;
+ parent->free_space = 0;
+ }
+ else
+ {
+ /* cut the block from the parent's list of blocks */
+ parent->top->next = block->next;
+ if( block->next )
+ block->next->prev = parent->top;
+ }
+ }
+
+ /* link block */
+ block->next = 0;
+ block->prev = storage->top;
+
+ if( storage->top )
+ storage->top->next = block;
+ else
+ storage->top = storage->bottom = block;
+ }
+
+ if( storage->top->next )
+ storage->top = storage->top->next;
+ storage->free_space = storage->block_size - sizeof(CvMemBlock);
+ assert( storage->free_space % CV_STRUCT_ALIGN == 0 );
+
+ __END__;
+}
+
+
+/* Remember memory storage position: */
+CV_IMPL void
+cvSaveMemStoragePos( const CvMemStorage * storage, CvMemStoragePos * pos )
+{
+ CV_FUNCNAME( "cvSaveMemStoragePos" );
+
+ __BEGIN__;
+
+ if( !storage || !pos )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ pos->top = storage->top;
+ pos->free_space = storage->free_space;
+
+ __END__;
+}
+
+
+/* Restore memory storage position: */
+CV_IMPL void
+cvRestoreMemStoragePos( CvMemStorage * storage, CvMemStoragePos * pos )
+{
+ CV_FUNCNAME( "cvRestoreMemStoragePos" );
+
+ __BEGIN__;
+
+ if( !storage || !pos )
+ CV_ERROR( CV_StsNullPtr, "" );
+ if( pos->free_space > storage->block_size )
+ CV_ERROR( CV_StsBadSize, "" );
+
+ /*
+ // this breaks icvGoNextMemBlock, so comment it off for now
+ if( storage->parent && (!pos->top || pos->top->next) )
+ {
+ CvMemBlock* save_bottom;
+ if( !pos->top )
+ save_bottom = 0;
+ else
+ {
+ save_bottom = storage->bottom;
+ storage->bottom = pos->top->next;
+ pos->top->next = 0;
+ storage->bottom->prev = 0;
+ }
+ icvDestroyMemStorage( storage );
+ storage->bottom = save_bottom;
+ }*/
+
+ storage->top = pos->top;
+ storage->free_space = pos->free_space;
+
+ if( !storage->top )
+ {
+ storage->top = storage->bottom;
+ storage->free_space = storage->top ? storage->block_size - sizeof(CvMemBlock) : 0;
+ }
+
+ __END__;
+}
+
+
+/* Allocate continuous buffer of the specified size in the storage: */
+CV_IMPL void*
+cvMemStorageAlloc( CvMemStorage* storage, size_t size )
+{
+ schar *ptr = 0;
+
+ CV_FUNCNAME( "cvMemStorageAlloc" );
+
+ __BEGIN__;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "NULL storage pointer" );
+
+ if( size > INT_MAX )
+ CV_ERROR( CV_StsOutOfRange, "Too large memory block is requested" );
+
+ assert( storage->free_space % CV_STRUCT_ALIGN == 0 );
+
+ if( (size_t)storage->free_space < size )
+ {
+ size_t max_free_space = cvAlignLeft(storage->block_size - sizeof(CvMemBlock), CV_STRUCT_ALIGN);
+ if( max_free_space < size )
+ CV_ERROR( CV_StsOutOfRange, "requested size is negative or too big" );
+
+ CV_CALL( icvGoNextMemBlock( storage ));
+ }
+
+ ptr = ICV_FREE_PTR(storage);
+ assert( (size_t)ptr % CV_STRUCT_ALIGN == 0 );
+ storage->free_space = cvAlignLeft(storage->free_space - (int)size, CV_STRUCT_ALIGN );
+
+ __END__;
+
+ return ptr;
+}
+
+
+CV_IMPL CvString
+cvMemStorageAllocString( CvMemStorage* storage, const char* ptr, int len )
+{
+ CvString str;
+ CV_FUNCNAME( "cvMemStorageAllocString" );
+
+ __BEGIN__;
+
+ str.len = len >= 0 ? len : (int)strlen(ptr);
+ CV_CALL( str.ptr = (char*)cvMemStorageAlloc( storage, str.len + 1 ));
+ memcpy( str.ptr, ptr, str.len );
+ str.ptr[str.len] = '\0';
+
+ __END__;
+
+ return str;
+}
+
+
+/****************************************************************************************\
+* Sequence implementation *
+\****************************************************************************************/
+
+/* Create empty sequence: */
+CV_IMPL CvSeq *
+cvCreateSeq( int seq_flags, int header_size, int elem_size, CvMemStorage * storage )
+{
+ CvSeq *seq = 0;
+
+ CV_FUNCNAME( "cvCreateSeq" );
+
+ __BEGIN__;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "" );
+ if( header_size < (int)sizeof( CvSeq ) || elem_size <= 0 )
+ CV_ERROR( CV_StsBadSize, "" );
+
+ /* allocate sequence header */
+ CV_CALL( seq = (CvSeq*)cvMemStorageAlloc( storage, header_size ));
+ memset( seq, 0, header_size );
+
+ seq->header_size = header_size;
+ seq->flags = (seq_flags & ~CV_MAGIC_MASK) | CV_SEQ_MAGIC_VAL;
+ {
+ int elemtype = CV_MAT_TYPE(seq_flags);
+ int typesize = CV_ELEM_SIZE(elemtype);
+
+ if( elemtype != CV_SEQ_ELTYPE_GENERIC &&
+ typesize != 0 && typesize != elem_size )
+ CV_ERROR( CV_StsBadSize,
+ "Specified element size doesn't match to the size of the specified element type "
+ "(try to use 0 for element type)" );
+ }
+ seq->elem_size = elem_size;
+ seq->storage = storage;
+
+ CV_CALL( cvSetSeqBlockSize( seq, (1 << 10)/elem_size ));
+
+ __END__;
+
+ return seq;
+}
+
+
+/* adjusts <delta_elems> field of sequence. It determines how much the sequence
+ grows if there are no free space inside the sequence buffers */
+CV_IMPL void
+cvSetSeqBlockSize( CvSeq *seq, int delta_elements )
+{
+ int elem_size;
+ int useful_block_size;
+
+ CV_FUNCNAME( "cvSetSeqBlockSize" );
+
+ __BEGIN__;
+
+ if( !seq || !seq->storage )
+ CV_ERROR( CV_StsNullPtr, "" );
+ if( delta_elements < 0 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ useful_block_size = cvAlignLeft(seq->storage->block_size - sizeof(CvMemBlock) -
+ sizeof(CvSeqBlock), CV_STRUCT_ALIGN);
+ elem_size = seq->elem_size;
+
+ if( delta_elements == 0 )
+ {
+ delta_elements = (1 << 10) / elem_size;
+ delta_elements = MAX( delta_elements, 1 );
+ }
+ if( delta_elements * elem_size > useful_block_size )
+ {
+ delta_elements = useful_block_size / elem_size;
+ if( delta_elements == 0 )
+ CV_ERROR( CV_StsOutOfRange, "Storage block size is too small "
+ "to fit the sequence elements" );
+ }
+
+ seq->delta_elems = delta_elements;
+
+ __END__;
+}
+
+
+/* Find a sequence element by its index: */
+CV_IMPL schar*
+cvGetSeqElem( const CvSeq *seq, int index )
+{
+ CvSeqBlock *block;
+ int count, total = seq->total;
+
+ if( (unsigned)index >= (unsigned)total )
+ {
+ index += index < 0 ? total : 0;
+ index -= index >= total ? total : 0;
+ if( (unsigned)index >= (unsigned)total )
+ return 0;
+ }
+
+ block = seq->first;
+ if( index + index <= total )
+ {
+ while( index >= (count = block->count) )
+ {
+ block = block->next;
+ index -= count;
+ }
+ }
+ else
+ {
+ do
+ {
+ block = block->prev;
+ total -= block->count;
+ }
+ while( index < total );
+ index -= total;
+ }
+
+ return block->data + index * seq->elem_size;
+}
+
+
+/* Calculate index of a sequence element: */
+CV_IMPL int
+cvSeqElemIdx( const CvSeq* seq, const void* _element, CvSeqBlock** _block )
+{
+ const schar *element = (const schar *)_element;
+ int elem_size;
+ int id = -1;
+ CvSeqBlock *first_block;
+ CvSeqBlock *block;
+
+ CV_FUNCNAME( "cvSeqElemIdx" );
+
+ __BEGIN__;
+
+ if( !seq || !element )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ block = first_block = seq->first;
+ elem_size = seq->elem_size;
+
+ for( ;; )
+ {
+ if( (unsigned)(element - block->data) < (unsigned) (block->count * elem_size) )
+ {
+ if( _block )
+ *_block = block;
+ if( elem_size <= ICV_SHIFT_TAB_MAX && (id = icvPower2ShiftTab[elem_size - 1]) >= 0 )
+ id = (int)((size_t)(element - block->data) >> id);
+ else
+ id = (int)((size_t)(element - block->data) / elem_size);
+ id += block->start_index - seq->first->start_index;
+ break;
+ }
+ block = block->next;
+ if( block == first_block )
+ break;
+ }
+
+ __END__;
+
+ return id;
+}
+
+
+CV_IMPL int
+cvSliceLength( CvSlice slice, const CvSeq* seq )
+{
+ int total = seq->total;
+ int length = slice.end_index - slice.start_index;
+
+ if( length != 0 )
+ {
+ if( slice.start_index < 0 )
+ slice.start_index += total;
+ if( slice.end_index <= 0 )
+ slice.end_index += total;
+
+ length = slice.end_index - slice.start_index;
+ }
+
+ if( length < 0 )
+ {
+ length += total;
+ /*if( length < 0 )
+ length += total;*/
+ }
+ else if( length > total )
+ length = total;
+
+ return length;
+}
+
+
+/* Copy all sequence elements into single continuous array: */
+CV_IMPL void*
+cvCvtSeqToArray( const CvSeq *seq, void *array, CvSlice slice )
+{
+ CV_FUNCNAME( "cvCvtSeqToArray" );
+
+ __BEGIN__;
+
+ int elem_size, total;
+ CvSeqReader reader;
+ char *dst = (char*)array;
+
+ if( !seq || !array )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ elem_size = seq->elem_size;
+ total = cvSliceLength( slice, seq )*elem_size;
+
+ if( total == 0 )
+ EXIT;
+
+ cvStartReadSeq( seq, &reader, 0 );
+ CV_CALL( cvSetSeqReaderPos( &reader, slice.start_index, 0 ));
+
+ do
+ {
+ int count = (int)(reader.block_max - reader.ptr);
+ if( count > total )
+ count = total;
+
+ memcpy( dst, reader.ptr, count );
+ dst += count;
+ reader.block = reader.block->next;
+ reader.ptr = reader.block->data;
+ reader.block_max = reader.ptr + reader.block->count*elem_size;
+ total -= count;
+ }
+ while( total > 0 );
+
+ __END__;
+
+ return array;
+}
+
+
+/* Construct a sequence from an array without copying any data.
+ NB: The resultant sequence cannot grow beyond its initial size: */
+CV_IMPL CvSeq*
+cvMakeSeqHeaderForArray( int seq_flags, int header_size, int elem_size,
+ void *array, int total, CvSeq *seq, CvSeqBlock * block )
+{
+ CvSeq* result = 0;
+
+ CV_FUNCNAME( "cvMakeSeqHeaderForArray" );
+
+ __BEGIN__;
+
+ if( elem_size <= 0 || header_size < (int)sizeof( CvSeq ) || total < 0 )
+ CV_ERROR( CV_StsBadSize, "" );
+
+ if( !seq || ((!array || !block) && total > 0) )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ memset( seq, 0, header_size );
+
+ seq->header_size = header_size;
+ seq->flags = (seq_flags & ~CV_MAGIC_MASK) | CV_SEQ_MAGIC_VAL;
+ {
+ int elemtype = CV_MAT_TYPE(seq_flags);
+ int typesize = CV_ELEM_SIZE(elemtype);
+
+ if( elemtype != CV_SEQ_ELTYPE_GENERIC &&
+ typesize != 0 && typesize != elem_size )
+ CV_ERROR( CV_StsBadSize,
+ "Element size doesn't match to the size of predefined element type "
+ "(try to use 0 for sequence element type)" );
+ }
+ seq->elem_size = elem_size;
+ seq->total = total;
+ seq->block_max = seq->ptr = (schar *) array + total * elem_size;
+
+ if( total > 0 )
+ {
+ seq->first = block;
+ block->prev = block->next = block;
+ block->start_index = 0;
+ block->count = total;
+ block->data = (schar *) array;
+ }
+
+ result = seq;
+
+ __END__;
+
+ return result;
+}
+
+
+/* The function allocates space for at least one more sequence element.
+ If there are free sequence blocks (seq->free_blocks != 0)
+ they are reused, otherwise the space is allocated in the storage: */
+static void
+icvGrowSeq( CvSeq *seq, int in_front_of )
+{
+ CV_FUNCNAME( "icvGrowSeq" );
+
+ __BEGIN__;
+
+ CvSeqBlock *block;
+
+ if( !seq )
+ CV_ERROR( CV_StsNullPtr, "" );
+ block = seq->free_blocks;
+
+ if( !block )
+ {
+ int elem_size = seq->elem_size;
+ int delta_elems = seq->delta_elems;
+ CvMemStorage *storage = seq->storage;
+
+ if( seq->total >= delta_elems*4 )
+ cvSetSeqBlockSize( seq, delta_elems*2 );
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "The sequence has NULL storage pointer" );
+
+ /* If there is a free space just after last allocated block
+ and it is big enough then enlarge the last block.
+ This can happen only if the new block is added to the end of sequence: */
+ if( (unsigned)(ICV_FREE_PTR(storage) - seq->block_max) < CV_STRUCT_ALIGN &&
+ storage->free_space >= seq->elem_size && !in_front_of )
+ {
+ int delta = storage->free_space / elem_size;
+
+ delta = MIN( delta, delta_elems ) * elem_size;
+ seq->block_max += delta;
+ storage->free_space = cvAlignLeft((int)(((schar*)storage->top + storage->block_size) -
+ seq->block_max), CV_STRUCT_ALIGN );
+ EXIT;
+ }
+ else
+ {
+ int delta = elem_size * delta_elems + ICV_ALIGNED_SEQ_BLOCK_SIZE;
+
+ /* Try to allocate <delta_elements> elements: */
+ if( storage->free_space < delta )
+ {
+ int small_block_size = MAX(1, delta_elems/3)*elem_size +
+ ICV_ALIGNED_SEQ_BLOCK_SIZE;
+ /* try to allocate smaller part */
+ if( storage->free_space >= small_block_size + CV_STRUCT_ALIGN )
+ {
+ delta = (storage->free_space - ICV_ALIGNED_SEQ_BLOCK_SIZE)/seq->elem_size;
+ delta = delta*seq->elem_size + ICV_ALIGNED_SEQ_BLOCK_SIZE;
+ }
+ else
+ {
+ CV_CALL( icvGoNextMemBlock( storage ));
+ assert( storage->free_space >= delta );
+ }
+ }
+
+ CV_CALL( block = (CvSeqBlock*)cvMemStorageAlloc( storage, delta ));
+ block->data = (schar*)cvAlignPtr( block + 1, CV_STRUCT_ALIGN );
+ block->count = delta - ICV_ALIGNED_SEQ_BLOCK_SIZE;
+ block->prev = block->next = 0;
+ }
+ }
+ else
+ {
+ seq->free_blocks = block->next;
+ }
+
+ if( !(seq->first) )
+ {
+ seq->first = block;
+ block->prev = block->next = block;
+ }
+ else
+ {
+ block->prev = seq->first->prev;
+ block->next = seq->first;
+ block->prev->next = block->next->prev = block;
+ }
+
+ /* For free blocks the <count> field means
+ * total number of bytes in the block.
+ *
+ * For used blocks it means current number
+ * of sequence elements in the block:
+ */
+ assert( block->count % seq->elem_size == 0 && block->count > 0 );
+
+ if( !in_front_of )
+ {
+ seq->ptr = block->data;
+ seq->block_max = block->data + block->count;
+ block->start_index = block == block->prev ? 0 :
+ block->prev->start_index + block->prev->count;
+ }
+ else
+ {
+ int delta = block->count / seq->elem_size;
+ block->data += block->count;
+
+ if( block != block->prev )
+ {
+ assert( seq->first->start_index == 0 );
+ seq->first = block;
+ }
+ else
+ {
+ seq->block_max = seq->ptr = block->data;
+ }
+
+ block->start_index = 0;
+
+ for( ;; )
+ {
+ block->start_index += delta;
+ block = block->next;
+ if( block == seq->first )
+ break;
+ }
+ }
+
+ block->count = 0;
+
+ __END__;
+}
+
+/* Recycle a sequence block: */
+static void
+icvFreeSeqBlock( CvSeq *seq, int in_front_of )
+{
+ /*CV_FUNCNAME( "icvFreeSeqBlock" );*/
+
+ __BEGIN__;
+
+ CvSeqBlock *block = seq->first;
+
+ assert( (in_front_of ? block : block->prev)->count == 0 );
+
+ if( block == block->prev ) /* single block case */
+ {
+ block->count = (int)(seq->block_max - block->data) + block->start_index * seq->elem_size;
+ block->data = seq->block_max - block->count;
+ seq->first = 0;
+ seq->ptr = seq->block_max = 0;
+ seq->total = 0;
+ }
+ else
+ {
+ if( !in_front_of )
+ {
+ block = block->prev;
+ assert( seq->ptr == block->data );
+
+ block->count = (int)(seq->block_max - seq->ptr);
+ seq->block_max = seq->ptr = block->prev->data +
+ block->prev->count * seq->elem_size;
+ }
+ else
+ {
+ int delta = block->start_index;
+
+ block->count = delta * seq->elem_size;
+ block->data -= block->count;
+
+ /* Update start indices of sequence blocks: */
+ for( ;; )
+ {
+ block->start_index -= delta;
+ block = block->next;
+ if( block == seq->first )
+ break;
+ }
+
+ seq->first = block->next;
+ }
+
+ block->prev->next = block->next;
+ block->next->prev = block->prev;
+ }
+
+ assert( block->count > 0 && block->count % seq->elem_size == 0 );
+ block->next = seq->free_blocks;
+ seq->free_blocks = block;
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* Sequence Writer implementation *
+\****************************************************************************************/
+
+/* Initialize sequence writer: */
+CV_IMPL void
+cvStartAppendToSeq( CvSeq *seq, CvSeqWriter * writer )
+{
+ CV_FUNCNAME( "cvStartAppendToSeq" );
+
+ __BEGIN__;
+
+ if( !seq || !writer )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ memset( writer, 0, sizeof( *writer ));
+ writer->header_size = sizeof( CvSeqWriter );
+
+ writer->seq = seq;
+ writer->block = seq->first ? seq->first->prev : 0;
+ writer->ptr = seq->ptr;
+ writer->block_max = seq->block_max;
+
+ __END__;
+}
+
+
+/* Initialize sequence writer: */
+CV_IMPL void
+cvStartWriteSeq( int seq_flags, int header_size,
+ int elem_size, CvMemStorage * storage, CvSeqWriter * writer )
+{
+ CvSeq *seq = 0;
+
+ CV_FUNCNAME( "cvStartWriteSeq" );
+
+ __BEGIN__;
+
+ if( !storage || !writer )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ CV_CALL( seq = cvCreateSeq( seq_flags, header_size, elem_size, storage ));
+ cvStartAppendToSeq( seq, writer );
+
+ __END__;
+}
+
+
+/* Update sequence header: */
+CV_IMPL void
+cvFlushSeqWriter( CvSeqWriter * writer )
+{
+ CvSeq *seq = 0;
+
+ CV_FUNCNAME( "cvFlushSeqWriter" );
+
+ __BEGIN__;
+
+ if( !writer )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ seq = writer->seq;
+ seq->ptr = writer->ptr;
+
+ if( writer->block )
+ {
+ int total = 0;
+ CvSeqBlock *first_block = writer->seq->first;
+ CvSeqBlock *block = first_block;
+
+ writer->block->count = (int)((writer->ptr - writer->block->data) / seq->elem_size);
+ assert( writer->block->count > 0 );
+
+ do
+ {
+ total += block->count;
+ block = block->next;
+ }
+ while( block != first_block );
+
+ writer->seq->total = total;
+ }
+
+ __END__;
+}
+
+
+/* Calls icvFlushSeqWriter and finishes writing process: */
+CV_IMPL CvSeq *
+cvEndWriteSeq( CvSeqWriter * writer )
+{
+ CvSeq *seq = 0;
+
+ CV_FUNCNAME( "cvEndWriteSeq" );
+
+ __BEGIN__;
+
+ if( !writer )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ CV_CALL( cvFlushSeqWriter( writer ));
+ seq = writer->seq;
+
+ /* Truncate the last block: */
+ if( writer->block && writer->seq->storage )
+ {
+ CvMemStorage *storage = seq->storage;
+ schar *storage_block_max = (schar *) storage->top + storage->block_size;
+
+ assert( writer->block->count > 0 );
+
+ if( (unsigned)((storage_block_max - storage->free_space)
+ - seq->block_max) < CV_STRUCT_ALIGN )
+ {
+ storage->free_space = cvAlignLeft((int)(storage_block_max - seq->ptr), CV_STRUCT_ALIGN);
+ seq->block_max = seq->ptr;
+ }
+ }
+
+ writer->ptr = 0;
+
+ __END__;
+
+ return seq;
+}
+
+
+/* Create new sequence block: */
+CV_IMPL void
+cvCreateSeqBlock( CvSeqWriter * writer )
+{
+ CV_FUNCNAME( "cvCreateSeqBlock" );
+
+ __BEGIN__;
+
+ CvSeq *seq;
+
+ if( !writer || !writer->seq )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ seq = writer->seq;
+
+ cvFlushSeqWriter( writer );
+
+ CV_CALL( icvGrowSeq( seq, 0 ));
+
+ writer->block = seq->first->prev;
+ writer->ptr = seq->ptr;
+ writer->block_max = seq->block_max;
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* Sequence Reader implementation *
+\****************************************************************************************/
+
+/* Initialize sequence reader: */
+CV_IMPL void
+cvStartReadSeq( const CvSeq *seq, CvSeqReader * reader, int reverse )
+{
+ CvSeqBlock *first_block;
+ CvSeqBlock *last_block;
+
+ CV_FUNCNAME( "cvStartReadSeq" );
+
+ if( reader )
+ {
+ reader->seq = 0;
+ reader->block = 0;
+ reader->ptr = reader->block_max = reader->block_min = 0;
+ }
+
+ __BEGIN__;
+
+ if( !seq || !reader )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ reader->header_size = sizeof( CvSeqReader );
+ reader->seq = (CvSeq*)seq;
+
+ first_block = seq->first;
+
+ if( first_block )
+ {
+ last_block = first_block->prev;
+ reader->ptr = first_block->data;
+ reader->prev_elem = CV_GET_LAST_ELEM( seq, last_block );
+ reader->delta_index = seq->first->start_index;
+
+ if( reverse )
+ {
+ schar *temp = reader->ptr;
+
+ reader->ptr = reader->prev_elem;
+ reader->prev_elem = temp;
+
+ reader->block = last_block;
+ }
+ else
+ {
+ reader->block = first_block;
+ }
+
+ reader->block_min = reader->block->data;
+ reader->block_max = reader->block_min + reader->block->count * seq->elem_size;
+ }
+ else
+ {
+ reader->delta_index = 0;
+ reader->block = 0;
+
+ reader->ptr = reader->prev_elem = reader->block_min = reader->block_max = 0;
+ }
+
+ __END__;
+}
+
+
+/* Change the current reading block
+ * to the previous or to the next:
+ */
+CV_IMPL void
+cvChangeSeqBlock( void* _reader, int direction )
+{
+ CV_FUNCNAME( "cvChangeSeqBlock" );
+
+ __BEGIN__;
+
+ CvSeqReader* reader = (CvSeqReader*)_reader;
+
+ if( !reader )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( direction > 0 )
+ {
+ reader->block = reader->block->next;
+ reader->ptr = reader->block->data;
+ }
+ else
+ {
+ reader->block = reader->block->prev;
+ reader->ptr = CV_GET_LAST_ELEM( reader->seq, reader->block );
+ }
+ reader->block_min = reader->block->data;
+ reader->block_max = reader->block_min + reader->block->count * reader->seq->elem_size;
+
+ __END__;
+}
+
+
+/* Return the current reader position: */
+CV_IMPL int
+cvGetSeqReaderPos( CvSeqReader* reader )
+{
+ int elem_size;
+ int index = -1;
+
+ CV_FUNCNAME( "cvGetSeqReaderPos" );
+
+ __BEGIN__;
+
+ if( !reader || !reader->ptr )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ elem_size = reader->seq->elem_size;
+ if( elem_size <= ICV_SHIFT_TAB_MAX && (index = icvPower2ShiftTab[elem_size - 1]) >= 0 )
+ index = (int)((reader->ptr - reader->block_min) >> index);
+ else
+ index = (int)((reader->ptr - reader->block_min) / elem_size);
+
+ index += reader->block->start_index - reader->delta_index;
+
+ __END__;
+
+ return index;
+}
+
+
+/* Set reader position to given position,
+ * either absolute or relative to the
+ * current one:
+ */
+CV_IMPL void
+cvSetSeqReaderPos( CvSeqReader* reader, int index, int is_relative )
+{
+ CV_FUNCNAME( "cvSetSeqReaderPos" );
+
+ __BEGIN__;
+
+ CvSeqBlock *block;
+ int elem_size, count, total;
+
+ if( !reader || !reader->seq )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ total = reader->seq->total;
+ elem_size = reader->seq->elem_size;
+
+ if( !is_relative )
+ {
+ if( index < 0 )
+ {
+ if( index < -total )
+ CV_ERROR( CV_StsOutOfRange, "" );
+ index += total;
+ }
+ else if( index >= total )
+ {
+ index -= total;
+ if( index >= total )
+ CV_ERROR( CV_StsOutOfRange, "" );
+ }
+
+ block = reader->seq->first;
+ if( index >= (count = block->count) )
+ {
+ if( index + index <= total )
+ {
+ do
+ {
+ block = block->next;
+ index -= count;
+ }
+ while( index >= (count = block->count) );
+ }
+ else
+ {
+ do
+ {
+ block = block->prev;
+ total -= block->count;
+ }
+ while( index < total );
+ index -= total;
+ }
+ }
+ reader->ptr = block->data + index * elem_size;
+ if( reader->block != block )
+ {
+ reader->block = block;
+ reader->block_min = block->data;
+ reader->block_max = block->data + block->count * elem_size;
+ }
+ }
+ else
+ {
+ schar* ptr = reader->ptr;
+ index *= elem_size;
+ block = reader->block;
+
+ if( index > 0 )
+ {
+ while( ptr + index >= reader->block_max )
+ {
+ int delta = (int)(reader->block_max - ptr);
+ index -= delta;
+ reader->block = block = block->next;
+ reader->block_min = ptr = block->data;
+ reader->block_max = block->data + block->count*elem_size;
+ }
+ reader->ptr = ptr + index;
+ }
+ else
+ {
+ while( ptr + index < reader->block_min )
+ {
+ int delta = (int)(ptr - reader->block_min);
+ index += delta;
+ reader->block = block = block->prev;
+ reader->block_min = block->data;
+ reader->block_max = ptr = block->data + block->count*elem_size;
+ }
+ reader->ptr = ptr + index;
+ }
+ }
+
+ __END__;
+}
+
+
+/* Push element onto the sequence: */
+CV_IMPL schar*
+cvSeqPush( CvSeq *seq, void *element )
+{
+ schar *ptr = 0;
+ size_t elem_size;
+
+ CV_FUNCNAME( "cvSeqPush" );
+
+ __BEGIN__;
+
+ if( !seq )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ elem_size = seq->elem_size;
+ ptr = seq->ptr;
+
+ if( ptr >= seq->block_max )
+ {
+ CV_CALL( icvGrowSeq( seq, 0 ));
+
+ ptr = seq->ptr;
+ assert( ptr + elem_size <= seq->block_max /*&& ptr == seq->block_min */ );
+ }
+
+ if( element )
+ CV_MEMCPY_AUTO( ptr, element, elem_size );
+ seq->first->prev->count++;
+ seq->total++;
+ seq->ptr = ptr + elem_size;
+
+ __END__;
+
+ return ptr;
+}
+
+
+/* Pop last element off of the sequence: */
+CV_IMPL void
+cvSeqPop( CvSeq *seq, void *element )
+{
+ schar *ptr;
+ int elem_size;
+
+ CV_FUNCNAME( "cvSeqPop" );
+
+ __BEGIN__;
+
+ if( !seq )
+ CV_ERROR( CV_StsNullPtr, "" );
+ if( seq->total <= 0 )
+ CV_ERROR( CV_StsBadSize, "" );
+
+ elem_size = seq->elem_size;
+ seq->ptr = ptr = seq->ptr - elem_size;
+
+ if( element )
+ CV_MEMCPY_AUTO( element, ptr, elem_size );
+ seq->ptr = ptr;
+ seq->total--;
+
+ if( --(seq->first->prev->count) == 0 )
+ {
+ icvFreeSeqBlock( seq, 0 );
+ assert( seq->ptr == seq->block_max );
+ }
+
+ __END__;
+}
+
+
+/* Push element onto the front of the sequence: */
+CV_IMPL schar*
+cvSeqPushFront( CvSeq *seq, void *element )
+{
+ schar* ptr = 0;
+ int elem_size;
+ CvSeqBlock *block;
+
+ CV_FUNCNAME( "cvSeqPushFront" );
+
+ __BEGIN__;
+
+ if( !seq )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ elem_size = seq->elem_size;
+ block = seq->first;
+
+ if( !block || block->start_index == 0 )
+ {
+ CV_CALL( icvGrowSeq( seq, 1 ));
+
+ block = seq->first;
+ assert( block->start_index > 0 );
+ }
+
+ ptr = block->data -= elem_size;
+
+ if( element )
+ CV_MEMCPY_AUTO( ptr, element, elem_size );
+ block->count++;
+ block->start_index--;
+ seq->total++;
+
+ __END__;
+
+ return ptr;
+}
+
+
+/* Shift out first element of the sequence: */
+CV_IMPL void
+cvSeqPopFront( CvSeq *seq, void *element )
+{
+ int elem_size;
+ CvSeqBlock *block;
+
+ CV_FUNCNAME( "cvSeqPopFront" );
+
+ __BEGIN__;
+
+ if( !seq )
+ CV_ERROR( CV_StsNullPtr, "" );
+ if( seq->total <= 0 )
+ CV_ERROR( CV_StsBadSize, "" );
+
+ elem_size = seq->elem_size;
+ block = seq->first;
+
+ if( element )
+ CV_MEMCPY_AUTO( element, block->data, elem_size );
+ block->data += elem_size;
+ block->start_index++;
+ seq->total--;
+
+ if( --(block->count) == 0 )
+ {
+ icvFreeSeqBlock( seq, 1 );
+ }
+
+ __END__;
+}
+
+/* Insert new element in middle of sequence: */
+CV_IMPL schar*
+cvSeqInsert( CvSeq *seq, int before_index, void *element )
+{
+ int elem_size;
+ int block_size;
+ CvSeqBlock *block;
+ int delta_index;
+ int total;
+ schar* ret_ptr = 0;
+
+ CV_FUNCNAME( "cvSeqInsert" );
+
+ __BEGIN__;
+
+ if( !seq )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ total = seq->total;
+ before_index += before_index < 0 ? total : 0;
+ before_index -= before_index > total ? total : 0;
+
+ if( (unsigned)before_index > (unsigned)total )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ if( before_index == total )
+ {
+ CV_CALL( ret_ptr = cvSeqPush( seq, element ));
+ }
+ else if( before_index == 0 )
+ {
+ CV_CALL( ret_ptr = cvSeqPushFront( seq, element ));
+ }
+ else
+ {
+ elem_size = seq->elem_size;
+
+ if( before_index >= total >> 1 )
+ {
+ schar *ptr = seq->ptr + elem_size;
+
+ if( ptr > seq->block_max )
+ {
+ CV_CALL( icvGrowSeq( seq, 0 ));
+
+ ptr = seq->ptr + elem_size;
+ assert( ptr <= seq->block_max );
+ }
+
+ delta_index = seq->first->start_index;
+ block = seq->first->prev;
+ block->count++;
+ block_size = (int)(ptr - block->data);
+
+ while( before_index < block->start_index - delta_index )
+ {
+ CvSeqBlock *prev_block = block->prev;
+
+ memmove( block->data + elem_size, block->data, block_size - elem_size );
+ block_size = prev_block->count * elem_size;
+ memcpy( block->data, prev_block->data + block_size - elem_size, elem_size );
+ block = prev_block;
+
+ /* Check that we don't fall into an infinite loop: */
+ assert( block != seq->first->prev );
+ }
+
+ before_index = (before_index - block->start_index + delta_index) * elem_size;
+ memmove( block->data + before_index + elem_size, block->data + before_index,
+ block_size - before_index - elem_size );
+
+ ret_ptr = block->data + before_index;
+
+ if( element )
+ memcpy( ret_ptr, element, elem_size );
+ seq->ptr = ptr;
+ }
+ else
+ {
+ block = seq->first;
+
+ if( block->start_index == 0 )
+ {
+ CV_CALL( icvGrowSeq( seq, 1 ));
+
+ block = seq->first;
+ }
+
+ delta_index = block->start_index;
+ block->count++;
+ block->start_index--;
+ block->data -= elem_size;
+
+ while( before_index > block->start_index - delta_index + block->count )
+ {
+ CvSeqBlock *next_block = block->next;
+
+ block_size = block->count * elem_size;
+ memmove( block->data, block->data + elem_size, block_size - elem_size );
+ memcpy( block->data + block_size - elem_size, next_block->data, elem_size );
+ block = next_block;
+
+ /* Check that we don't fall into an infinite loop: */
+ assert( block != seq->first );
+ }
+
+ before_index = (before_index - block->start_index + delta_index) * elem_size;
+ memmove( block->data, block->data + elem_size, before_index - elem_size );
+
+ ret_ptr = block->data + before_index - elem_size;
+
+ if( element )
+ memcpy( ret_ptr, element, elem_size );
+ }
+
+ seq->total = total + 1;
+ }
+
+ __END__;
+
+ return ret_ptr;
+}
+
+
+/* Removes element from sequence: */
+CV_IMPL void
+cvSeqRemove( CvSeq *seq, int index )
+{
+ schar *ptr;
+ int elem_size;
+ int block_size;
+ CvSeqBlock *block;
+ int delta_index;
+ int total, front = 0;
+
+ CV_FUNCNAME( "cvSeqRemove" );
+
+ __BEGIN__;
+
+ if( !seq )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ total = seq->total;
+
+ index += index < 0 ? total : 0;
+ index -= index >= total ? total : 0;
+
+ if( (unsigned) index >= (unsigned) total )
+ CV_ERROR( CV_StsOutOfRange, "Invalid index" );
+
+ if( index == total - 1 )
+ {
+ cvSeqPop( seq, 0 );
+ }
+ else if( index == 0 )
+ {
+ cvSeqPopFront( seq, 0 );
+ }
+ else
+ {
+ block = seq->first;
+ elem_size = seq->elem_size;
+ delta_index = block->start_index;
+ while( block->start_index - delta_index + block->count <= index )
+ block = block->next;
+
+ ptr = block->data + (index - block->start_index + delta_index) * elem_size;
+
+ front = index < total >> 1;
+ if( !front )
+ {
+ block_size = block->count * elem_size - (int)(ptr - block->data);
+
+ while( block != seq->first->prev ) /* while not the last block */
+ {
+ CvSeqBlock *next_block = block->next;
+
+ memmove( ptr, ptr + elem_size, block_size - elem_size );
+ memcpy( ptr + block_size - elem_size, next_block->data, elem_size );
+ block = next_block;
+ ptr = block->data;
+ block_size = block->count * elem_size;
+ }
+
+ memmove( ptr, ptr + elem_size, block_size - elem_size );
+ seq->ptr -= elem_size;
+ }
+ else
+ {
+ ptr += elem_size;
+ block_size = (int)(ptr - block->data);
+
+ while( block != seq->first )
+ {
+ CvSeqBlock *prev_block = block->prev;
+
+ memmove( block->data + elem_size, block->data, block_size - elem_size );
+ block_size = prev_block->count * elem_size;
+ memcpy( block->data, prev_block->data + block_size - elem_size, elem_size );
+ block = prev_block;
+ }
+
+ memmove( block->data + elem_size, block->data, block_size - elem_size );
+ block->data += elem_size;
+ block->start_index++;
+ }
+
+ seq->total = total - 1;
+ if( --block->count == 0 )
+ icvFreeSeqBlock( seq, front );
+ }
+
+ __END__;
+}
+
+
+/* Add several elements to the beginning or end of a sequence: */
+CV_IMPL void
+cvSeqPushMulti( CvSeq *seq, void *_elements, int count, int front )
+{
+ char *elements = (char *) _elements;
+
+ CV_FUNCNAME( "cvSeqPushMulti" );
+
+ __BEGIN__;
+ int elem_size;
+
+ if( !seq )
+ CV_ERROR( CV_StsNullPtr, "NULL sequence pointer" );
+ if( count < 0 )
+ CV_ERROR( CV_StsBadSize, "number of removed elements is negative" );
+
+ elem_size = seq->elem_size;
+
+ if( !front )
+ {
+ while( count > 0 )
+ {
+ int delta = (int)((seq->block_max - seq->ptr) / elem_size);
+
+ delta = MIN( delta, count );
+ if( delta > 0 )
+ {
+ seq->first->prev->count += delta;
+ seq->total += delta;
+ count -= delta;
+ delta *= elem_size;
+ if( elements )
+ {
+ memcpy( seq->ptr, elements, delta );
+ elements += delta;
+ }
+ seq->ptr += delta;
+ }
+
+ if( count > 0 )
+ CV_CALL( icvGrowSeq( seq, 0 ));
+ }
+ }
+ else
+ {
+ CvSeqBlock* block = seq->first;
+
+ while( count > 0 )
+ {
+ int delta;
+
+ if( !block || block->start_index == 0 )
+ {
+ CV_CALL( icvGrowSeq( seq, 1 ));
+
+ block = seq->first;
+ assert( block->start_index > 0 );
+ }
+
+ delta = MIN( block->start_index, count );
+ count -= delta;
+ block->start_index -= delta;
+ block->count += delta;
+ seq->total += delta;
+ delta *= elem_size;
+ block->data -= delta;
+
+ if( elements )
+ memcpy( block->data, elements + count*elem_size, delta );
+ }
+ }
+
+ __END__;
+}
+
+
+/* Remove several elements from the end of sequence: */
+CV_IMPL void
+cvSeqPopMulti( CvSeq *seq, void *_elements, int count, int front )
+{
+ char *elements = (char *) _elements;
+
+ CV_FUNCNAME( "cvSeqPopMulti" );
+
+ __BEGIN__;
+
+ if( !seq )
+ CV_ERROR( CV_StsNullPtr, "NULL sequence pointer" );
+ if( count < 0 )
+ CV_ERROR( CV_StsBadSize, "number of removed elements is negative" );
+
+ count = MIN( count, seq->total );
+
+ if( !front )
+ {
+ if( elements )
+ elements += count * seq->elem_size;
+
+ while( count > 0 )
+ {
+ int delta = seq->first->prev->count;
+
+ delta = MIN( delta, count );
+ assert( delta > 0 );
+
+ seq->first->prev->count -= delta;
+ seq->total -= delta;
+ count -= delta;
+ delta *= seq->elem_size;
+ seq->ptr -= delta;
+
+ if( elements )
+ {
+ elements -= delta;
+ memcpy( elements, seq->ptr, delta );
+ }
+
+ if( seq->first->prev->count == 0 )
+ icvFreeSeqBlock( seq, 0 );
+ }
+ }
+ else
+ {
+ while( count > 0 )
+ {
+ int delta = seq->first->count;
+
+ delta = MIN( delta, count );
+ assert( delta > 0 );
+
+ seq->first->count -= delta;
+ seq->total -= delta;
+ count -= delta;
+ seq->first->start_index += delta;
+ delta *= seq->elem_size;
+
+ if( elements )
+ {
+ memcpy( elements, seq->first->data, delta );
+ elements += delta;
+ }
+
+ seq->first->data += delta;
+ if( seq->first->count == 0 )
+ icvFreeSeqBlock( seq, 1 );
+ }
+ }
+
+ __END__;
+}
+
+
+/* Remove all elements from a sequence: */
+CV_IMPL void
+cvClearSeq( CvSeq *seq )
+{
+ CV_FUNCNAME( "cvClearSeq" );
+
+ __BEGIN__;
+
+ if( !seq )
+ CV_ERROR( CV_StsNullPtr, "" );
+ cvSeqPopMulti( seq, 0, seq->total );
+
+ __END__;
+}
+
+
+CV_IMPL CvSeq*
+cvSeqSlice( const CvSeq* seq, CvSlice slice, CvMemStorage* storage, int copy_data )
+{
+ CvSeq* subseq = 0;
+
+ CV_FUNCNAME("cvSeqSlice");
+
+ __BEGIN__;
+
+ int elem_size, count, length;
+ CvSeqReader reader;
+ CvSeqBlock *block, *first_block = 0, *last_block = 0;
+
+ if( !CV_IS_SEQ(seq) )
+ CV_ERROR( CV_StsBadArg, "Invalid sequence header" );
+
+ if( !storage )
+ {
+ storage = seq->storage;
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "NULL storage pointer" );
+ }
+
+ elem_size = seq->elem_size;
+ length = cvSliceLength( slice, seq );
+ if( slice.start_index < 0 )
+ slice.start_index += seq->total;
+ else if( slice.start_index >= seq->total )
+ slice.start_index -= seq->total;
+ if( (unsigned)length > (unsigned)seq->total ||
+ ((unsigned)slice.start_index >= (unsigned)seq->total && length != 0) )
+ CV_ERROR( CV_StsOutOfRange, "Bad sequence slice" );
+
+ CV_CALL( subseq = cvCreateSeq( seq->flags, seq->header_size, elem_size, storage ));
+
+ if( length > 0 )
+ {
+ cvStartReadSeq( seq, &reader, 0 );
+ cvSetSeqReaderPos( &reader, slice.start_index, 0 );
+ count = (int)((reader.block_max - reader.ptr)/elem_size);
+
+ do
+ {
+ int bl = MIN( count, length );
+
+ if( !copy_data )
+ {
+ block = (CvSeqBlock*)cvMemStorageAlloc( storage, sizeof(*block) );
+ if( !first_block )
+ {
+ first_block = subseq->first = block->prev = block->next = block;
+ block->start_index = 0;
+ }
+ else
+ {
+ block->prev = last_block;
+ block->next = first_block;
+ last_block->next = first_block->prev = block;
+ block->start_index = last_block->start_index + last_block->count;
+ }
+ last_block = block;
+ block->data = reader.ptr;
+ block->count = bl;
+ subseq->total += bl;
+ }
+ else
+ cvSeqPushMulti( subseq, reader.ptr, bl, 0 );
+ length -= bl;
+ reader.block = reader.block->next;
+ reader.ptr = reader.block->data;
+ count = reader.block->count;
+ }
+ while( length > 0 );
+ }
+
+ __END__;
+
+ return subseq;
+}
+
+
+// Remove slice from the middle of the sequence.
+// !!! TODO !!! Implement more efficient algorithm
+CV_IMPL void
+cvSeqRemoveSlice( CvSeq* seq, CvSlice slice )
+{
+ CV_FUNCNAME("cvSeqRemoveSlice");
+
+ __BEGIN__;
+
+ int total, length;
+
+ if( !CV_IS_SEQ(seq) )
+ CV_ERROR( CV_StsBadArg, "Invalid sequence header" );
+
+ length = cvSliceLength( slice, seq );
+ total = seq->total;
+
+ if( slice.start_index < 0 )
+ slice.start_index += total;
+ else if( slice.start_index >= total )
+ slice.start_index -= total;
+
+ if( (unsigned)slice.start_index >= (unsigned)total )
+ CV_ERROR( CV_StsOutOfRange, "start slice index is out of range" );
+
+ slice.end_index = slice.start_index + length;
+
+ if( slice.end_index < total )
+ {
+ CvSeqReader reader_to, reader_from;
+ int elem_size = seq->elem_size;
+
+ cvStartReadSeq( seq, &reader_to );
+ cvStartReadSeq( seq, &reader_from );
+
+ if( slice.start_index > total - slice.end_index )
+ {
+ int i, count = seq->total - slice.end_index;
+ cvSetSeqReaderPos( &reader_to, slice.start_index );
+ cvSetSeqReaderPos( &reader_from, slice.end_index );
+
+ for( i = 0; i < count; i++ )
+ {
+ CV_MEMCPY_AUTO( reader_to.ptr, reader_from.ptr, elem_size );
+ CV_NEXT_SEQ_ELEM( elem_size, reader_to );
+ CV_NEXT_SEQ_ELEM( elem_size, reader_from );
+ }
+
+ cvSeqPopMulti( seq, 0, slice.end_index - slice.start_index );
+ }
+ else
+ {
+ int i, count = slice.start_index;
+ cvSetSeqReaderPos( &reader_to, slice.end_index );
+ cvSetSeqReaderPos( &reader_from, slice.start_index );
+
+ for( i = 0; i < count; i++ )
+ {
+ CV_PREV_SEQ_ELEM( elem_size, reader_to );
+ CV_PREV_SEQ_ELEM( elem_size, reader_from );
+
+ CV_MEMCPY_AUTO( reader_to.ptr, reader_from.ptr, elem_size );
+ }
+
+ cvSeqPopMulti( seq, 0, slice.end_index - slice.start_index, 1 );
+ }
+ }
+ else
+ {
+ cvSeqPopMulti( seq, 0, total - slice.start_index );
+ cvSeqPopMulti( seq, 0, slice.end_index - total, 1 );
+ }
+
+ __END__;
+}
+
+
+// Insert a sequence into the middle of another sequence:
+// !!! TODO !!! Implement more efficient algorithm
+CV_IMPL void
+cvSeqInsertSlice( CvSeq* seq, int index, const CvArr* from_arr )
+{
+ CvSeqReader reader_to, reader_from;
+ int i, elem_size, total, from_total;
+
+ CV_FUNCNAME("cvSeqInsertSlice");
+
+ __BEGIN__;
+
+ CvSeq from_header, *from = (CvSeq*)from_arr;
+ CvSeqBlock block;
+
+ if( !CV_IS_SEQ(seq) )
+ CV_ERROR( CV_StsBadArg, "Invalid destination sequence header" );
+
+ if( !CV_IS_SEQ(from))
+ {
+ CvMat* mat = (CvMat*)from;
+ if( !CV_IS_MAT(mat))
+ CV_ERROR( CV_StsBadArg, "Source is not a sequence nor matrix" );
+
+ if( !CV_IS_MAT_CONT(mat->type) || (mat->rows != 1 && mat->cols != 1) )
+ CV_ERROR( CV_StsBadArg, "The source array must be 1d coninuous vector" );
+
+ CV_CALL( from = cvMakeSeqHeaderForArray( CV_SEQ_KIND_GENERIC, sizeof(from_header),
+ CV_ELEM_SIZE(mat->type),
+ mat->data.ptr, mat->cols + mat->rows - 1,
+ &from_header, &block ));
+ }
+
+ if( seq->elem_size != from->elem_size )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Source and destination sequence element sizes are different." );
+
+ from_total = from->total;
+
+ if( from_total == 0 )
+ EXIT;
+
+ total = seq->total;
+ index += index < 0 ? total : 0;
+ index -= index > total ? total : 0;
+
+ if( (unsigned)index > (unsigned)total )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ elem_size = seq->elem_size;
+
+ if( index < (total >> 1) )
+ {
+ cvSeqPushMulti( seq, 0, from_total, 1 );
+
+ cvStartReadSeq( seq, &reader_to );
+ cvStartReadSeq( seq, &reader_from );
+ cvSetSeqReaderPos( &reader_from, from_total );
+
+ for( i = 0; i < index; i++ )
+ {
+ CV_MEMCPY_AUTO( reader_to.ptr, reader_from.ptr, elem_size );
+ CV_NEXT_SEQ_ELEM( elem_size, reader_to );
+ CV_NEXT_SEQ_ELEM( elem_size, reader_from );
+ }
+ }
+ else
+ {
+ cvSeqPushMulti( seq, 0, from_total );
+
+ cvStartReadSeq( seq, &reader_to );
+ cvStartReadSeq( seq, &reader_from );
+ cvSetSeqReaderPos( &reader_from, total );
+ cvSetSeqReaderPos( &reader_to, seq->total );
+
+ for( i = 0; i < total - index; i++ )
+ {
+ CV_PREV_SEQ_ELEM( elem_size, reader_to );
+ CV_PREV_SEQ_ELEM( elem_size, reader_from );
+ CV_MEMCPY_AUTO( reader_to.ptr, reader_from.ptr, elem_size );
+ }
+ }
+
+ cvStartReadSeq( from, &reader_from );
+ cvSetSeqReaderPos( &reader_to, index );
+
+ for( i = 0; i < from_total; i++ )
+ {
+ CV_MEMCPY_AUTO( reader_to.ptr, reader_from.ptr, elem_size );
+ CV_NEXT_SEQ_ELEM( elem_size, reader_to );
+ CV_NEXT_SEQ_ELEM( elem_size, reader_from );
+ }
+
+ __END__;
+}
+
+// Sort the sequence using user-specified comparison function.
+// The semantics is similar to qsort() function.
+// The code is based on BSD system qsort():
+// * Copyright (c) 1992, 1993
+// * The Regents of the University of California. All rights reserved.
+// *
+// * Redistribution and use in source and binary forms, with or without
+// * modification, are permitted provided that the following conditions
+// * are met:
+// * 1. Redistributions of source code must retain the above copyright
+// * notice, this list of conditions and the following disclaimer.
+// * 2. Redistributions in binary form must reproduce the above copyright
+// * notice, this list of conditions and the following disclaimer in the
+// * documentation and/or other materials provided with the distribution.
+// * 3. All advertising materials mentioning features or use of this software
+// * must display the following acknowledgement:
+// * This product includes software developed by the University of
+// * California, Berkeley and its contributors.
+// * 4. Neither the name of the University nor the names of its contributors
+// * may be used to endorse or promote products derived from this software
+// * without specific prior written permission.
+// *
+// * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+// * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+// * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// * SUCH DAMAGE.
+
+typedef struct CvSeqReaderPos
+{
+ CvSeqBlock* block;
+ schar* ptr;
+ schar* block_min;
+ schar* block_max;
+}
+CvSeqReaderPos;
+
+#define CV_SAVE_READER_POS( reader, pos ) \
+{ \
+ (pos).block = (reader).block; \
+ (pos).ptr = (reader).ptr; \
+ (pos).block_min = (reader).block_min; \
+ (pos).block_max = (reader).block_max; \
+}
+
+#define CV_RESTORE_READER_POS( reader, pos )\
+{ \
+ (reader).block = (pos).block; \
+ (reader).ptr = (pos).ptr; \
+ (reader).block_min = (pos).block_min; \
+ (reader).block_max = (pos).block_max; \
+}
+
+inline schar*
+icvMed3( schar* a, schar* b, schar* c, CvCmpFunc cmp_func, void* aux )
+{
+ return cmp_func(a, b, aux) < 0 ?
+ (cmp_func(b, c, aux) < 0 ? b : cmp_func(a, c, aux) < 0 ? c : a)
+ :(cmp_func(b, c, aux) > 0 ? b : cmp_func(a, c, aux) < 0 ? a : c);
+}
+
+CV_IMPL void
+cvSeqSort( CvSeq* seq, CvCmpFunc cmp_func, void* aux )
+{
+ int elem_size;
+ int isort_thresh = 7;
+ CvSeqReader left, right;
+ int sp = 0;
+
+ struct
+ {
+ CvSeqReaderPos lb;
+ CvSeqReaderPos ub;
+ }
+ stack[48];
+
+ CV_FUNCNAME( "cvSeqSort" );
+
+ __BEGIN__;
+
+ if( !CV_IS_SEQ(seq) )
+ CV_ERROR( !seq ? CV_StsNullPtr : CV_StsBadArg, "Bad input sequence" );
+
+ if( !cmp_func )
+ CV_ERROR( CV_StsNullPtr, "Null compare function" );
+
+ if( seq->total <= 1 )
+ EXIT;
+
+ elem_size = seq->elem_size;
+ isort_thresh *= elem_size;
+
+ cvStartReadSeq( seq, &left, 0 );
+ right = left;
+ CV_SAVE_READER_POS( left, stack[0].lb );
+ CV_PREV_SEQ_ELEM( elem_size, right );
+ CV_SAVE_READER_POS( right, stack[0].ub );
+
+ while( sp >= 0 )
+ {
+ CV_RESTORE_READER_POS( left, stack[sp].lb );
+ CV_RESTORE_READER_POS( right, stack[sp].ub );
+ sp--;
+
+ for(;;)
+ {
+ int i, n, m;
+ CvSeqReader ptr, ptr2;
+
+ if( left.block == right.block )
+ n = (int)(right.ptr - left.ptr) + elem_size;
+ else
+ {
+ n = cvGetSeqReaderPos( &right );
+ n = (n - cvGetSeqReaderPos( &left ) + 1)*elem_size;
+ }
+
+ if( n <= isort_thresh )
+ {
+ insert_sort:
+ ptr = ptr2 = left;
+ CV_NEXT_SEQ_ELEM( elem_size, ptr );
+ CV_NEXT_SEQ_ELEM( elem_size, right );
+ while( ptr.ptr != right.ptr )
+ {
+ ptr2.ptr = ptr.ptr;
+ if( ptr2.block != ptr.block )
+ {
+ ptr2.block = ptr.block;
+ ptr2.block_min = ptr.block_min;
+ ptr2.block_max = ptr.block_max;
+ }
+ while( ptr2.ptr != left.ptr )
+ {
+ schar* cur = ptr2.ptr;
+ CV_PREV_SEQ_ELEM( elem_size, ptr2 );
+ if( cmp_func( ptr2.ptr, cur, aux ) <= 0 )
+ break;
+ CV_SWAP_ELEMS( ptr2.ptr, cur, elem_size );
+ }
+ CV_NEXT_SEQ_ELEM( elem_size, ptr );
+ }
+ break;
+ }
+ else
+ {
+ CvSeqReader left0, left1, right0, right1;
+ CvSeqReader tmp0, tmp1;
+ schar *m1, *m2, *m3, *pivot;
+ int swap_cnt = 0;
+ int l, l0, l1, r, r0, r1;
+
+ left0 = tmp0 = left;
+ right0 = right1 = right;
+ n /= elem_size;
+
+ if( n > 40 )
+ {
+ int d = n / 8;
+ schar *p1, *p2, *p3;
+ p1 = tmp0.ptr;
+ cvSetSeqReaderPos( &tmp0, d, 1 );
+ p2 = tmp0.ptr;
+ cvSetSeqReaderPos( &tmp0, d, 1 );
+ p3 = tmp0.ptr;
+ m1 = icvMed3( p1, p2, p3, cmp_func, aux );
+ cvSetSeqReaderPos( &tmp0, (n/2) - d*3, 1 );
+ p1 = tmp0.ptr;
+ cvSetSeqReaderPos( &tmp0, d, 1 );
+ p2 = tmp0.ptr;
+ cvSetSeqReaderPos( &tmp0, d, 1 );
+ p3 = tmp0.ptr;
+ m2 = icvMed3( p1, p2, p3, cmp_func, aux );
+ cvSetSeqReaderPos( &tmp0, n - 1 - d*3 - n/2, 1 );
+ p1 = tmp0.ptr;
+ cvSetSeqReaderPos( &tmp0, d, 1 );
+ p2 = tmp0.ptr;
+ cvSetSeqReaderPos( &tmp0, d, 1 );
+ p3 = tmp0.ptr;
+ m3 = icvMed3( p1, p2, p3, cmp_func, aux );
+ }
+ else
+ {
+ m1 = tmp0.ptr;
+ cvSetSeqReaderPos( &tmp0, n/2, 1 );
+ m2 = tmp0.ptr;
+ cvSetSeqReaderPos( &tmp0, n - 1 - n/2, 1 );
+ m3 = tmp0.ptr;
+ }
+
+ pivot = icvMed3( m1, m2, m3, cmp_func, aux );
+ left = left0;
+ if( pivot != left.ptr )
+ {
+ CV_SWAP_ELEMS( pivot, left.ptr, elem_size );
+ pivot = left.ptr;
+ }
+ CV_NEXT_SEQ_ELEM( elem_size, left );
+ left1 = left;
+
+ for(;;)
+ {
+ while( left.ptr != right.ptr && (r = cmp_func(left.ptr, pivot, aux)) <= 0 )
+ {
+ if( r == 0 )
+ {
+ if( left1.ptr != left.ptr )
+ CV_SWAP_ELEMS( left1.ptr, left.ptr, elem_size );
+ swap_cnt = 1;
+ CV_NEXT_SEQ_ELEM( elem_size, left1 );
+ }
+ CV_NEXT_SEQ_ELEM( elem_size, left );
+ }
+
+ while( left.ptr != right.ptr && (r = cmp_func(right.ptr,pivot, aux)) >= 0 )
+ {
+ if( r == 0 )
+ {
+ if( right1.ptr != right.ptr )
+ CV_SWAP_ELEMS( right1.ptr, right.ptr, elem_size );
+ swap_cnt = 1;
+ CV_PREV_SEQ_ELEM( elem_size, right1 );
+ }
+ CV_PREV_SEQ_ELEM( elem_size, right );
+ }
+
+ if( left.ptr == right.ptr )
+ {
+ r = cmp_func(left.ptr, pivot, aux);
+ if( r == 0 )
+ {
+ if( left1.ptr != left.ptr )
+ CV_SWAP_ELEMS( left1.ptr, left.ptr, elem_size );
+ swap_cnt = 1;
+ CV_NEXT_SEQ_ELEM( elem_size, left1 );
+ }
+ if( r <= 0 )
+ {
+ CV_NEXT_SEQ_ELEM( elem_size, left );
+ }
+ else
+ {
+ CV_PREV_SEQ_ELEM( elem_size, right );
+ }
+ break;
+ }
+
+ CV_SWAP_ELEMS( left.ptr, right.ptr, elem_size );
+ CV_NEXT_SEQ_ELEM( elem_size, left );
+ r = left.ptr == right.ptr;
+ CV_PREV_SEQ_ELEM( elem_size, right );
+ swap_cnt = 1;
+ if( r )
+ break;
+ }
+
+ if( swap_cnt == 0 )
+ {
+ left = left0, right = right0;
+ goto insert_sort;
+ }
+
+ l = cvGetSeqReaderPos( &left );
+ if( l == 0 )
+ l = seq->total;
+ l0 = cvGetSeqReaderPos( &left0 );
+ l1 = cvGetSeqReaderPos( &left1 );
+ if( l1 == 0 )
+ l1 = seq->total;
+
+ n = MIN( l - l1, l1 - l0 );
+ if( n > 0 )
+ {
+ tmp0 = left0;
+ tmp1 = left;
+ cvSetSeqReaderPos( &tmp1, 0-n, 1 );
+ for( i = 0; i < n; i++ )
+ {
+ CV_SWAP_ELEMS( tmp0.ptr, tmp1.ptr, elem_size );
+ CV_NEXT_SEQ_ELEM( elem_size, tmp0 );
+ CV_NEXT_SEQ_ELEM( elem_size, tmp1 );
+ }
+ }
+
+ r = cvGetSeqReaderPos( &right );
+ r0 = cvGetSeqReaderPos( &right0 );
+ r1 = cvGetSeqReaderPos( &right1 );
+ m = MIN( r0 - r1, r1 - r );
+ if( m > 0 )
+ {
+ tmp0 = left;
+ tmp1 = right0;
+ cvSetSeqReaderPos( &tmp1, 1-m, 1 );
+ for( i = 0; i < m; i++ )
+ {
+ CV_SWAP_ELEMS( tmp0.ptr, tmp1.ptr, elem_size );
+ CV_NEXT_SEQ_ELEM( elem_size, tmp0 );
+ CV_NEXT_SEQ_ELEM( elem_size, tmp1 );
+ }
+ }
+
+ n = l - l1;
+ m = r1 - r;
+ if( n > 1 )
+ {
+ if( m > 1 )
+ {
+ if( n > m )
+ {
+ sp++;
+ CV_SAVE_READER_POS( left0, stack[sp].lb );
+ cvSetSeqReaderPos( &left0, n - 1, 1 );
+ CV_SAVE_READER_POS( left0, stack[sp].ub );
+ left = right = right0;
+ cvSetSeqReaderPos( &left, 1 - m, 1 );
+ }
+ else
+ {
+ sp++;
+ CV_SAVE_READER_POS( right0, stack[sp].ub );
+ cvSetSeqReaderPos( &right0, 1 - m, 1 );
+ CV_SAVE_READER_POS( right0, stack[sp].lb );
+ left = right = left0;
+ cvSetSeqReaderPos( &right, n - 1, 1 );
+ }
+ }
+ else
+ {
+ left = right = left0;
+ cvSetSeqReaderPos( &right, n - 1, 1 );
+ }
+ }
+ else if( m > 1 )
+ {
+ left = right = right0;
+ cvSetSeqReaderPos( &left, 1 - m, 1 );
+ }
+ else
+ break;
+ }
+ }
+ }
+
+ __END__;
+}
+
+
+CV_IMPL schar*
+cvSeqSearch( CvSeq* seq, const void* _elem, CvCmpFunc cmp_func,
+ int is_sorted, int* _idx, void* userdata )
+{
+ schar* result = 0;
+ const schar* elem = (const schar*)_elem;
+ int idx = -1;
+
+ CV_FUNCNAME("cvSeqSearch");
+
+ __BEGIN__;
+
+ int elem_size, i, j, total;
+
+ if( !CV_IS_SEQ(seq) )
+ CV_ERROR( !seq ? CV_StsNullPtr : CV_StsBadArg, "Bad input sequence" );
+
+ if( !elem )
+ CV_ERROR( CV_StsNullPtr, "Null element pointer" );
+
+ elem_size = seq->elem_size;
+ total = seq->total;
+
+ if( total == 0 )
+ EXIT;
+
+ if( !is_sorted )
+ {
+ CvSeqReader reader;
+ cvStartReadSeq( seq, &reader, 0 );
+
+ if( cmp_func )
+ {
+ for( i = 0; i < total; i++ )
+ {
+ if( cmp_func( elem, reader.ptr, userdata ) == 0 )
+ break;
+ CV_NEXT_SEQ_ELEM( elem_size, reader );
+ }
+ }
+ else if( (elem_size & (sizeof(int)-1)) == 0 )
+ {
+ for( i = 0; i < total; i++ )
+ {
+ for( j = 0; j < elem_size; j += sizeof(int) )
+ {
+ if( *(const int*)(reader.ptr + j) != *(const int*)(elem + j) )
+ break;
+ }
+ if( j == elem_size )
+ break;
+ CV_NEXT_SEQ_ELEM( elem_size, reader );
+ }
+ }
+ else
+ {
+ for( i = 0; i < total; i++ )
+ {
+ for( j = 0; j < elem_size; j++ )
+ {
+ if( reader.ptr[j] != elem[j] )
+ break;
+ }
+ if( j == elem_size )
+ break;
+ CV_NEXT_SEQ_ELEM( elem_size, reader );
+ }
+ }
+
+ idx = i;
+ if( i < total )
+ result = reader.ptr;
+ }
+ else
+ {
+ if( !cmp_func )
+ CV_ERROR( CV_StsNullPtr, "Null compare function" );
+
+ i = 0, j = total;
+
+ while( j > i )
+ {
+ int k = (i+j)>>1, code;
+ schar* ptr = cvGetSeqElem( seq, k );
+ code = cmp_func( elem, ptr, userdata );
+ if( !code )
+ {
+ result = ptr;
+ idx = k;
+ EXIT;
+ }
+ if( code < 0 )
+ j = k;
+ else
+ i = k+1;
+ }
+ idx = j;
+ }
+
+ __END__;
+
+ if( _idx )
+ *_idx = idx;
+
+ return result;
+}
+
+
+CV_IMPL void
+cvSeqInvert( CvSeq* seq )
+{
+ CV_FUNCNAME( "cvSeqInvert" );
+
+ __BEGIN__;
+
+ CvSeqReader left_reader, right_reader;
+ int elem_size;
+ int i, count;
+
+ CV_CALL( cvStartReadSeq( seq, &left_reader, 0 ));
+ CV_CALL( cvStartReadSeq( seq, &right_reader, 1 ));
+ elem_size = seq->elem_size;
+ count = seq->total >> 1;
+
+ for( i = 0; i < count; i++ )
+ {
+ CV_SWAP_ELEMS( left_reader.ptr, right_reader.ptr, elem_size );
+ CV_NEXT_SEQ_ELEM( elem_size, left_reader );
+ CV_PREV_SEQ_ELEM( elem_size, right_reader );
+ }
+
+ __END__;
+}
+
+
+typedef struct CvPTreeNode
+{
+ struct CvPTreeNode* parent;
+ schar* element;
+ int rank;
+}
+CvPTreeNode;
+
+
+// This function splits the input sequence or set into one or more equivalence classes.
+// is_equal(a,b,...) returns non-zero if the two sequence elements
+// belong to the same class. The function returns sequence of integers -
+// 0-based class indexes for each element.
+//
+// The algorithm is described in "Introduction to Algorithms"
+// by Cormen, Leiserson and Rivest, chapter "Data structures for disjoint sets"
+CV_IMPL int
+cvSeqPartition( const CvSeq* seq, CvMemStorage* storage, CvSeq** labels,
+ CvCmpFunc is_equal, void* userdata )
+{
+ CvSeq* result = 0;
+ CvMemStorage* temp_storage = 0;
+ int class_idx = 0;
+
+ CV_FUNCNAME( "cvSeqPartition" );
+
+ __BEGIN__;
+
+ CvSeqWriter writer;
+ CvSeqReader reader, reader0;
+ CvSeq* nodes;
+ int i, j;
+ int is_set;
+
+ if( !labels )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !seq || !is_equal )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !storage )
+ storage = seq->storage;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ is_set = CV_IS_SET(seq);
+
+ temp_storage = cvCreateChildMemStorage( storage );
+
+ nodes = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPTreeNode), temp_storage );
+
+ cvStartReadSeq( seq, &reader );
+ memset( &writer, 0, sizeof(writer));
+ cvStartAppendToSeq( nodes, &writer );
+
+ // Initial O(N) pass. Make a forest of single-vertex trees.
+ for( i = 0; i < seq->total; i++ )
+ {
+ CvPTreeNode node = { 0, 0, 0 };
+ if( !is_set || CV_IS_SET_ELEM( reader.ptr ))
+ node.element = reader.ptr;
+ CV_WRITE_SEQ_ELEM( node, writer );
+ CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
+ }
+
+ cvEndWriteSeq( &writer );
+
+ // Because in the next loop we will iterate
+ // through all the sequence nodes each time,
+ // we do not need to initialize reader every time:
+ cvStartReadSeq( nodes, &reader );
+ cvStartReadSeq( nodes, &reader0 );
+
+ // The main O(N^2) pass. Merge connected components.
+ for( i = 0; i < nodes->total; i++ )
+ {
+ CvPTreeNode* node = (CvPTreeNode*)(reader0.ptr);
+ CvPTreeNode* root = node;
+ CV_NEXT_SEQ_ELEM( nodes->elem_size, reader0 );
+
+ if( !node->element )
+ continue;
+
+ // find root
+ while( root->parent )
+ root = root->parent;
+
+ for( j = 0; j < nodes->total; j++ )
+ {
+ CvPTreeNode* node2 = (CvPTreeNode*)reader.ptr;
+
+ if( node2->element && node2 != node &&
+ is_equal( node->element, node2->element, userdata ))
+ {
+ CvPTreeNode* root2 = node2;
+
+ // unite both trees
+ while( root2->parent )
+ root2 = root2->parent;
+
+ if( root2 != root )
+ {
+ if( root->rank > root2->rank )
+ root2->parent = root;
+ else
+ {
+ root->parent = root2;
+ root2->rank += root->rank == root2->rank;
+ root = root2;
+ }
+ assert( root->parent == 0 );
+
+ // Compress path from node2 to the root:
+ while( node2->parent )
+ {
+ CvPTreeNode* temp = node2;
+ node2 = node2->parent;
+ temp->parent = root;
+ }
+
+ // Compress path from node to the root:
+ node2 = node;
+ while( node2->parent )
+ {
+ CvPTreeNode* temp = node2;
+ node2 = node2->parent;
+ temp->parent = root;
+ }
+ }
+ }
+
+ CV_NEXT_SEQ_ELEM( sizeof(*node), reader );
+ }
+ }
+
+ // Final O(N) pass (Enumerate classes)
+ // Reuse reader one more time
+ result = cvCreateSeq( 0, sizeof(CvSeq), sizeof(int), storage );
+ cvStartAppendToSeq( result, &writer );
+
+ for( i = 0; i < nodes->total; i++ )
+ {
+ CvPTreeNode* node = (CvPTreeNode*)reader.ptr;
+ int idx = -1;
+
+ if( node->element )
+ {
+ while( node->parent )
+ node = node->parent;
+ if( node->rank >= 0 )
+ node->rank = ~class_idx++;
+ idx = ~node->rank;
+ }
+
+ CV_NEXT_SEQ_ELEM( sizeof(*node), reader );
+ CV_WRITE_SEQ_ELEM( idx, writer );
+ }
+
+ cvEndWriteSeq( &writer );
+
+ __END__;
+
+ if( labels )
+ *labels = result;
+
+ cvReleaseMemStorage( &temp_storage );
+ return class_idx;
+}
+
+
+/****************************************************************************************\
+* Set implementation *
+\****************************************************************************************/
+
+/* Creates empty set: */
+CV_IMPL CvSet*
+cvCreateSet( int set_flags, int header_size, int elem_size, CvMemStorage * storage )
+{
+ CvSet *set = 0;
+
+ CV_FUNCNAME( "cvCreateSet" );
+
+ __BEGIN__;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "" );
+ if( header_size < (int)sizeof( CvSet ) ||
+ elem_size < (int)sizeof(void*)*2 ||
+ (elem_size & (sizeof(void*)-1)) != 0 )
+ CV_ERROR( CV_StsBadSize, "" );
+
+ set = (CvSet*) cvCreateSeq( set_flags, header_size, elem_size, storage );
+ set->flags = (set->flags & ~CV_MAGIC_MASK) | CV_SET_MAGIC_VAL;
+
+ __END__;
+
+ return set;
+}
+
+
+/* Add new element to the set: */
+CV_IMPL int
+cvSetAdd( CvSet* set, CvSetElem* element, CvSetElem** inserted_element )
+{
+ int id = -1;
+
+ CV_FUNCNAME( "cvSetAdd" );
+
+ __BEGIN__;
+
+ CvSetElem *free_elem;
+
+ if( !set )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !(set->free_elems) )
+ {
+ int count = set->total;
+ int elem_size = set->elem_size;
+ schar *ptr;
+ CV_CALL( icvGrowSeq( (CvSeq *) set, 0 ));
+
+ set->free_elems = (CvSetElem*) (ptr = set->ptr);
+ for( ; ptr + elem_size <= set->block_max; ptr += elem_size, count++ )
+ {
+ ((CvSetElem*)ptr)->flags = count | CV_SET_ELEM_FREE_FLAG;
+ ((CvSetElem*)ptr)->next_free = (CvSetElem*)(ptr + elem_size);
+ }
+ assert( count <= CV_SET_ELEM_IDX_MASK+1 );
+ ((CvSetElem*)(ptr - elem_size))->next_free = 0;
+ set->first->prev->count += count - set->total;
+ set->total = count;
+ set->ptr = set->block_max;
+ }
+
+ free_elem = set->free_elems;
+ set->free_elems = free_elem->next_free;
+
+ id = free_elem->flags & CV_SET_ELEM_IDX_MASK;
+ if( element )
+ CV_MEMCPY_INT( free_elem, element, (size_t)set->elem_size/sizeof(int) );
+
+ free_elem->flags = id;
+ set->active_count++;
+
+ if( inserted_element )
+ *inserted_element = free_elem;
+
+ __END__;
+
+ return id;
+}
+
+
+/* Remove element from a set given element index: */
+CV_IMPL void
+cvSetRemove( CvSet* set, int index )
+{
+ CV_FUNCNAME( "cvSetRemove" );
+
+ __BEGIN__;
+
+ CvSetElem* elem = cvGetSetElem( set, index );
+ if( elem )
+ cvSetRemoveByPtr( set, elem );
+ else if( !set )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ __END__;
+}
+
+
+/* Remove all elements from a set: */
+CV_IMPL void
+cvClearSet( CvSet* set )
+{
+ CV_FUNCNAME( "cvClearSet" );
+
+ __BEGIN__;
+
+ CV_CALL( cvClearSeq( (CvSeq*)set ));
+ set->free_elems = 0;
+ set->active_count = 0;
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* Graph implementation *
+\****************************************************************************************/
+
+/* Create a new graph: */
+CV_IMPL CvGraph *
+cvCreateGraph( int graph_type, int header_size,
+ int vtx_size, int edge_size, CvMemStorage * storage )
+{
+ CvGraph *graph = 0;
+ CvSet *edges = 0;
+
+ CV_FUNCNAME( "cvCleateGraph" );
+
+ __BEGIN__;
+
+ CvSet *vertices = 0;
+
+ if( header_size < (int) sizeof( CvGraph )
+ || edge_size < (int) sizeof( CvGraphEdge )
+ || vtx_size < (int) sizeof( CvGraphVtx )
+ ){
+ CV_ERROR( CV_StsBadSize, "" );
+ }
+
+ CV_CALL( vertices = cvCreateSet( graph_type, header_size, vtx_size, storage ));
+ CV_CALL( edges = cvCreateSet( CV_SEQ_KIND_GENERIC | CV_SEQ_ELTYPE_GRAPH_EDGE,
+ sizeof( CvSet ), edge_size, storage ));
+
+ graph = (CvGraph*)vertices;
+ graph->edges = edges;
+
+ __END__;
+
+ return graph;
+}
+
+
+/* Remove all vertices and edges from a graph: */
+CV_IMPL void
+cvClearGraph( CvGraph * graph )
+{
+ CV_FUNCNAME( "cvClearGraph" );
+
+ __BEGIN__;
+
+ if( !graph )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ cvClearSet( graph->edges );
+ cvClearSet( (CvSet*)graph );
+
+ __END__;
+}
+
+
+/* Add a vertex to a graph: */
+CV_IMPL int
+cvGraphAddVtx( CvGraph* graph, const CvGraphVtx* _vertex, CvGraphVtx** _inserted_vertex )
+{
+ CvGraphVtx *vertex = 0;
+ int index = -1;
+
+ CV_FUNCNAME( "cvGraphAddVtx" );
+
+ __BEGIN__;
+
+ if( !graph )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ vertex = (CvGraphVtx*)cvSetNew((CvSet*)graph);
+ if( vertex )
+ {
+ if( _vertex )
+ CV_MEMCPY_INT( vertex + 1, _vertex + 1,
+ (size_t)(graph->elem_size - sizeof(CvGraphVtx))/sizeof(int) );
+ vertex->first = 0;
+ index = vertex->flags;
+ }
+
+ if( _inserted_vertex )
+ *_inserted_vertex = vertex;
+
+ __END__;
+
+ return index;
+}
+
+
+/* Remove a vertex from the graph together with its incident edges: */
+CV_IMPL int
+cvGraphRemoveVtxByPtr( CvGraph* graph, CvGraphVtx* vtx )
+{
+ int count = -1;
+
+ CV_FUNCNAME( "cvGraphRemoveVtxByPtr" );
+
+ __BEGIN__;
+
+ if( !graph || !vtx )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( !CV_IS_SET_ELEM(vtx))
+ CV_ERROR( CV_StsBadArg, "The vertex does not belong to the graph" );
+
+ count = graph->edges->active_count;
+ for( ;; )
+ {
+ CvGraphEdge *edge = vtx->first;
+ if( !edge )
+ break;
+ cvGraphRemoveEdgeByPtr( graph, edge->vtx[0], edge->vtx[1] );
+ }
+ count -= graph->edges->active_count;
+ cvSetRemoveByPtr( (CvSet*)graph, vtx );
+
+ __END__;
+
+ return count;
+}
+
+
+/* Remove a vertex from the graph together with its incident edges: */
+CV_IMPL int
+cvGraphRemoveVtx( CvGraph* graph, int index )
+{
+ int count = -1;
+ CvGraphVtx *vtx = 0;
+
+ CV_FUNCNAME( "cvGraphRemoveVtx" );
+
+ __BEGIN__;
+
+ if( !graph )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ vtx = cvGetGraphVtx( graph, index );
+ if( !vtx )
+ CV_ERROR( CV_StsBadArg, "The vertex is not found" );
+
+ count = graph->edges->active_count;
+ for( ;; )
+ {
+ CvGraphEdge *edge = vtx->first;
+ count++;
+
+ if( !edge )
+ break;
+ cvGraphRemoveEdgeByPtr( graph, edge->vtx[0], edge->vtx[1] );
+ }
+ count -= graph->edges->active_count;
+ cvSetRemoveByPtr( (CvSet*)graph, vtx );
+
+ __END__;
+
+ return count;
+}
+
+
+/* Find a graph edge given pointers to the ending vertices: */
+CV_IMPL CvGraphEdge*
+cvFindGraphEdgeByPtr( const CvGraph* graph,
+ const CvGraphVtx* start_vtx,
+ const CvGraphVtx* end_vtx )
+{
+ CvGraphEdge *edge = 0;
+ CV_FUNCNAME( "cvFindGraphEdgeByPtr" );
+
+ __BEGIN__;
+
+ int ofs = 0;
+
+ if( !graph || !start_vtx || !end_vtx )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( start_vtx == end_vtx )
+ EXIT;
+
+ if( !CV_IS_GRAPH_ORIENTED( graph ) &&
+ (start_vtx->flags & CV_SET_ELEM_IDX_MASK) > (end_vtx->flags & CV_SET_ELEM_IDX_MASK) )
+ {
+ const CvGraphVtx* t;
+ CV_SWAP( start_vtx, end_vtx, t );
+ }
+
+ edge = start_vtx->first;
+ for( ; edge; edge = edge->next[ofs] )
+ {
+ ofs = start_vtx == edge->vtx[1];
+ assert( ofs == 1 || start_vtx == edge->vtx[0] );
+ if( edge->vtx[1] == end_vtx )
+ break;
+ }
+
+ __END__;
+
+ return edge;
+}
+
+
+/* Find an edge in the graph given indices of the ending vertices: */
+CV_IMPL CvGraphEdge *
+cvFindGraphEdge( const CvGraph* graph, int start_idx, int end_idx )
+{
+ CvGraphEdge *edge = 0;
+ CvGraphVtx *start_vtx;
+ CvGraphVtx *end_vtx;
+
+ CV_FUNCNAME( "cvFindGraphEdge" );
+
+ __BEGIN__;
+
+ if( !graph )
+ CV_ERROR( CV_StsNullPtr, "graph pointer is NULL" );
+
+ start_vtx = cvGetGraphVtx( graph, start_idx );
+ end_vtx = cvGetGraphVtx( graph, end_idx );
+
+ edge = cvFindGraphEdgeByPtr( graph, start_vtx, end_vtx );
+
+ __END__;
+
+ return edge;
+}
+
+
+/* Given two vertices, return the edge
+ * connecting them, creating it if it
+ * did not already exist:
+ */
+CV_IMPL int
+cvGraphAddEdgeByPtr( CvGraph* graph,
+ CvGraphVtx* start_vtx, CvGraphVtx* end_vtx,
+ const CvGraphEdge* _edge,
+ CvGraphEdge ** _inserted_edge )
+{
+ CvGraphEdge *edge = 0;
+ int result = -1;
+
+ CV_FUNCNAME( "cvGraphAddEdgeByPtr" );
+
+ __BEGIN__;
+
+ int delta;
+
+ if( !graph )
+ CV_ERROR( CV_StsNullPtr, "graph pointer is NULL" );
+
+ if( !CV_IS_GRAPH_ORIENTED( graph ) &&
+ (start_vtx->flags & CV_SET_ELEM_IDX_MASK) > (end_vtx->flags & CV_SET_ELEM_IDX_MASK) )
+ {
+ CvGraphVtx* t;
+ CV_SWAP( start_vtx, end_vtx, t );
+ }
+
+ CV_CALL( edge = cvFindGraphEdgeByPtr( graph, start_vtx, end_vtx ));
+ if( edge )
+ {
+ result = 0;
+ EXIT;
+ }
+
+ if( start_vtx == end_vtx )
+ CV_ERROR( start_vtx ? CV_StsBadArg : CV_StsNullPtr,
+ "vertex pointers coinside (or set to NULL)" );
+
+ CV_CALL( edge = (CvGraphEdge*)cvSetNew( (CvSet*)(graph->edges) ));
+ assert( edge->flags >= 0 );
+
+ edge->vtx[0] = start_vtx;
+ edge->vtx[1] = end_vtx;
+ edge->next[0] = start_vtx->first;
+ edge->next[1] = end_vtx->first;
+ start_vtx->first = end_vtx->first = edge;
+
+ delta = (graph->edges->elem_size - sizeof(*edge))/sizeof(int);
+ if( _edge )
+ {
+ if( delta > 0 )
+ CV_MEMCPY_INT( edge + 1, _edge + 1, delta );
+ edge->weight = _edge->weight;
+ }
+ else
+ {
+ if( delta > 0 )
+ CV_ZERO_INT( edge + 1, delta );
+ edge->weight = 1.f;
+ }
+
+ result = 1;
+
+ __END__;
+
+ if( _inserted_edge )
+ *_inserted_edge = edge;
+
+ return result;
+}
+
+/* Given two vertices, return the edge
+ * connecting them, creating it if it
+ * did not already exist:
+ */
+CV_IMPL int
+cvGraphAddEdge( CvGraph* graph,
+ int start_idx, int end_idx,
+ const CvGraphEdge* _edge,
+ CvGraphEdge ** _inserted_edge )
+{
+ CvGraphVtx *start_vtx;
+ CvGraphVtx *end_vtx;
+ int result = -1;
+
+ CV_FUNCNAME( "cvGraphAddEdge" );
+
+ __BEGIN__;
+
+ if( !graph )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ start_vtx = cvGetGraphVtx( graph, start_idx );
+ end_vtx = cvGetGraphVtx( graph, end_idx );
+
+ result = cvGraphAddEdgeByPtr( graph, start_vtx, end_vtx, _edge, _inserted_edge );
+
+ __END__;
+
+ return result;
+}
+
+
+/* Remove the graph edge connecting two given vertices: */
+CV_IMPL void
+cvGraphRemoveEdgeByPtr( CvGraph* graph, CvGraphVtx* start_vtx, CvGraphVtx* end_vtx )
+{
+ CV_FUNCNAME( "cvGraphRemoveEdgeByPtr" );
+
+ __BEGIN__;
+
+ int ofs, prev_ofs;
+ CvGraphEdge *edge, *next_edge, *prev_edge;
+
+ if( !graph || !start_vtx || !end_vtx )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( start_vtx == end_vtx )
+ EXIT;
+
+ if( !CV_IS_GRAPH_ORIENTED( graph ) &&
+ (start_vtx->flags & CV_SET_ELEM_IDX_MASK) > (end_vtx->flags & CV_SET_ELEM_IDX_MASK) )
+ {
+ CvGraphVtx* t;
+ CV_SWAP( start_vtx, end_vtx, t );
+ }
+
+ for( ofs = prev_ofs = 0, prev_edge = 0, edge = start_vtx->first; edge != 0;
+ prev_ofs = ofs, prev_edge = edge, edge = edge->next[ofs] )
+ {
+ ofs = start_vtx == edge->vtx[1];
+ assert( ofs == 1 || start_vtx == edge->vtx[0] );
+ if( edge->vtx[1] == end_vtx )
+ break;
+ }
+
+ if( !edge )
+ EXIT;
+
+ next_edge = edge->next[ofs];
+ if( prev_edge )
+ prev_edge->next[prev_ofs] = next_edge;
+ else
+ start_vtx->first = next_edge;
+
+ for( ofs = prev_ofs = 0, prev_edge = 0, edge = end_vtx->first; edge != 0;
+ prev_ofs = ofs, prev_edge = edge, edge = edge->next[ofs] )
+ {
+ ofs = end_vtx == edge->vtx[1];
+ assert( ofs == 1 || end_vtx == edge->vtx[0] );
+ if( edge->vtx[0] == start_vtx )
+ break;
+ }
+
+ assert( edge != 0 );
+
+ next_edge = edge->next[ofs];
+ if( prev_edge )
+ prev_edge->next[prev_ofs] = next_edge;
+ else
+ end_vtx->first = next_edge;
+
+ cvSetRemoveByPtr( graph->edges, edge );
+
+ __END__;
+}
+
+
+/* Remove the graph edge connecting two given vertices: */
+CV_IMPL void
+cvGraphRemoveEdge( CvGraph* graph, int start_idx, int end_idx )
+{
+ CvGraphVtx *start_vtx;
+ CvGraphVtx *end_vtx;
+
+ CV_FUNCNAME( "cvGraphRemoveEdge" );
+
+ __BEGIN__;
+
+ if( !graph )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ start_vtx = cvGetGraphVtx( graph, start_idx );
+ end_vtx = cvGetGraphVtx( graph, end_idx );
+
+ cvGraphRemoveEdgeByPtr( graph, start_vtx, end_vtx );
+
+ __END__;
+}
+
+
+/* Count number of edges incident to a given vertex: */
+CV_IMPL int
+cvGraphVtxDegreeByPtr( const CvGraph* graph, const CvGraphVtx* vertex )
+{
+ CvGraphEdge *edge;
+ int count = -1;
+
+ CV_FUNCNAME( "cvGraphVtxDegreeByPtr" );
+
+ __BEGIN__;
+
+ if( !graph || !vertex )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ for( edge = vertex->first, count = 0; edge; )
+ {
+ count++;
+ edge = CV_NEXT_GRAPH_EDGE( edge, vertex );
+ }
+
+ __END__;
+
+ return count;
+}
+
+
+/* Count number of edges incident to a given vertex: */
+CV_IMPL int
+cvGraphVtxDegree( const CvGraph* graph, int vtx_idx )
+{
+ CvGraphVtx *vertex;
+ CvGraphEdge *edge;
+ int count = -1;
+
+ CV_FUNCNAME( "cvGraphVtxDegree" );
+
+ __BEGIN__;
+
+ if( !graph )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ vertex = cvGetGraphVtx( graph, vtx_idx );
+ if( !vertex )
+ CV_ERROR( CV_StsObjectNotFound, "" );
+
+ for( edge = vertex->first, count = 0; edge; )
+ {
+ count++;
+ edge = CV_NEXT_GRAPH_EDGE( edge, vertex );
+ }
+
+ __END__;
+
+ return count;
+}
+
+
+typedef struct CvGraphItem
+{
+ CvGraphVtx* vtx;
+ CvGraphEdge* edge;
+}
+CvGraphItem;
+
+
+static void
+icvSeqElemsClearFlags( CvSeq* seq, int offset, int clear_mask )
+{
+ CV_FUNCNAME("icvStartScanGraph");
+
+ __BEGIN__;
+
+ CvSeqReader reader;
+ int i, total, elem_size;
+
+ if( !seq )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ elem_size = seq->elem_size;
+ total = seq->total;
+
+ if( (unsigned)offset > (unsigned)elem_size )
+ CV_ERROR( CV_StsBadArg, "" );
+
+ CV_CALL( cvStartReadSeq( seq, &reader ));
+
+ for( i = 0; i < total; i++ )
+ {
+ int* flag_ptr = (int*)(reader.ptr + offset);
+ *flag_ptr &= ~clear_mask;
+
+ CV_NEXT_SEQ_ELEM( elem_size, reader );
+ }
+
+ __END__;
+}
+
+
+static schar*
+icvSeqFindNextElem( CvSeq* seq, int offset, int mask,
+ int value, int* start_index )
+{
+ schar* elem_ptr = 0;
+
+ CV_FUNCNAME("icvStartScanGraph");
+
+ __BEGIN__;
+
+ CvSeqReader reader;
+ int total, elem_size, index;
+
+ if( !seq || !start_index )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ elem_size = seq->elem_size;
+ total = seq->total;
+ index = *start_index;
+
+ if( (unsigned)offset > (unsigned)elem_size )
+ CV_ERROR( CV_StsBadArg, "" );
+
+ if( total == 0 )
+ EXIT;
+
+ if( (unsigned)index >= (unsigned)total )
+ {
+ index %= total;
+ index += index < 0 ? total : 0;
+ }
+
+ CV_CALL( cvStartReadSeq( seq, &reader ));
+
+ if( index != 0 )
+ CV_CALL( cvSetSeqReaderPos( &reader, index ));
+
+ for( index = 0; index < total; index++ )
+ {
+ int* flag_ptr = (int*)(reader.ptr + offset);
+ if( (*flag_ptr & mask) == value )
+ break;
+
+ CV_NEXT_SEQ_ELEM( elem_size, reader );
+ }
+
+ if( index < total )
+ {
+ elem_ptr = reader.ptr;
+ *start_index = index;
+ }
+
+ __END__;
+
+ return elem_ptr;
+}
+
+#define CV_FIELD_OFFSET( field, structtype ) ((int)(size_t)&((structtype*)0)->field)
+
+CV_IMPL CvGraphScanner*
+cvCreateGraphScanner( CvGraph* graph, CvGraphVtx* vtx, int mask )
+{
+ CvGraphScanner* scanner = 0;
+ CvMemStorage* child_storage = 0;
+
+ CV_FUNCNAME("cvCreateGraphScanner");
+
+ __BEGIN__;
+
+ if( !graph )
+ CV_ERROR( CV_StsNullPtr, "Null graph pointer" );
+
+ CV_ASSERT( graph->storage != 0 );
+
+ CV_CALL( scanner = (CvGraphScanner*)cvAlloc( sizeof(*scanner) ));
+ memset( scanner, 0, sizeof(*scanner));
+
+ scanner->graph = graph;
+ scanner->mask = mask;
+ scanner->vtx = vtx;
+ scanner->index = vtx == 0 ? 0 : -1;
+
+ CV_CALL( child_storage = cvCreateChildMemStorage( graph->storage ));
+
+ CV_CALL( scanner->stack = cvCreateSeq( 0, sizeof(CvSet),
+ sizeof(CvGraphItem), child_storage ));
+
+ CV_CALL( icvSeqElemsClearFlags( (CvSeq*)graph,
+ CV_FIELD_OFFSET( flags, CvGraphVtx),
+ CV_GRAPH_ITEM_VISITED_FLAG|
+ CV_GRAPH_SEARCH_TREE_NODE_FLAG ));
+
+ CV_CALL( icvSeqElemsClearFlags( (CvSeq*)(graph->edges),
+ CV_FIELD_OFFSET( flags, CvGraphEdge),
+ CV_GRAPH_ITEM_VISITED_FLAG ));
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ {
+ cvReleaseMemStorage( &child_storage );
+ cvFree( &scanner );
+ }
+
+ return scanner;
+}
+
+
+CV_IMPL void
+cvReleaseGraphScanner( CvGraphScanner** scanner )
+{
+ CV_FUNCNAME("cvReleaseGraphScanner");
+
+ __BEGIN__;
+
+ if( !scanner )
+ CV_ERROR( CV_StsNullPtr, "Null double pointer to graph scanner" );
+
+ if( *scanner )
+ {
+ if( (*scanner)->stack )
+ CV_CALL( cvReleaseMemStorage( &((*scanner)->stack->storage)));
+ cvFree( scanner );
+ }
+
+ __END__;
+}
+
+
+CV_IMPL int
+cvNextGraphItem( CvGraphScanner* scanner )
+{
+ int code = -1;
+
+ CV_FUNCNAME("cvNextGraphItem");
+
+ __BEGIN__;
+
+ CvGraphVtx* vtx;
+ CvGraphVtx* dst;
+ CvGraphEdge* edge;
+ CvGraphItem item;
+
+ if( !scanner || !(scanner->stack))
+ CV_ERROR( CV_StsNullPtr, "Null graph scanner" );
+
+ dst = scanner->dst;
+ vtx = scanner->vtx;
+ edge = scanner->edge;
+
+ for(;;)
+ {
+ for(;;)
+ {
+ if( dst && !CV_IS_GRAPH_VERTEX_VISITED(dst) )
+ {
+ scanner->vtx = vtx = dst;
+ edge = vtx->first;
+ dst->flags |= CV_GRAPH_ITEM_VISITED_FLAG;
+
+ if((scanner->mask & CV_GRAPH_VERTEX))
+ {
+ scanner->vtx = vtx;
+ scanner->edge = vtx->first;
+ scanner->dst = 0;
+ code = CV_GRAPH_VERTEX;
+ EXIT;
+ }
+ }
+
+ while( edge )
+ {
+ dst = edge->vtx[vtx == edge->vtx[0]];
+
+ if( !CV_IS_GRAPH_EDGE_VISITED(edge) )
+ {
+ // Check that the edge is outgoing:
+ if( !CV_IS_GRAPH_ORIENTED( scanner->graph ) || dst != edge->vtx[0] )
+ {
+ edge->flags |= CV_GRAPH_ITEM_VISITED_FLAG;
+
+ if( !CV_IS_GRAPH_VERTEX_VISITED(dst) )
+ {
+ item.vtx = vtx;
+ item.edge = edge;
+
+ vtx->flags |= CV_GRAPH_SEARCH_TREE_NODE_FLAG;
+
+ cvSeqPush( scanner->stack, &item );
+
+ if( scanner->mask & CV_GRAPH_TREE_EDGE )
+ {
+ code = CV_GRAPH_TREE_EDGE;
+ scanner->vtx = vtx;
+ scanner->dst = dst;
+ scanner->edge = edge;
+ EXIT;
+ }
+ break;
+ }
+ else
+ {
+ if( scanner->mask & (CV_GRAPH_BACK_EDGE|
+ CV_GRAPH_CROSS_EDGE|
+ CV_GRAPH_FORWARD_EDGE) )
+ {
+ code = (dst->flags & CV_GRAPH_SEARCH_TREE_NODE_FLAG) ?
+ CV_GRAPH_BACK_EDGE :
+ (edge->flags & CV_GRAPH_FORWARD_EDGE_FLAG) ?
+ CV_GRAPH_FORWARD_EDGE : CV_GRAPH_CROSS_EDGE;
+ edge->flags &= ~CV_GRAPH_FORWARD_EDGE_FLAG;
+ if( scanner->mask & code )
+ {
+ scanner->vtx = vtx;
+ scanner->dst = dst;
+ scanner->edge = edge;
+ EXIT;
+ }
+ }
+ }
+ }
+ else if( (dst->flags & (CV_GRAPH_ITEM_VISITED_FLAG|
+ CV_GRAPH_SEARCH_TREE_NODE_FLAG)) ==
+ (CV_GRAPH_ITEM_VISITED_FLAG|
+ CV_GRAPH_SEARCH_TREE_NODE_FLAG))
+ {
+ edge->flags |= CV_GRAPH_FORWARD_EDGE_FLAG;
+ }
+ }
+
+ edge = CV_NEXT_GRAPH_EDGE( edge, vtx );
+ }
+
+ if( !edge ) /* need to backtrack */
+ {
+ if( scanner->stack->total == 0 )
+ {
+ if( scanner->index >= 0 )
+ vtx = 0;
+ else
+ scanner->index = 0;
+ break;
+ }
+ cvSeqPop( scanner->stack, &item );
+ vtx = item.vtx;
+ vtx->flags &= ~CV_GRAPH_SEARCH_TREE_NODE_FLAG;
+ edge = item.edge;
+ dst = 0;
+
+ if( scanner->mask & CV_GRAPH_BACKTRACKING )
+ {
+ scanner->vtx = vtx;
+ scanner->edge = edge;
+ scanner->dst = edge->vtx[vtx == edge->vtx[0]];
+ code = CV_GRAPH_BACKTRACKING;
+ EXIT;
+ }
+ }
+ }
+
+ if( !vtx )
+ {
+ vtx = (CvGraphVtx*)icvSeqFindNextElem( (CvSeq*)(scanner->graph),
+ CV_FIELD_OFFSET( flags, CvGraphVtx ), CV_GRAPH_ITEM_VISITED_FLAG|INT_MIN,
+ 0, &(scanner->index) );
+
+ if( !vtx )
+ {
+ code = CV_GRAPH_OVER;
+ break;
+ }
+ }
+
+ dst = vtx;
+ if( scanner->mask & CV_GRAPH_NEW_TREE )
+ {
+ scanner->dst = dst;
+ scanner->edge = 0;
+ scanner->vtx = 0;
+ code = CV_GRAPH_NEW_TREE;
+ break;
+ }
+ }
+
+ __END__;
+
+ return code;
+}
+
+
+CV_IMPL CvGraph*
+cvCloneGraph( const CvGraph* graph, CvMemStorage* storage )
+{
+ int* flag_buffer = 0;
+ CvGraphVtx** ptr_buffer = 0;
+ CvGraph* result = 0;
+
+ CV_FUNCNAME( "cvCloneGraph" );
+
+ __BEGIN__;
+
+ int i, k;
+ int vtx_size, edge_size;
+ CvSeqReader reader;
+
+ if( !CV_IS_GRAPH(graph))
+ CV_ERROR( CV_StsBadArg, "Invalid graph pointer" );
+
+ if( !storage )
+ storage = graph->storage;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "NULL storage pointer" );
+
+ vtx_size = graph->elem_size;
+ edge_size = graph->edges->elem_size;
+
+ CV_CALL( flag_buffer = (int*)cvAlloc( graph->total*sizeof(flag_buffer[0])));
+ CV_CALL( ptr_buffer = (CvGraphVtx**)cvAlloc( graph->total*sizeof(ptr_buffer[0])));
+ CV_CALL( result = cvCreateGraph( graph->flags, graph->header_size,
+ vtx_size, edge_size, storage ));
+ memcpy( result + sizeof(CvGraph), graph + sizeof(CvGraph),
+ graph->header_size - sizeof(CvGraph));
+
+ // Pass 1. Save flags, copy vertices:
+ cvStartReadSeq( (CvSeq*)graph, &reader );
+ for( i = 0, k = 0; i < graph->total; i++ )
+ {
+ if( CV_IS_SET_ELEM( reader.ptr ))
+ {
+ CvGraphVtx* vtx = (CvGraphVtx*)reader.ptr;
+ CvGraphVtx* dstvtx = 0;
+ CV_CALL( cvGraphAddVtx( result, vtx, &dstvtx ));
+ flag_buffer[k] = dstvtx->flags = vtx->flags;
+ vtx->flags = k;
+ ptr_buffer[k++] = dstvtx;
+ }
+ CV_NEXT_SEQ_ELEM( vtx_size, reader );
+ }
+
+ // Pass 2. Copy edges:
+ cvStartReadSeq( (CvSeq*)graph->edges, &reader );
+ for( i = 0; i < graph->edges->total; i++ )
+ {
+ if( CV_IS_SET_ELEM( reader.ptr ))
+ {
+ CvGraphEdge* edge = (CvGraphEdge*)reader.ptr;
+ CvGraphEdge* dstedge = 0;
+ CvGraphVtx* new_org = ptr_buffer[edge->vtx[0]->flags];
+ CvGraphVtx* new_dst = ptr_buffer[edge->vtx[1]->flags];
+ CV_CALL( cvGraphAddEdgeByPtr( result, new_org, new_dst, edge, &dstedge ));
+ dstedge->flags = edge->flags;
+ }
+ CV_NEXT_SEQ_ELEM( edge_size, reader );
+ }
+
+ // Pass 3. Restore flags:
+ cvStartReadSeq( (CvSeq*)graph, &reader );
+ for( i = 0, k = 0; i < graph->edges->total; i++ )
+ {
+ if( CV_IS_SET_ELEM( reader.ptr ))
+ {
+ CvGraphVtx* vtx = (CvGraphVtx*)reader.ptr;
+ vtx->flags = flag_buffer[k++];
+ }
+ CV_NEXT_SEQ_ELEM( vtx_size, reader );
+ }
+
+ __END__;
+
+ cvFree( &flag_buffer );
+ cvFree( &ptr_buffer );
+
+ if( cvGetErrStatus() < 0 )
+ result = 0;
+
+ return result;
+}
+
+
+/****************************************************************************************\
+* Working with sequence tree *
+\****************************************************************************************/
+
+// Gather pointers to all the sequences, accessible from the <first>, to the single sequence.
+CV_IMPL CvSeq*
+cvTreeToNodeSeq( const void* first, int header_size, CvMemStorage* storage )
+{
+ CvSeq* allseq = 0;
+
+ CV_FUNCNAME("cvTreeToNodeSeq");
+
+ __BEGIN__;
+
+ CvTreeNodeIterator iterator;
+
+ if( !storage )
+ CV_ERROR( CV_StsNullPtr, "NULL storage pointer" );
+
+ CV_CALL( allseq = cvCreateSeq( 0, header_size, sizeof(first), storage ));
+
+ if( first )
+ {
+ CV_CALL( cvInitTreeNodeIterator( &iterator, first, INT_MAX ));
+
+ for(;;)
+ {
+ void* node = cvNextTreeNode( &iterator );
+ if( !node )
+ break;
+ cvSeqPush( allseq, &node );
+ }
+ }
+
+ __END__;
+
+ return allseq;
+}
+
+
+typedef struct CvTreeNode
+{
+ int flags; /* micsellaneous flags */
+ int header_size; /* size of sequence header */
+ struct CvTreeNode* h_prev; /* previous sequence */
+ struct CvTreeNode* h_next; /* next sequence */
+ struct CvTreeNode* v_prev; /* 2nd previous sequence */
+ struct CvTreeNode* v_next; /* 2nd next sequence */
+}
+CvTreeNode;
+
+
+
+// Insert contour into tree given certain parent sequence.
+// If parent is equal to frame (the most external contour),
+// then added contour will have null pointer to parent:
+CV_IMPL void
+cvInsertNodeIntoTree( void* _node, void* _parent, void* _frame )
+{
+ CV_FUNCNAME( "cvInsertNodeIntoTree" );
+
+ __BEGIN__;
+
+ CvTreeNode* node = (CvTreeNode*)_node;
+ CvTreeNode* parent = (CvTreeNode*)_parent;
+
+ if( !node || !parent )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ node->v_prev = _parent != _frame ? parent : 0;
+ node->h_next = parent->v_next;
+
+ assert( parent->v_next != node );
+
+ if( parent->v_next )
+ parent->v_next->h_prev = node;
+ parent->v_next = node;
+
+ __END__;
+}
+
+
+// Remove contour from tree, together with the contour's children:
+CV_IMPL void
+cvRemoveNodeFromTree( void* _node, void* _frame )
+{
+ CV_FUNCNAME( "cvRemoveNodeFromTree" );
+
+ __BEGIN__;
+
+ CvTreeNode* node = (CvTreeNode*)_node;
+ CvTreeNode* frame = (CvTreeNode*)_frame;
+
+ if( !node )
+ CV_ERROR_FROM_CODE( CV_StsNullPtr );
+
+ if( node == frame )
+ CV_ERROR( CV_StsBadArg, "frame node could not be deleted" );
+
+ if( node->h_next )
+ node->h_next->h_prev = node->h_prev;
+
+ if( node->h_prev )
+ node->h_prev->h_next = node->h_next;
+ else
+ {
+ CvTreeNode* parent = node->v_prev;
+ if( !parent )
+ parent = frame;
+
+ if( parent )
+ {
+ assert( parent->v_next == node );
+ parent->v_next = node->h_next;
+ }
+ }
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvInitTreeNodeIterator( CvTreeNodeIterator* treeIterator,
+ const void* first, int max_level )
+{
+ CV_FUNCNAME("icvInitTreeNodeIterator");
+
+ __BEGIN__;
+
+ if( !treeIterator || !first )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( max_level < 0 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ treeIterator->node = (void*)first;
+ treeIterator->level = 0;
+ treeIterator->max_level = max_level;
+
+ __END__;
+}
+
+
+CV_IMPL void*
+cvNextTreeNode( CvTreeNodeIterator* treeIterator )
+{
+ CvTreeNode* prevNode = 0;
+
+ CV_FUNCNAME("cvNextTreeNode");
+
+ __BEGIN__;
+
+ CvTreeNode* node;
+ int level;
+
+ if( !treeIterator )
+ CV_ERROR( CV_StsNullPtr, "NULL iterator pointer" );
+
+ prevNode = node = (CvTreeNode*)treeIterator->node;
+ level = treeIterator->level;
+
+ if( node )
+ {
+ if( node->v_next && level+1 < treeIterator->max_level )
+ {
+ node = node->v_next;
+ level++;
+ }
+ else
+ {
+ while( node->h_next == 0 )
+ {
+ node = node->v_prev;
+ if( --level < 0 )
+ {
+ node = 0;
+ break;
+ }
+ }
+ node = node && treeIterator->max_level != 0 ? node->h_next : 0;
+ }
+ }
+
+ treeIterator->node = node;
+ treeIterator->level = level;
+
+ __END__;
+
+ return prevNode;
+}
+
+
+CV_IMPL void*
+cvPrevTreeNode( CvTreeNodeIterator* treeIterator )
+{
+ CvTreeNode* prevNode = 0;
+
+ CV_FUNCNAME("cvPrevTreeNode");
+
+ __BEGIN__;
+
+ CvTreeNode* node;
+ int level;
+
+ if( !treeIterator )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ prevNode = node = (CvTreeNode*)treeIterator->node;
+ level = treeIterator->level;
+
+ if( node )
+ {
+ if( !node->h_prev )
+ {
+ node = node->v_prev;
+ if( --level < 0 )
+ node = 0;
+ }
+ else
+ {
+ node = node->h_prev;
+
+ while( node->v_next && level < treeIterator->max_level )
+ {
+ node = node->v_next;
+ level++;
+
+ while( node->h_next )
+ node = node->h_next;
+ }
+ }
+ }
+
+ treeIterator->node = node;
+ treeIterator->level = level;
+
+ __END__;
+
+ return prevNode;
+}
+
+/* End of file. */
diff --git a/cxcore/src/cxdrawing.cpp b/cxcore/src/cxdrawing.cpp
new file mode 100644
index 0000000..ecbe22e
--- /dev/null
+++ b/cxcore/src/cxdrawing.cpp
@@ -0,0 +1,2597 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "_cxcore.h"
+
+#define XY_SHIFT 16
+#define XY_ONE (1 << XY_SHIFT)
+
+#define CV_DRAWING_STORAGE_BLOCK ((1 << 12) - 256)
+
+typedef struct CvPolyEdge
+{
+ int x, dx;
+ union
+ {
+ struct CvPolyEdge *next;
+ int y0;
+ };
+ int y1;
+}
+CvPolyEdge;
+
+static void
+icvCollectPolyEdges( CvMat* img, CvSeq* v, CvContour* edges,
+ const void* color, int line_type,
+ int shift, CvPoint offset=cvPoint(0,0) );
+
+static void
+icvFillEdgeCollection( CvMat* img, CvContour* edges, const void* color );
+
+static void
+icvPolyLine( CvMat* img, CvPoint *v, int count, int closed,
+ const void* color, int thickness, int line_type, int shift );
+
+static void
+icvFillConvexPoly( CvMat* img, CvPoint* v, int npts,
+ const void* color, int line_type, int shift );
+
+/****************************************************************************************\
+* Lines *
+\****************************************************************************************/
+
+CV_IMPL int
+cvClipLine( CvSize img_size, CvPoint* pt1, CvPoint* pt2 )
+{
+ int result = 0;
+
+ CV_FUNCNAME( "cvClipLine" );
+
+ __BEGIN__;
+
+ int x1, y1, x2, y2;
+ int c1, c2;
+ int right = img_size.width-1, bottom = img_size.height-1;
+
+ if( !pt1 || !pt2 )
+ CV_ERROR( CV_StsNullPtr, "One of point pointers is NULL" );
+
+ if( right < 0 || bottom < 0 )
+ CV_ERROR( CV_StsOutOfRange, "Image width or height are negative" );
+
+ x1 = pt1->x; y1 = pt1->y; x2 = pt2->x; y2 = pt2->y;
+ c1 = (x1 < 0) + (x1 > right) * 2 + (y1 < 0) * 4 + (y1 > bottom) * 8;
+ c2 = (x2 < 0) + (x2 > right) * 2 + (y2 < 0) * 4 + (y2 > bottom) * 8;
+
+ if( (c1 & c2) == 0 && (c1 | c2) != 0 )
+ {
+ int a;
+
+ if( c1 & 12 )
+ {
+ a = c1 < 8 ? 0 : bottom;
+ x1 += (int) (((int64) (a - y1)) * (x2 - x1) / (y2 - y1));
+ y1 = a;
+ c1 = (x1 < 0) + (x1 > right) * 2;
+ }
+ if( c2 & 12 )
+ {
+ a = c2 < 8 ? 0 : bottom;
+ x2 += (int) (((int64) (a - y2)) * (x2 - x1) / (y2 - y1));
+ y2 = a;
+ c2 = (x2 < 0) + (x2 > right) * 2;
+ }
+ if( (c1 & c2) == 0 && (c1 | c2) != 0 )
+ {
+ if( c1 )
+ {
+ a = c1 == 1 ? 0 : right;
+ y1 += (int) (((int64) (a - x1)) * (y2 - y1) / (x2 - x1));
+ x1 = a;
+ c1 = 0;
+ }
+ if( c2 )
+ {
+ a = c2 == 1 ? 0 : right;
+ y2 += (int) (((int64) (a - x2)) * (y2 - y1) / (x2 - x1));
+ x2 = a;
+ c2 = 0;
+ }
+ }
+
+ assert( (c1 & c2) != 0 || (x1 | y1 | x2 | y2) >= 0 );
+
+ pt1->x = x1;
+ pt1->y = y1;
+ pt2->x = x2;
+ pt2->y = y2;
+ }
+
+ result = ( c1 | c2 ) == 0;
+
+ __END__;
+
+ return result;
+}
+
+
+/*
+ Initializes line iterator.
+ Returns number of points on the line or negative number if error.
+*/
+CV_IMPL int
+cvInitLineIterator( const CvArr* img, CvPoint pt1, CvPoint pt2,
+ CvLineIterator* iterator, int connectivity,
+ int left_to_right )
+{
+ int count = -1;
+
+ CV_FUNCNAME( "cvInitLineIterator" );
+
+ __BEGIN__;
+
+ CvMat stub, *mat = (CvMat*)img;
+ int dx, dy, s;
+ int bt_pix, bt_pix0, step;
+
+ if( !CV_IS_MAT(mat) )
+ CV_CALL( mat = cvGetMat( mat, &stub ));
+
+ if( !iterator )
+ CV_ERROR( CV_StsNullPtr, "Pointer to the iterator state is NULL" );
+
+ if( connectivity != 8 && connectivity != 4 )
+ CV_ERROR( CV_StsBadArg, "Connectivity must be 8 or 4" );
+
+ if( (unsigned)pt1.x >= (unsigned)(mat->width) ||
+ (unsigned)pt2.x >= (unsigned)(mat->width) ||
+ (unsigned)pt1.y >= (unsigned)(mat->height) ||
+ (unsigned)pt2.y >= (unsigned)(mat->height) )
+ CV_ERROR( CV_StsBadPoint,
+ "One of the ending points is outside of the image, use cvClipLine" );
+
+ bt_pix0 = bt_pix = CV_ELEM_SIZE(mat->type);
+ step = mat->step;
+
+ dx = pt2.x - pt1.x;
+ dy = pt2.y - pt1.y;
+ s = dx < 0 ? -1 : 0;
+
+ if( left_to_right )
+ {
+ dx = (dx ^ s) - s;
+ dy = (dy ^ s) - s;
+ pt1.x ^= (pt1.x ^ pt2.x) & s;
+ pt1.y ^= (pt1.y ^ pt2.y) & s;
+ }
+ else
+ {
+ dx = (dx ^ s) - s;
+ bt_pix = (bt_pix ^ s) - s;
+ }
+
+ iterator->ptr = (uchar*)(mat->data.ptr + pt1.y * step + pt1.x * bt_pix0);
+
+ s = dy < 0 ? -1 : 0;
+ dy = (dy ^ s) - s;
+ step = (step ^ s) - s;
+
+ s = dy > dx ? -1 : 0;
+
+ /* conditional swaps */
+ dx ^= dy & s;
+ dy ^= dx & s;
+ dx ^= dy & s;
+
+ bt_pix ^= step & s;
+ step ^= bt_pix & s;
+ bt_pix ^= step & s;
+
+ if( connectivity == 8 )
+ {
+ assert( dx >= 0 && dy >= 0 );
+
+ iterator->err = dx - (dy + dy);
+ iterator->plus_delta = dx + dx;
+ iterator->minus_delta = -(dy + dy);
+ iterator->plus_step = step;
+ iterator->minus_step = bt_pix;
+ count = dx + 1;
+ }
+ else /* connectivity == 4 */
+ {
+ assert( dx >= 0 && dy >= 0 );
+
+ iterator->err = 0;
+ iterator->plus_delta = (dx + dx) + (dy + dy);
+ iterator->minus_delta = -(dy + dy);
+ iterator->plus_step = step - bt_pix;
+ iterator->minus_step = bt_pix;
+ count = dx + dy + 1;
+ }
+
+ __END__;
+
+ return count;
+}
+
+static void
+icvLine( CvMat* mat, CvPoint pt1, CvPoint pt2,
+ const void* color, int connectivity = 8 )
+{
+ if( cvClipLine( cvGetMatSize(mat), &pt1, &pt2 ))
+ {
+ CvLineIterator iterator;
+ int pix_size = CV_ELEM_SIZE(mat->type);
+ int i, count;
+
+ if( connectivity == 0 )
+ connectivity = 8;
+ if( connectivity == 1 )
+ connectivity = 4;
+
+ count = cvInitLineIterator( mat, pt1, pt2, &iterator, connectivity, 1 );
+
+ for( i = 0; i < count; i++ )
+ {
+ CV_MEMCPY_AUTO( iterator.ptr, color, pix_size );
+ CV_NEXT_LINE_POINT( iterator );
+ }
+ }
+}
+
+
+/* Correction table depent on the slope */
+static const uchar icvSlopeCorrTable[] = {
+ 181, 181, 181, 182, 182, 183, 184, 185, 187, 188, 190, 192, 194, 196, 198, 201,
+ 203, 206, 209, 211, 214, 218, 221, 224, 227, 231, 235, 238, 242, 246, 250, 254
+};
+
+/* Gaussian for antialiasing filter */
+static const int icvFilterTable[] = {
+ 168, 177, 185, 194, 202, 210, 218, 224, 231, 236, 241, 246, 249, 252, 254, 254,
+ 254, 254, 252, 249, 246, 241, 236, 231, 224, 218, 210, 202, 194, 185, 177, 168,
+ 158, 149, 140, 131, 122, 114, 105, 97, 89, 82, 75, 68, 62, 56, 50, 45,
+ 40, 36, 32, 28, 25, 22, 19, 16, 14, 12, 11, 9, 8, 7, 5, 5
+};
+
+static void
+icvLineAA( CvMat* img, CvPoint pt1, CvPoint pt2,
+ const void* color )
+{
+ int dx, dy;
+ int ecount, scount = 0;
+ int slope;
+ int ax, ay;
+ int x_step, y_step;
+ int i, j;
+ int ep_table[9];
+ int cb = ((uchar*)color)[0], cg = ((uchar*)color)[1], cr = ((uchar*)color)[2];
+ int _cb, _cg, _cr;
+ int nch = CV_MAT_CN( img->type );
+ uchar* ptr = (uchar*)(img->data.ptr);
+ int step = img->step;
+ CvSize size = cvGetMatSize( img );
+
+ assert( img && (nch == 1 || nch == 3) && CV_MAT_DEPTH(img->type) == CV_8U );
+
+ pt1.x -= XY_ONE*2;
+ pt1.y -= XY_ONE*2;
+ pt2.x -= XY_ONE*2;
+ pt2.y -= XY_ONE*2;
+ ptr += img->step*2 + 2*nch;
+
+ size.width = ((size.width - 5) << XY_SHIFT) + 1;
+ size.height = ((size.height - 5) << XY_SHIFT) + 1;
+
+ if( !cvClipLine( size, &pt1, &pt2 ))
+ return;
+
+ dx = pt2.x - pt1.x;
+ dy = pt2.y - pt1.y;
+
+ j = dx < 0 ? -1 : 0;
+ ax = (dx ^ j) - j;
+ i = dy < 0 ? -1 : 0;
+ ay = (dy ^ i) - i;
+
+ if( ax > ay )
+ {
+ dx = ax;
+ dy = (dy ^ j) - j;
+ pt1.x ^= pt2.x & j;
+ pt2.x ^= pt1.x & j;
+ pt1.x ^= pt2.x & j;
+ pt1.y ^= pt2.y & j;
+ pt2.y ^= pt1.y & j;
+ pt1.y ^= pt2.y & j;
+
+ x_step = XY_ONE;
+ y_step = (int) (((int64) dy << XY_SHIFT) / (ax | 1));
+ pt2.x += XY_ONE;
+ ecount = (pt2.x >> XY_SHIFT) - (pt1.x >> XY_SHIFT);
+ j = -(pt1.x & (XY_ONE - 1));
+ pt1.y += (int) ((((int64) y_step) * j) >> XY_SHIFT) + (XY_ONE >> 1);
+ slope = (y_step >> (XY_SHIFT - 5)) & 0x3f;
+ slope ^= (y_step < 0 ? 0x3f : 0);
+
+ /* Get 4-bit fractions for end-point adjustments */
+ i = (pt1.x >> (XY_SHIFT - 7)) & 0x78;
+ j = (pt2.x >> (XY_SHIFT - 7)) & 0x78;
+ }
+ else
+ {
+ dy = ay;
+ dx = (dx ^ i) - i;
+ pt1.x ^= pt2.x & i;
+ pt2.x ^= pt1.x & i;
+ pt1.x ^= pt2.x & i;
+ pt1.y ^= pt2.y & i;
+ pt2.y ^= pt1.y & i;
+ pt1.y ^= pt2.y & i;
+
+ x_step = (int) (((int64) dx << XY_SHIFT) / (ay | 1));
+ y_step = XY_ONE;
+ pt2.y += XY_ONE;
+ ecount = (pt2.y >> XY_SHIFT) - (pt1.y >> XY_SHIFT);
+ j = -(pt1.y & (XY_ONE - 1));
+ pt1.x += (int) ((((int64) x_step) * j) >> XY_SHIFT) + (XY_ONE >> 1);
+ slope = (x_step >> (XY_SHIFT - 5)) & 0x3f;
+ slope ^= (x_step < 0 ? 0x3f : 0);
+
+ /* Get 4-bit fractions for end-point adjustments */
+ i = (pt1.y >> (XY_SHIFT - 7)) & 0x78;
+ j = (pt2.y >> (XY_SHIFT - 7)) & 0x78;
+ }
+
+ slope = (slope & 0x20) ? 0x100 : icvSlopeCorrTable[slope];
+
+ /* Calc end point correction table */
+ {
+ int t0 = slope << 7;
+ int t1 = ((0x78 - i) | 4) * slope;
+ int t2 = (j | 4) * slope;
+
+ ep_table[0] = 0;
+ ep_table[8] = slope;
+ ep_table[1] = ep_table[3] = ((((j - i) & 0x78) | 4) * slope >> 8) & 0x1ff;
+ ep_table[2] = (t1 >> 8) & 0x1ff;
+ ep_table[4] = ((((j - i) + 0x80) | 4) * slope >> 8) & 0x1ff;
+ ep_table[5] = ((t1 + t0) >> 8) & 0x1ff;
+ ep_table[6] = (t2 >> 8) & 0x1ff;
+ ep_table[7] = ((t2 + t0) >> 8) & 0x1ff;
+ }
+
+ if( nch == 3 )
+ {
+ #define ICV_PUT_POINT() \
+ { \
+ _cb = tptr[0]; \
+ _cb += ((cb - _cb)*a + 127)>> 8;\
+ _cg = tptr[1]; \
+ _cg += ((cg - _cg)*a + 127)>> 8;\
+ _cr = tptr[2]; \
+ _cr += ((cr - _cr)*a + 127)>> 8;\
+ tptr[0] = (uchar)_cb; \
+ tptr[1] = (uchar)_cg; \
+ tptr[2] = (uchar)_cr; \
+ }
+ if( ax > ay )
+ {
+ ptr += (pt1.x >> XY_SHIFT) * 3;
+
+ while( ecount >= 0 )
+ {
+ uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step;
+
+ int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
+ (((ecount >= 2) + 1) & (ecount | 2))];
+ int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31;
+
+ a = (ep_corr * icvFilterTable[dist + 32] >> 8) & 0xff;
+ ICV_PUT_POINT();
+ ICV_PUT_POINT();
+
+ tptr += step;
+ a = (ep_corr * icvFilterTable[dist] >> 8) & 0xff;
+ ICV_PUT_POINT();
+ ICV_PUT_POINT();
+
+ tptr += step;
+ a = (ep_corr * icvFilterTable[63 - dist] >> 8) & 0xff;
+ ICV_PUT_POINT();
+ ICV_PUT_POINT();
+
+ pt1.y += y_step;
+ ptr += 3;
+ scount++;
+ ecount--;
+ }
+ }
+ else
+ {
+ ptr += (pt1.y >> XY_SHIFT) * step;
+
+ while( ecount >= 0 )
+ {
+ uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1) * 3;
+
+ int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
+ (((ecount >= 2) + 1) & (ecount | 2))];
+ int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31;
+
+ a = (ep_corr * icvFilterTable[dist + 32] >> 8) & 0xff;
+ ICV_PUT_POINT();
+ ICV_PUT_POINT();
+
+ tptr += 3;
+ a = (ep_corr * icvFilterTable[dist] >> 8) & 0xff;
+ ICV_PUT_POINT();
+ ICV_PUT_POINT();
+
+ tptr += 3;
+ a = (ep_corr * icvFilterTable[63 - dist] >> 8) & 0xff;
+ ICV_PUT_POINT();
+ ICV_PUT_POINT();
+
+ pt1.x += x_step;
+ ptr += step;
+ scount++;
+ ecount--;
+ }
+ }
+ #undef ICV_PUT_POINT
+ }
+ else
+ {
+ #define ICV_PUT_POINT() \
+ { \
+ _cb = tptr[0]; \
+ _cb += ((cb - _cb)*a + 127)>> 8;\
+ tptr[0] = (uchar)_cb; \
+ }
+
+ if( ax > ay )
+ {
+ ptr += (pt1.x >> XY_SHIFT);
+
+ while( ecount >= 0 )
+ {
+ uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step;
+
+ int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
+ (((ecount >= 2) + 1) & (ecount | 2))];
+ int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31;
+
+ a = (ep_corr * icvFilterTable[dist + 32] >> 8) & 0xff;
+ ICV_PUT_POINT();
+ ICV_PUT_POINT();
+
+ tptr += step;
+ a = (ep_corr * icvFilterTable[dist] >> 8) & 0xff;
+ ICV_PUT_POINT();
+ ICV_PUT_POINT();
+
+ tptr += step;
+ a = (ep_corr * icvFilterTable[63 - dist] >> 8) & 0xff;
+ ICV_PUT_POINT();
+ ICV_PUT_POINT();
+
+ pt1.y += y_step;
+ ptr++;
+ scount++;
+ ecount--;
+ }
+ }
+ else
+ {
+ ptr += (pt1.y >> XY_SHIFT) * step;
+
+ while( ecount >= 0 )
+ {
+ uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1);
+
+ int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
+ (((ecount >= 2) + 1) & (ecount | 2))];
+ int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31;
+
+ a = (ep_corr * icvFilterTable[dist + 32] >> 8) & 0xff;
+ ICV_PUT_POINT();
+ ICV_PUT_POINT();
+
+ tptr++;
+ a = (ep_corr * icvFilterTable[dist] >> 8) & 0xff;
+ ICV_PUT_POINT();
+ ICV_PUT_POINT();
+
+ tptr++;
+ a = (ep_corr * icvFilterTable[63 - dist] >> 8) & 0xff;
+ ICV_PUT_POINT();
+ ICV_PUT_POINT();
+
+ pt1.x += x_step;
+ ptr += step;
+ scount++;
+ ecount--;
+ }
+ }
+ #undef ICV_PUT_POINT
+ }
+}
+
+
+static void
+icvLine2( CvMat* img, CvPoint pt1, CvPoint pt2, const void* color )
+{
+ int dx, dy;
+ int ecount;
+ int ax, ay;
+ int i, j;
+ int x_step, y_step;
+ int cb = ((uchar*)color)[0];
+ int cg = ((uchar*)color)[1];
+ int cr = ((uchar*)color)[2];
+ int pix_size = CV_ELEM_SIZE( img->type );
+ uchar *ptr = (uchar*)(img->data.ptr), *tptr;
+ int step = img->step;
+ CvSize size = cvGetMatSize( img );
+
+ //assert( img && (nch == 1 || nch == 3) && CV_MAT_DEPTH(img->type) == CV_8U );
+
+ pt1.x -= XY_ONE*2;
+ pt1.y -= XY_ONE*2;
+ pt2.x -= XY_ONE*2;
+ pt2.y -= XY_ONE*2;
+ ptr += img->step*2 + 2*pix_size;
+
+ size.width = ((size.width - 5) << XY_SHIFT) + 1;
+ size.height = ((size.height - 5) << XY_SHIFT) + 1;
+
+ if( !cvClipLine( size, &pt1, &pt2 ))
+ return;
+
+ dx = pt2.x - pt1.x;
+ dy = pt2.y - pt1.y;
+
+ j = dx < 0 ? -1 : 0;
+ ax = (dx ^ j) - j;
+ i = dy < 0 ? -1 : 0;
+ ay = (dy ^ i) - i;
+
+ if( ax > ay )
+ {
+ dx = ax;
+ dy = (dy ^ j) - j;
+ pt1.x ^= pt2.x & j;
+ pt2.x ^= pt1.x & j;
+ pt1.x ^= pt2.x & j;
+ pt1.y ^= pt2.y & j;
+ pt2.y ^= pt1.y & j;
+ pt1.y ^= pt2.y & j;
+
+ x_step = XY_ONE;
+ y_step = (int) (((int64) dy << XY_SHIFT) / (ax | 1));
+ ecount = (pt2.x - pt1.x) >> XY_SHIFT;
+ }
+ else
+ {
+ dy = ay;
+ dx = (dx ^ i) - i;
+ pt1.x ^= pt2.x & i;
+ pt2.x ^= pt1.x & i;
+ pt1.x ^= pt2.x & i;
+ pt1.y ^= pt2.y & i;
+ pt2.y ^= pt1.y & i;
+ pt1.y ^= pt2.y & i;
+
+ x_step = (int) (((int64) dx << XY_SHIFT) / (ay | 1));
+ y_step = XY_ONE;
+ ecount = (pt2.y - pt1.y) >> XY_SHIFT;
+ }
+
+ pt1.x += (XY_ONE >> 1);
+ pt1.y += (XY_ONE >> 1);
+
+ if( pix_size == 3 )
+ {
+ #define ICV_PUT_POINT() \
+ { \
+ tptr[0] = (uchar)cb; \
+ tptr[1] = (uchar)cg; \
+ tptr[2] = (uchar)cr; \
+ }
+
+ tptr = ptr + ((pt2.x + (XY_ONE >> 1))>> XY_SHIFT)*3 +
+ ((pt2.y + (XY_ONE >> 1)) >> XY_SHIFT)*step;
+ ICV_PUT_POINT();
+
+ if( ax > ay )
+ {
+ ptr += (pt1.x >> XY_SHIFT) * 3;
+
+ while( ecount >= 0 )
+ {
+ tptr = ptr + (pt1.y >> XY_SHIFT) * step;
+ ICV_PUT_POINT();
+ pt1.y += y_step;
+ ptr += 3;
+ ecount--;
+ }
+ }
+ else
+ {
+ ptr += (pt1.y >> XY_SHIFT) * step;
+
+ while( ecount >= 0 )
+ {
+ tptr = ptr + (pt1.x >> XY_SHIFT) * 3;
+ ICV_PUT_POINT();
+ pt1.x += x_step;
+ ptr += step;
+ ecount--;
+ }
+ }
+
+ #undef ICV_PUT_POINT
+ }
+ else if( pix_size == 1 )
+ {
+ #define ICV_PUT_POINT() \
+ { \
+ tptr[0] = (uchar)cb; \
+ }
+
+ tptr = ptr + ((pt2.x + (XY_ONE >> 1))>> XY_SHIFT) +
+ ((pt2.y + (XY_ONE >> 1)) >> XY_SHIFT)*step;
+ ICV_PUT_POINT();
+
+ if( ax > ay )
+ {
+ ptr += (pt1.x >> XY_SHIFT);
+
+ while( ecount >= 0 )
+ {
+ tptr = ptr + (pt1.y >> XY_SHIFT) * step;
+ ICV_PUT_POINT();
+ pt1.y += y_step;
+ ptr++;
+ ecount--;
+ }
+ }
+ else
+ {
+ ptr += (pt1.y >> XY_SHIFT) * step;
+
+ while( ecount >= 0 )
+ {
+ tptr = ptr + (pt1.x >> XY_SHIFT);
+ ICV_PUT_POINT();
+ pt1.x += x_step;
+ ptr += step;
+ ecount--;
+ }
+ }
+ #undef ICV_PUT_POINT
+ }
+ else
+ {
+ #define ICV_PUT_POINT() \
+ for( j = 0; j < pix_size; j++ ) \
+ tptr[j] = ((uchar*)color)[j];
+
+ tptr = ptr + ((pt2.x + (XY_ONE >> 1))>> XY_SHIFT)*pix_size +
+ ((pt2.y + (XY_ONE >> 1)) >> XY_SHIFT)*step;
+ ICV_PUT_POINT();
+
+ if( ax > ay )
+ {
+ ptr += (pt1.x >> XY_SHIFT) * pix_size;
+
+ while( ecount >= 0 )
+ {
+ tptr = ptr + (pt1.y >> XY_SHIFT) * step;
+ ICV_PUT_POINT();
+ pt1.y += y_step;
+ ptr += pix_size;
+ ecount--;
+ }
+ }
+ else
+ {
+ ptr += (pt1.y >> XY_SHIFT) * step;
+
+ while( ecount >= 0 )
+ {
+ tptr = ptr + (pt1.x >> XY_SHIFT) * pix_size;
+ ICV_PUT_POINT();
+ pt1.x += x_step;
+ ptr += step;
+ ecount--;
+ }
+ }
+
+ #undef ICV_PUT_POINT
+ }
+}
+
+
+/****************************************************************************************\
+* Antialiazed Elliptic Arcs via Antialiazed Lines *
+\****************************************************************************************/
+
+static const float icvSinTable[] =
+ { 0.0000000f, 0.0174524f, 0.0348995f, 0.0523360f, 0.0697565f, 0.0871557f,
+ 0.1045285f, 0.1218693f, 0.1391731f, 0.1564345f, 0.1736482f, 0.1908090f,
+ 0.2079117f, 0.2249511f, 0.2419219f, 0.2588190f, 0.2756374f, 0.2923717f,
+ 0.3090170f, 0.3255682f, 0.3420201f, 0.3583679f, 0.3746066f, 0.3907311f,
+ 0.4067366f, 0.4226183f, 0.4383711f, 0.4539905f, 0.4694716f, 0.4848096f,
+ 0.5000000f, 0.5150381f, 0.5299193f, 0.5446390f, 0.5591929f, 0.5735764f,
+ 0.5877853f, 0.6018150f, 0.6156615f, 0.6293204f, 0.6427876f, 0.6560590f,
+ 0.6691306f, 0.6819984f, 0.6946584f, 0.7071068f, 0.7193398f, 0.7313537f,
+ 0.7431448f, 0.7547096f, 0.7660444f, 0.7771460f, 0.7880108f, 0.7986355f,
+ 0.8090170f, 0.8191520f, 0.8290376f, 0.8386706f, 0.8480481f, 0.8571673f,
+ 0.8660254f, 0.8746197f, 0.8829476f, 0.8910065f, 0.8987940f, 0.9063078f,
+ 0.9135455f, 0.9205049f, 0.9271839f, 0.9335804f, 0.9396926f, 0.9455186f,
+ 0.9510565f, 0.9563048f, 0.9612617f, 0.9659258f, 0.9702957f, 0.9743701f,
+ 0.9781476f, 0.9816272f, 0.9848078f, 0.9876883f, 0.9902681f, 0.9925462f,
+ 0.9945219f, 0.9961947f, 0.9975641f, 0.9986295f, 0.9993908f, 0.9998477f,
+ 1.0000000f, 0.9998477f, 0.9993908f, 0.9986295f, 0.9975641f, 0.9961947f,
+ 0.9945219f, 0.9925462f, 0.9902681f, 0.9876883f, 0.9848078f, 0.9816272f,
+ 0.9781476f, 0.9743701f, 0.9702957f, 0.9659258f, 0.9612617f, 0.9563048f,
+ 0.9510565f, 0.9455186f, 0.9396926f, 0.9335804f, 0.9271839f, 0.9205049f,
+ 0.9135455f, 0.9063078f, 0.8987940f, 0.8910065f, 0.8829476f, 0.8746197f,
+ 0.8660254f, 0.8571673f, 0.8480481f, 0.8386706f, 0.8290376f, 0.8191520f,
+ 0.8090170f, 0.7986355f, 0.7880108f, 0.7771460f, 0.7660444f, 0.7547096f,
+ 0.7431448f, 0.7313537f, 0.7193398f, 0.7071068f, 0.6946584f, 0.6819984f,
+ 0.6691306f, 0.6560590f, 0.6427876f, 0.6293204f, 0.6156615f, 0.6018150f,
+ 0.5877853f, 0.5735764f, 0.5591929f, 0.5446390f, 0.5299193f, 0.5150381f,
+ 0.5000000f, 0.4848096f, 0.4694716f, 0.4539905f, 0.4383711f, 0.4226183f,
+ 0.4067366f, 0.3907311f, 0.3746066f, 0.3583679f, 0.3420201f, 0.3255682f,
+ 0.3090170f, 0.2923717f, 0.2756374f, 0.2588190f, 0.2419219f, 0.2249511f,
+ 0.2079117f, 0.1908090f, 0.1736482f, 0.1564345f, 0.1391731f, 0.1218693f,
+ 0.1045285f, 0.0871557f, 0.0697565f, 0.0523360f, 0.0348995f, 0.0174524f,
+ 0.0000000f, -0.0174524f, -0.0348995f, -0.0523360f, -0.0697565f, -0.0871557f,
+ -0.1045285f, -0.1218693f, -0.1391731f, -0.1564345f, -0.1736482f, -0.1908090f,
+ -0.2079117f, -0.2249511f, -0.2419219f, -0.2588190f, -0.2756374f, -0.2923717f,
+ -0.3090170f, -0.3255682f, -0.3420201f, -0.3583679f, -0.3746066f, -0.3907311f,
+ -0.4067366f, -0.4226183f, -0.4383711f, -0.4539905f, -0.4694716f, -0.4848096f,
+ -0.5000000f, -0.5150381f, -0.5299193f, -0.5446390f, -0.5591929f, -0.5735764f,
+ -0.5877853f, -0.6018150f, -0.6156615f, -0.6293204f, -0.6427876f, -0.6560590f,
+ -0.6691306f, -0.6819984f, -0.6946584f, -0.7071068f, -0.7193398f, -0.7313537f,
+ -0.7431448f, -0.7547096f, -0.7660444f, -0.7771460f, -0.7880108f, -0.7986355f,
+ -0.8090170f, -0.8191520f, -0.8290376f, -0.8386706f, -0.8480481f, -0.8571673f,
+ -0.8660254f, -0.8746197f, -0.8829476f, -0.8910065f, -0.8987940f, -0.9063078f,
+ -0.9135455f, -0.9205049f, -0.9271839f, -0.9335804f, -0.9396926f, -0.9455186f,
+ -0.9510565f, -0.9563048f, -0.9612617f, -0.9659258f, -0.9702957f, -0.9743701f,
+ -0.9781476f, -0.9816272f, -0.9848078f, -0.9876883f, -0.9902681f, -0.9925462f,
+ -0.9945219f, -0.9961947f, -0.9975641f, -0.9986295f, -0.9993908f, -0.9998477f,
+ -1.0000000f, -0.9998477f, -0.9993908f, -0.9986295f, -0.9975641f, -0.9961947f,
+ -0.9945219f, -0.9925462f, -0.9902681f, -0.9876883f, -0.9848078f, -0.9816272f,
+ -0.9781476f, -0.9743701f, -0.9702957f, -0.9659258f, -0.9612617f, -0.9563048f,
+ -0.9510565f, -0.9455186f, -0.9396926f, -0.9335804f, -0.9271839f, -0.9205049f,
+ -0.9135455f, -0.9063078f, -0.8987940f, -0.8910065f, -0.8829476f, -0.8746197f,
+ -0.8660254f, -0.8571673f, -0.8480481f, -0.8386706f, -0.8290376f, -0.8191520f,
+ -0.8090170f, -0.7986355f, -0.7880108f, -0.7771460f, -0.7660444f, -0.7547096f,
+ -0.7431448f, -0.7313537f, -0.7193398f, -0.7071068f, -0.6946584f, -0.6819984f,
+ -0.6691306f, -0.6560590f, -0.6427876f, -0.6293204f, -0.6156615f, -0.6018150f,
+ -0.5877853f, -0.5735764f, -0.5591929f, -0.5446390f, -0.5299193f, -0.5150381f,
+ -0.5000000f, -0.4848096f, -0.4694716f, -0.4539905f, -0.4383711f, -0.4226183f,
+ -0.4067366f, -0.3907311f, -0.3746066f, -0.3583679f, -0.3420201f, -0.3255682f,
+ -0.3090170f, -0.2923717f, -0.2756374f, -0.2588190f, -0.2419219f, -0.2249511f,
+ -0.2079117f, -0.1908090f, -0.1736482f, -0.1564345f, -0.1391731f, -0.1218693f,
+ -0.1045285f, -0.0871557f, -0.0697565f, -0.0523360f, -0.0348995f, -0.0174524f,
+ -0.0000000f, 0.0174524f, 0.0348995f, 0.0523360f, 0.0697565f, 0.0871557f,
+ 0.1045285f, 0.1218693f, 0.1391731f, 0.1564345f, 0.1736482f, 0.1908090f,
+ 0.2079117f, 0.2249511f, 0.2419219f, 0.2588190f, 0.2756374f, 0.2923717f,
+ 0.3090170f, 0.3255682f, 0.3420201f, 0.3583679f, 0.3746066f, 0.3907311f,
+ 0.4067366f, 0.4226183f, 0.4383711f, 0.4539905f, 0.4694716f, 0.4848096f,
+ 0.5000000f, 0.5150381f, 0.5299193f, 0.5446390f, 0.5591929f, 0.5735764f,
+ 0.5877853f, 0.6018150f, 0.6156615f, 0.6293204f, 0.6427876f, 0.6560590f,
+ 0.6691306f, 0.6819984f, 0.6946584f, 0.7071068f, 0.7193398f, 0.7313537f,
+ 0.7431448f, 0.7547096f, 0.7660444f, 0.7771460f, 0.7880108f, 0.7986355f,
+ 0.8090170f, 0.8191520f, 0.8290376f, 0.8386706f, 0.8480481f, 0.8571673f,
+ 0.8660254f, 0.8746197f, 0.8829476f, 0.8910065f, 0.8987940f, 0.9063078f,
+ 0.9135455f, 0.9205049f, 0.9271839f, 0.9335804f, 0.9396926f, 0.9455186f,
+ 0.9510565f, 0.9563048f, 0.9612617f, 0.9659258f, 0.9702957f, 0.9743701f,
+ 0.9781476f, 0.9816272f, 0.9848078f, 0.9876883f, 0.9902681f, 0.9925462f,
+ 0.9945219f, 0.9961947f, 0.9975641f, 0.9986295f, 0.9993908f, 0.9998477f,
+ 1.0000000f
+};
+
+
+static void
+icvSinCos( int angle, float *cosval, float *sinval )
+{
+ angle += (angle < 0 ? 360 : 0);
+ *sinval = icvSinTable[angle];
+ *cosval = icvSinTable[450 - angle];
+}
+
+/*
+ constructs polygon that represents elliptic arc.
+*/
+CV_IMPL int
+cvEllipse2Poly( CvPoint center, CvSize axes, int angle,
+ int arc_start, int arc_end, CvPoint* pts, int delta )
+{
+ float alpha, beta;
+ double size_a = axes.width, size_b = axes.height;
+ double cx = center.x, cy = center.y;
+ CvPoint *pts_origin = pts;
+ int i;
+
+ while( angle < 0 )
+ angle += 360;
+ while( angle > 360 )
+ angle -= 360;
+
+ if( arc_start > arc_end )
+ {
+ i = arc_start;
+ arc_start = arc_end;
+ arc_end = i;
+ }
+ while( arc_start < 0 )
+ {
+ arc_start += 360;
+ arc_end += 360;
+ }
+ while( arc_end > 360 )
+ {
+ arc_end -= 360;
+ arc_start -= 360;
+ }
+ if( arc_end - arc_start > 360 )
+ {
+ arc_start = 0;
+ arc_end = 360;
+ }
+ icvSinCos( angle, &alpha, &beta );
+
+ for( i = arc_start; i < arc_end + delta; i += delta )
+ {
+ double x, y;
+ angle = i;
+ if( angle > arc_end )
+ angle = arc_end;
+ if( angle < 0 )
+ angle += 360;
+
+ x = size_a * icvSinTable[450-angle];
+ y = size_b * icvSinTable[angle];
+ pts->x = cvRound( cx + x * alpha - y * beta );
+ pts->y = cvRound( cy - x * beta - y * alpha );
+ pts += i == arc_start || pts->x != pts[-1].x || pts->y != pts[-1].y;
+ }
+
+ i = (int)(pts - pts_origin);
+ for( ; i < 2; i++ )
+ pts_origin[i] = pts_origin[i-1];
+ return i;
+}
+
+
+static void
+icvEllipseEx( CvMat* img, CvPoint center, CvSize axes,
+ int angle, int arc_start, int arc_end,
+ const void* color, int thickness, int line_type )
+{
+ CvMemStorage* st = 0;
+
+ CV_FUNCNAME( "icvEllipseEx" );
+
+ __BEGIN__;
+
+ CvPoint v[1 << 8];
+ int count, delta;
+
+ if( axes.width < 0 || axes.height < 0 )
+ CV_ERROR( CV_StsBadSize, "" );
+
+ delta = (MAX(axes.width,axes.height)+(XY_ONE>>1))>>XY_SHIFT;
+ delta = delta < 3 ? 90 : delta < 10 ? 30 : delta < 15 ? 18 : 5;
+
+ count = cvEllipse2Poly( center, axes, angle, arc_start, arc_end, v, delta );
+
+ if( thickness >= 0 )
+ {
+ icvPolyLine( img, v, count, 0, color, thickness, line_type, XY_SHIFT );
+ }
+ else if( arc_end - arc_start >= 360 )
+ {
+ icvFillConvexPoly( img, v, count, color, line_type, XY_SHIFT );
+ }
+ else
+ {
+ CvContour* edges;
+ CvSeq vtx;
+ CvSeqBlock block;
+
+ CV_CALL( st = cvCreateMemStorage( CV_DRAWING_STORAGE_BLOCK ));
+ CV_CALL( edges = (CvContour*)cvCreateSeq( 0, sizeof(CvContour), sizeof(CvPolyEdge), st ));
+ v[count++] = center;
+
+ CV_CALL( cvMakeSeqHeaderForArray( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint),
+ v, count, &vtx, &block ));
+
+ CV_CALL( icvCollectPolyEdges( img, &vtx, edges, color, line_type, XY_SHIFT ));
+ CV_CALL( icvFillEdgeCollection( img, edges, color ));
+ }
+
+ __END__;
+
+ if( st )
+ cvReleaseMemStorage( &st );
+}
+
+
+/****************************************************************************************\
+* Polygons filling *
+\****************************************************************************************/
+
+/* helper macros: filling horizontal row */
+#define ICV_HLINE( ptr, xl, xr, color, pix_size ) \
+{ \
+ uchar* hline_ptr = (uchar*)(ptr) + (xl)*(pix_size); \
+ uchar* hline_max_ptr = (uchar*)(ptr) + (xr)*(pix_size); \
+ \
+ for( ; hline_ptr <= hline_max_ptr; hline_ptr += (pix_size))\
+ { \
+ int hline_j; \
+ for( hline_j = 0; hline_j < (pix_size); hline_j++ ) \
+ { \
+ hline_ptr[hline_j] = ((uchar*)color)[hline_j]; \
+ } \
+ } \
+}
+
+
+/* filling convex polygon. v - array of vertices, ntps - number of points */
+static void
+icvFillConvexPoly( CvMat* img, CvPoint *v, int npts, const void* color, int line_type, int shift )
+{
+ struct
+ {
+ int idx, di;
+ int x, dx, ye;
+ }
+ edge[2];
+
+ int delta = shift ? 1 << (shift - 1) : 0;
+ int i, y, imin = 0, left = 0, right = 1, x1, x2;
+ int edges = npts;
+ int xmin, xmax, ymin, ymax;
+ uchar* ptr = img->data.ptr;
+ CvSize size = cvGetMatSize( img );
+ int pix_size = CV_ELEM_SIZE(img->type);
+ CvPoint p0;
+ int delta1, delta2;
+
+ if( line_type < CV_AA )
+ delta1 = delta2 = XY_ONE >> 1;
+ //delta1 = 0, delta2 = XY_ONE - 1;
+ else
+ delta1 = XY_ONE - 1, delta2 = 0;
+
+ p0 = v[npts - 1];
+ p0.x <<= XY_SHIFT - shift;
+ p0.y <<= XY_SHIFT - shift;
+
+ assert( 0 <= shift && shift <= XY_SHIFT );
+ xmin = xmax = v[0].x;
+ ymin = ymax = v[0].y;
+
+ for( i = 0; i < npts; i++ )
+ {
+ CvPoint p = v[i];
+ if( p.y < ymin )
+ {
+ ymin = p.y;
+ imin = i;
+ }
+
+ ymax = MAX( ymax, p.y );
+ xmax = MAX( xmax, p.x );
+ xmin = MIN( xmin, p.x );
+
+ p.x <<= XY_SHIFT - shift;
+ p.y <<= XY_SHIFT - shift;
+
+ if( line_type <= 8 )
+ {
+ if( shift == 0 )
+ {
+ CvPoint pt0, pt1;
+ pt0.x = p0.x >> XY_SHIFT;
+ pt0.y = p0.y >> XY_SHIFT;
+ pt1.x = p.x >> XY_SHIFT;
+ pt1.y = p.y >> XY_SHIFT;
+ icvLine( img, pt0, pt1, color, line_type );
+ }
+ else
+ icvLine2( img, p0, p, color );
+ }
+ else
+ icvLineAA( img, p0, p, color );
+ p0 = p;
+ }
+
+ xmin = (xmin + delta) >> shift;
+ xmax = (xmax + delta) >> shift;
+ ymin = (ymin + delta) >> shift;
+ ymax = (ymax + delta) >> shift;
+
+ if( npts < 3 || xmax < 0 || ymax < 0 || xmin >= size.width || ymin >= size.height )
+ return;
+
+ ymax = MIN( ymax, size.height - 1 );
+ edge[0].idx = edge[1].idx = imin;
+
+ edge[0].ye = edge[1].ye = y = ymin;
+ edge[0].di = 1;
+ edge[1].di = npts - 1;
+
+ ptr += img->step*y;
+
+ do
+ {
+ if( line_type < CV_AA || y < ymax || y == ymin )
+ {
+ for( i = 0; i < 2; i++ )
+ {
+ if( y >= edge[i].ye )
+ {
+ int idx = edge[i].idx, di = edge[i].di;
+ int xs = 0, xe, ye, ty = 0;
+
+ for(;;)
+ {
+ ty = (v[idx].y + delta) >> shift;
+ if( ty > y || edges == 0 )
+ break;
+ xs = v[idx].x;
+ idx += di;
+ idx -= ((idx < npts) - 1) & npts; /* idx -= idx >= npts ? npts : 0 */
+ edges--;
+ }
+
+ ye = ty;
+ xs <<= XY_SHIFT - shift;
+ xe = v[idx].x << (XY_SHIFT - shift);
+
+ /* no more edges */
+ if( y >= ye )
+ return;
+
+ edge[i].ye = ye;
+ edge[i].dx = ((xe - xs)*2 + (ye - y)) / (2 * (ye - y));
+ edge[i].x = xs;
+ edge[i].idx = idx;
+ }
+ }
+ }
+
+ if( edge[left].x > edge[right].x )
+ {
+ left ^= 1;
+ right ^= 1;
+ }
+
+ x1 = edge[left].x;
+ x2 = edge[right].x;
+
+ if( y >= 0 )
+ {
+ int xx1 = (x1 + delta1) >> XY_SHIFT;
+ int xx2 = (x2 + delta2) >> XY_SHIFT;
+
+ if( xx2 >= 0 && xx1 < size.width )
+ {
+ if( xx1 < 0 )
+ xx1 = 0;
+ if( xx2 >= size.width )
+ xx2 = size.width - 1;
+ ICV_HLINE( ptr, xx1, xx2, color, pix_size );
+ }
+ }
+
+ x1 += edge[left].dx;
+ x2 += edge[right].dx;
+
+ edge[left].x = x1;
+ edge[right].x = x2;
+ ptr += img->step;
+ }
+ while( ++y <= ymax );
+}
+
+
+/******** Arbitrary polygon **********/
+
+static void
+icvCollectPolyEdges( CvMat* img, CvSeq* v, CvContour* edges,
+ const void* color, int line_type, int shift,
+ CvPoint offset )
+{
+ int i, count = v->total;
+ CvRect bounds = edges->rect;
+ int delta = offset.y + (shift ? 1 << (shift - 1) : 0);
+ int elem_type = CV_MAT_TYPE(v->flags);
+
+ CvSeqReader reader;
+ CvSeqWriter writer;
+
+ cvStartReadSeq( v, &reader );
+ cvStartAppendToSeq( (CvSeq*)edges, &writer );
+
+ for( i = 0; i < count; i++ )
+ {
+ CvPoint pt0, pt1, t0, t1;
+ CvPolyEdge edge;
+ CV_READ_EDGE( pt0, pt1, reader );
+
+ if( elem_type == CV_32SC2 )
+ {
+ pt0.x = (pt0.x + offset.x) << (XY_SHIFT - shift);
+ pt0.y = (pt0.y + delta) >> shift;
+ pt1.x = (pt1.x + offset.x) << (XY_SHIFT - shift);
+ pt1.y = (pt1.y + delta) >> shift;
+ }
+ else
+ {
+ Cv32suf x, y;
+ assert( shift == 0 );
+
+ x.i = pt0.x; y.i = pt0.y;
+ pt0.x = cvRound((x.f + offset.x) * XY_ONE);
+ pt0.y = cvRound(y.f + offset.y);
+ x.i = pt1.x; y.i = pt1.y;
+ pt1.x = cvRound((x.f + offset.x) * XY_ONE);
+ pt1.y = cvRound(y.f + offset.y);
+ }
+
+ if( line_type < CV_AA )
+ {
+ t0.y = pt0.y; t1.y = pt1.y;
+ t0.x = (pt0.x + (XY_ONE >> 1)) >> XY_SHIFT;
+ t1.x = (pt1.x + (XY_ONE >> 1)) >> XY_SHIFT;
+ icvLine( img, t0, t1, color, line_type );
+ }
+ else
+ {
+ t0.x = pt0.x; t1.x = pt1.x;
+ t0.y = pt0.y << XY_SHIFT;
+ t1.y = pt1.y << XY_SHIFT;
+ icvLineAA( img, t0, t1, color );
+ }
+
+ if( pt0.y == pt1.y )
+ continue;
+
+ if( pt0.y > pt1.y )
+ CV_SWAP( pt0, pt1, t0 );
+
+ bounds.y = MIN( bounds.y, pt0.y );
+ bounds.height = MAX( bounds.height, pt1.y );
+
+ if( pt0.x < pt1.x )
+ {
+ bounds.x = MIN( bounds.x, pt0.x );
+ bounds.width = MAX( bounds.width, pt1.x );
+ }
+ else
+ {
+ bounds.x = MIN( bounds.x, pt1.x );
+ bounds.width = MAX( bounds.width, pt0.x );
+ }
+
+ edge.y0 = pt0.y;
+ edge.y1 = pt1.y;
+ edge.x = pt0.x;
+ edge.dx = (pt1.x - pt0.x) / (pt1.y - pt0.y);
+ assert( edge.y0 < edge.y1 );
+
+ CV_WRITE_SEQ_ELEM( edge, writer );
+ }
+
+ edges->rect = bounds;
+ cvEndWriteSeq( &writer );
+}
+
+static int
+icvCmpEdges( const void* _e1, const void* _e2, void* /*userdata*/ )
+{
+ CvPolyEdge *e1 = (CvPolyEdge*)_e1, *e2 = (CvPolyEdge*)_e2;
+ return e1->y0 - e2->y0 ? e1->y0 - e2->y0 :
+ e1->x - e2->x ? e1->x - e2->x : e1->dx - e2->dx;
+}
+
+/**************** helper macros and functions for sequence/contour processing ***********/
+
+static void
+icvFillEdgeCollection( CvMat* img, CvContour* edges, const void* color )
+{
+ CvPolyEdge tmp;
+ int i, y, total = edges->total;
+ CvSeqReader reader;
+ CvSize size = cvGetMatSize(img);
+ CvPolyEdge* e;
+ int y_max = INT_MIN;
+ int pix_size = CV_ELEM_SIZE(img->type);
+
+ __BEGIN__;
+
+ memset( &tmp, 0, sizeof(tmp));
+
+ /* check parameters */
+ if( edges->total < 2 || edges->rect.height < 0 || edges->rect.y >= size.height ||
+ edges->rect.width < 0 || edges->rect.x >= size.width )
+ EXIT;
+
+ cvSeqSort( (CvSeq*)edges, icvCmpEdges, 0 );
+ cvStartReadSeq( (CvSeq*)edges, &reader );
+
+#ifdef _DEBUG
+ e = &tmp;
+ tmp.y0 = INT_MIN;
+#endif
+
+ for( i = 0; i < total; i++ )
+ {
+ CvPolyEdge* e1 = (CvPolyEdge*)(reader.ptr);
+
+#ifdef _DEBUG
+ assert( e1->y0 < e1->y1 && (i == 0 || icvCmpEdges( e, e1, 0 ) <= 0) );
+ e = e1;
+#endif
+ y_max = MAX( y_max, e1->y1 );
+
+ CV_NEXT_SEQ_ELEM( sizeof(CvPolyEdge), reader );
+ }
+
+ /* start drawing */
+ tmp.y0 = INT_MAX;
+ cvSeqPush( (CvSeq*)edges, &tmp );
+
+ i = 0;
+ tmp.next = 0;
+ cvStartReadSeq( (CvSeq*)edges, &reader );
+ e = (CvPolyEdge*)(reader.ptr);
+ y_max = MIN( y_max, size.height );
+
+ for( y = e->y0; y < y_max; y++ )
+ {
+ CvPolyEdge *last, *prelast, *keep_prelast;
+ int sort_flag = 0;
+ int draw = 0;
+ int clipline = y < 0;
+
+ prelast = &tmp;
+ last = tmp.next;
+ while( last || e->y0 == y )
+ {
+ if( last && last->y1 == y )
+ {
+ /* exlude edge if y reachs its lower point */
+ prelast->next = last->next;
+ last = last->next;
+ continue;
+ }
+ keep_prelast = prelast;
+ if( last && (e->y0 > y || last->x < e->x) )
+ {
+ /* go to the next edge in active list */
+ prelast = last;
+ last = last->next;
+ }
+ else if( i < total )
+ {
+ /* insert new edge into active list if y reachs its upper point */
+ prelast->next = e;
+ e->next = last;
+ prelast = e;
+ CV_NEXT_SEQ_ELEM( edges->elem_size, reader );
+ e = (CvPolyEdge*)(reader.ptr);
+ i++;
+ }
+ else
+ break;
+
+ if( draw )
+ {
+ if( !clipline )
+ {
+ /* convert x's from fixed-point to image coordinates */
+ uchar *timg = (uchar*)(img->data.ptr) + y * img->step;
+ int x1 = keep_prelast->x;
+ int x2 = prelast->x;
+
+ if( x1 > x2 )
+ {
+ int t = x1;
+
+ x1 = x2;
+ x2 = t;
+ }
+
+ x1 = (x1 + XY_ONE - 1) >> XY_SHIFT;
+ x2 = x2 >> XY_SHIFT;
+
+ /* clip and draw the line */
+ if( x1 < size.width && x2 >= 0 )
+ {
+ if( x1 < 0 )
+ x1 = 0;
+ if( x2 >= size.width )
+ x2 = size.width - 1;
+ ICV_HLINE( timg, x1, x2, color, pix_size );
+ }
+ }
+ keep_prelast->x += keep_prelast->dx;
+ prelast->x += prelast->dx;
+ }
+ draw ^= 1;
+ }
+
+ /* sort edges (bubble sort on list) */
+ keep_prelast = 0;
+
+ do
+ {
+ prelast = &tmp;
+ last = tmp.next;
+
+ while( last != keep_prelast && last->next != 0 )
+ {
+ CvPolyEdge *te = last->next;
+
+ /* swap edges */
+ if( last->x > te->x )
+ {
+ prelast->next = te;
+ last->next = te->next;
+ te->next = last;
+ prelast = te;
+ sort_flag = 1;
+ }
+ else
+ {
+ prelast = last;
+ last = te;
+ }
+ }
+ keep_prelast = prelast;
+ }
+ while( sort_flag && keep_prelast != tmp.next && keep_prelast != &tmp );
+ }
+
+ __END__;
+}
+
+
+/* draws simple or filled circle */
+static void
+icvCircle( CvMat* img, CvPoint center, int radius, const void* color, int fill )
+{
+ CvSize size = cvGetMatSize( img );
+ int step = img->step;
+ int pix_size = CV_ELEM_SIZE(img->type);
+ uchar* ptr = (uchar*)(img->data.ptr);
+ int err = 0, dx = radius, dy = 0, plus = 1, minus = (radius << 1) - 1;
+ int inside = center.x >= radius && center.x < size.width - radius &&
+ center.y >= radius && center.y < size.height - radius;
+
+ #define ICV_PUT_POINT( ptr, x ) \
+ CV_MEMCPY_CHAR( ptr + (x)*pix_size, color, pix_size );
+
+ while( dx >= dy )
+ {
+ int mask;
+ int y11 = center.y - dy, y12 = center.y + dy, y21 = center.y - dx, y22 = center.y + dx;
+ int x11 = center.x - dx, x12 = center.x + dx, x21 = center.x - dy, x22 = center.x + dy;
+
+ if( inside )
+ {
+ uchar *tptr0 = ptr + y11 * step;
+ uchar *tptr1 = ptr + y12 * step;
+
+ if( !fill )
+ {
+ ICV_PUT_POINT( tptr0, x11 );
+ ICV_PUT_POINT( tptr1, x11 );
+ ICV_PUT_POINT( tptr0, x12 );
+ ICV_PUT_POINT( tptr1, x12 );
+ }
+ else
+ {
+ ICV_HLINE( tptr0, x11, x12, color, pix_size );
+ ICV_HLINE( tptr1, x11, x12, color, pix_size );
+ }
+
+ tptr0 = ptr + y21 * step;
+ tptr1 = ptr + y22 * step;
+
+ if( !fill )
+ {
+ ICV_PUT_POINT( tptr0, x21 );
+ ICV_PUT_POINT( tptr1, x21 );
+ ICV_PUT_POINT( tptr0, x22 );
+ ICV_PUT_POINT( tptr1, x22 );
+ }
+ else
+ {
+ ICV_HLINE( tptr0, x21, x22, color, pix_size );
+ ICV_HLINE( tptr1, x21, x22, color, pix_size );
+ }
+ }
+ else if( x11 < size.width && x12 >= 0 && y21 < size.height && y22 >= 0 )
+ {
+ if( fill )
+ {
+ x11 = MAX( x11, 0 );
+ x12 = MIN( x12, size.width - 1 );
+ }
+
+ if( (unsigned)y11 < (unsigned)size.height )
+ {
+ uchar *tptr = ptr + y11 * step;
+
+ if( !fill )
+ {
+ if( x11 >= 0 )
+ ICV_PUT_POINT( tptr, x11 );
+ if( x12 < size.width )
+ ICV_PUT_POINT( tptr, x12 );
+ }
+ else
+ ICV_HLINE( tptr, x11, x12, color, pix_size );
+ }
+
+ if( (unsigned)y12 < (unsigned)size.height )
+ {
+ uchar *tptr = ptr + y12 * step;
+
+ if( !fill )
+ {
+ if( x11 >= 0 )
+ ICV_PUT_POINT( tptr, x11 );
+ if( x12 < size.width )
+ ICV_PUT_POINT( tptr, x12 );
+ }
+ else
+ ICV_HLINE( tptr, x11, x12, color, pix_size );
+ }
+
+ if( x21 < size.width && x22 >= 0 )
+ {
+ if( fill )
+ {
+ x21 = MAX( x21, 0 );
+ x22 = MIN( x22, size.width - 1 );
+ }
+
+ if( (unsigned)y21 < (unsigned)size.height )
+ {
+ uchar *tptr = ptr + y21 * step;
+
+ if( !fill )
+ {
+ if( x21 >= 0 )
+ ICV_PUT_POINT( tptr, x21 );
+ if( x22 < size.width )
+ ICV_PUT_POINT( tptr, x22 );
+ }
+ else
+ ICV_HLINE( tptr, x21, x22, color, pix_size );
+ }
+
+ if( (unsigned)y22 < (unsigned)size.height )
+ {
+ uchar *tptr = ptr + y22 * step;
+
+ if( !fill )
+ {
+ if( x21 >= 0 )
+ ICV_PUT_POINT( tptr, x21 );
+ if( x22 < size.width )
+ ICV_PUT_POINT( tptr, x22 );
+ }
+ else
+ ICV_HLINE( tptr, x21, x22, color, pix_size );
+ }
+ }
+ }
+ dy++;
+ err += plus;
+ plus += 2;
+
+ mask = (err <= 0) - 1;
+
+ err -= minus & mask;
+ dx += mask;
+ minus -= mask & 2;
+ }
+
+ #undef ICV_PUT_POINT
+}
+
+
+static void
+icvThickLine( CvMat* img, CvPoint p0, CvPoint p1, const void* color,
+ int thickness, int line_type, int flags, int shift )
+{
+ static const double INV_XY_ONE = 1./XY_ONE;
+
+ p0.x <<= XY_SHIFT - shift;
+ p0.y <<= XY_SHIFT - shift;
+ p1.x <<= XY_SHIFT - shift;
+ p1.y <<= XY_SHIFT - shift;
+
+ if( thickness <= 1 )
+ {
+ if( line_type < CV_AA )
+ {
+ if( line_type == 1 || line_type == 4 || shift == 0 )
+ {
+ p0.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT;
+ p0.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT;
+ p1.x = (p1.x + (XY_ONE>>1)) >> XY_SHIFT;
+ p1.y = (p1.y + (XY_ONE>>1)) >> XY_SHIFT;
+ icvLine( img, p0, p1, color, line_type );
+ }
+ else
+ icvLine2( img, p0, p1, color );
+ }
+ else
+ icvLineAA( img, p0, p1, color );
+ }
+ else
+ {
+ CvPoint pt[4], dp = {0,0};
+ double dx = (p0.x - p1.x)*INV_XY_ONE, dy = (p1.y - p0.y)*INV_XY_ONE;
+ double r = dx * dx + dy * dy;
+ int i;
+ thickness <<= XY_SHIFT - 1;
+
+ if( fabs(r) > DBL_EPSILON )
+ {
+ r = thickness * cvInvSqrt( (float) r );
+ dp.x = cvRound( dy * r );
+ dp.y = cvRound( dx * r );
+ }
+
+ pt[0].x = p0.x + dp.x;
+ pt[0].y = p0.y + dp.y;
+ pt[1].x = p0.x - dp.x;
+ pt[1].y = p0.y - dp.y;
+ pt[2].x = p1.x - dp.x;
+ pt[2].y = p1.y - dp.y;
+ pt[3].x = p1.x + dp.x;
+ pt[3].y = p1.y + dp.y;
+
+ icvFillConvexPoly( img, pt, 4, color, line_type, XY_SHIFT );
+
+ for( i = 0; i < 2; i++ )
+ {
+ if( flags & (i+1) )
+ {
+ if( line_type < CV_AA )
+ {
+ CvPoint center;
+ center.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT;
+ center.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT;
+ icvCircle( img, center, thickness >> XY_SHIFT, color, 1 );
+ }
+ else
+ {
+ icvEllipseEx( img, p0, cvSize(thickness, thickness),
+ 0, 0, 360, color, -1, line_type );
+ }
+ }
+ p0 = p1;
+ }
+ }
+}
+
+
+static void
+icvPolyLine( CvMat* img, CvPoint *v, int count, int is_closed,
+ const void* color, int thickness,
+ int line_type, int shift )
+{
+ CV_FUNCNAME("icvPolyLine");
+
+ __BEGIN__;
+
+ if( count > 0 )
+ {
+ int i = is_closed ? count - 1 : 0;
+ int flags = 2 + !is_closed;
+ CvPoint p0;
+ assert( 0 <= shift && shift <= XY_SHIFT );
+ assert( img && thickness >= 0 );
+ assert( v && count >= 0 );
+
+ if( !v )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ p0 = v[i];
+ for( i = !is_closed; i < count; i++ )
+ {
+ CvPoint p = v[i];
+ icvThickLine( img, p0, p, color, thickness, line_type, flags, shift );
+ p0 = p;
+ flags = 2;
+ }
+ }
+
+ __END__;
+}
+
+/****************************************************************************************\
+* External functions *
+\****************************************************************************************/
+
+CV_IMPL CvScalar cvColorToScalar( double packed_color, int type )
+{
+ CvScalar scalar;
+
+ if( CV_MAT_DEPTH( type ) == CV_8U )
+ {
+ int icolor = cvRound( packed_color );
+ if( CV_MAT_CN( type ) > 1 )
+ {
+ scalar.val[0] = icolor & 255;
+ scalar.val[1] = (icolor >> 8) & 255;
+ scalar.val[2] = (icolor >> 16) & 255;
+ scalar.val[3] = (icolor >> 24) & 255;
+ }
+ else
+ {
+ scalar.val[0] = CV_CAST_8U( icolor );
+ scalar.val[1] = scalar.val[2] = scalar.val[3] = 0;
+ }
+ }
+ else if( CV_MAT_DEPTH( type ) == CV_8S )
+ {
+ int icolor = cvRound( packed_color );
+ if( CV_MAT_CN( type ) > 1 )
+ {
+ scalar.val[0] = (char)icolor;
+ scalar.val[1] = (char)(icolor >> 8);
+ scalar.val[2] = (char)(icolor >> 16);
+ scalar.val[3] = (char)(icolor >> 24);
+ }
+ else
+ {
+ scalar.val[0] = CV_CAST_8S( icolor );
+ scalar.val[1] = scalar.val[2] = scalar.val[3] = 0;
+ }
+ }
+ else
+ {
+ int cn = CV_MAT_CN( type );
+ switch( cn )
+ {
+ case 1:
+ scalar.val[0] = packed_color;
+ scalar.val[1] = scalar.val[2] = scalar.val[3] = 0;
+ break;
+ case 2:
+ scalar.val[0] = scalar.val[1] = packed_color;
+ scalar.val[2] = scalar.val[3] = 0;
+ break;
+ case 3:
+ scalar.val[0] = scalar.val[1] = scalar.val[2] = packed_color;
+ scalar.val[3] = 0;
+ break;
+ default:
+ scalar.val[0] = scalar.val[1] =
+ scalar.val[2] = scalar.val[3] = packed_color;
+ break;
+ }
+ }
+
+ return scalar;
+}
+
+
+CV_IMPL void
+cvLine( void* img, CvPoint pt1, CvPoint pt2, CvScalar color,
+ int thickness, int line_type, int shift )
+{
+ CV_FUNCNAME( "cvLine" );
+
+ __BEGIN__;
+
+ int coi = 0;
+ CvMat stub, *mat = (CvMat*)img;
+ double buf[4];
+
+ CV_CALL( mat = cvGetMat( img, &stub, &coi ));
+
+ if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
+ line_type = 8;
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
+
+ if( (unsigned)thickness > 255 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ if( shift < 0 || XY_SHIFT < shift )
+ CV_ERROR( CV_StsOutOfRange, "shift must be between 0 and 16" );
+
+ CV_CALL( cvScalarToRawData( &color, buf, mat->type, 0 ));
+ icvThickLine( mat, pt1, pt2, buf, thickness, line_type, 3, shift );
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvRectangle( void* img, CvPoint pt1, CvPoint pt2,
+ CvScalar color, int thickness,
+ int line_type, int shift )
+{
+ CvPoint pt[4];
+
+ CV_FUNCNAME("cvRectangle");
+
+ __BEGIN__;
+
+ int coi = 0;
+ CvMat stub, *mat = (CvMat*)img;
+ double buf[4];
+
+ if( thickness > 255 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ CV_CALL( mat = cvGetMat( img, &stub, &coi ));
+
+ if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
+ line_type = 8;
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
+
+ if( shift < 0 || XY_SHIFT < shift )
+ CV_ERROR( CV_StsOutOfRange, "shift must be between 0 and 16" );
+
+ CV_CALL( cvScalarToRawData( &color, buf, mat->type, 0 ));
+
+ pt[0] = pt1;
+ pt[1].x = pt2.x;
+ pt[1].y = pt1.y;
+ pt[2] = pt2;
+ pt[3].x = pt1.x;
+ pt[3].y = pt2.y;
+
+ if( thickness >= 0 )
+ icvPolyLine( mat, pt, 4, 1, buf, thickness, line_type, shift );
+ else
+ icvFillConvexPoly( mat, pt, 4, buf, line_type, shift );
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvCircle( void *img, CvPoint center, int radius,
+ CvScalar color, int thickness, int line_type, int shift )
+{
+ CV_FUNCNAME( "cvCircle" );
+
+ __BEGIN__;
+
+ int coi = 0;
+ CvMat stub, *mat = (CvMat*)img;
+ double buf[4];
+
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+
+ if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
+ line_type = 8;
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
+
+ if( radius < 0 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ if( thickness > 255 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ if( shift < 0 || XY_SHIFT < shift )
+ CV_ERROR( CV_StsOutOfRange, "shift must be between 0 and 16" );
+
+ CV_CALL( cvScalarToRawData( &color, buf, mat->type, 0 ));
+
+ if( thickness > 1 || line_type >= CV_AA )
+ {
+ center.x <<= XY_SHIFT - shift;
+ center.y <<= XY_SHIFT - shift;
+ radius <<= XY_SHIFT - shift;
+ icvEllipseEx( mat, center, cvSize( radius, radius ),
+ 0, 0, 360, buf, thickness, line_type );
+ }
+ else
+ {
+ icvCircle( mat, center, radius, buf, thickness < 0 );
+ }
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvEllipse( void *img, CvPoint center, CvSize axes,
+ double angle, double start_angle, double end_angle,
+ CvScalar color, int thickness, int line_type, int shift )
+{
+ CV_FUNCNAME( "cvEllipse" );
+
+ __BEGIN__;
+
+ int coi = 0;
+ CvMat stub, *mat = (CvMat*)img;
+ double buf[4];
+
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+
+ if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
+ line_type = 8;
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
+
+ if( axes.width < 0 || axes.height < 0 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ if( thickness > 255 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ if( shift < 0 || XY_SHIFT < shift )
+ CV_ERROR( CV_StsOutOfRange, "shift must be between 0 and 16" );
+
+ CV_CALL( cvScalarToRawData( &color, buf, mat->type, 0 ));
+
+ {
+ int _angle = cvRound(angle);
+ int _start_angle = cvRound(start_angle);
+ int _end_angle = cvRound(end_angle);
+ center.x <<= XY_SHIFT - shift;
+ center.y <<= XY_SHIFT - shift;
+ axes.width <<= XY_SHIFT - shift;
+ axes.height <<= XY_SHIFT - shift;
+
+ CV_CALL( icvEllipseEx( mat, center, axes, _angle, _start_angle,
+ _end_angle, buf, thickness, line_type ));
+ }
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvFillConvexPoly( void *img, CvPoint *pts, int npts, CvScalar color, int line_type, int shift )
+{
+ CV_FUNCNAME( "cvFillConvexPoly" );
+
+ __BEGIN__;
+
+ int coi = 0;
+ CvMat stub, *mat = (CvMat*)img;
+ double buf[4];
+
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+
+ if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
+ line_type = 8;
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
+
+ if( !pts )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( npts <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ if( shift < 0 || XY_SHIFT < shift )
+ CV_ERROR( CV_StsOutOfRange, "shift must be between 0 and 16" );
+
+ CV_CALL( cvScalarToRawData( &color, buf, mat->type, 0 ));
+ icvFillConvexPoly( mat, pts, npts, buf, line_type, shift );
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvFillPoly( void *img, CvPoint **pts, int *npts, int contours,
+ CvScalar color, int line_type, int shift )
+{
+ CvMemStorage* st = 0;
+
+ CV_FUNCNAME( "cvFillPoly" );
+
+ __BEGIN__;
+
+ int coi = 0;
+ CvMat stub, *mat = (CvMat*)img;
+ double buf[4];
+
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+
+ if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
+ line_type = 8;
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
+
+ if( contours <= 0 )
+ CV_ERROR( CV_StsBadArg, "" );
+
+ if( !pts )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( npts <= 0 )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( shift < 0 || XY_SHIFT < shift )
+ CV_ERROR( CV_StsOutOfRange, "shift must be between 0 and 16" );
+
+ CV_CALL( cvScalarToRawData( &color, buf, mat->type, 0 ));
+
+ {
+ CvContour* edges = 0;
+ CvSeq vtx;
+ CvSeqBlock block;
+
+ CV_CALL( st = cvCreateMemStorage( CV_DRAWING_STORAGE_BLOCK ));
+ CV_CALL( edges = (CvContour*)cvCreateSeq( 0, sizeof(CvContour),
+ sizeof(CvPolyEdge), st ));
+
+ for( int i = 0; i < contours; i++ )
+ {
+ if( !pts[i] )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( npts[i] < 0 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ cvMakeSeqHeaderForArray( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint),
+ pts[i], npts[i], &vtx, &block );
+
+ CV_CALL( icvCollectPolyEdges( mat, &vtx, edges, buf, line_type, shift ));
+ }
+
+ CV_CALL( icvFillEdgeCollection( mat, edges, buf ));
+ }
+
+ __END__;
+
+ cvReleaseMemStorage( &st );
+}
+
+
+
+CV_IMPL void
+cvPolyLine( void *img, CvPoint **pts, int *npts,
+ int contours, int closed, CvScalar color,
+ int thickness, int line_type, int shift )
+{
+ CV_FUNCNAME( "cvPolyLine" );
+
+ __BEGIN__;
+
+ int coi = 0, i;
+ CvMat stub, *mat = (CvMat*)img;
+ double buf[4];
+
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+
+ if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
+ line_type = 8;
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
+
+ if( contours <= 0 )
+ CV_ERROR( CV_StsBadArg, "" );
+
+ if( thickness < -1 || thickness > 255 )
+ CV_ERROR( CV_StsBadArg, "" );
+
+ if( !pts )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( npts <= 0 )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( shift < 0 || XY_SHIFT < shift )
+ CV_ERROR( CV_StsOutOfRange, "shift must be between 0 and 16" );
+
+ CV_CALL( cvScalarToRawData( &color, buf, mat->type, 0 ));
+
+ for( i = 0; i < contours; i++ )
+ icvPolyLine( mat, pts[i], npts[i], closed, buf, thickness, line_type, shift );
+
+ __END__;
+}
+
+
+#define CV_FONT_SIZE_SHIFT 8
+#define CV_FONT_ITALIC_ALPHA (1 << 8)
+#define CV_FONT_ITALIC_DIGIT (2 << 8)
+#define CV_FONT_ITALIC_PUNCT (4 << 8)
+#define CV_FONT_ITALIC_BRACES (8 << 8)
+#define CV_FONT_HAVE_GREEK (16 << 8)
+#define CV_FONT_HAVE_CYRILLIC (32 << 8)
+
+static const int icvHersheyPlain[] = {
+(5 + 4*16) + CV_FONT_HAVE_GREEK,
+199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220,
+200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192,
+215, 190, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 193, 84,
+194, 85, 86, 87, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
+195, 223, 196, 88 };
+
+static const int icvHersheyPlainItalic[] = {
+(5 + 4*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_HAVE_GREEK,
+199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220,
+200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192,
+215, 190, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 193, 84,
+194, 85, 86, 87, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161,
+162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
+195, 223, 196, 88 };
+
+static const int icvHersheyComplexSmall[] = {
+(6 + 7*16) + CV_FONT_HAVE_GREEK,
+1199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220,
+1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 2213, 1241, 1238, 1242,
+1215, 1273, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013,
+1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1223, 1084,
+1224, 1247, 586, 1249, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111,
+1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126,
+1225, 1229, 1226, 1246 };
+
+static const int icvHersheyComplexSmallItalic[] = {
+(6 + 7*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_HAVE_GREEK,
+1199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220,
+1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 1213, 1241, 1238, 1242,
+1215, 1273, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063,
+1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1223, 1084,
+1224, 1247, 586, 1249, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161,
+1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176,
+1225, 1229, 1226, 1246 };
+
+static const int icvHersheySimplex[] = {
+(9 + 12*16) + CV_FONT_HAVE_GREEK,
+2199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720,
+700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692,
+715, 690, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513,
+514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 693, 584,
+694, 2247, 586, 2249, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611,
+612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626,
+695, 723, 696, 2246 };
+
+static const int icvHersheyDuplex[] = {
+(9 + 12*16) + CV_FONT_HAVE_GREEK,
+2199, 2714, 2728, 2732, 2719, 2733, 2718, 2727, 2721, 2722, 2723, 2725, 2711, 2724, 2710, 2720,
+2700, 2701, 2702, 2703, 2704, 2705, 2706, 2707, 2708, 2709, 2712, 2713, 2730, 2726, 2731,
+2715, 2734, 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, 2512, 2513,
+2514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524, 2525, 2526, 2223, 2084,
+2224, 2247, 587, 2249, 2601, 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611,
+2612, 2613, 2614, 2615, 2616, 2617, 2618, 2619, 2620, 2621, 2622, 2623, 2624, 2625, 2626,
+2225, 2229, 2226, 2246 };
+
+static const int icvHersheyComplex[] = {
+(9 + 12*16) + CV_FONT_HAVE_GREEK + CV_FONT_HAVE_CYRILLIC,
+2199, 2214, 2217, 2275, 2274, 2271, 2272, 2216, 2221, 2222, 2219, 2232, 2211, 2231, 2210, 2220,
+2200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2212, 2213, 2241, 2238, 2242,
+2215, 2273, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
+2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2223, 2084,
+2224, 2247, 587, 2249, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111,
+2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126,
+2225, 2229, 2226, 2246 };
+
+static const int icvHersheyComplexItalic[] = {
+(9 + 12*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_ITALIC_DIGIT + CV_FONT_ITALIC_PUNCT +
+CV_FONT_HAVE_GREEK + CV_FONT_HAVE_CYRILLIC,
+2199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220,
+2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242,
+2765, 2273, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063,
+2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2223, 2084,
+2224, 2247, 587, 2249, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161,
+2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176,
+2225, 2229, 2226, 2246 };
+
+static const int icvHersheyTriplex[] = {
+(9 + 12*16) + CV_FONT_HAVE_GREEK,
+2199, 3214, 3228, 3232, 3219, 3233, 3218, 3227, 3221, 3222, 3223, 3225, 3211, 3224, 3210, 3220,
+3200, 3201, 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, 3212, 3213, 3230, 3226, 3231,
+3215, 3234, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013,
+2014, 3015, 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 2223, 2084,
+2224, 2247, 587, 2249, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111,
+3112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3125, 3126,
+2225, 2229, 2226, 2246 };
+
+static const int icvHersheyTriplexItalic[] = {
+(9 + 12*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_ITALIC_DIGIT +
+CV_FONT_ITALIC_PUNCT + CV_FONT_HAVE_GREEK,
+2199, 3264, 3278, 3282, 3269, 3233, 3268, 3277, 3271, 3272, 3223, 3225, 3261, 3224, 3260, 3270,
+3250, 3251, 3252, 3253, 3254, 3255, 3256, 3257, 3258, 3259, 3262, 3263, 3230, 3226, 3231,
+3265, 3234, 3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063,
+2064, 3065, 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076, 2223, 2084,
+2224, 2247, 587, 2249, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161,
+3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, 3175, 3176,
+2225, 2229, 2226, 2246 };
+
+static const int icvHersheyScriptSimplex[] = {
+(9 + 12*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_HAVE_GREEK,
+2199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720,
+700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692,
+715, 690, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563,
+564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 693, 584,
+694, 2247, 586, 2249, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661,
+662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676,
+695, 723, 696, 2246 };
+
+static const int icvHersheyScriptComplex[] = {
+(9 + 12*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_ITALIC_DIGIT + CV_FONT_ITALIC_PUNCT + CV_FONT_HAVE_GREEK,
+2199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220,
+2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242,
+2215, 2273, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563,
+2564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2572, 2573, 2574, 2575, 2576, 2223, 2084,
+2224, 2247, 586, 2249, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661,
+2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676,
+2225, 2229, 2226, 2246 };
+
+
+CV_IMPL void
+cvPutText( void *img, const char *text, CvPoint org, const CvFont *font, CvScalar color )
+{
+ CV_FUNCNAME( "cvPutText" );
+
+ __BEGIN__;
+
+ int view_x, view_y;
+ int coi = 0;
+ int top_bottom = 0, base_line;
+ int hscale, vscale, default_shear, italic_shear;
+ int thickness, line_type;
+ CvMat stub, *mat = (CvMat*)img;
+ double buf[4];
+ CvPoint pt[1 << 10];
+ int count;
+
+ int i;
+ const char **faces = icvHersheyGlyphs;
+
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
+
+ if( CV_IS_IMAGE_HDR(img) && ((IplImage*)img)->origin )
+ top_bottom = 1;
+
+ if( !text || !font || !font->ascii )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ CV_CALL( cvScalarToRawData( &color, buf, mat->type, 0 ));
+ base_line = -(font->ascii[0] & 15);
+ hscale = cvRound(font->hscale*XY_ONE);
+ vscale = cvRound(font->vscale*XY_ONE);
+ default_shear = cvRound(font->shear*font->vscale*XY_ONE);
+ italic_shear = !(font->font_face & CV_FONT_ITALIC) ? 0 : cvRound(font->vscale*.25*XY_ONE);
+ thickness = font->thickness;
+ line_type = font->line_type;
+
+ if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
+ line_type = 8;
+
+ if( top_bottom )
+ vscale = -vscale;
+
+ view_x = org.x << XY_SHIFT;
+ view_y = (org.y << XY_SHIFT) + base_line*vscale;
+
+ for( i = 0; text[i] != '\0'; i++ )
+ {
+ int c = (uchar)text[i];
+ int dx, shear = default_shear;
+ const char* ptr;
+ CvPoint p;
+
+ if( c > 128 || c < ' ' )
+ c = '?';
+
+ if( italic_shear )
+ {
+ if( ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
+ {
+ if( !(font->ascii[0] & CV_FONT_ITALIC_ALPHA) )
+ shear += italic_shear;
+ }
+ else if( '0' <= c && c <= '9' )
+ {
+ if( !(font->ascii[0] & CV_FONT_ITALIC_DIGIT) )
+ shear += italic_shear;
+ }
+ else if( c < 'A' )
+ {
+ if( !(font->ascii[0] & CV_FONT_ITALIC_PUNCT) )
+ shear += italic_shear;
+ }
+ else
+ {
+ shear += italic_shear;
+ }
+ }
+
+ ptr = faces[font->ascii[(c-' ')+1]];
+ p.x = (unsigned char)ptr[0] - 'R';
+ p.y = (unsigned char)ptr[1] - 'R';
+ dx = p.y*hscale;
+ view_x -= p.x*hscale;
+ count = 0;
+
+ for( ptr += 2;; )
+ {
+ if( *ptr == ' ' || !*ptr )
+ {
+ if( count > 1 )
+ icvPolyLine( mat, pt, count, 0, buf, thickness, line_type, XY_SHIFT );
+ if( !*ptr++ )
+ break;
+ count = 0;
+ }
+ else
+ {
+ p.x = (unsigned char)ptr[0] - 'R';
+ p.y = (unsigned char)ptr[1] - 'R';
+ ptr += 2;
+ pt[count].x = p.x*hscale - p.y*shear + view_x;
+ pt[count++].y = p.y*vscale + view_y;
+ }
+ }
+ view_x += dx;
+ }
+
+ __END__;
+}
+
+CV_IMPL void
+cvInitFont( CvFont *font, int font_face, double hscale, double vscale,
+ double shear, int thickness, int line_type )
+{
+ CV_FUNCNAME( "cvInitFont" );
+
+ __BEGIN__;
+
+ int is_italic = font_face & CV_FONT_ITALIC;
+
+ if( !font )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( hscale <= 0 || vscale <= 0 || thickness < 0 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ switch( (font_face & 7) )
+ {
+ case CV_FONT_HERSHEY_SIMPLEX:
+ font->ascii = icvHersheySimplex;
+ break;
+ case CV_FONT_HERSHEY_PLAIN:
+ font->ascii = !is_italic ? icvHersheyPlain : icvHersheyPlainItalic;
+ break;
+ case CV_FONT_HERSHEY_DUPLEX:
+ font->ascii = icvHersheyDuplex;
+ break;
+ case CV_FONT_HERSHEY_COMPLEX:
+ font->ascii = !is_italic ? icvHersheyComplex : icvHersheyComplexItalic;
+ break;
+ case CV_FONT_HERSHEY_TRIPLEX:
+ font->ascii = !is_italic ? icvHersheyTriplex : icvHersheyTriplexItalic;
+ break;
+ case CV_FONT_HERSHEY_COMPLEX_SMALL:
+ font->ascii = !is_italic ? icvHersheyComplexSmall : icvHersheyComplexSmallItalic;
+ break;
+ case CV_FONT_HERSHEY_SCRIPT_SIMPLEX:
+ font->ascii = icvHersheyScriptSimplex;
+ break;
+ case CV_FONT_HERSHEY_SCRIPT_COMPLEX:
+ font->ascii = icvHersheyScriptComplex;
+ break;
+ default:
+ CV_ERROR( CV_StsOutOfRange, "Unknown font type" );
+ }
+
+ font->font_face = font_face;
+ font->hscale = (float)hscale;
+ font->vscale = (float)vscale;
+ font->thickness = thickness;
+ font->shear = (float)shear;
+ font->greek = font->cyrillic = 0;
+ font->line_type = line_type;
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvGetTextSize( const char *text, const CvFont *font, CvSize *size, int *_base_line )
+{
+ CV_FUNCNAME( "cvGetTextSize" );
+
+ __BEGIN__;
+
+ float view_x = 0;
+ int base_line, cap_line;
+
+ int i;
+ const char **faces = icvHersheyGlyphs;
+
+ if( !text || !font || !font->ascii || !size )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ base_line = (font->ascii[0] & 15);
+ cap_line = (font->ascii[0] >> 4) & 15;
+ if( _base_line )
+ *_base_line = cvRound(base_line*font->vscale);
+ size->height = cvRound((cap_line + base_line)*font->vscale + font->thickness);
+
+ for( i = 0; text[i] != '\0'; i++ )
+ {
+ int c = (uchar)text[i];
+ const char* ptr;
+ CvPoint p;
+
+ if( c > 128 || c < ' ' )
+ c = '?';
+
+ ptr = faces[font->ascii[(c-' ')+1]];
+ p.x = (unsigned char)ptr[0] - 'R';
+ p.y = (unsigned char)ptr[1] - 'R';
+ view_x += (p.y - p.x)*font->hscale;
+ }
+
+ size->width = cvRound(view_x + font->thickness);
+
+ __END__;
+}
+
+
+static const CvPoint icvCodeDeltas[8] =
+{ {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} };
+
+#define CV_ADJUST_EDGE_COUNT( count, seq ) \
+ ((count) -= ((count) == (seq)->total && !CV_IS_SEQ_CLOSED(seq)))
+
+CV_IMPL void
+cvDrawContours( void* img, CvSeq* contour,
+ CvScalar externalColor, CvScalar holeColor,
+ int maxLevel, int thickness,
+ int line_type, CvPoint offset )
+{
+ CvSeq *contour0 = contour, *h_next = 0;
+ CvMemStorage* st = 0;
+ CvSeq* tseq = 0;
+ CvContour* edges = 0;
+ CvSeqWriter writer;
+ CvTreeNodeIterator iterator;
+
+ CV_FUNCNAME( "cvDrawContours" );
+
+ __BEGIN__;
+
+ int coi = 0;
+ CvMat stub, *mat = (CvMat*)img;
+ double ext_buf[4], hole_buf[4];
+
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+
+ if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
+ line_type = 8;
+
+ if( !contour )
+ EXIT;
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
+
+ if( thickness < -1 || thickness > 255 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+
+ CV_CALL( cvScalarToRawData( &externalColor, ext_buf, mat->type, 0 ));
+ CV_CALL( cvScalarToRawData( &holeColor, hole_buf, mat->type, 0 ));
+
+ if( maxLevel < 0 )
+ {
+ h_next = contour->h_next;
+ contour->h_next = 0;
+ maxLevel = -maxLevel+1;
+ }
+
+ if( thickness < 0 )
+ {
+ if( contour->storage )
+ st = cvCreateChildMemStorage( contour->storage );
+ else
+ st = cvCreateMemStorage( CV_DRAWING_STORAGE_BLOCK );
+ tseq = cvCreateSeq( 0, sizeof(CvContour), sizeof(CvPoint), st );
+ edges = (CvContour*)cvCreateSeq( 0, sizeof(CvContour), sizeof(CvPolyEdge), st );
+ }
+
+ memset( &writer, 0, sizeof(writer));
+
+ cvInitTreeNodeIterator( &iterator, contour, maxLevel );
+
+ while( (contour = (CvSeq*)cvNextTreeNode( &iterator )) != 0 )
+ {
+ CvSeqReader reader;
+ int i, count = contour->total;
+ int elem_type = CV_MAT_TYPE(contour->flags);
+ void* clr = (contour->flags & CV_SEQ_FLAG_HOLE) == 0 ? ext_buf : hole_buf;
+
+ cvStartReadSeq( contour, &reader, 0 );
+
+ if( CV_IS_SEQ_CHAIN_CONTOUR( contour ))
+ {
+ CvPoint pt = ((CvChain*)contour)->origin;
+ CvPoint prev_pt = pt;
+ char prev_code = reader.ptr ? reader.ptr[0] : '\0';
+
+ if( thickness < 0 )
+ {
+ cvClearSeq( tseq );
+ cvStartAppendToSeq( tseq, &writer );
+ CV_WRITE_SEQ_ELEM( pt, writer );
+ }
+
+ prev_pt.x += offset.x;
+ prev_pt.y += offset.y;
+
+ for( i = 0; i < count; i++ )
+ {
+ char code;
+ CV_READ_SEQ_ELEM( code, reader );
+
+ assert( (code & ~7) == 0 );
+
+ if( code != prev_code )
+ {
+ prev_code = code;
+ if( thickness >= 0 )
+ {
+ icvThickLine( mat, prev_pt, pt, clr, thickness, line_type, 2, 0 );
+ }
+ else
+ {
+ CV_WRITE_SEQ_ELEM( pt, writer );
+ }
+ prev_pt = pt;
+ }
+
+ pt.x += icvCodeDeltas[(int)code].x;
+ pt.y += icvCodeDeltas[(int)code].y;
+ }
+
+ if( thickness >= 0 )
+ {
+ icvThickLine( mat, prev_pt, ((CvChain*)contour)->origin,
+ clr, thickness, line_type, 2, 0 );
+ }
+ else
+ {
+ CV_WRITE_SEQ_ELEM( pt, writer );
+ cvEndWriteSeq( &writer );
+ CV_CALL( icvCollectPolyEdges( mat, tseq, edges, ext_buf, line_type, 0 ));
+ }
+ }
+ else if( CV_IS_SEQ_POLYLINE( contour ))
+ {
+ if( thickness >= 0 )
+ {
+ CvPoint pt1, pt2;
+ int shift = 0;
+
+ count -= !CV_IS_SEQ_CLOSED(contour);
+ if( elem_type == CV_32SC2 )
+ {
+ CV_READ_SEQ_ELEM( pt1, reader );
+ pt1.x += offset.x;
+ pt1.y += offset.y;
+ }
+ else
+ {
+ CvPoint2D32f pt1f;
+ CV_READ_SEQ_ELEM( pt1f, reader );
+ pt1.x = cvRound( (pt1f.x + offset.x) * XY_ONE );
+ pt1.y = cvRound( (pt1f.y + offset.y) * XY_ONE );
+ shift = XY_SHIFT;
+ }
+
+ for( i = 0; i < count; i++ )
+ {
+ if( elem_type == CV_32SC2 )
+ {
+ CV_READ_SEQ_ELEM( pt2, reader );
+ pt2.x += offset.x;
+ pt2.y += offset.y;
+ }
+ else
+ {
+ CvPoint2D32f pt2f;
+ CV_READ_SEQ_ELEM( pt2f, reader );
+ pt2.x = cvRound( pt2f.x * XY_ONE );
+ pt2.y = cvRound( pt2f.y * XY_ONE );
+ }
+ icvThickLine( mat, pt1, pt2, clr, thickness, line_type, 2, shift );
+ pt1 = pt2;
+ }
+ }
+ else
+ {
+ CV_CALL( icvCollectPolyEdges( mat, contour, edges, ext_buf, line_type, 0, offset ));
+ }
+ }
+ }
+
+ if( thickness < 0 )
+ {
+ CV_CALL( icvFillEdgeCollection( mat, edges, ext_buf ));
+ }
+
+ __END__;
+
+ if( h_next && contour0 )
+ contour0->h_next = h_next;
+
+ cvReleaseMemStorage( &st );
+}
+
+/* End of file. */
diff --git a/cxcore/src/cxdxt.cpp b/cxcore/src/cxdxt.cpp
new file mode 100644
index 0000000..60b3c89
--- /dev/null
+++ b/cxcore/src/cxdxt.cpp
@@ -0,0 +1,3003 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+
+// On Win64 (IA64) optimized versions of DFT and DCT fail the tests
+#if defined WIN64 && !defined EM64T
+#pragma optimize("", off)
+#endif
+
+icvDFTInitAlloc_C_32fc_t icvDFTInitAlloc_C_32fc_p = 0;
+icvDFTFree_C_32fc_t icvDFTFree_C_32fc_p = 0;
+icvDFTGetBufSize_C_32fc_t icvDFTGetBufSize_C_32fc_p = 0;
+icvDFTFwd_CToC_32fc_t icvDFTFwd_CToC_32fc_p = 0;
+icvDFTInv_CToC_32fc_t icvDFTInv_CToC_32fc_p = 0;
+
+icvDFTInitAlloc_C_64fc_t icvDFTInitAlloc_C_64fc_p = 0;
+icvDFTFree_C_64fc_t icvDFTFree_C_64fc_p = 0;
+icvDFTGetBufSize_C_64fc_t icvDFTGetBufSize_C_64fc_p = 0;
+icvDFTFwd_CToC_64fc_t icvDFTFwd_CToC_64fc_p = 0;
+icvDFTInv_CToC_64fc_t icvDFTInv_CToC_64fc_p = 0;
+
+icvDFTInitAlloc_R_32f_t icvDFTInitAlloc_R_32f_p = 0;
+icvDFTFree_R_32f_t icvDFTFree_R_32f_p = 0;
+icvDFTGetBufSize_R_32f_t icvDFTGetBufSize_R_32f_p = 0;
+icvDFTFwd_RToPack_32f_t icvDFTFwd_RToPack_32f_p = 0;
+icvDFTInv_PackToR_32f_t icvDFTInv_PackToR_32f_p = 0;
+
+icvDFTInitAlloc_R_64f_t icvDFTInitAlloc_R_64f_p = 0;
+icvDFTFree_R_64f_t icvDFTFree_R_64f_p = 0;
+icvDFTGetBufSize_R_64f_t icvDFTGetBufSize_R_64f_p = 0;
+icvDFTFwd_RToPack_64f_t icvDFTFwd_RToPack_64f_p = 0;
+icvDFTInv_PackToR_64f_t icvDFTInv_PackToR_64f_p = 0;
+
+/*icvDCTFwdInitAlloc_32f_t icvDCTFwdInitAlloc_32f_p = 0;
+icvDCTFwdFree_32f_t icvDCTFwdFree_32f_p = 0;
+icvDCTFwdGetBufSize_32f_t icvDCTFwdGetBufSize_32f_p = 0;
+icvDCTFwd_32f_t icvDCTFwd_32f_p = 0;
+
+icvDCTInvInitAlloc_32f_t icvDCTInvInitAlloc_32f_p = 0;
+icvDCTInvFree_32f_t icvDCTInvFree_32f_p = 0;
+icvDCTInvGetBufSize_32f_t icvDCTInvGetBufSize_32f_p = 0;
+icvDCTInv_32f_t icvDCTInv_32f_p = 0;
+
+icvDCTFwdInitAlloc_64f_t icvDCTFwdInitAlloc_64f_p = 0;
+icvDCTFwdFree_64f_t icvDCTFwdFree_64f_p = 0;
+icvDCTFwdGetBufSize_64f_t icvDCTFwdGetBufSize_64f_p = 0;
+icvDCTFwd_64f_t icvDCTFwd_64f_p = 0;
+
+icvDCTInvInitAlloc_64f_t icvDCTInvInitAlloc_64f_p = 0;
+icvDCTInvFree_64f_t icvDCTInvFree_64f_p = 0;
+icvDCTInvGetBufSize_64f_t icvDCTInvGetBufSize_64f_p = 0;
+icvDCTInv_64f_t icvDCTInv_64f_p = 0;*/
+
+/****************************************************************************************\
+ Discrete Fourier Transform
+\****************************************************************************************/
+
+#define CV_MAX_LOCAL_DFT_SIZE (1 << 15)
+
+static const uchar log2tab[] = { 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0 };
+static int icvlog2( int n )
+{
+ int m = 0;
+ int f = (n >= (1 << 16))*16;
+ n >>= f;
+ m += f;
+ f = (n >= (1 << 8))*8;
+ n >>= f;
+ m += f;
+ f = (n >= (1 << 4))*4;
+ n >>= f;
+ return m + f + log2tab[n];
+}
+
+static unsigned char icvRevTable[] =
+{
+ 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
+ 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
+ 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
+ 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
+ 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
+ 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
+ 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
+ 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
+ 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
+ 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
+ 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
+ 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
+ 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
+ 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
+ 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
+ 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
+};
+
+static const double icvDxtTab[][2] =
+{
+{ 1.00000000000000000, 0.00000000000000000 },
+{-1.00000000000000000, 0.00000000000000000 },
+{ 0.00000000000000000, 1.00000000000000000 },
+{ 0.70710678118654757, 0.70710678118654746 },
+{ 0.92387953251128674, 0.38268343236508978 },
+{ 0.98078528040323043, 0.19509032201612825 },
+{ 0.99518472667219693, 0.09801714032956060 },
+{ 0.99879545620517241, 0.04906767432741802 },
+{ 0.99969881869620425, 0.02454122852291229 },
+{ 0.99992470183914450, 0.01227153828571993 },
+{ 0.99998117528260111, 0.00613588464915448 },
+{ 0.99999529380957619, 0.00306795676296598 },
+{ 0.99999882345170188, 0.00153398018628477 },
+{ 0.99999970586288223, 0.00076699031874270 },
+{ 0.99999992646571789, 0.00038349518757140 },
+{ 0.99999998161642933, 0.00019174759731070 },
+{ 0.99999999540410733, 0.00009587379909598 },
+{ 0.99999999885102686, 0.00004793689960307 },
+{ 0.99999999971275666, 0.00002396844980842 },
+{ 0.99999999992818922, 0.00001198422490507 },
+{ 0.99999999998204725, 0.00000599211245264 },
+{ 0.99999999999551181, 0.00000299605622633 },
+{ 0.99999999999887801, 0.00000149802811317 },
+{ 0.99999999999971945, 0.00000074901405658 },
+{ 0.99999999999992983, 0.00000037450702829 },
+{ 0.99999999999998246, 0.00000018725351415 },
+{ 0.99999999999999567, 0.00000009362675707 },
+{ 0.99999999999999889, 0.00000004681337854 },
+{ 0.99999999999999978, 0.00000002340668927 },
+{ 0.99999999999999989, 0.00000001170334463 },
+{ 1.00000000000000000, 0.00000000585167232 },
+{ 1.00000000000000000, 0.00000000292583616 }
+};
+
+#define icvBitRev(i,shift) \
+ ((int)((((unsigned)icvRevTable[(i)&255] << 24)+ \
+ ((unsigned)icvRevTable[((i)>> 8)&255] << 16)+ \
+ ((unsigned)icvRevTable[((i)>>16)&255] << 8)+ \
+ ((unsigned)icvRevTable[((i)>>24)])) >> (shift)))
+
+static int
+icvDFTFactorize( int n, int* factors )
+{
+ int nf = 0, f, i, j;
+
+ if( n <= 5 )
+ {
+ factors[0] = n;
+ return 1;
+ }
+
+ f = (((n - 1)^n)+1) >> 1;
+ if( f > 1 )
+ {
+ factors[nf++] = f;
+ n = f == n ? 1 : n/f;
+ }
+
+ for( f = 3; n > 1; )
+ {
+ int d = n/f;
+ if( d*f == n )
+ {
+ factors[nf++] = f;
+ n = d;
+ }
+ else
+ {
+ f += 2;
+ if( f*f > n )
+ break;
+ }
+ }
+
+ if( n > 1 )
+ factors[nf++] = n;
+
+ f = (factors[0] & 1) == 0;
+ for( i = f; i < (nf+f)/2; i++ )
+ CV_SWAP( factors[i], factors[nf-i-1+f], j );
+
+ return nf;
+}
+
+static void
+icvDFTInit( int n0, int nf, int* factors, int* itab, int elem_size, void* _wave, int inv_itab )
+{
+ int digits[34], radix[34];
+ int n = factors[0], m = 0;
+ int* itab0 = itab;
+ int i, j, k;
+ CvComplex64f w, w1;
+ double t;
+
+ if( n0 <= 5 )
+ {
+ itab[0] = 0;
+ itab[n0-1] = n0-1;
+
+ if( n0 != 4 )
+ {
+ for( i = 1; i < n0-1; i++ )
+ itab[i] = i;
+ }
+ else
+ {
+ itab[1] = 2;
+ itab[2] = 1;
+ }
+ if( n0 == 5 )
+ {
+ if( elem_size == sizeof(CvComplex64f) )
+ ((CvComplex64f*)_wave)[0] = CvComplex64f(1.,0.);
+ else
+ ((CvComplex32f*)_wave)[0] = CvComplex32f(1.f,0.f);
+ }
+ if( n0 != 4 )
+ return;
+ m = 2;
+ }
+ else
+ {
+ // radix[] is initialized from index 'nf' down to zero
+ assert (nf < 34);
+ radix[nf] = 1;
+ digits[nf] = 0;
+ for( i = 0; i < nf; i++ )
+ {
+ digits[i] = 0;
+ radix[nf-i-1] = radix[nf-i]*factors[nf-i-1];
+ }
+
+ if( inv_itab && factors[0] != factors[nf-1] )
+ itab = (int*)_wave;
+
+ if( (n & 1) == 0 )
+ {
+ int a = radix[1], na2 = n*a>>1, na4 = na2 >> 1;
+ m = icvlog2(n);
+
+ if( n <= 2 )
+ {
+ itab[0] = 0;
+ itab[1] = na2;
+ }
+ else if( n <= 256 )
+ {
+ int shift = 10 - m;
+ for( i = 0; i <= n - 4; i += 4 )
+ {
+ j = (icvRevTable[i>>2]>>shift)*a;
+ itab[i] = j;
+ itab[i+1] = j + na2;
+ itab[i+2] = j + na4;
+ itab[i+3] = j + na2 + na4;
+ }
+ }
+ else
+ {
+ int shift = 34 - m;
+ for( i = 0; i < n; i += 4 )
+ {
+ int i4 = i >> 2;
+ j = icvBitRev(i4,shift)*a;
+ itab[i] = j;
+ itab[i+1] = j + na2;
+ itab[i+2] = j + na4;
+ itab[i+3] = j + na2 + na4;
+ }
+ }
+
+ digits[1]++;
+
+ if( nf >= 2 )
+ {
+ for( i = n, j = radix[2]; i < n0; )
+ {
+ for( k = 0; k < n; k++ )
+ itab[i+k] = itab[k] + j;
+ if( (i += n) >= n0 )
+ break;
+ j += radix[2];
+ for( k = 1; ++digits[k] >= factors[k]; k++ )
+ {
+ digits[k] = 0;
+ j += radix[k+2] - radix[k];
+ }
+ }
+ }
+ }
+ else
+ {
+ for( i = 0, j = 0;; )
+ {
+ itab[i] = j;
+ if( ++i >= n0 )
+ break;
+ j += radix[1];
+ for( k = 0; ++digits[k] >= factors[k]; k++ )
+ {
+ digits[k] = 0;
+ j += radix[k+2] - radix[k];
+ }
+ }
+ }
+
+ if( itab != itab0 )
+ {
+ itab0[0] = 0;
+ for( i = n0 & 1; i < n0; i += 2 )
+ {
+ int k0 = itab[i];
+ int k1 = itab[i+1];
+ itab0[k0] = i;
+ itab0[k1] = i+1;
+ }
+ }
+ }
+
+ if( (n0 & (n0-1)) == 0 )
+ {
+ w.re = w1.re = icvDxtTab[m][0];
+ w.im = w1.im = -icvDxtTab[m][1];
+ }
+ else
+ {
+ t = -CV_PI*2/n0;
+ w.im = w1.im = sin(t);
+ w.re = w1.re = sqrt(1. - w1.im*w1.im);
+ }
+ n = (n0+1)/2;
+
+ if( elem_size == sizeof(CvComplex64f) )
+ {
+ CvComplex64f* wave = (CvComplex64f*)_wave;
+
+ wave[0].re = 1.;
+ wave[0].im = 0.;
+
+ if( (n0 & 1) == 0 )
+ {
+ wave[n].re = -1.;
+ wave[n].im = 0;
+ }
+
+ for( i = 1; i < n; i++ )
+ {
+ wave[i] = w;
+ wave[n0-i].re = w.re;
+ wave[n0-i].im = -w.im;
+
+ t = w.re*w1.re - w.im*w1.im;
+ w.im = w.re*w1.im + w.im*w1.re;
+ w.re = t;
+ }
+ }
+ else
+ {
+ CvComplex32f* wave = (CvComplex32f*)_wave;
+ assert( elem_size == sizeof(CvComplex32f) );
+
+ wave[0].re = 1.f;
+ wave[0].im = 0.f;
+
+ if( (n0 & 1) == 0 )
+ {
+ wave[n].re = -1.f;
+ wave[n].im = 0.f;
+ }
+
+ for( i = 1; i < n; i++ )
+ {
+ wave[i].re = (float)w.re;
+ wave[i].im = (float)w.im;
+ wave[n0-i].re = (float)w.re;
+ wave[n0-i].im = (float)-w.im;
+
+ t = w.re*w1.re - w.im*w1.im;
+ w.im = w.re*w1.im + w.im*w1.re;
+ w.re = t;
+ }
+ }
+}
+
+
+static const double icv_sin_120 = 0.86602540378443864676372317075294;
+static const double icv_sin_45 = 0.70710678118654752440084436210485;
+static const double icv_fft5_2 = 0.559016994374947424102293417182819;
+static const double icv_fft5_3 = -0.951056516295153572116439333379382;
+static const double icv_fft5_4 = -1.538841768587626701285145288018455;
+static const double icv_fft5_5 = 0.363271264002680442947733378740309;
+
+#define ICV_DFT_NO_PERMUTE 2
+#define ICV_DFT_COMPLEX_INPUT_OR_OUTPUT 4
+
+// mixed-radix complex discrete Fourier transform: double-precision version
+static CvStatus CV_STDCALL
+icvDFT_64fc( const CvComplex64f* src, CvComplex64f* dst, int n,
+ int nf, int* factors, const int* itab,
+ const CvComplex64f* wave, int tab_size,
+ const void* spec, CvComplex64f* buf,
+ int flags, double scale )
+{
+ int n0 = n, f_idx, nx;
+ int inv = flags & CV_DXT_INVERSE;
+ int dw0 = tab_size, dw;
+ int i, j, k;
+ CvComplex64f t;
+ int tab_step;
+
+ if( spec )
+ {
+ assert( icvDFTFwd_CToC_64fc_p != 0 && icvDFTInv_CToC_64fc_p != 0 );
+ return !inv ?
+ icvDFTFwd_CToC_64fc_p( src, dst, spec, buf ):
+ icvDFTInv_CToC_64fc_p( src, dst, spec, buf );
+ }
+
+ tab_step = tab_size == n ? 1 : tab_size == n*2 ? 2 : tab_size/n;
+
+ // 0. shuffle data
+ if( dst != src )
+ {
+ assert( (flags & ICV_DFT_NO_PERMUTE) == 0 );
+ if( !inv )
+ {
+ for( i = 0; i <= n - 2; i += 2, itab += 2*tab_step )
+ {
+ int k0 = itab[0], k1 = itab[tab_step];
+ assert( (unsigned)k0 < (unsigned)n && (unsigned)k1 < (unsigned)n );
+ dst[i] = src[k0]; dst[i+1] = src[k1];
+ }
+
+ if( i < n )
+ dst[n-1] = src[n-1];
+ }
+ else
+ {
+ for( i = 0; i <= n - 2; i += 2, itab += 2*tab_step )
+ {
+ int k0 = itab[0], k1 = itab[tab_step];
+ assert( (unsigned)k0 < (unsigned)n && (unsigned)k1 < (unsigned)n );
+ t.re = src[k0].re; t.im = -src[k0].im;
+ dst[i] = t;
+ t.re = src[k1].re; t.im = -src[k1].im;
+ dst[i+1] = t;
+ }
+
+ if( i < n )
+ {
+ t.re = src[n-1].re; t.im = -src[n-1].im;
+ dst[i] = t;
+ }
+ }
+ }
+ else
+ {
+ if( (flags & ICV_DFT_NO_PERMUTE) == 0 )
+ {
+ if( factors[0] != factors[nf-1] )
+ return CV_INPLACE_NOT_SUPPORTED_ERR;
+ if( nf == 1 )
+ {
+ if( (n & 3) == 0 )
+ {
+ int n2 = n/2;
+ CvComplex64f* dsth = dst + n2;
+
+ for( i = 0; i < n2; i += 2, itab += tab_step*2 )
+ {
+ j = itab[0];
+ assert( (unsigned)j < (unsigned)n2 );
+
+ CV_SWAP(dst[i+1], dsth[j], t);
+ if( j > i )
+ {
+ CV_SWAP(dst[i], dst[j], t);
+ CV_SWAP(dsth[i+1], dsth[j+1], t);
+ }
+ }
+ }
+ // else do nothing
+ }
+ else
+ {
+ for( i = 0; i < n; i++, itab += tab_step )
+ {
+ j = itab[0];
+ assert( (unsigned)j < (unsigned)n );
+ if( j > i )
+ CV_SWAP(dst[i], dst[j], t);
+ }
+ }
+ }
+
+ if( inv )
+ {
+ for( i = 0; i <= n - 2; i += 2 )
+ {
+ double t0 = -dst[i].im;
+ double t1 = -dst[i+1].im;
+ dst[i].im = t0; dst[i+1].im = t1;
+ }
+
+ if( i < n )
+ dst[n-1].im = -dst[n-1].im;
+ }
+ }
+
+ n = 1;
+ // 1. power-2 transforms
+ if( (factors[0] & 1) == 0 )
+ {
+ // radix-4 transform
+ for( ; n*4 <= factors[0]; )
+ {
+ nx = n;
+ n *= 4;
+ dw0 /= 4;
+
+ for( i = 0; i < n0; i += n )
+ {
+ CvComplex64f* v0;
+ CvComplex64f* v1;
+ double r0, i0, r1, i1, r2, i2, r3, i3, r4, i4;
+
+ v0 = dst + i;
+ v1 = v0 + nx*2;
+
+ r2 = v0[0].re; i2 = v0[0].im;
+ r1 = v0[nx].re; i1 = v0[nx].im;
+
+ r0 = r1 + r2; i0 = i1 + i2;
+ r2 -= r1; i2 -= i1;
+
+ i3 = v1[nx].re; r3 = v1[nx].im;
+ i4 = v1[0].re; r4 = v1[0].im;
+
+ r1 = i4 + i3; i1 = r4 + r3;
+ r3 = r4 - r3; i3 = i3 - i4;
+
+ v0[0].re = r0 + r1; v0[0].im = i0 + i1;
+ v1[0].re = r0 - r1; v1[0].im = i0 - i1;
+ v0[nx].re = r2 + r3; v0[nx].im = i2 + i3;
+ v1[nx].re = r2 - r3; v1[nx].im = i2 - i3;
+
+ for( j = 1, dw = dw0; j < nx; j++, dw += dw0 )
+ {
+ v0 = dst + i + j;
+ v1 = v0 + nx*2;
+
+ r2 = v0[nx].re*wave[dw*2].re - v0[nx].im*wave[dw*2].im;
+ i2 = v0[nx].re*wave[dw*2].im + v0[nx].im*wave[dw*2].re;
+ r0 = v1[0].re*wave[dw].im + v1[0].im*wave[dw].re;
+ i0 = v1[0].re*wave[dw].re - v1[0].im*wave[dw].im;
+ r3 = v1[nx].re*wave[dw*3].im + v1[nx].im*wave[dw*3].re;
+ i3 = v1[nx].re*wave[dw*3].re - v1[nx].im*wave[dw*3].im;
+
+ r1 = i0 + i3; i1 = r0 + r3;
+ r3 = r0 - r3; i3 = i3 - i0;
+ r4 = v0[0].re; i4 = v0[0].im;
+
+ r0 = r4 + r2; i0 = i4 + i2;
+ r2 = r4 - r2; i2 = i4 - i2;
+
+ v0[0].re = r0 + r1; v0[0].im = i0 + i1;
+ v1[0].re = r0 - r1; v1[0].im = i0 - i1;
+ v0[nx].re = r2 + r3; v0[nx].im = i2 + i3;
+ v1[nx].re = r2 - r3; v1[nx].im = i2 - i3;
+ }
+ }
+ }
+
+ for( ; n < factors[0]; )
+ {
+ // do the remaining radix-2 transform
+ nx = n;
+ n *= 2;
+ dw0 /= 2;
+
+ for( i = 0; i < n0; i += n )
+ {
+ CvComplex64f* v = dst + i;
+ double r0 = v[0].re + v[nx].re;
+ double i0 = v[0].im + v[nx].im;
+ double r1 = v[0].re - v[nx].re;
+ double i1 = v[0].im - v[nx].im;
+ v[0].re = r0; v[0].im = i0;
+ v[nx].re = r1; v[nx].im = i1;
+
+ for( j = 1, dw = dw0; j < nx; j++, dw += dw0 )
+ {
+ v = dst + i + j;
+ r1 = v[nx].re*wave[dw].re - v[nx].im*wave[dw].im;
+ i1 = v[nx].im*wave[dw].re + v[nx].re*wave[dw].im;
+ r0 = v[0].re; i0 = v[0].im;
+
+ v[0].re = r0 + r1; v[0].im = i0 + i1;
+ v[nx].re = r0 - r1; v[nx].im = i0 - i1;
+ }
+ }
+ }
+ }
+
+ // 2. all the other transforms
+ for( f_idx = (factors[0]&1) ? 0 : 1; f_idx < nf; f_idx++ )
+ {
+ int factor = factors[f_idx];
+ nx = n;
+ n *= factor;
+ dw0 /= factor;
+
+ if( factor == 3 )
+ {
+ // radix-3
+ for( i = 0; i < n0; i += n )
+ {
+ CvComplex64f* v = dst + i;
+
+ double r1 = v[nx].re + v[nx*2].re;
+ double i1 = v[nx].im + v[nx*2].im;
+ double r0 = v[0].re;
+ double i0 = v[0].im;
+ double r2 = icv_sin_120*(v[nx].im - v[nx*2].im);
+ double i2 = icv_sin_120*(v[nx*2].re - v[nx].re);
+ v[0].re = r0 + r1; v[0].im = i0 + i1;
+ r0 -= 0.5*r1; i0 -= 0.5*i1;
+ v[nx].re = r0 + r2; v[nx].im = i0 + i2;
+ v[nx*2].re = r0 - r2; v[nx*2].im = i0 - i2;
+
+ for( j = 1, dw = dw0; j < nx; j++, dw += dw0 )
+ {
+ v = dst + i + j;
+ r0 = v[nx].re*wave[dw].re - v[nx].im*wave[dw].im;
+ i0 = v[nx].re*wave[dw].im + v[nx].im*wave[dw].re;
+ i2 = v[nx*2].re*wave[dw*2].re - v[nx*2].im*wave[dw*2].im;
+ r2 = v[nx*2].re*wave[dw*2].im + v[nx*2].im*wave[dw*2].re;
+ r1 = r0 + i2; i1 = i0 + r2;
+
+ r2 = icv_sin_120*(i0 - r2); i2 = icv_sin_120*(i2 - r0);
+ r0 = v[0].re; i0 = v[0].im;
+ v[0].re = r0 + r1; v[0].im = i0 + i1;
+ r0 -= 0.5*r1; i0 -= 0.5*i1;
+ v[nx].re = r0 + r2; v[nx].im = i0 + i2;
+ v[nx*2].re = r0 - r2; v[nx*2].im = i0 - i2;
+ }
+ }
+ }
+ else if( factor == 5 )
+ {
+ // radix-5
+ for( i = 0; i < n0; i += n )
+ {
+ for( j = 0, dw = 0; j < nx; j++, dw += dw0 )
+ {
+ CvComplex64f* v0 = dst + i + j;
+ CvComplex64f* v1 = v0 + nx*2;
+ CvComplex64f* v2 = v1 + nx*2;
+
+ double r0, i0, r1, i1, r2, i2, r3, i3, r4, i4, r5, i5;
+
+ r3 = v0[nx].re*wave[dw].re - v0[nx].im*wave[dw].im;
+ i3 = v0[nx].re*wave[dw].im + v0[nx].im*wave[dw].re;
+ r2 = v2[0].re*wave[dw*4].re - v2[0].im*wave[dw*4].im;
+ i2 = v2[0].re*wave[dw*4].im + v2[0].im*wave[dw*4].re;
+
+ r1 = r3 + r2; i1 = i3 + i2;
+ r3 -= r2; i3 -= i2;
+
+ r4 = v1[nx].re*wave[dw*3].re - v1[nx].im*wave[dw*3].im;
+ i4 = v1[nx].re*wave[dw*3].im + v1[nx].im*wave[dw*3].re;
+ r0 = v1[0].re*wave[dw*2].re - v1[0].im*wave[dw*2].im;
+ i0 = v1[0].re*wave[dw*2].im + v1[0].im*wave[dw*2].re;
+
+ r2 = r4 + r0; i2 = i4 + i0;
+ r4 -= r0; i4 -= i0;
+
+ r0 = v0[0].re; i0 = v0[0].im;
+ r5 = r1 + r2; i5 = i1 + i2;
+
+ v0[0].re = r0 + r5; v0[0].im = i0 + i5;
+
+ r0 -= 0.25*r5; i0 -= 0.25*i5;
+ r1 = icv_fft5_2*(r1 - r2); i1 = icv_fft5_2*(i1 - i2);
+ r2 = -icv_fft5_3*(i3 + i4); i2 = icv_fft5_3*(r3 + r4);
+
+ i3 *= -icv_fft5_5; r3 *= icv_fft5_5;
+ i4 *= -icv_fft5_4; r4 *= icv_fft5_4;
+
+ r5 = r2 + i3; i5 = i2 + r3;
+ r2 -= i4; i2 -= r4;
+
+ r3 = r0 + r1; i3 = i0 + i1;
+ r0 -= r1; i0 -= i1;
+
+ v0[nx].re = r3 + r2; v0[nx].im = i3 + i2;
+ v2[0].re = r3 - r2; v2[0].im = i3 - i2;
+
+ v1[0].re = r0 + r5; v1[0].im = i0 + i5;
+ v1[nx].re = r0 - r5; v1[nx].im = i0 - i5;
+ }
+ }
+ }
+ else
+ {
+ // radix-"factor" - an odd number
+ int p, q, factor2 = (factor - 1)/2;
+ int d, dd, dw_f = tab_size/factor;
+ CvComplex64f* a = buf;
+ CvComplex64f* b = buf + factor2;
+
+ for( i = 0; i < n0; i += n )
+ {
+ for( j = 0, dw = 0; j < nx; j++, dw += dw0 )
+ {
+ CvComplex64f* v = dst + i + j;
+ CvComplex64f v_0 = v[0];
+ CvComplex64f vn_0 = v_0;
+
+ if( j == 0 )
+ {
+ for( p = 1, k = nx; p <= factor2; p++, k += nx )
+ {
+ double r0 = v[k].re + v[n-k].re;
+ double i0 = v[k].im - v[n-k].im;
+ double r1 = v[k].re - v[n-k].re;
+ double i1 = v[k].im + v[n-k].im;
+
+ vn_0.re += r0; vn_0.im += i1;
+ a[p-1].re = r0; a[p-1].im = i0;
+ b[p-1].re = r1; b[p-1].im = i1;
+ }
+ }
+ else
+ {
+ const CvComplex64f* wave_ = wave + dw*factor;
+ d = dw;
+
+ for( p = 1, k = nx; p <= factor2; p++, k += nx, d += dw )
+ {
+ double r2 = v[k].re*wave[d].re - v[k].im*wave[d].im;
+ double i2 = v[k].re*wave[d].im + v[k].im*wave[d].re;
+
+ double r1 = v[n-k].re*wave_[-d].re - v[n-k].im*wave_[-d].im;
+ double i1 = v[n-k].re*wave_[-d].im + v[n-k].im*wave_[-d].re;
+
+ double r0 = r2 + r1;
+ double i0 = i2 - i1;
+ r1 = r2 - r1;
+ i1 = i2 + i1;
+
+ vn_0.re += r0; vn_0.im += i1;
+ a[p-1].re = r0; a[p-1].im = i0;
+ b[p-1].re = r1; b[p-1].im = i1;
+ }
+ }
+
+ v[0] = vn_0;
+
+ for( p = 1, k = nx; p <= factor2; p++, k += nx )
+ {
+ CvComplex64f s0 = v_0, s1 = v_0;
+ d = dd = dw_f*p;
+
+ for( q = 0; q < factor2; q++ )
+ {
+ double r0 = wave[d].re * a[q].re;
+ double i0 = wave[d].im * a[q].im;
+ double r1 = wave[d].re * b[q].im;
+ double i1 = wave[d].im * b[q].re;
+
+ s1.re += r0 + i0; s0.re += r0 - i0;
+ s1.im += r1 - i1; s0.im += r1 + i1;
+
+ d += dd;
+ d -= -(d >= tab_size) & tab_size;
+ }
+
+ v[k] = s0;
+ v[n-k] = s1;
+ }
+ }
+ }
+ }
+ }
+
+ if( fabs(scale - 1.) > DBL_EPSILON )
+ {
+ double re_scale = scale, im_scale = scale;
+ if( inv )
+ im_scale = -im_scale;
+
+ for( i = 0; i < n0; i++ )
+ {
+ double t0 = dst[i].re*re_scale;
+ double t1 = dst[i].im*im_scale;
+ dst[i].re = t0;
+ dst[i].im = t1;
+ }
+ }
+ else if( inv )
+ {
+ for( i = 0; i <= n0 - 2; i += 2 )
+ {
+ double t0 = -dst[i].im;
+ double t1 = -dst[i+1].im;
+ dst[i].im = t0;
+ dst[i+1].im = t1;
+ }
+
+ if( i < n0 )
+ dst[n0-1].im = -dst[n0-1].im;
+ }
+
+ return CV_OK;
+}
+
+
+// mixed-radix complex discrete Fourier transform: single-precision version
+static CvStatus CV_STDCALL
+icvDFT_32fc( const CvComplex32f* src, CvComplex32f* dst, int n,
+ int nf, int* factors, const int* itab,
+ const CvComplex32f* wave, int tab_size,
+ const void* spec, CvComplex32f* buf,
+ int flags, double scale )
+{
+ int n0 = n, f_idx, nx;
+ int inv = flags & CV_DXT_INVERSE;
+ int dw0 = tab_size, dw;
+ int i, j, k;
+ CvComplex32f t;
+ int tab_step = tab_size == n ? 1 : tab_size == n*2 ? 2 : tab_size/n;
+
+ if( spec )
+ {
+ assert( icvDFTFwd_CToC_32fc_p != 0 && icvDFTInv_CToC_32fc_p != 0 );
+ return !inv ?
+ icvDFTFwd_CToC_32fc_p( src, dst, spec, buf ):
+ icvDFTInv_CToC_32fc_p( src, dst, spec, buf );
+ }
+
+ // 0. shuffle data
+ if( dst != src )
+ {
+ assert( (flags & ICV_DFT_NO_PERMUTE) == 0 );
+ if( !inv )
+ {
+ for( i = 0; i <= n - 2; i += 2, itab += 2*tab_step )
+ {
+ int k0 = itab[0], k1 = itab[tab_step];
+ assert( (unsigned)k0 < (unsigned)n && (unsigned)k1 < (unsigned)n );
+ dst[i] = src[k0]; dst[i+1] = src[k1];
+ }
+
+ if( i < n )
+ dst[n-1] = src[n-1];
+ }
+ else
+ {
+ for( i = 0; i <= n - 2; i += 2, itab += 2*tab_step )
+ {
+ int k0 = itab[0], k1 = itab[tab_step];
+ assert( (unsigned)k0 < (unsigned)n && (unsigned)k1 < (unsigned)n );
+ t.re = src[k0].re; t.im = -src[k0].im;
+ dst[i] = t;
+ t.re = src[k1].re; t.im = -src[k1].im;
+ dst[i+1] = t;
+ }
+
+ if( i < n )
+ {
+ t.re = src[n-1].re; t.im = -src[n-1].im;
+ dst[i] = t;
+ }
+ }
+ }
+ else
+ {
+ if( (flags & ICV_DFT_NO_PERMUTE) == 0 )
+ {
+ if( factors[0] != factors[nf-1] )
+ return CV_INPLACE_NOT_SUPPORTED_ERR;
+ if( nf == 1 )
+ {
+ if( (n & 3) == 0 )
+ {
+ int n2 = n/2;
+ CvComplex32f* dsth = dst + n2;
+
+ for( i = 0; i < n2; i += 2, itab += tab_step*2 )
+ {
+ j = itab[0];
+ assert( (unsigned)j < (unsigned)n2 );
+
+ CV_SWAP(dst[i+1], dsth[j], t);
+ if( j > i )
+ {
+ CV_SWAP(dst[i], dst[j], t);
+ CV_SWAP(dsth[i+1], dsth[j+1], t);
+ }
+ }
+ }
+ // else do nothing
+ }
+ else
+ {
+ for( i = 0;
+ i < n;
+ i++)
+ {
+ j = itab[0];
+ assert( (unsigned)j < (unsigned)n );
+ if( j > i )
+ CV_SWAP(dst[i], dst[j], t);
+ itab += tab_step;
+ }
+ }
+ }
+
+ if( inv )
+ {
+ // conjugate the vector - i.e. invert sign of the imaginary part
+ int* idst = (int*)dst;
+ for( i = 0; i <= n - 2; i += 2 )
+ {
+ int t0 = idst[i*2+1] ^ 0x80000000;
+ int t1 = idst[i*2+3] ^ 0x80000000;
+ idst[i*2+1] = t0; idst[i*2+3] = t1;
+ }
+
+ if( i < n )
+ idst[2*i+1] ^= 0x80000000;
+ }
+ }
+
+ n = 1;
+ // 1. power-2 transforms
+ if( (factors[0] & 1) == 0 )
+ {
+ // radix-4 transform
+ for( ; n*4 <= factors[0]; )
+ {
+ nx = n;
+ n *= 4;
+ dw0 /= 4;
+
+ for( i = 0; i < n0; i += n )
+ {
+ CvComplex32f* v0;
+ CvComplex32f* v1;
+ double r0, i0, r1, i1, r2, i2, r3, i3, r4, i4;
+
+ v0 = dst + i;
+ v1 = v0 + nx*2;
+
+ r2 = v0[0].re; i2 = v0[0].im;
+ r1 = v0[nx].re; i1 = v0[nx].im;
+
+ r0 = r1 + r2; i0 = i1 + i2;
+ r2 -= r1; i2 -= i1;
+
+ i3 = v1[nx].re; r3 = v1[nx].im;
+ i4 = v1[0].re; r4 = v1[0].im;
+
+ r1 = i4 + i3; i1 = r4 + r3;
+ r3 = r4 - r3; i3 = i3 - i4;
+
+ v0[0].re = (float)(r0 + r1); v0[0].im = (float)(i0 + i1);
+ v1[0].re = (float)(r0 - r1); v1[0].im = (float)(i0 - i1);
+ v0[nx].re = (float)(r2 + r3); v0[nx].im = (float)(i2 + i3);
+ v1[nx].re = (float)(r2 - r3); v1[nx].im = (float)(i2 - i3);
+
+ for( j = 1, dw = dw0; j < nx; j++, dw += dw0 )
+ {
+ v0 = dst + i + j;
+ v1 = v0 + nx*2;
+
+ r2 = v0[nx].re*wave[dw*2].re - v0[nx].im*wave[dw*2].im;
+ i2 = v0[nx].re*wave[dw*2].im + v0[nx].im*wave[dw*2].re;
+ r0 = v1[0].re*wave[dw].im + v1[0].im*wave[dw].re;
+ i0 = v1[0].re*wave[dw].re - v1[0].im*wave[dw].im;
+ r3 = v1[nx].re*wave[dw*3].im + v1[nx].im*wave[dw*3].re;
+ i3 = v1[nx].re*wave[dw*3].re - v1[nx].im*wave[dw*3].im;
+
+ r1 = i0 + i3; i1 = r0 + r3;
+ r3 = r0 - r3; i3 = i3 - i0;
+ r4 = v0[0].re; i4 = v0[0].im;
+
+ r0 = r4 + r2; i0 = i4 + i2;
+ r2 = r4 - r2; i2 = i4 - i2;
+
+ v0[0].re = (float)(r0 + r1); v0[0].im = (float)(i0 + i1);
+ v1[0].re = (float)(r0 - r1); v1[0].im = (float)(i0 - i1);
+ v0[nx].re = (float)(r2 + r3); v0[nx].im = (float)(i2 + i3);
+ v1[nx].re = (float)(r2 - r3); v1[nx].im = (float)(i2 - i3);
+ }
+ }
+ }
+
+ for( ; n < factors[0]; )
+ {
+ // do the remaining radix-2 transform
+ nx = n;
+ n *= 2;
+ dw0 /= 2;
+
+ for( i = 0; i < n0; i += n )
+ {
+ CvComplex32f* v = dst + i;
+ double r0 = v[0].re + v[nx].re;
+ double i0 = v[0].im + v[nx].im;
+ double r1 = v[0].re - v[nx].re;
+ double i1 = v[0].im - v[nx].im;
+ v[0].re = (float)r0; v[0].im = (float)i0;
+ v[nx].re = (float)r1; v[nx].im = (float)i1;
+
+ for( j = 1, dw = dw0; j < nx; j++, dw += dw0 )
+ {
+ v = dst + i + j;
+ r1 = v[nx].re*wave[dw].re - v[nx].im*wave[dw].im;
+ i1 = v[nx].im*wave[dw].re + v[nx].re*wave[dw].im;
+ r0 = v[0].re; i0 = v[0].im;
+
+ v[0].re = (float)(r0 + r1); v[0].im = (float)(i0 + i1);
+ v[nx].re = (float)(r0 - r1); v[nx].im = (float)(i0 - i1);
+ }
+ }
+ }
+ }
+
+ // 2. all the other transforms
+ for( f_idx = (factors[0]&1) ? 0 : 1; f_idx < nf; f_idx++ )
+ {
+ int factor = factors[f_idx];
+ nx = n;
+ n *= factor;
+ dw0 /= factor;
+
+ if( factor == 3 )
+ {
+ // radix-3
+ for( i = 0; i < n0; i += n )
+ {
+ CvComplex32f* v = dst + i;
+
+ double r1 = v[nx].re + v[nx*2].re;
+ double i1 = v[nx].im + v[nx*2].im;
+ double r0 = v[0].re;
+ double i0 = v[0].im;
+ double r2 = icv_sin_120*(v[nx].im - v[nx*2].im);
+ double i2 = icv_sin_120*(v[nx*2].re - v[nx].re);
+ v[0].re = (float)(r0 + r1); v[0].im = (float)(i0 + i1);
+ r0 -= 0.5*r1; i0 -= 0.5*i1;
+ v[nx].re = (float)(r0 + r2); v[nx].im = (float)(i0 + i2);
+ v[nx*2].re = (float)(r0 - r2); v[nx*2].im = (float)(i0 - i2);
+
+ for( j = 1, dw = dw0; j < nx; j++, dw += dw0 )
+ {
+ v = dst + i + j;
+ r0 = v[nx].re*wave[dw].re - v[nx].im*wave[dw].im;
+ i0 = v[nx].re*wave[dw].im + v[nx].im*wave[dw].re;
+ i2 = v[nx*2].re*wave[dw*2].re - v[nx*2].im*wave[dw*2].im;
+ r2 = v[nx*2].re*wave[dw*2].im + v[nx*2].im*wave[dw*2].re;
+ r1 = r0 + i2; i1 = i0 + r2;
+
+ r2 = icv_sin_120*(i0 - r2); i2 = icv_sin_120*(i2 - r0);
+ r0 = v[0].re; i0 = v[0].im;
+ v[0].re = (float)(r0 + r1); v[0].im = (float)(i0 + i1);
+ r0 -= 0.5*r1; i0 -= 0.5*i1;
+ v[nx].re = (float)(r0 + r2); v[nx].im = (float)(i0 + i2);
+ v[nx*2].re = (float)(r0 - r2); v[nx*2].im = (float)(i0 - i2);
+ }
+ }
+ }
+ else if( factor == 5 )
+ {
+ // radix-5
+ for( i = 0; i < n0; i += n )
+ {
+ for( j = 0, dw = 0; j < nx; j++, dw += dw0 )
+ {
+ CvComplex32f* v0 = dst + i + j;
+ CvComplex32f* v1 = v0 + nx*2;
+ CvComplex32f* v2 = v1 + nx*2;
+
+ double r0, i0, r1, i1, r2, i2, r3, i3, r4, i4, r5, i5;
+
+ r3 = v0[nx].re*wave[dw].re - v0[nx].im*wave[dw].im;
+ i3 = v0[nx].re*wave[dw].im + v0[nx].im*wave[dw].re;
+ r2 = v2[0].re*wave[dw*4].re - v2[0].im*wave[dw*4].im;
+ i2 = v2[0].re*wave[dw*4].im + v2[0].im*wave[dw*4].re;
+
+ r1 = r3 + r2; i1 = i3 + i2;
+ r3 -= r2; i3 -= i2;
+
+ r4 = v1[nx].re*wave[dw*3].re - v1[nx].im*wave[dw*3].im;
+ i4 = v1[nx].re*wave[dw*3].im + v1[nx].im*wave[dw*3].re;
+ r0 = v1[0].re*wave[dw*2].re - v1[0].im*wave[dw*2].im;
+ i0 = v1[0].re*wave[dw*2].im + v1[0].im*wave[dw*2].re;
+
+ r2 = r4 + r0; i2 = i4 + i0;
+ r4 -= r0; i4 -= i0;
+
+ r0 = v0[0].re; i0 = v0[0].im;
+ r5 = r1 + r2; i5 = i1 + i2;
+
+ v0[0].re = (float)(r0 + r5); v0[0].im = (float)(i0 + i5);
+
+ r0 -= 0.25*r5; i0 -= 0.25*i5;
+ r1 = icv_fft5_2*(r1 - r2); i1 = icv_fft5_2*(i1 - i2);
+ r2 = -icv_fft5_3*(i3 + i4); i2 = icv_fft5_3*(r3 + r4);
+
+ i3 *= -icv_fft5_5; r3 *= icv_fft5_5;
+ i4 *= -icv_fft5_4; r4 *= icv_fft5_4;
+
+ r5 = r2 + i3; i5 = i2 + r3;
+ r2 -= i4; i2 -= r4;
+
+ r3 = r0 + r1; i3 = i0 + i1;
+ r0 -= r1; i0 -= i1;
+
+ v0[nx].re = (float)(r3 + r2); v0[nx].im = (float)(i3 + i2);
+ v2[0].re = (float)(r3 - r2); v2[0].im = (float)(i3 - i2);
+
+ v1[0].re = (float)(r0 + r5); v1[0].im = (float)(i0 + i5);
+ v1[nx].re = (float)(r0 - r5); v1[nx].im = (float)(i0 - i5);
+ }
+ }
+ }
+ else
+ {
+ // radix-"factor" - an odd number
+ int p, q, factor2 = (factor - 1)/2;
+ int d, dd, dw_f = tab_size/factor;
+ CvComplex32f* a = buf;
+ CvComplex32f* b = buf + factor2;
+
+ for( i = 0; i < n0; i += n )
+ {
+ for( j = 0, dw = 0; j < nx; j++, dw += dw0 )
+ {
+ CvComplex32f* v = dst + i + j;
+ CvComplex32f v_0 = v[0];
+ CvComplex64f vn_0(v_0);
+
+ if( j == 0 )
+ {
+ for( p = 1, k = nx; p <= factor2; p++, k += nx )
+ {
+ double r0 = v[k].re + v[n-k].re;
+ double i0 = v[k].im - v[n-k].im;
+ double r1 = v[k].re - v[n-k].re;
+ double i1 = v[k].im + v[n-k].im;
+
+ vn_0.re += r0; vn_0.im += i1;
+ a[p-1].re = (float)r0; a[p-1].im = (float)i0;
+ b[p-1].re = (float)r1; b[p-1].im = (float)i1;
+ }
+ }
+ else
+ {
+ const CvComplex32f* wave_ = wave + dw*factor;
+ d = dw;
+
+ for( p = 1, k = nx; p <= factor2; p++, k += nx, d += dw )
+ {
+ double r2 = v[k].re*wave[d].re - v[k].im*wave[d].im;
+ double i2 = v[k].re*wave[d].im + v[k].im*wave[d].re;
+
+ double r1 = v[n-k].re*wave_[-d].re - v[n-k].im*wave_[-d].im;
+ double i1 = v[n-k].re*wave_[-d].im + v[n-k].im*wave_[-d].re;
+
+ double r0 = r2 + r1;
+ double i0 = i2 - i1;
+ r1 = r2 - r1;
+ i1 = i2 + i1;
+
+ vn_0.re += r0; vn_0.im += i1;
+ a[p-1].re = (float)r0; a[p-1].im = (float)i0;
+ b[p-1].re = (float)r1; b[p-1].im = (float)i1;
+ }
+ }
+
+ v[0].re = (float)vn_0.re;
+ v[0].im = (float)vn_0.im;
+
+ for( p = 1, k = nx; p <= factor2; p++, k += nx )
+ {
+ CvComplex64f s0(v_0), s1 = s0;
+ d = dd = dw_f*p;
+
+ for( q = 0; q < factor2; q++ )
+ {
+ double r0 = wave[d].re * a[q].re;
+ double i0 = wave[d].im * a[q].im;
+ double r1 = wave[d].re * b[q].im;
+ double i1 = wave[d].im * b[q].re;
+
+ s1.re += r0 + i0; s0.re += r0 - i0;
+ s1.im += r1 - i1; s0.im += r1 + i1;
+
+ d += dd;
+ d -= -(d >= tab_size) & tab_size;
+ }
+
+ v[k].re = (float)s0.re;
+ v[k].im = (float)s0.im;
+ v[n-k].re = (float)s1.re;
+ v[n-k].im = (float)s1.im;
+ }
+ }
+ }
+ }
+ }
+
+ if( fabs(scale - 1.) > DBL_EPSILON )
+ {
+ double re_scale = scale, im_scale = scale;
+ if( inv )
+ im_scale = -im_scale;
+
+ for( i = 0; i < n0; i++ )
+ {
+ double t0 = dst[i].re*re_scale;
+ double t1 = dst[i].im*im_scale;
+ dst[i].re = (float)t0;
+ dst[i].im = (float)t1;
+ }
+ }
+ else if( inv )
+ {
+ for( i = 0; i <= n0 - 2; i += 2 )
+ {
+ double t0 = -dst[i].im;
+ double t1 = -dst[i+1].im;
+ dst[i].im = (float)t0;
+ dst[i+1].im = (float)t1;
+ }
+
+ if( i < n0 )
+ dst[n0-1].im = -dst[n0-1].im;
+ }
+
+ return CV_OK;
+}
+
+
+/* FFT of real vector
+ output vector format:
+ re(0), re(1), im(1), ... , re(n/2-1), im((n+1)/2-1) [, re((n+1)/2)] OR ...
+ re(0), 0, re(1), im(1), ..., re(n/2-1), im((n+1)/2-1) [, re((n+1)/2), 0] */
+#define ICV_REAL_DFT( flavor, datatype ) \
+static CvStatus CV_STDCALL \
+icvRealDFT_##flavor( const datatype* src, datatype* dst, \
+ int n, int nf, int* factors, const int* itab, \
+ const CvComplex##flavor* wave, int tab_size, \
+ const void* spec, CvComplex##flavor* buf, \
+ int flags, double scale ) \
+{ \
+ int complex_output = (flags & ICV_DFT_COMPLEX_INPUT_OR_OUTPUT) != 0;\
+ int j, n2 = n >> 1; \
+ dst += complex_output; \
+ \
+ if( spec ) \
+ { \
+ icvDFTFwd_RToPack_##flavor##_p( src, dst, spec, buf ); \
+ goto finalize; \
+ } \
+ \
+ assert( tab_size == n ); \
+ \
+ if( n == 1 ) \
+ { \
+ dst[0] = (datatype)(src[0]*scale); \
+ } \
+ else if( n == 2 ) \
+ { \
+ double t = (src[0] + src[1])*scale; \
+ dst[1] = (datatype)((src[0] - src[1])*scale); \
+ dst[0] = (datatype)t; \
+ } \
+ else if( n & 1 ) \
+ { \
+ dst -= complex_output; \
+ CvComplex##flavor* _dst = (CvComplex##flavor*)dst; \
+ _dst[0].re = (datatype)(src[0]*scale); \
+ _dst[0].im = 0; \
+ for( j = 1; j < n; j += 2 ) \
+ { \
+ double t0 = src[itab[j]]*scale; \
+ double t1 = src[itab[j+1]]*scale; \
+ _dst[j].re = (datatype)t0; \
+ _dst[j].im = 0; \
+ _dst[j+1].re = (datatype)t1; \
+ _dst[j+1].im = 0; \
+ } \
+ icvDFT_##flavor##c( _dst, _dst, n, nf, factors, itab, wave, \
+ tab_size, 0, buf, ICV_DFT_NO_PERMUTE, 1. ); \
+ if( !complex_output ) \
+ dst[1] = dst[0]; \
+ return CV_OK; \
+ } \
+ else \
+ { \
+ double t0, t; \
+ double h1_re, h1_im, h2_re, h2_im; \
+ double scale2 = scale*0.5; \
+ factors[0] >>= 1; \
+ \
+ icvDFT_##flavor##c( (CvComplex##flavor*)src, \
+ (CvComplex##flavor*)dst, n2, \
+ nf - (factors[0] == 1), \
+ factors + (factors[0] == 1), \
+ itab, wave, tab_size, 0, buf, 0, 1. ); \
+ factors[0] <<= 1; \
+ \
+ t = dst[0] - dst[1]; \
+ dst[0] = (datatype)((dst[0] + dst[1])*scale); \
+ dst[1] = (datatype)(t*scale); \
+ \
+ t0 = dst[n2]; \
+ t = dst[n-1]; \
+ dst[n-1] = dst[1]; \
+ \
+ for( j = 2, wave++; j < n2; j += 2, wave++ ) \
+ { \
+ /* calc odd */ \
+ h2_re = scale2*(dst[j+1] + t); \
+ h2_im = scale2*(dst[n-j] - dst[j]); \
+ \
+ /* calc even */ \
+ h1_re = scale2*(dst[j] + dst[n-j]); \
+ h1_im = scale2*(dst[j+1] - t); \
+ \
+ /* rotate */ \
+ t = h2_re*wave->re - h2_im*wave->im; \
+ h2_im = h2_re*wave->im + h2_im*wave->re; \
+ h2_re = t; \
+ t = dst[n-j-1]; \
+ \
+ dst[j-1] = (datatype)(h1_re + h2_re); \
+ dst[n-j-1] = (datatype)(h1_re - h2_re); \
+ dst[j] = (datatype)(h1_im + h2_im); \
+ dst[n-j] = (datatype)(h2_im - h1_im); \
+ } \
+ \
+ if( j <= n2 ) \
+ { \
+ dst[n2-1] = (datatype)(t0*scale); \
+ dst[n2] = (datatype)(-t*scale); \
+ } \
+ } \
+ \
+finalize: \
+ if( complex_output ) \
+ { \
+ dst[-1] = dst[0]; \
+ dst[0] = 0; \
+ if( (n & 1) == 0 ) \
+ dst[n] = 0; \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+/* Inverse FFT of complex conjugate-symmetric vector
+ input vector format:
+ re[0], re[1], im[1], ... , re[n/2-1], im[n/2-1], re[n/2] OR
+ re(0), 0, re(1), im(1), ..., re(n/2-1), im((n+1)/2-1) [, re((n+1)/2), 0] */
+#define ICV_CCS_IDFT( flavor, datatype ) \
+static CvStatus CV_STDCALL \
+icvCCSIDFT_##flavor( const datatype* src, datatype* dst, \
+ int n, int nf, int* factors, const int* itab, \
+ const CvComplex##flavor* wave, int tab_size, \
+ const void* spec, CvComplex##flavor* buf, \
+ int flags, double scale ) \
+{ \
+ int complex_input = (flags & ICV_DFT_COMPLEX_INPUT_OR_OUTPUT) != 0; \
+ int j, k, n2 = (n+1) >> 1; \
+ double save_s1 = 0.; \
+ double t0, t1, t2, t3, t; \
+ \
+ assert( tab_size == n ); \
+ \
+ if( complex_input ) \
+ { \
+ assert( src != dst ); \
+ save_s1 = src[1]; \
+ ((datatype*)src)[1] = src[0]; \
+ src++; \
+ } \
+ \
+ if( spec ) \
+ { \
+ icvDFTInv_PackToR_##flavor##_p( src, dst, spec, buf ); \
+ goto finalize; \
+ } \
+ \
+ if( n == 1 ) \
+ { \
+ dst[0] = (datatype)(src[0]*scale); \
+ } \
+ else if( n == 2 ) \
+ { \
+ t = (src[0] + src[1])*scale; \
+ dst[1] = (datatype)((src[0] - src[1])*scale); \
+ dst[0] = (datatype)t; \
+ } \
+ else if( n & 1 ) \
+ { \
+ CvComplex##flavor* _src = (CvComplex##flavor*)(src-1); \
+ CvComplex##flavor* _dst = (CvComplex##flavor*)dst; \
+ \
+ _dst[0].re = src[0]; \
+ _dst[0].im = 0; \
+ for( j = 1; j < n2; j++ ) \
+ { \
+ int k0 = itab[j], k1 = itab[n-j]; \
+ t0 = _src[j].re; t1 = _src[j].im; \
+ _dst[k0].re = (datatype)t0; _dst[k0].im = (datatype)-t1; \
+ _dst[k1].re = (datatype)t0; _dst[k1].im = (datatype)t1; \
+ } \
+ \
+ icvDFT_##flavor##c( _dst, _dst, n, nf, factors, itab, wave, \
+ tab_size, 0, buf, ICV_DFT_NO_PERMUTE, 1. ); \
+ dst[0] = (datatype)(dst[0]*scale); \
+ for( j = 1; j < n; j += 2 ) \
+ { \
+ t0 = dst[j*2]*scale; \
+ t1 = dst[j*2+2]*scale; \
+ dst[j] = (datatype)t0; \
+ dst[j+1] = (datatype)t1; \
+ } \
+ } \
+ else \
+ { \
+ int inplace = src == dst; \
+ const CvComplex##flavor* w = wave; \
+ \
+ t = src[1]; \
+ t0 = (src[0] + src[n-1]); \
+ t1 = (src[n-1] - src[0]); \
+ dst[0] = (datatype)t0; \
+ dst[1] = (datatype)t1; \
+ \
+ for( j = 2, w++; j < n2; j += 2, w++ ) \
+ { \
+ double h1_re, h1_im, h2_re, h2_im; \
+ \
+ h1_re = (t + src[n-j-1]); \
+ h1_im = (src[j] - src[n-j]); \
+ \
+ h2_re = (t - src[n-j-1]); \
+ h2_im = (src[j] + src[n-j]); \
+ \
+ t = h2_re*w->re + h2_im*w->im; \
+ h2_im = h2_im*w->re - h2_re*w->im; \
+ h2_re = t; \
+ \
+ t = src[j+1]; \
+ t0 = h1_re - h2_im; \
+ t1 = -h1_im - h2_re; \
+ t2 = h1_re + h2_im; \
+ t3 = h1_im - h2_re; \
+ \
+ if( inplace ) \
+ { \
+ dst[j] = (datatype)t0; \
+ dst[j+1] = (datatype)t1; \
+ dst[n-j] = (datatype)t2; \
+ dst[n-j+1]= (datatype)t3; \
+ } \
+ else \
+ { \
+ int j2 = j >> 1; \
+ k = itab[j2]; \
+ dst[k] = (datatype)t0; \
+ dst[k+1] = (datatype)t1; \
+ k = itab[n2-j2]; \
+ dst[k] = (datatype)t2; \
+ dst[k+1]= (datatype)t3; \
+ } \
+ } \
+ \
+ if( j <= n2 ) \
+ { \
+ t0 = t*2; \
+ t1 = src[n2]*2; \
+ \
+ if( inplace ) \
+ { \
+ dst[n2] = (datatype)t0; \
+ dst[n2+1] = (datatype)t1; \
+ } \
+ else \
+ { \
+ k = itab[n2]; \
+ dst[k*2] = (datatype)t0; \
+ dst[k*2+1] = (datatype)t1; \
+ } \
+ } \
+ \
+ factors[0] >>= 1; \
+ icvDFT_##flavor##c( (CvComplex##flavor*)dst, \
+ (CvComplex##flavor*)dst, n2, \
+ nf - (factors[0] == 1), \
+ factors + (factors[0] == 1), itab, \
+ wave, tab_size, 0, buf, \
+ inplace ? 0 : ICV_DFT_NO_PERMUTE, 1. ); \
+ factors[0] <<= 1; \
+ \
+ for( j = 0; j < n; j += 2 ) \
+ { \
+ t0 = dst[j]*scale; \
+ t1 = dst[j+1]*(-scale); \
+ dst[j] = (datatype)t0; \
+ dst[j+1] = (datatype)t1; \
+ } \
+ } \
+ \
+finalize: \
+ if( complex_input ) \
+ ((datatype*)src)[0] = (datatype)save_s1; \
+ \
+ return CV_OK; \
+}
+
+
+ICV_REAL_DFT( 64f, double )
+ICV_CCS_IDFT( 64f, double )
+ICV_REAL_DFT( 32f, float )
+ICV_CCS_IDFT( 32f, float )
+
+
+static void
+icvCopyColumn( const uchar* _src, int src_step,
+ uchar* _dst, int dst_step,
+ int len, int elem_size )
+{
+ int i, t0, t1;
+ const int* src = (const int*)_src;
+ int* dst = (int*)_dst;
+ src_step /= sizeof(src[0]);
+ dst_step /= sizeof(dst[0]);
+
+ if( elem_size == sizeof(int) )
+ {
+ for( i = 0; i < len; i++, src += src_step, dst += dst_step )
+ dst[0] = src[0];
+ }
+ else if( elem_size == sizeof(int)*2 )
+ {
+ for( i = 0; i < len; i++, src += src_step, dst += dst_step )
+ {
+ t0 = src[0]; t1 = src[1];
+ dst[0] = t0; dst[1] = t1;
+ }
+ }
+ else if( elem_size == sizeof(int)*4 )
+ {
+ for( i = 0; i < len; i++, src += src_step, dst += dst_step )
+ {
+ t0 = src[0]; t1 = src[1];
+ dst[0] = t0; dst[1] = t1;
+ t0 = src[2]; t1 = src[3];
+ dst[2] = t0; dst[3] = t1;
+ }
+ }
+}
+
+
+static void
+icvCopyFrom2Columns( const uchar* _src, int src_step,
+ uchar* _dst0, uchar* _dst1,
+ int len, int elem_size )
+{
+ int i, t0, t1;
+ const int* src = (const int*)_src;
+ int* dst0 = (int*)_dst0;
+ int* dst1 = (int*)_dst1;
+ src_step /= sizeof(src[0]);
+
+ if( elem_size == sizeof(int) )
+ {
+ for( i = 0; i < len; i++, src += src_step )
+ {
+ t0 = src[0]; t1 = src[1];
+ dst0[i] = t0; dst1[i] = t1;
+ }
+ }
+ else if( elem_size == sizeof(int)*2 )
+ {
+ for( i = 0; i < len*2; i += 2, src += src_step )
+ {
+ t0 = src[0]; t1 = src[1];
+ dst0[i] = t0; dst0[i+1] = t1;
+ t0 = src[2]; t1 = src[3];
+ dst1[i] = t0; dst1[i+1] = t1;
+ }
+ }
+ else if( elem_size == sizeof(int)*4 )
+ {
+ for( i = 0; i < len*4; i += 4, src += src_step )
+ {
+ t0 = src[0]; t1 = src[1];
+ dst0[i] = t0; dst0[i+1] = t1;
+ t0 = src[2]; t1 = src[3];
+ dst0[i+2] = t0; dst0[i+3] = t1;
+ t0 = src[4]; t1 = src[5];
+ dst1[i] = t0; dst1[i+1] = t1;
+ t0 = src[6]; t1 = src[7];
+ dst1[i+2] = t0; dst1[i+3] = t1;
+ }
+ }
+}
+
+
+static void
+icvCopyTo2Columns( const uchar* _src0, const uchar* _src1,
+ uchar* _dst, int dst_step,
+ int len, int elem_size )
+{
+ int i, t0, t1;
+ const int* src0 = (const int*)_src0;
+ const int* src1 = (const int*)_src1;
+ int* dst = (int*)_dst;
+ dst_step /= sizeof(dst[0]);
+
+ if( elem_size == sizeof(int) )
+ {
+ for( i = 0; i < len; i++, dst += dst_step )
+ {
+ t0 = src0[i]; t1 = src1[i];
+ dst[0] = t0; dst[1] = t1;
+ }
+ }
+ else if( elem_size == sizeof(int)*2 )
+ {
+ for( i = 0; i < len*2; i += 2, dst += dst_step )
+ {
+ t0 = src0[i]; t1 = src0[i+1];
+ dst[0] = t0; dst[1] = t1;
+ t0 = src1[i]; t1 = src1[i+1];
+ dst[2] = t0; dst[3] = t1;
+ }
+ }
+ else if( elem_size == sizeof(int)*4 )
+ {
+ for( i = 0; i < len*4; i += 4, dst += dst_step )
+ {
+ t0 = src0[i]; t1 = src0[i+1];
+ dst[0] = t0; dst[1] = t1;
+ t0 = src0[i+2]; t1 = src0[i+3];
+ dst[2] = t0; dst[3] = t1;
+ t0 = src1[i]; t1 = src1[i+1];
+ dst[4] = t0; dst[5] = t1;
+ t0 = src1[i+2]; t1 = src1[i+3];
+ dst[6] = t0; dst[7] = t1;
+ }
+ }
+}
+
+
+static void
+icvExpandCCS( uchar* _ptr, int len, int elem_size )
+{
+ int i;
+ _ptr -= elem_size;
+ memcpy( _ptr, _ptr + elem_size, elem_size );
+ memset( _ptr + elem_size, 0, elem_size );
+ if( (len & 1) == 0 )
+ memset( _ptr + (len+1)*elem_size, 0, elem_size );
+
+ if( elem_size == sizeof(float) )
+ {
+ CvComplex32f* ptr = (CvComplex32f*)_ptr;
+
+ for( i = 1; i < (len+1)/2; i++ )
+ {
+ CvComplex32f t;
+ t.re = ptr[i].re;
+ t.im = -ptr[i].im;
+ ptr[len-i] = t;
+ }
+ }
+ else
+ {
+ CvComplex64f* ptr = (CvComplex64f*)_ptr;
+
+ for( i = 1; i < (len+1)/2; i++ )
+ {
+ CvComplex64f t;
+ t.re = ptr[i].re;
+ t.im = -ptr[i].im;
+ ptr[len-i] = t;
+ }
+ }
+}
+
+
+typedef CvStatus (CV_STDCALL *CvDFTFunc)(
+ const void* src, void* dst, int n, int nf, int* factors,
+ const int* itab, const void* wave, int tab_size,
+ const void* spec, void* buf, int inv, double scale );
+
+CV_IMPL void
+cvDFT( const CvArr* srcarr, CvArr* dstarr, int flags, int nonzero_rows )
+{
+ static CvDFTFunc dft_tbl[6];
+ static int inittab = 0;
+
+ void* buffer = 0;
+ int local_alloc = 1;
+ int depth = -1;
+ void *spec_c = 0, *spec_r = 0, *spec = 0;
+
+ CV_FUNCNAME( "cvDFT" );
+
+ __BEGIN__;
+
+ int prev_len = 0, buf_size = 0, stage = 0;
+ int nf = 0, inv = (flags & CV_DXT_INVERSE) != 0;
+ int real_transform = 0;
+ CvMat *src = (CvMat*)srcarr, *dst = (CvMat*)dstarr;
+ CvMat srcstub, dststub, *src0;
+ int complex_elem_size, elem_size;
+ int factors[34], inplace_transform = 0;
+ int ipp_norm_flag = 0;
+
+ if( !inittab )
+ {
+ dft_tbl[0] = (CvDFTFunc)icvDFT_32fc;
+ dft_tbl[1] = (CvDFTFunc)icvRealDFT_32f;
+ dft_tbl[2] = (CvDFTFunc)icvCCSIDFT_32f;
+ dft_tbl[3] = (CvDFTFunc)icvDFT_64fc;
+ dft_tbl[4] = (CvDFTFunc)icvRealDFT_64f;
+ dft_tbl[5] = (CvDFTFunc)icvCCSIDFT_64f;
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT( src ))
+ {
+ int coi = 0;
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_IS_MAT( dst ))
+ {
+ int coi = 0;
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ src0 = src;
+ elem_size = CV_ELEM_SIZE1(src->type);
+ complex_elem_size = elem_size*2;
+
+ // check types and sizes
+ if( !CV_ARE_DEPTHS_EQ(src, dst) )
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ depth = CV_MAT_DEPTH(src->type);
+ if( depth < CV_32F )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Only 32fC1, 32fC2, 64fC1 and 64fC2 formats are supported" );
+
+ if( CV_ARE_CNS_EQ(src, dst) )
+ {
+ if( CV_MAT_CN(src->type) > 2 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Only 32fC1, 32fC2, 64fC1 and 64fC2 formats are supported" );
+
+ if( !CV_ARE_SIZES_EQ(src, dst) )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+ real_transform = CV_MAT_CN(src->type) == 1;
+ if( !real_transform )
+ elem_size = complex_elem_size;
+ }
+ else if( !inv && CV_MAT_CN(src->type) == 1 && CV_MAT_CN(dst->type) == 2 )
+ {
+ if( (src->cols != 1 || dst->cols != 1 ||
+ (src->rows/2+1 != dst->rows && src->rows != dst->rows)) &&
+ (src->cols/2+1 != dst->cols || src->rows != dst->rows) )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+ real_transform = 1;
+ }
+ else if( inv && CV_MAT_CN(src->type) == 2 && CV_MAT_CN(dst->type) == 1 )
+ {
+ if( (src->cols != 1 || dst->cols != 1 ||
+ (dst->rows/2+1 != src->rows && src->rows != dst->rows)) &&
+ (dst->cols/2+1 != src->cols || src->rows != dst->rows) )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+ real_transform = 1;
+ }
+ else
+ CV_ERROR( CV_StsUnmatchedFormats,
+ "Incorrect or unsupported combination of input & output formats" );
+
+ if( src->cols == 1 && nonzero_rows > 0 )
+ CV_ERROR( CV_StsNotImplemented,
+ "This mode (using nonzero_rows with a single-column matrix) breaks the function logic, so it is prohibited.\n"
+ "For fast convolution/correlation use 2-column matrix or single-row matrix instead" );
+
+ // determine, which transform to do first - row-wise
+ // (stage 0) or column-wise (stage 1) transform
+ if( !(flags & CV_DXT_ROWS) && src->rows > 1 &&
+ ((src->cols == 1 && !CV_IS_MAT_CONT(src->type & dst->type)) ||
+ (src->cols > 1 && inv && real_transform)) )
+ stage = 1;
+
+ ipp_norm_flag = !(flags & CV_DXT_SCALE) ? 8 : (flags & CV_DXT_INVERSE) ? 2 : 1;
+
+ for(;;)
+ {
+ double scale = 1;
+ uchar* wave = 0;
+ int* itab = 0;
+ uchar* ptr;
+ int i, len, count, sz = 0;
+ int use_buf = 0, odd_real = 0;
+ CvDFTFunc dft_func;
+
+ if( stage == 0 ) // row-wise transform
+ {
+ len = !inv ? src->cols : dst->cols;
+ count = src->rows;
+ if( len == 1 && !(flags & CV_DXT_ROWS) )
+ {
+ len = !inv ? src->rows : dst->rows;
+ count = 1;
+ }
+ odd_real = real_transform && (len & 1);
+ }
+ else
+ {
+ len = dst->rows;
+ count = !inv ? src0->cols : dst->cols;
+ sz = 2*len*complex_elem_size;
+ }
+
+ spec = 0;
+ if( len*count >= 64 && icvDFTInitAlloc_R_32f_p != 0 ) // use IPP DFT if available
+ {
+ int ipp_sz = 0;
+
+ if( real_transform && stage == 0 )
+ {
+ if( depth == CV_32F )
+ {
+ if( spec_r )
+ IPPI_CALL( icvDFTFree_R_32f_p( spec_r ));
+ IPPI_CALL( icvDFTInitAlloc_R_32f_p(
+ &spec_r, len, ipp_norm_flag, cvAlgHintNone ));
+ IPPI_CALL( icvDFTGetBufSize_R_32f_p( spec_r, &ipp_sz ));
+ }
+ else
+ {
+ if( spec_r )
+ IPPI_CALL( icvDFTFree_R_64f_p( spec_r ));
+ IPPI_CALL( icvDFTInitAlloc_R_64f_p(
+ &spec_r, len, ipp_norm_flag, cvAlgHintNone ));
+ IPPI_CALL( icvDFTGetBufSize_R_64f_p( spec_r, &ipp_sz ));
+ }
+ spec = spec_r;
+ }
+ else
+ {
+ if( depth == CV_32F )
+ {
+ if( spec_c )
+ IPPI_CALL( icvDFTFree_C_32fc_p( spec_c ));
+ IPPI_CALL( icvDFTInitAlloc_C_32fc_p(
+ &spec_c, len, ipp_norm_flag, cvAlgHintNone ));
+ IPPI_CALL( icvDFTGetBufSize_C_32fc_p( spec_c, &ipp_sz ));
+ }
+ else
+ {
+ if( spec_c )
+ IPPI_CALL( icvDFTFree_C_64fc_p( spec_c ));
+ IPPI_CALL( icvDFTInitAlloc_C_64fc_p(
+ &spec_c, len, ipp_norm_flag, cvAlgHintNone ));
+ IPPI_CALL( icvDFTGetBufSize_C_64fc_p( spec_c, &ipp_sz ));
+ }
+ spec = spec_c;
+ }
+
+ sz += ipp_sz;
+ }
+ else
+ {
+ if( len != prev_len )
+ nf = icvDFTFactorize( len, factors );
+
+ inplace_transform = factors[0] == factors[nf-1];
+ sz += len*(complex_elem_size + sizeof(int));
+ i = nf > 1 && (factors[0] & 1) == 0;
+ if( (factors[i] & 1) != 0 && factors[i] > 5 )
+ sz += (factors[i]+1)*complex_elem_size;
+
+ if( (stage == 0 && ((src->data.ptr == dst->data.ptr && !inplace_transform) || odd_real)) ||
+ (stage == 1 && !inplace_transform) )
+ {
+ use_buf = 1;
+ sz += len*complex_elem_size;
+ }
+ }
+
+ if( sz > buf_size )
+ {
+ prev_len = 0; // because we release the buffer,
+ // force recalculation of
+ // twiddle factors and permutation table
+ if( !local_alloc && buffer )
+ cvFree( &buffer );
+ if( sz <= CV_MAX_LOCAL_DFT_SIZE )
+ {
+ buf_size = sz = CV_MAX_LOCAL_DFT_SIZE;
+ buffer = cvStackAlloc(sz + 32);
+ local_alloc = 1;
+ }
+ else
+ {
+ CV_CALL( buffer = cvAlloc(sz + 32) );
+ buf_size = sz;
+ local_alloc = 0;
+ }
+ }
+
+ ptr = (uchar*)buffer;
+ if( !spec )
+ {
+ wave = ptr;
+ ptr += len*complex_elem_size;
+ itab = (int*)ptr;
+ ptr = (uchar*)cvAlignPtr( ptr + len*sizeof(int), 16 );
+
+ if( len != prev_len || (!inplace_transform && inv && real_transform))
+ icvDFTInit( len, nf, factors, itab, complex_elem_size,
+ wave, stage == 0 && inv && real_transform );
+ // otherwise reuse the tables calculated on the previous stage
+ }
+
+ if( stage == 0 )
+ {
+ uchar* tmp_buf = 0;
+ int dptr_offset = 0;
+ int dst_full_len = len*elem_size;
+ int _flags = inv + (CV_MAT_CN(src->type) != CV_MAT_CN(dst->type) ?
+ ICV_DFT_COMPLEX_INPUT_OR_OUTPUT : 0);
+ if( use_buf )
+ {
+ tmp_buf = ptr;
+ ptr += len*complex_elem_size;
+ if( odd_real && !inv && len > 1 &&
+ !(_flags & ICV_DFT_COMPLEX_INPUT_OR_OUTPUT))
+ dptr_offset = elem_size;
+ }
+
+ if( !inv && (_flags & ICV_DFT_COMPLEX_INPUT_OR_OUTPUT) )
+ dst_full_len += (len & 1) ? elem_size : complex_elem_size;
+
+ dft_func = dft_tbl[(!real_transform ? 0 : !inv ? 1 : 2) + (depth == CV_64F)*3];
+
+ if( count > 1 && !(flags & CV_DXT_ROWS) && (!inv || !real_transform) )
+ stage = 1;
+ else if( flags & CV_DXT_SCALE )
+ scale = 1./(len * (flags & CV_DXT_ROWS ? 1 : count));
+
+ if( nonzero_rows <= 0 || nonzero_rows > count )
+ nonzero_rows = count;
+
+ for( i = 0; i < nonzero_rows; i++ )
+ {
+ uchar* sptr = src->data.ptr + i*src->step;
+ uchar* dptr0 = dst->data.ptr + i*dst->step;
+ uchar* dptr = dptr0;
+
+ if( tmp_buf )
+ dptr = tmp_buf;
+
+ dft_func( sptr, dptr, len, nf, factors, itab, wave, len, spec, ptr, _flags, scale );
+ if( dptr != dptr0 )
+ memcpy( dptr0, dptr + dptr_offset, dst_full_len );
+ }
+
+ for( ; i < count; i++ )
+ {
+ uchar* dptr0 = dst->data.ptr + i*dst->step;
+ memset( dptr0, 0, dst_full_len );
+ }
+
+ if( stage != 1 )
+ break;
+ src = dst;
+ }
+ else
+ {
+ int a = 0, b = count;
+ uchar *buf0, *buf1, *dbuf0, *dbuf1;
+ uchar* sptr0 = src->data.ptr;
+ uchar* dptr0 = dst->data.ptr;
+ buf0 = ptr;
+ ptr += len*complex_elem_size;
+ buf1 = ptr;
+ ptr += len*complex_elem_size;
+ dbuf0 = buf0, dbuf1 = buf1;
+
+ if( use_buf )
+ {
+ dbuf1 = ptr;
+ dbuf0 = buf1;
+ ptr += len*complex_elem_size;
+ }
+
+ dft_func = dft_tbl[(depth == CV_64F)*3];
+
+ if( real_transform && inv && src->cols > 1 )
+ stage = 0;
+ else if( flags & CV_DXT_SCALE )
+ scale = 1./(len * count);
+
+ if( real_transform )
+ {
+ int even;
+ a = 1;
+ even = (count & 1) == 0;
+ b = (count+1)/2;
+ if( !inv )
+ {
+ memset( buf0, 0, len*complex_elem_size );
+ icvCopyColumn( sptr0, src->step, buf0, complex_elem_size, len, elem_size );
+ sptr0 += CV_MAT_CN(dst->type)*elem_size;
+ if( even )
+ {
+ memset( buf1, 0, len*complex_elem_size );
+ icvCopyColumn( sptr0 + (count-2)*elem_size, src->step,
+ buf1, complex_elem_size, len, elem_size );
+ }
+ }
+ else if( CV_MAT_CN(src->type) == 1 )
+ {
+ icvCopyColumn( sptr0, src->step, buf0 + elem_size, elem_size, len, elem_size );
+ icvExpandCCS( buf0 + elem_size, len, elem_size );
+ if( even )
+ {
+ icvCopyColumn( sptr0 + (count-1)*elem_size, src->step,
+ buf1 + elem_size, elem_size, len, elem_size );
+ icvExpandCCS( buf1 + elem_size, len, elem_size );
+ }
+ sptr0 += elem_size;
+ }
+ else
+ {
+ icvCopyColumn( sptr0, src->step, buf0, complex_elem_size, len, complex_elem_size );
+ //memcpy( buf0 + elem_size, buf0, elem_size );
+ //icvExpandCCS( buf0 + elem_size, len, elem_size );
+ if( even )
+ {
+ icvCopyColumn( sptr0 + b*complex_elem_size, src->step,
+ buf1, complex_elem_size, len, complex_elem_size );
+ //memcpy( buf0 + elem_size, buf0, elem_size );
+ //icvExpandCCS( buf0 + elem_size, len, elem_size );
+ }
+ sptr0 += complex_elem_size;
+ }
+
+ if( even )
+ IPPI_CALL( dft_func( buf1, dbuf1, len, nf, factors, itab,
+ wave, len, spec, ptr, inv, scale ));
+ IPPI_CALL( dft_func( buf0, dbuf0, len, nf, factors, itab,
+ wave, len, spec, ptr, inv, scale ));
+
+ if( CV_MAT_CN(dst->type) == 1 )
+ {
+ if( !inv )
+ {
+ // copy the half of output vector to the first/last column.
+ // before doing that, defgragment the vector
+ memcpy( dbuf0 + elem_size, dbuf0, elem_size );
+ icvCopyColumn( dbuf0 + elem_size, elem_size, dptr0,
+ dst->step, len, elem_size );
+ if( even )
+ {
+ memcpy( dbuf1 + elem_size, dbuf1, elem_size );
+ icvCopyColumn( dbuf1 + elem_size, elem_size,
+ dptr0 + (count-1)*elem_size,
+ dst->step, len, elem_size );
+ }
+ dptr0 += elem_size;
+ }
+ else
+ {
+ // copy the real part of the complex vector to the first/last column
+ icvCopyColumn( dbuf0, complex_elem_size, dptr0, dst->step, len, elem_size );
+ if( even )
+ icvCopyColumn( dbuf1, complex_elem_size, dptr0 + (count-1)*elem_size,
+ dst->step, len, elem_size );
+ dptr0 += elem_size;
+ }
+ }
+ else
+ {
+ assert( !inv );
+ icvCopyColumn( dbuf0, complex_elem_size, dptr0,
+ dst->step, len, complex_elem_size );
+ if( even )
+ icvCopyColumn( dbuf1, complex_elem_size,
+ dptr0 + b*complex_elem_size,
+ dst->step, len, complex_elem_size );
+ dptr0 += complex_elem_size;
+ }
+ }
+
+ for( i = a; i < b; i += 2 )
+ {
+ if( i+1 < b )
+ {
+ icvCopyFrom2Columns( sptr0, src->step, buf0, buf1, len, complex_elem_size );
+ IPPI_CALL( dft_func( buf1, dbuf1, len, nf, factors, itab,
+ wave, len, spec, ptr, inv, scale ));
+ }
+ else
+ icvCopyColumn( sptr0, src->step, buf0, complex_elem_size, len, complex_elem_size );
+
+ IPPI_CALL( dft_func( buf0, dbuf0, len, nf, factors, itab,
+ wave, len, spec, ptr, inv, scale ));
+
+ if( i+1 < b )
+ icvCopyTo2Columns( dbuf0, dbuf1, dptr0, dst->step, len, complex_elem_size );
+ else
+ icvCopyColumn( dbuf0, complex_elem_size, dptr0, dst->step, len, complex_elem_size );
+ sptr0 += 2*complex_elem_size;
+ dptr0 += 2*complex_elem_size;
+ }
+
+ if( stage != 0 )
+ break;
+ src = dst;
+ }
+ }
+
+ __END__;
+
+ if( buffer && !local_alloc )
+ cvFree( &buffer );
+
+ if( spec_c )
+ {
+ if( depth == CV_32F )
+ icvDFTFree_C_32fc_p( spec_c );
+ else
+ icvDFTFree_C_64fc_p( spec_c );
+ }
+
+ if( spec_r )
+ {
+ if( depth == CV_32F )
+ icvDFTFree_R_32f_p( spec_r );
+ else
+ icvDFTFree_R_64f_p( spec_r );
+ }
+}
+
+
+CV_IMPL void
+cvMulSpectrums( const CvArr* srcAarr, const CvArr* srcBarr,
+ CvArr* dstarr, int flags )
+{
+ CV_FUNCNAME( "cvMulSpectrums" );
+
+ __BEGIN__;
+
+ CvMat stubA, *srcA = (CvMat*)srcAarr;
+ CvMat stubB, *srcB = (CvMat*)srcBarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ int stepA, stepB, stepC;
+ int type, cn, is_1d;
+ int j, j0, j1, k, rows, cols, ncols;
+
+ if( !CV_IS_MAT(srcA))
+ CV_CALL( srcA = cvGetMat( srcA, &stubA, 0 ));
+
+ if( !CV_IS_MAT(srcB))
+ CV_CALL( srcB = cvGetMat( srcB, &stubB, 0 ));
+
+ if( !CV_IS_MAT(dst))
+ CV_CALL( dst = cvGetMat( dst, &dststub, 0 ));
+
+ if( !CV_ARE_TYPES_EQ( srcA, srcB ) || !CV_ARE_TYPES_EQ( srcA, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( !CV_ARE_SIZES_EQ( srcA, srcB ) || !CV_ARE_SIZES_EQ( srcA, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ type = CV_MAT_TYPE( dst->type );
+ cn = CV_MAT_CN(type);
+ rows = srcA->rows;
+ cols = srcA->cols;
+ is_1d = (flags & CV_DXT_ROWS) ||
+ (rows == 1 || (cols == 1 &&
+ CV_IS_MAT_CONT( srcA->type & srcB->type & dst->type )));
+
+ if( is_1d && !(flags & CV_DXT_ROWS) )
+ cols = cols + rows - 1, rows = 1;
+ ncols = cols*cn;
+ j0 = cn == 1;
+ j1 = ncols - (cols % 2 == 0 && cn == 1);
+
+ if( CV_MAT_DEPTH(type) == CV_32F )
+ {
+ float* dataA = srcA->data.fl;
+ float* dataB = srcB->data.fl;
+ float* dataC = dst->data.fl;
+
+ stepA = srcA->step/sizeof(dataA[0]);
+ stepB = srcB->step/sizeof(dataB[0]);
+ stepC = dst->step/sizeof(dataC[0]);
+
+ if( !is_1d && cn == 1 )
+ {
+ for( k = 0; k < (cols % 2 ? 1 : 2); k++ )
+ {
+ if( k == 1 )
+ dataA += cols - 1, dataB += cols - 1, dataC += cols - 1;
+ dataC[0] = dataA[0]*dataB[0];
+ if( rows % 2 == 0 )
+ dataC[(rows-1)*stepC] = dataA[(rows-1)*stepA]*dataB[(rows-1)*stepB];
+ if( !(flags & CV_DXT_MUL_CONJ) )
+ for( j = 1; j <= rows - 2; j += 2 )
+ {
+ double re = (double)dataA[j*stepA]*dataB[j*stepB] -
+ (double)dataA[(j+1)*stepA]*dataB[(j+1)*stepB];
+ double im = (double)dataA[j*stepA]*dataB[(j+1)*stepB] +
+ (double)dataA[(j+1)*stepA]*dataB[j*stepB];
+ dataC[j*stepC] = (float)re; dataC[(j+1)*stepC] = (float)im;
+ }
+ else
+ for( j = 1; j <= rows - 2; j += 2 )
+ {
+ double re = (double)dataA[j*stepA]*dataB[j*stepB] +
+ (double)dataA[(j+1)*stepA]*dataB[(j+1)*stepB];
+ double im = (double)dataA[(j+1)*stepA]*dataB[j*stepB] -
+ (double)dataA[j*stepA]*dataB[(j+1)*stepB];
+ dataC[j*stepC] = (float)re; dataC[(j+1)*stepC] = (float)im;
+ }
+ if( k == 1 )
+ dataA -= cols - 1, dataB -= cols - 1, dataC -= cols - 1;
+ }
+ }
+
+ for( ; rows--; dataA += stepA, dataB += stepB, dataC += stepC )
+ {
+ if( is_1d && cn == 1 )
+ {
+ dataC[0] = dataA[0]*dataB[0];
+ if( cols % 2 == 0 )
+ dataC[j1] = dataA[j1]*dataB[j1];
+ }
+
+ if( !(flags & CV_DXT_MUL_CONJ) )
+ for( j = j0; j < j1; j += 2 )
+ {
+ double re = (double)dataA[j]*dataB[j] - (double)dataA[j+1]*dataB[j+1];
+ double im = (double)dataA[j+1]*dataB[j] + (double)dataA[j]*dataB[j+1];
+ dataC[j] = (float)re; dataC[j+1] = (float)im;
+ }
+ else
+ for( j = j0; j < j1; j += 2 )
+ {
+ double re = (double)dataA[j]*dataB[j] + (double)dataA[j+1]*dataB[j+1];
+ double im = (double)dataA[j+1]*dataB[j] - (double)dataA[j]*dataB[j+1];
+ dataC[j] = (float)re; dataC[j+1] = (float)im;
+ }
+ }
+ }
+ else if( CV_MAT_DEPTH(type) == CV_64F )
+ {
+ double* dataA = srcA->data.db;
+ double* dataB = srcB->data.db;
+ double* dataC = dst->data.db;
+
+ stepA = srcA->step/sizeof(dataA[0]);
+ stepB = srcB->step/sizeof(dataB[0]);
+ stepC = dst->step/sizeof(dataC[0]);
+
+ if( !is_1d && cn == 1 )
+ {
+ for( k = 0; k < (cols % 2 ? 1 : 2); k++ )
+ {
+ if( k == 1 )
+ dataA += cols - 1, dataB += cols - 1, dataC += cols - 1;
+ dataC[0] = dataA[0]*dataB[0];
+ if( rows % 2 == 0 )
+ dataC[(rows-1)*stepC] = dataA[(rows-1)*stepA]*dataB[(rows-1)*stepB];
+ if( !(flags & CV_DXT_MUL_CONJ) )
+ for( j = 1; j <= rows - 2; j += 2 )
+ {
+ double re = dataA[j*stepA]*dataB[j*stepB] -
+ dataA[(j+1)*stepA]*dataB[(j+1)*stepB];
+ double im = dataA[j*stepA]*dataB[(j+1)*stepB] +
+ dataA[(j+1)*stepA]*dataB[j*stepB];
+ dataC[j*stepC] = re; dataC[(j+1)*stepC] = im;
+ }
+ else
+ for( j = 1; j <= rows - 2; j += 2 )
+ {
+ double re = dataA[j*stepA]*dataB[j*stepB] +
+ dataA[(j+1)*stepA]*dataB[(j+1)*stepB];
+ double im = dataA[(j+1)*stepA]*dataB[j*stepB] -
+ dataA[j*stepA]*dataB[(j+1)*stepB];
+ dataC[j*stepC] = re; dataC[(j+1)*stepC] = im;
+ }
+ if( k == 1 )
+ dataA -= cols - 1, dataB -= cols - 1, dataC -= cols - 1;
+ }
+ }
+
+ for( ; rows--; dataA += stepA, dataB += stepB, dataC += stepC )
+ {
+ if( is_1d && cn == 1 )
+ {
+ dataC[0] = dataA[0]*dataB[0];
+ if( cols % 2 == 0 )
+ dataC[j1] = dataA[j1]*dataB[j1];
+ }
+
+ if( !(flags & CV_DXT_MUL_CONJ) )
+ for( j = j0; j < j1; j += 2 )
+ {
+ double re = dataA[j]*dataB[j] - dataA[j+1]*dataB[j+1];
+ double im = dataA[j+1]*dataB[j] + dataA[j]*dataB[j+1];
+ dataC[j] = re; dataC[j+1] = im;
+ }
+ else
+ for( j = j0; j < j1; j += 2 )
+ {
+ double re = dataA[j]*dataB[j] + dataA[j+1]*dataB[j+1];
+ double im = dataA[j+1]*dataB[j] - dataA[j]*dataB[j+1];
+ dataC[j] = re; dataC[j+1] = im;
+ }
+ }
+ }
+ else
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Only 32f and 64f types are supported" );
+ }
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+ Discrete Cosine Transform
+\****************************************************************************************/
+
+/* DCT is calculated using DFT, as described here:
+ http://www.ece.utexas.edu/~bevans/courses/ee381k/lectures/09_DCT/lecture9/:
+*/
+#define ICV_DCT_FWD( flavor, datatype ) \
+static CvStatus CV_STDCALL \
+icvDCT_fwd_##flavor( const datatype* src, int src_step, datatype* dft_src,\
+ datatype* dft_dst, datatype* dst, int dst_step, \
+ int n, int nf, int* factors, const int* itab, \
+ const CvComplex##flavor* dft_wave, \
+ const CvComplex##flavor* dct_wave, \
+ const void* spec, CvComplex##flavor* buf ) \
+{ \
+ int j, n2 = n >> 1; \
+ \
+ src_step /= sizeof(src[0]); \
+ dst_step /= sizeof(dst[0]); \
+ datatype* dst1 = dst + (n-1)*dst_step; \
+ \
+ if( n == 1 ) \
+ { \
+ dst[0] = src[0]; \
+ return CV_OK; \
+ } \
+ \
+ for( j = 0; j < n2; j++, src += src_step*2 ) \
+ { \
+ dft_src[j] = src[0]; \
+ dft_src[n-j-1] = src[src_step]; \
+ } \
+ \
+ icvRealDFT_##flavor( dft_src, dft_dst, n, nf, factors, \
+ itab, dft_wave, n, spec, buf, 0, 1.0 ); \
+ src = dft_dst; \
+ \
+ dst[0] = (datatype)(src[0]*dct_wave->re*icv_sin_45); \
+ dst += dst_step; \
+ for( j = 1, dct_wave++; j < n2; j++, dct_wave++, \
+ dst += dst_step, dst1 -= dst_step ) \
+ { \
+ double t0 = dct_wave->re*src[j*2-1] - dct_wave->im*src[j*2]; \
+ double t1 = -dct_wave->im*src[j*2-1] - dct_wave->re*src[j*2]; \
+ dst[0] = (datatype)t0; \
+ dst1[0] = (datatype)t1; \
+ } \
+ \
+ dst[0] = (datatype)(src[n-1]*dct_wave->re); \
+ return CV_OK; \
+}
+
+
+#define ICV_DCT_INV( flavor, datatype ) \
+static CvStatus CV_STDCALL \
+icvDCT_inv_##flavor( const datatype* src, int src_step, datatype* dft_src,\
+ datatype* dft_dst, datatype* dst, int dst_step, \
+ int n, int nf, int* factors, const int* itab, \
+ const CvComplex##flavor* dft_wave, \
+ const CvComplex##flavor* dct_wave, \
+ const void* spec, CvComplex##flavor* buf ) \
+{ \
+ int j, n2 = n >> 1; \
+ \
+ src_step /= sizeof(src[0]); \
+ dst_step /= sizeof(dst[0]); \
+ const datatype* src1 = src + (n-1)*src_step; \
+ \
+ if( n == 1 ) \
+ { \
+ dst[0] = src[0]; \
+ return CV_OK; \
+ } \
+ \
+ dft_src[0] = (datatype)(src[0]*2*dct_wave->re*icv_sin_45); \
+ src += src_step; \
+ for( j = 1, dct_wave++; j < n2; j++, dct_wave++, \
+ src += src_step, src1 -= src_step ) \
+ { \
+ double t0 = dct_wave->re*src[0] - dct_wave->im*src1[0]; \
+ double t1 = -dct_wave->im*src[0] - dct_wave->re*src1[0]; \
+ dft_src[j*2-1] = (datatype)t0; \
+ dft_src[j*2] = (datatype)t1; \
+ } \
+ \
+ dft_src[n-1] = (datatype)(src[0]*2*dct_wave->re); \
+ icvCCSIDFT_##flavor( dft_src, dft_dst, n, nf, factors, itab, \
+ dft_wave, n, spec, buf, CV_DXT_INVERSE, 1.0 ); \
+ \
+ for( j = 0; j < n2; j++, dst += dst_step*2 ) \
+ { \
+ dst[0] = dft_dst[j]; \
+ dst[dst_step] = dft_dst[n-j-1]; \
+ } \
+ return CV_OK; \
+}
+
+
+ICV_DCT_FWD( 64f, double )
+ICV_DCT_INV( 64f, double )
+ICV_DCT_FWD( 32f, float )
+ICV_DCT_INV( 32f, float )
+
+static void
+icvDCTInit( int n, int elem_size, void* _wave, int inv )
+{
+ static const double icvDctScale[] =
+ {
+ 0.707106781186547570, 0.500000000000000000, 0.353553390593273790,
+ 0.250000000000000000, 0.176776695296636890, 0.125000000000000000,
+ 0.088388347648318447, 0.062500000000000000, 0.044194173824159223,
+ 0.031250000000000000, 0.022097086912079612, 0.015625000000000000,
+ 0.011048543456039806, 0.007812500000000000, 0.005524271728019903,
+ 0.003906250000000000, 0.002762135864009952, 0.001953125000000000,
+ 0.001381067932004976, 0.000976562500000000, 0.000690533966002488,
+ 0.000488281250000000, 0.000345266983001244, 0.000244140625000000,
+ 0.000172633491500622, 0.000122070312500000, 0.000086316745750311,
+ 0.000061035156250000, 0.000043158372875155, 0.000030517578125000
+ };
+
+ int i;
+ CvComplex64f w, w1;
+ double t, scale;
+
+ if( n == 1 )
+ return;
+
+ assert( (n&1) == 0 );
+
+ if( (n & (n - 1)) == 0 )
+ {
+ int m = icvlog2(n);
+ scale = (!inv ? 2 : 1)*icvDctScale[m];
+ w1.re = icvDxtTab[m+2][0];
+ w1.im = -icvDxtTab[m+2][1];
+ }
+ else
+ {
+ t = 1./(2*n);
+ scale = (!inv ? 2 : 1)*sqrt(t);
+ w1.im = sin(-CV_PI*t);
+ w1.re = sqrt(1. - w1.im*w1.im);
+ }
+ n >>= 1;
+
+ if( elem_size == sizeof(CvComplex64f) )
+ {
+ CvComplex64f* wave = (CvComplex64f*)_wave;
+
+ w.re = scale;
+ w.im = 0.;
+
+ for( i = 0; i <= n; i++ )
+ {
+ wave[i] = w;
+ t = w.re*w1.re - w.im*w1.im;
+ w.im = w.re*w1.im + w.im*w1.re;
+ w.re = t;
+ }
+ }
+ else
+ {
+ CvComplex32f* wave = (CvComplex32f*)_wave;
+ assert( elem_size == sizeof(CvComplex32f) );
+
+ w.re = (float)scale;
+ w.im = 0.f;
+
+ for( i = 0; i <= n; i++ )
+ {
+ wave[i].re = (float)w.re;
+ wave[i].im = (float)w.im;
+ t = w.re*w1.re - w.im*w1.im;
+ w.im = w.re*w1.im + w.im*w1.re;
+ w.re = t;
+ }
+ }
+}
+
+
+typedef CvStatus (CV_STDCALL * CvDCTFunc)(
+ const void* src, int src_step, void* dft_src,
+ void* dft_dst, void* dst, int dst_step, int n,
+ int nf, int* factors, const int* itab, const void* dft_wave,
+ const void* dct_wave, const void* spec, void* buf );
+
+CV_IMPL void
+cvDCT( const CvArr* srcarr, CvArr* dstarr, int flags )
+{
+ static CvDCTFunc dct_tbl[4];
+ static int inittab = 0;
+
+ void* buffer = 0;
+ int local_alloc = 1;
+ int inv = (flags & CV_DXT_INVERSE) != 0, depth = -1;
+ void *spec_dft = 0, *spec = 0;
+
+ CV_FUNCNAME( "cvDCT" );
+
+ __BEGIN__;
+
+ double scale = 1.;
+ int prev_len = 0, buf_size = 0, nf = 0, stage, end_stage;
+ CvMat *src = (CvMat*)srcarr, *dst = (CvMat*)dstarr;
+ uchar *src_dft_buf = 0, *dst_dft_buf = 0;
+ uchar *dft_wave = 0, *dct_wave = 0;
+ int* itab = 0;
+ uchar* ptr = 0;
+ CvMat srcstub, dststub;
+ int complex_elem_size, elem_size;
+ int factors[34], inplace_transform;
+ int i, len, count;
+ CvDCTFunc dct_func;
+
+ if( !inittab )
+ {
+ dct_tbl[0] = (CvDCTFunc)icvDCT_fwd_32f;
+ dct_tbl[1] = (CvDCTFunc)icvDCT_inv_32f;
+ dct_tbl[2] = (CvDCTFunc)icvDCT_fwd_64f;
+ dct_tbl[3] = (CvDCTFunc)icvDCT_inv_64f;
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT( src ))
+ {
+ int coi = 0;
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_IS_MAT( dst ))
+ {
+ int coi = 0;
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ depth = CV_MAT_DEPTH(src->type);
+ elem_size = CV_ELEM_SIZE1(depth);
+ complex_elem_size = elem_size*2;
+
+ // check types and sizes
+ if( !CV_ARE_TYPES_EQ(src, dst) )
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( depth < CV_32F || CV_MAT_CN(src->type) != 1 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Only 32fC1 and 64fC1 formats are supported" );
+
+ dct_func = dct_tbl[inv + (depth == CV_64F)*2];
+
+ if( (flags & CV_DXT_ROWS) || src->rows == 1 ||
+ (src->cols == 1 && CV_IS_MAT_CONT(src->type & dst->type)))
+ {
+ stage = end_stage = 0;
+ }
+ else
+ {
+ stage = src->cols == 1;
+ end_stage = 1;
+ }
+
+ for( ; stage <= end_stage; stage++ )
+ {
+ uchar *sptr = src->data.ptr, *dptr = dst->data.ptr;
+ int sstep0, sstep1, dstep0, dstep1;
+
+ if( stage == 0 )
+ {
+ len = src->cols;
+ count = src->rows;
+ if( len == 1 && !(flags & CV_DXT_ROWS) )
+ {
+ len = src->rows;
+ count = 1;
+ }
+ sstep0 = src->step;
+ dstep0 = dst->step;
+ sstep1 = dstep1 = elem_size;
+ }
+ else
+ {
+ len = dst->rows;
+ count = dst->cols;
+ sstep1 = src->step;
+ dstep1 = dst->step;
+ sstep0 = dstep0 = elem_size;
+ }
+
+ if( len != prev_len )
+ {
+ int sz;
+
+ if( len > 1 && (len & 1) )
+ CV_ERROR( CV_StsNotImplemented, "Odd-size DCT\'s are not implemented" );
+
+ sz = len*elem_size;
+ sz += (len/2 + 1)*complex_elem_size;
+
+ spec = 0;
+ inplace_transform = 1;
+ if( len*count >= 64 && icvDFTInitAlloc_R_32f_p )
+ {
+ int ipp_sz = 0;
+ if( depth == CV_32F )
+ {
+ if( spec_dft )
+ IPPI_CALL( icvDFTFree_R_32f_p( spec_dft ));
+ IPPI_CALL( icvDFTInitAlloc_R_32f_p( &spec_dft, len, 8, cvAlgHintNone ));
+ IPPI_CALL( icvDFTGetBufSize_R_32f_p( spec_dft, &ipp_sz ));
+ }
+ else
+ {
+ if( spec_dft )
+ IPPI_CALL( icvDFTFree_R_64f_p( spec_dft ));
+ IPPI_CALL( icvDFTInitAlloc_R_64f_p( &spec_dft, len, 8, cvAlgHintNone ));
+ IPPI_CALL( icvDFTGetBufSize_R_64f_p( spec_dft, &ipp_sz ));
+ }
+ spec = spec_dft;
+ sz += ipp_sz;
+ }
+ else
+ {
+ sz += len*(complex_elem_size + sizeof(int)) + complex_elem_size;
+
+ nf = icvDFTFactorize( len, factors );
+ inplace_transform = factors[0] == factors[nf-1];
+
+ i = nf > 1 && (factors[0] & 1) == 0;
+ if( (factors[i] & 1) != 0 && factors[i] > 5 )
+ sz += (factors[i]+1)*complex_elem_size;
+
+ if( !inplace_transform )
+ sz += len*elem_size;
+ }
+
+ if( sz > buf_size )
+ {
+ if( !local_alloc && buffer )
+ cvFree( &buffer );
+ if( sz <= CV_MAX_LOCAL_DFT_SIZE )
+ {
+ buf_size = sz = CV_MAX_LOCAL_DFT_SIZE;
+ buffer = cvStackAlloc(sz + 32);
+ local_alloc = 1;
+ }
+ else
+ {
+ CV_CALL( buffer = cvAlloc(sz + 32) );
+ buf_size = sz;
+ local_alloc = 0;
+ }
+ }
+
+ ptr = (uchar*)buffer;
+ if( !spec )
+ {
+ dft_wave = ptr;
+ ptr += len*complex_elem_size;
+ itab = (int*)ptr;
+ ptr = (uchar*)cvAlignPtr( ptr + len*sizeof(int), 16 );
+ icvDFTInit( len, nf, factors, itab, complex_elem_size, dft_wave, inv );
+ }
+
+ dct_wave = ptr;
+ ptr += (len/2 + 1)*complex_elem_size;
+ src_dft_buf = dst_dft_buf = ptr;
+ ptr += len*elem_size;
+ if( !inplace_transform )
+ {
+ dst_dft_buf = ptr;
+ ptr += len*elem_size;
+ }
+ icvDCTInit( len, complex_elem_size, dct_wave, inv );
+ if( !inv )
+ scale += scale;
+ prev_len = len;
+ }
+ // otherwise reuse the tables calculated on the previous stage
+
+ for( i = 0; i < count; i++ )
+ {
+ dct_func( sptr + i*sstep0, sstep1, src_dft_buf, dst_dft_buf,
+ dptr + i*dstep0, dstep1, len, nf, factors,
+ itab, dft_wave, dct_wave, spec, ptr );
+ }
+ src = dst;
+ }
+
+ __END__;
+
+ if( spec_dft )
+ {
+ if( depth == CV_32F )
+ icvDFTFree_R_32f_p( spec_dft );
+ else
+ icvDFTFree_R_64f_p( spec_dft );
+ }
+
+ if( buffer && !local_alloc )
+ cvFree( &buffer );
+}
+
+
+static const int icvOptimalDFTSize[] = {
+1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36, 40, 45, 48,
+50, 54, 60, 64, 72, 75, 80, 81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160,
+162, 180, 192, 200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375,
+384, 400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675, 720,
+729, 750, 768, 800, 810, 864, 900, 960, 972, 1000, 1024, 1080, 1125, 1152, 1200,
+1215, 1250, 1280, 1296, 1350, 1440, 1458, 1500, 1536, 1600, 1620, 1728, 1800, 1875,
+1920, 1944, 2000, 2025, 2048, 2160, 2187, 2250, 2304, 2400, 2430, 2500, 2560, 2592,
+2700, 2880, 2916, 3000, 3072, 3125, 3200, 3240, 3375, 3456, 3600, 3645, 3750, 3840,
+3888, 4000, 4050, 4096, 4320, 4374, 4500, 4608, 4800, 4860, 5000, 5120, 5184, 5400,
+5625, 5760, 5832, 6000, 6075, 6144, 6250, 6400, 6480, 6561, 6750, 6912, 7200, 7290,
+7500, 7680, 7776, 8000, 8100, 8192, 8640, 8748, 9000, 9216, 9375, 9600, 9720, 10000,
+10125, 10240, 10368, 10800, 10935, 11250, 11520, 11664, 12000, 12150, 12288, 12500,
+12800, 12960, 13122, 13500, 13824, 14400, 14580, 15000, 15360, 15552, 15625, 16000,
+16200, 16384, 16875, 17280, 17496, 18000, 18225, 18432, 18750, 19200, 19440, 19683,
+20000, 20250, 20480, 20736, 21600, 21870, 22500, 23040, 23328, 24000, 24300, 24576,
+25000, 25600, 25920, 26244, 27000, 27648, 28125, 28800, 29160, 30000, 30375, 30720,
+31104, 31250, 32000, 32400, 32768, 32805, 33750, 34560, 34992, 36000, 36450, 36864,
+37500, 38400, 38880, 39366, 40000, 40500, 40960, 41472, 43200, 43740, 45000, 46080,
+46656, 46875, 48000, 48600, 49152, 50000, 50625, 51200, 51840, 52488, 54000, 54675,
+55296, 56250, 57600, 58320, 59049, 60000, 60750, 61440, 62208, 62500, 64000, 64800,
+65536, 65610, 67500, 69120, 69984, 72000, 72900, 73728, 75000, 76800, 77760, 78125,
+78732, 80000, 81000, 81920, 82944, 84375, 86400, 87480, 90000, 91125, 92160, 93312,
+93750, 96000, 97200, 98304, 98415, 100000, 101250, 102400, 103680, 104976, 108000,
+109350, 110592, 112500, 115200, 116640, 118098, 120000, 121500, 122880, 124416, 125000,
+128000, 129600, 131072, 131220, 135000, 138240, 139968, 140625, 144000, 145800, 147456,
+150000, 151875, 153600, 155520, 156250, 157464, 160000, 162000, 163840, 164025, 165888,
+168750, 172800, 174960, 177147, 180000, 182250, 184320, 186624, 187500, 192000, 194400,
+196608, 196830, 200000, 202500, 204800, 207360, 209952, 216000, 218700, 221184, 225000,
+230400, 233280, 234375, 236196, 240000, 243000, 245760, 248832, 250000, 253125, 256000,
+259200, 262144, 262440, 270000, 273375, 276480, 279936, 281250, 288000, 291600, 294912,
+295245, 300000, 303750, 307200, 311040, 312500, 314928, 320000, 324000, 327680, 328050,
+331776, 337500, 345600, 349920, 354294, 360000, 364500, 368640, 373248, 375000, 384000,
+388800, 390625, 393216, 393660, 400000, 405000, 409600, 414720, 419904, 421875, 432000,
+437400, 442368, 450000, 455625, 460800, 466560, 468750, 472392, 480000, 486000, 491520,
+492075, 497664, 500000, 506250, 512000, 518400, 524288, 524880, 531441, 540000, 546750,
+552960, 559872, 562500, 576000, 583200, 589824, 590490, 600000, 607500, 614400, 622080,
+625000, 629856, 640000, 648000, 655360, 656100, 663552, 675000, 691200, 699840, 703125,
+708588, 720000, 729000, 737280, 746496, 750000, 759375, 768000, 777600, 781250, 786432,
+787320, 800000, 810000, 819200, 820125, 829440, 839808, 843750, 864000, 874800, 884736,
+885735, 900000, 911250, 921600, 933120, 937500, 944784, 960000, 972000, 983040, 984150,
+995328, 1000000, 1012500, 1024000, 1036800, 1048576, 1049760, 1062882, 1080000, 1093500,
+1105920, 1119744, 1125000, 1152000, 1166400, 1171875, 1179648, 1180980, 1200000,
+1215000, 1228800, 1244160, 1250000, 1259712, 1265625, 1280000, 1296000, 1310720,
+1312200, 1327104, 1350000, 1366875, 1382400, 1399680, 1406250, 1417176, 1440000,
+1458000, 1474560, 1476225, 1492992, 1500000, 1518750, 1536000, 1555200, 1562500,
+1572864, 1574640, 1594323, 1600000, 1620000, 1638400, 1640250, 1658880, 1679616,
+1687500, 1728000, 1749600, 1769472, 1771470, 1800000, 1822500, 1843200, 1866240,
+1875000, 1889568, 1920000, 1944000, 1953125, 1966080, 1968300, 1990656, 2000000,
+2025000, 2048000, 2073600, 2097152, 2099520, 2109375, 2125764, 2160000, 2187000,
+2211840, 2239488, 2250000, 2278125, 2304000, 2332800, 2343750, 2359296, 2361960,
+2400000, 2430000, 2457600, 2460375, 2488320, 2500000, 2519424, 2531250, 2560000,
+2592000, 2621440, 2624400, 2654208, 2657205, 2700000, 2733750, 2764800, 2799360,
+2812500, 2834352, 2880000, 2916000, 2949120, 2952450, 2985984, 3000000, 3037500,
+3072000, 3110400, 3125000, 3145728, 3149280, 3188646, 3200000, 3240000, 3276800,
+3280500, 3317760, 3359232, 3375000, 3456000, 3499200, 3515625, 3538944, 3542940,
+3600000, 3645000, 3686400, 3732480, 3750000, 3779136, 3796875, 3840000, 3888000,
+3906250, 3932160, 3936600, 3981312, 4000000, 4050000, 4096000, 4100625, 4147200,
+4194304, 4199040, 4218750, 4251528, 4320000, 4374000, 4423680, 4428675, 4478976,
+4500000, 4556250, 4608000, 4665600, 4687500, 4718592, 4723920, 4782969, 4800000,
+4860000, 4915200, 4920750, 4976640, 5000000, 5038848, 5062500, 5120000, 5184000,
+5242880, 5248800, 5308416, 5314410, 5400000, 5467500, 5529600, 5598720, 5625000,
+5668704, 5760000, 5832000, 5859375, 5898240, 5904900, 5971968, 6000000, 6075000,
+6144000, 6220800, 6250000, 6291456, 6298560, 6328125, 6377292, 6400000, 6480000,
+6553600, 6561000, 6635520, 6718464, 6750000, 6834375, 6912000, 6998400, 7031250,
+7077888, 7085880, 7200000, 7290000, 7372800, 7381125, 7464960, 7500000, 7558272,
+7593750, 7680000, 7776000, 7812500, 7864320, 7873200, 7962624, 7971615, 8000000,
+8100000, 8192000, 8201250, 8294400, 8388608, 8398080, 8437500, 8503056, 8640000,
+8748000, 8847360, 8857350, 8957952, 9000000, 9112500, 9216000, 9331200, 9375000,
+9437184, 9447840, 9565938, 9600000, 9720000, 9765625, 9830400, 9841500, 9953280,
+10000000, 10077696, 10125000, 10240000, 10368000, 10485760, 10497600, 10546875, 10616832,
+10628820, 10800000, 10935000, 11059200, 11197440, 11250000, 11337408, 11390625, 11520000,
+11664000, 11718750, 11796480, 11809800, 11943936, 12000000, 12150000, 12288000, 12301875,
+12441600, 12500000, 12582912, 12597120, 12656250, 12754584, 12800000, 12960000, 13107200,
+13122000, 13271040, 13286025, 13436928, 13500000, 13668750, 13824000, 13996800, 14062500,
+14155776, 14171760, 14400000, 14580000, 14745600, 14762250, 14929920, 15000000, 15116544,
+15187500, 15360000, 15552000, 15625000, 15728640, 15746400, 15925248, 15943230, 16000000,
+16200000, 16384000, 16402500, 16588800, 16777216, 16796160, 16875000, 17006112, 17280000,
+17496000, 17578125, 17694720, 17714700, 17915904, 18000000, 18225000, 18432000, 18662400,
+18750000, 18874368, 18895680, 18984375, 19131876, 19200000, 19440000, 19531250, 19660800,
+19683000, 19906560, 20000000, 20155392, 20250000, 20480000, 20503125, 20736000, 20971520,
+20995200, 21093750, 21233664, 21257640, 21600000, 21870000, 22118400, 22143375, 22394880,
+22500000, 22674816, 22781250, 23040000, 23328000, 23437500, 23592960, 23619600, 23887872,
+23914845, 24000000, 24300000, 24576000, 24603750, 24883200, 25000000, 25165824, 25194240,
+25312500, 25509168, 25600000, 25920000, 26214400, 26244000, 26542080, 26572050, 26873856,
+27000000, 27337500, 27648000, 27993600, 28125000, 28311552, 28343520, 28800000, 29160000,
+29296875, 29491200, 29524500, 29859840, 30000000, 30233088, 30375000, 30720000, 31104000,
+31250000, 31457280, 31492800, 31640625, 31850496, 31886460, 32000000, 32400000, 32768000,
+32805000, 33177600, 33554432, 33592320, 33750000, 34012224, 34171875, 34560000, 34992000,
+35156250, 35389440, 35429400, 35831808, 36000000, 36450000, 36864000, 36905625, 37324800,
+37500000, 37748736, 37791360, 37968750, 38263752, 38400000, 38880000, 39062500, 39321600,
+39366000, 39813120, 39858075, 40000000, 40310784, 40500000, 40960000, 41006250, 41472000,
+41943040, 41990400, 42187500, 42467328, 42515280, 43200000, 43740000, 44236800, 44286750,
+44789760, 45000000, 45349632, 45562500, 46080000, 46656000, 46875000, 47185920, 47239200,
+47775744, 47829690, 48000000, 48600000, 48828125, 49152000, 49207500, 49766400, 50000000,
+50331648, 50388480, 50625000, 51018336, 51200000, 51840000, 52428800, 52488000, 52734375,
+53084160, 53144100, 53747712, 54000000, 54675000, 55296000, 55987200, 56250000, 56623104,
+56687040, 56953125, 57600000, 58320000, 58593750, 58982400, 59049000, 59719680, 60000000,
+60466176, 60750000, 61440000, 61509375, 62208000, 62500000, 62914560, 62985600, 63281250,
+63700992, 63772920, 64000000, 64800000, 65536000, 65610000, 66355200, 66430125, 67108864,
+67184640, 67500000, 68024448, 68343750, 69120000, 69984000, 70312500, 70778880, 70858800,
+71663616, 72000000, 72900000, 73728000, 73811250, 74649600, 75000000, 75497472, 75582720,
+75937500, 76527504, 76800000, 77760000, 78125000, 78643200, 78732000, 79626240, 79716150,
+80000000, 80621568, 81000000, 81920000, 82012500, 82944000, 83886080, 83980800, 84375000,
+84934656, 85030560, 86400000, 87480000, 87890625, 88473600, 88573500, 89579520, 90000000,
+90699264, 91125000, 92160000, 93312000, 93750000, 94371840, 94478400, 94921875, 95551488,
+95659380, 96000000, 97200000, 97656250, 98304000, 98415000, 99532800, 100000000,
+100663296, 100776960, 101250000, 102036672, 102400000, 102515625, 103680000, 104857600,
+104976000, 105468750, 106168320, 106288200, 107495424, 108000000, 109350000, 110592000,
+110716875, 111974400, 112500000, 113246208, 113374080, 113906250, 115200000, 116640000,
+117187500, 117964800, 118098000, 119439360, 119574225, 120000000, 120932352, 121500000,
+122880000, 123018750, 124416000, 125000000, 125829120, 125971200, 126562500, 127401984,
+127545840, 128000000, 129600000, 131072000, 131220000, 132710400, 132860250, 134217728,
+134369280, 135000000, 136048896, 136687500, 138240000, 139968000, 140625000, 141557760,
+141717600, 143327232, 144000000, 145800000, 146484375, 147456000, 147622500, 149299200,
+150000000, 150994944, 151165440, 151875000, 153055008, 153600000, 155520000, 156250000,
+157286400, 157464000, 158203125, 159252480, 159432300, 160000000, 161243136, 162000000,
+163840000, 164025000, 165888000, 167772160, 167961600, 168750000, 169869312, 170061120,
+170859375, 172800000, 174960000, 175781250, 176947200, 177147000, 179159040, 180000000,
+181398528, 182250000, 184320000, 184528125, 186624000, 187500000, 188743680, 188956800,
+189843750, 191102976, 191318760, 192000000, 194400000, 195312500, 196608000, 196830000,
+199065600, 199290375, 200000000, 201326592, 201553920, 202500000, 204073344, 204800000,
+205031250, 207360000, 209715200, 209952000, 210937500, 212336640, 212576400, 214990848,
+216000000, 218700000, 221184000, 221433750, 223948800, 225000000, 226492416, 226748160,
+227812500, 230400000, 233280000, 234375000, 235929600, 236196000, 238878720, 239148450,
+240000000, 241864704, 243000000, 244140625, 245760000, 246037500, 248832000, 250000000,
+251658240, 251942400, 253125000, 254803968, 255091680, 256000000, 259200000, 262144000,
+262440000, 263671875, 265420800, 265720500, 268435456, 268738560, 270000000, 272097792,
+273375000, 276480000, 279936000, 281250000, 283115520, 283435200, 284765625, 286654464,
+288000000, 291600000, 292968750, 294912000, 295245000, 298598400, 300000000, 301989888,
+302330880, 303750000, 306110016, 307200000, 307546875, 311040000, 312500000, 314572800,
+314928000, 316406250, 318504960, 318864600, 320000000, 322486272, 324000000, 327680000,
+328050000, 331776000, 332150625, 335544320, 335923200, 337500000, 339738624, 340122240,
+341718750, 345600000, 349920000, 351562500, 353894400, 354294000, 358318080, 360000000,
+362797056, 364500000, 368640000, 369056250, 373248000, 375000000, 377487360, 377913600,
+379687500, 382205952, 382637520, 384000000, 388800000, 390625000, 393216000, 393660000,
+398131200, 398580750, 400000000, 402653184, 403107840, 405000000, 408146688, 409600000,
+410062500, 414720000, 419430400, 419904000, 421875000, 424673280, 425152800, 429981696,
+432000000, 437400000, 439453125, 442368000, 442867500, 447897600, 450000000, 452984832,
+453496320, 455625000, 460800000, 466560000, 468750000, 471859200, 472392000, 474609375,
+477757440, 478296900, 480000000, 483729408, 486000000, 488281250, 491520000, 492075000,
+497664000, 500000000, 503316480, 503884800, 506250000, 509607936, 510183360, 512000000,
+512578125, 518400000, 524288000, 524880000, 527343750, 530841600, 531441000, 536870912,
+537477120, 540000000, 544195584, 546750000, 552960000, 553584375, 559872000, 562500000,
+566231040, 566870400, 569531250, 573308928, 576000000, 583200000, 585937500, 589824000,
+590490000, 597196800, 597871125, 600000000, 603979776, 604661760, 607500000, 612220032,
+614400000, 615093750, 622080000, 625000000, 629145600, 629856000, 632812500, 637009920,
+637729200, 640000000, 644972544, 648000000, 655360000, 656100000, 663552000, 664301250,
+671088640, 671846400, 675000000, 679477248, 680244480, 683437500, 691200000, 699840000,
+703125000, 707788800, 708588000, 716636160, 720000000, 725594112, 729000000, 732421875,
+737280000, 738112500, 746496000, 750000000, 754974720, 755827200, 759375000, 764411904,
+765275040, 768000000, 777600000, 781250000, 786432000, 787320000, 791015625, 796262400,
+797161500, 800000000, 805306368, 806215680, 810000000, 816293376, 819200000, 820125000,
+829440000, 838860800, 839808000, 843750000, 849346560, 850305600, 854296875, 859963392,
+864000000, 874800000, 878906250, 884736000, 885735000, 895795200, 900000000, 905969664,
+906992640, 911250000, 921600000, 922640625, 933120000, 937500000, 943718400, 944784000,
+949218750, 955514880, 956593800, 960000000, 967458816, 972000000, 976562500, 983040000,
+984150000, 995328000, 996451875, 1000000000, 1006632960, 1007769600, 1012500000,
+1019215872, 1020366720, 1024000000, 1025156250, 1036800000, 1048576000, 1049760000,
+1054687500, 1061683200, 1062882000, 1073741824, 1074954240, 1080000000, 1088391168,
+1093500000, 1105920000, 1107168750, 1119744000, 1125000000, 1132462080, 1133740800,
+1139062500, 1146617856, 1152000000, 1166400000, 1171875000, 1179648000, 1180980000,
+1194393600, 1195742250, 1200000000, 1207959552, 1209323520, 1215000000, 1220703125,
+1224440064, 1228800000, 1230187500, 1244160000, 1250000000, 1258291200, 1259712000,
+1265625000, 1274019840, 1275458400, 1280000000, 1289945088, 1296000000, 1310720000,
+1312200000, 1318359375, 1327104000, 1328602500, 1342177280, 1343692800, 1350000000,
+1358954496, 1360488960, 1366875000, 1382400000, 1399680000, 1406250000, 1415577600,
+1417176000, 1423828125, 1433272320, 1440000000, 1451188224, 1458000000, 1464843750,
+1474560000, 1476225000, 1492992000, 1500000000, 1509949440, 1511654400, 1518750000,
+1528823808, 1530550080, 1536000000, 1537734375, 1555200000, 1562500000, 1572864000,
+1574640000, 1582031250, 1592524800, 1594323000, 1600000000, 1610612736, 1612431360,
+1620000000, 1632586752, 1638400000, 1640250000, 1658880000, 1660753125, 1677721600,
+1679616000, 1687500000, 1698693120, 1700611200, 1708593750, 1719926784, 1728000000,
+1749600000, 1757812500, 1769472000, 1771470000, 1791590400, 1800000000, 1811939328,
+1813985280, 1822500000, 1843200000, 1845281250, 1866240000, 1875000000, 1887436800,
+1889568000, 1898437500, 1911029760, 1913187600, 1920000000, 1934917632, 1944000000,
+1953125000, 1966080000, 1968300000, 1990656000, 1992903750, 2000000000, 2013265920,
+2015539200, 2025000000, 2038431744, 2040733440, 2048000000, 2050312500, 2073600000,
+2097152000, 2099520000, 2109375000, 2123366400, 2125764000
+};
+
+
+CV_IMPL int
+cvGetOptimalDFTSize( int size0 )
+{
+ int a = 0, b = sizeof(icvOptimalDFTSize)/sizeof(icvOptimalDFTSize[0]) - 1;
+ if( (unsigned)size0 >= (unsigned)icvOptimalDFTSize[b] )
+ return -1;
+
+ while( a < b )
+ {
+ int c = (a + b) >> 1;
+ if( size0 <= icvOptimalDFTSize[c] )
+ b = c;
+ else
+ a = c+1;
+ }
+
+ return icvOptimalDFTSize[b];
+}
+
+/* End of file. */
diff --git a/cxcore/src/cxerror.cpp b/cxcore/src/cxerror.cpp
new file mode 100644
index 0000000..1901fad
--- /dev/null
+++ b/cxcore/src/cxerror.cpp
@@ -0,0 +1,460 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+
+#if defined WIN32 || defined WIN64
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+
+typedef struct
+{
+ const char* file;
+ int line;
+}
+CvStackRecord;
+
+typedef struct CvContext
+{
+ int err_code;
+ int err_mode;
+ CvErrorCallback error_callback;
+ void* userdata;
+ char err_msg[4096];
+ CvStackRecord err_ctx;
+} CvContext;
+
+#if defined WIN32 || defined WIN64
+#define CV_DEFAULT_ERROR_CALLBACK cvGuiBoxReport
+#else
+#define CV_DEFAULT_ERROR_CALLBACK cvStdErrReport
+#endif
+
+static CvContext*
+icvCreateContext(void)
+{
+ CvContext* context = (CvContext*)malloc( sizeof(*context) );
+
+ context->err_mode = CV_ErrModeLeaf;
+ context->err_code = CV_StsOk;
+
+ context->error_callback = CV_DEFAULT_ERROR_CALLBACK;
+ context->userdata = 0;
+
+ return context;
+}
+
+static void
+icvDestroyContext(CvContext* context)
+{
+ free(context);
+}
+
+#if defined WIN32 || defined WIN64
+ static DWORD g_TlsIndex = TLS_OUT_OF_INDEXES;
+#else
+ static pthread_key_t g_TlsIndex;
+#endif
+
+static CvContext*
+icvGetContext(void)
+{
+#ifdef CV_DLL
+#if defined WIN32 || defined WIN64
+ CvContext* context;
+
+ //assert(g_TlsIndex != TLS_OUT_OF_INDEXES);
+ if( g_TlsIndex == TLS_OUT_OF_INDEXES )
+ {
+ g_TlsIndex = TlsAlloc();
+ if( g_TlsIndex == TLS_OUT_OF_INDEXES )
+ FatalAppExit( 0, "Only set CV_DLL for DLL usage" );
+ }
+
+ context = (CvContext*)TlsGetValue( g_TlsIndex );
+ if( !context )
+ {
+ context = icvCreateContext();
+ if( !context )
+ FatalAppExit( 0, "OpenCV. Problem to allocate memory for TLS OpenCV context." );
+
+ TlsSetValue( g_TlsIndex, context );
+ }
+ return context;
+#else
+ CvContext* context = (CvContext*)pthread_getspecific( g_TlsIndex );
+ if( !context )
+ {
+ context = icvCreateContext();
+ if( !context )
+ {
+ fprintf(stderr,"OpenCV. Problem to allocate memory for OpenCV context.");
+ exit(1);
+ }
+ pthread_setspecific( g_TlsIndex, context );
+ }
+ return context;
+#endif
+#else /* static single-thread library case */
+ static CvContext* context = 0;
+
+ if( !context )
+ context = icvCreateContext();
+
+ return context;
+#endif
+}
+
+
+CV_IMPL int
+cvStdErrReport( int code, const char *func_name, const char *err_msg,
+ const char *file, int line, void* )
+{
+ if( code == CV_StsBackTrace || code == CV_StsAutoTrace )
+ fprintf( stderr, "\tcalled from " );
+ else
+ fprintf( stderr, "OpenCV ERROR: %s (%s)\n\tin function ",
+ cvErrorStr(code), err_msg ? err_msg : "no description" );
+
+ fprintf( stderr, "%s, %s(%d)\n", func_name ? func_name : "<unknown>",
+ file != NULL ? file : "", line );
+
+ if( cvGetErrMode() == CV_ErrModeLeaf )
+ {
+ fprintf( stderr, "Terminating the application...\n" );
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+CV_IMPL int
+cvGuiBoxReport( int code, const char *func_name, const char *err_msg,
+ const char *file, int line, void* )
+{
+#if !defined WIN32 && !defined WIN64
+ return cvStdErrReport( code, func_name, err_msg, file, line, 0 );
+#else
+ if( code != CV_StsBackTrace && code != CV_StsAutoTrace )
+ {
+ size_t msg_len = strlen(err_msg ? err_msg : "") + 1024;
+ char* message = (char*)alloca(msg_len);
+ char title[100];
+
+ wsprintf( message, "%s (%s)\nin function %s, %s(%d)\n\n"
+ "Press \"Abort\" to terminate application.\n"
+ "Press \"Retry\" to debug (if the app is running under debugger).\n"
+ "Press \"Ignore\" to continue (this is not safe).\n",
+ cvErrorStr(code), err_msg ? err_msg : "no description",
+ func_name, file, line );
+
+ wsprintf( title, "OpenCV GUI Error Handler" );
+
+ int answer = MessageBox( NULL, message, title, MB_ICONERROR|MB_ABORTRETRYIGNORE|MB_SYSTEMMODAL );
+
+ if( answer == IDRETRY )
+ {
+ CV_DBG_BREAK();
+ }
+ return answer != IDIGNORE;
+ }
+ return 0;
+#endif
+}
+
+
+CV_IMPL int cvNulDevReport( int /*code*/, const char* /*func_name*/,
+ const char* /*err_msg*/, const char* /*file*/, int /*line*/, void* )
+{
+ return cvGetErrMode() == CV_ErrModeLeaf;
+}
+
+
+CV_IMPL CvErrorCallback
+cvRedirectError( CvErrorCallback func, void* userdata, void** prev_userdata )
+{
+ CvContext* context = icvGetContext();
+
+ CvErrorCallback old = context->error_callback;
+ if( prev_userdata )
+ *prev_userdata = context->userdata;
+ if( func )
+ {
+ context->error_callback = func;
+ context->userdata = userdata;
+ }
+ else
+ {
+ context->error_callback = CV_DEFAULT_ERROR_CALLBACK;
+ context->userdata = 0;
+ }
+
+ return old;
+}
+
+
+CV_IMPL int cvGetErrInfo( const char** errorcode_desc, const char** description,
+ const char** filename, int* line )
+{
+ int code = cvGetErrStatus();
+
+ if( errorcode_desc )
+ *errorcode_desc = cvErrorStr( code );
+
+ if( code >= 0 )
+ {
+ if( description )
+ *description = 0;
+ if( filename )
+ *filename = 0;
+ if( line )
+ *line = 0;
+ }
+ else
+ {
+ CvContext* ctx = icvGetContext();
+
+ if( description )
+ *description = ctx->err_msg;
+ if( filename )
+ *filename = ctx->err_ctx.file;
+ if( line )
+ *line = ctx->err_ctx.line;
+ }
+
+ return code;
+}
+
+
+CV_IMPL const char* cvErrorStr( int status )
+{
+ static char buf[256];
+
+ switch (status)
+ {
+ case CV_StsOk : return "No Error";
+ case CV_StsBackTrace : return "Backtrace";
+ case CV_StsError : return "Unspecified error";
+ case CV_StsInternal : return "Internal error";
+ case CV_StsNoMem : return "Insufficient memory";
+ case CV_StsBadArg : return "Bad argument";
+ case CV_StsNoConv : return "Iterations do not converge";
+ case CV_StsAutoTrace : return "Autotrace call";
+ case CV_StsBadSize : return "Incorrect size of input array";
+ case CV_StsNullPtr : return "Null pointer";
+ case CV_StsDivByZero : return "Divizion by zero occured";
+ case CV_BadStep : return "Image step is wrong";
+ case CV_StsInplaceNotSupported : return "Inplace operation is not supported";
+ case CV_StsObjectNotFound : return "Requested object was not found";
+ case CV_BadDepth : return "Input image depth is not supported by function";
+ case CV_StsUnmatchedFormats : return "Formats of input arguments do not match";
+ case CV_StsUnmatchedSizes : return "Sizes of input arguments do not match";
+ case CV_StsOutOfRange : return "One of arguments\' values is out of range";
+ case CV_StsUnsupportedFormat : return "Unsupported format or combination of formats";
+ case CV_BadCOI : return "Input COI is not supported";
+ case CV_BadNumChannels : return "Bad number of channels";
+ case CV_StsBadFlag : return "Bad flag (parameter or structure field)";
+ case CV_StsBadPoint : return "Bad parameter of type CvPoint";
+ case CV_StsBadMask : return "Bad type of mask argument";
+ case CV_StsParseError : return "Parsing error";
+ case CV_StsNotImplemented : return "The function/feature is not implemented";
+ case CV_StsBadMemBlock : return "Memory block has been corrupted";
+ };
+
+ sprintf(buf, "Unknown %s code %d", status >= 0 ? "status":"error", status);
+ return buf;
+}
+
+CV_IMPL int cvGetErrMode(void)
+{
+ return icvGetContext()->err_mode;
+}
+
+CV_IMPL int cvSetErrMode( int mode )
+{
+ CvContext* context = icvGetContext();
+ int prev_mode = context->err_mode;
+ context->err_mode = mode;
+ return prev_mode;
+}
+
+CV_IMPL int cvGetErrStatus()
+{
+ return icvGetContext()->err_code;
+}
+
+CV_IMPL void cvSetErrStatus( int code )
+{
+ icvGetContext()->err_code = code;
+}
+
+
+CV_IMPL void cvError( int code, const char* func_name,
+ const char* err_msg,
+ const char* file_name, int line )
+{
+ if( code == CV_StsOk )
+ cvSetErrStatus( code );
+ else
+ {
+ CvContext* context = icvGetContext();
+
+ if( code != CV_StsBackTrace && code != CV_StsAutoTrace )
+ {
+ char* message = context->err_msg;
+ context->err_code = code;
+
+ strcpy( message, err_msg );
+ context->err_ctx.file = file_name;
+ context->err_ctx.line = line;
+ }
+
+ if( context->err_mode != CV_ErrModeSilent )
+ {
+ int terminate = context->error_callback( code, func_name, err_msg,
+ file_name, line, context->userdata );
+ if( terminate )
+ {
+ CV_DBG_BREAK();
+ //exit(-abs(terminate));
+ }
+ }
+ }
+}
+
+
+/******************** End of implementation of profiling stuff *********************/
+
+
+/**********************DllMain********************************/
+
+#if defined WIN32 || defined WIN64
+BOOL WINAPI DllMain( HINSTANCE, DWORD fdwReason, LPVOID )
+{
+ CvContext *pContext;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ g_TlsIndex = TlsAlloc();
+ if( g_TlsIndex == TLS_OUT_OF_INDEXES ) return FALSE;
+ //break;
+
+ case DLL_THREAD_ATTACH:
+ pContext = icvCreateContext();
+ if( pContext == NULL)
+ return FALSE;
+ TlsSetValue( g_TlsIndex, (LPVOID)pContext );
+ break;
+
+ case DLL_THREAD_DETACH:
+ if( g_TlsIndex != TLS_OUT_OF_INDEXES )
+ {
+ pContext = (CvContext*)TlsGetValue( g_TlsIndex );
+ if( pContext != NULL )
+ icvDestroyContext( pContext );
+ }
+ break;
+
+ case DLL_PROCESS_DETACH:
+ if( g_TlsIndex != TLS_OUT_OF_INDEXES )
+ {
+ pContext = (CvContext*)TlsGetValue( g_TlsIndex );
+ if( pContext != NULL )
+ icvDestroyContext( pContext );
+ }
+ TlsFree( g_TlsIndex );
+ break;
+ default:
+ ;
+ }
+ return TRUE;
+}
+#else
+/* POSIX pthread */
+
+/* function - destructor of thread */
+void icvPthreadDestructor(void* key_val)
+{
+ CvContext* context = (CvContext*) key_val;
+ icvDestroyContext( context );
+}
+
+int pthrerr = pthread_key_create( &g_TlsIndex, icvPthreadDestructor );
+
+#endif
+
+/* function, which converts int to int */
+CV_IMPL int
+cvErrorFromIppStatus( int status )
+{
+ switch (status)
+ {
+ case CV_BADSIZE_ERR: return CV_StsBadSize;
+ case CV_BADMEMBLOCK_ERR: return CV_StsBadMemBlock;
+ case CV_NULLPTR_ERR: return CV_StsNullPtr;
+ case CV_DIV_BY_ZERO_ERR: return CV_StsDivByZero;
+ case CV_BADSTEP_ERR: return CV_BadStep ;
+ case CV_OUTOFMEM_ERR: return CV_StsNoMem;
+ case CV_BADARG_ERR: return CV_StsBadArg;
+ case CV_NOTDEFINED_ERR: return CV_StsError;
+ case CV_INPLACE_NOT_SUPPORTED_ERR: return CV_StsInplaceNotSupported;
+ case CV_NOTFOUND_ERR: return CV_StsObjectNotFound;
+ case CV_BADCONVERGENCE_ERR: return CV_StsNoConv;
+ case CV_BADDEPTH_ERR: return CV_BadDepth;
+ case CV_UNMATCHED_FORMATS_ERR: return CV_StsUnmatchedFormats;
+ case CV_UNSUPPORTED_COI_ERR: return CV_BadCOI;
+ case CV_UNSUPPORTED_CHANNELS_ERR: return CV_BadNumChannels;
+ case CV_BADFLAG_ERR: return CV_StsBadFlag;
+ case CV_BADRANGE_ERR: return CV_StsBadArg;
+ case CV_BADCOEF_ERR: return CV_StsBadArg;
+ case CV_BADFACTOR_ERR: return CV_StsBadArg;
+ case CV_BADPOINT_ERR: return CV_StsBadPoint;
+
+ default: return CV_StsError;
+ }
+}
+/* End of file */
+
+
diff --git a/cxcore/src/cximage.cpp b/cxcore/src/cximage.cpp
new file mode 100644
index 0000000..85f40ce
--- /dev/null
+++ b/cxcore/src/cximage.cpp
@@ -0,0 +1,397 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/* ////////////////////////////////////////////////////////////////////
+//
+// C++ classes for image and matrices
+//
+// */
+
+#include "_cxcore.h"
+
+/////////////////////////////// CvImage implementation //////////////////////////////////
+
+static CvLoadImageFunc load_image = 0;
+static CvLoadImageMFunc load_image_m = 0;
+static CvSaveImageFunc save_image = 0;
+static CvShowImageFunc show_image = NULL;
+
+static bool
+icvIsXmlOrYaml( const char* filename )
+{
+ const char* suffix = strrchr( filename, '.' );
+ return suffix &&
+ (strcmp( suffix, ".xml" ) == 0 ||
+ strcmp( suffix, ".Xml" ) == 0 ||
+ strcmp( suffix, ".XML" ) == 0 ||
+ strcmp( suffix, ".yml" ) == 0 ||
+ strcmp( suffix, ".Yml" ) == 0 ||
+ strcmp( suffix, ".YML" ) == 0 ||
+ strcmp( suffix, ".yaml" ) == 0 ||
+ strcmp( suffix, ".Yaml" ) == 0 ||
+ strcmp( suffix, ".YAML" ) == 0);
+}
+
+
+static IplImage*
+icvRetrieveImage( void* obj )
+{
+ IplImage* img = 0;
+
+ CV_FUNCNAME( "icvRetrieveImage" );
+
+ __BEGIN__;
+
+ if( CV_IS_IMAGE(obj) )
+ img = (IplImage*)obj;
+ else if( CV_IS_MAT(obj) )
+ {
+ CvMat* m = (CvMat*)obj;
+ CV_CALL( img = cvCreateImageHeader( cvSize(m->cols,m->rows),
+ CV_MAT_DEPTH(m->type), CV_MAT_CN(m->type) ));
+ cvSetData( img, m->data.ptr, m->step );
+ img->imageDataOrigin = (char*)m->refcount;
+ m->data.ptr = 0; m->step = 0;
+ cvReleaseMat( &m );
+ }
+ else if( obj )
+ {
+ cvRelease( &obj );
+ CV_ERROR( CV_StsUnsupportedFormat, "The object is neither an image, nor a matrix" );
+ }
+
+ __END__;
+
+ return img;
+}
+
+
+bool CvImage::load( const char* filename, const char* imgname, int color )
+{
+ IplImage* img = 0;
+
+ CV_FUNCNAME( "CvImage::read" );
+
+ __BEGIN__;
+
+ if( icvIsXmlOrYaml(filename) )
+ {
+ img = icvRetrieveImage(cvLoad(filename,0,imgname));
+ if( (img->nChannels > 1) != (color == 0) )
+ CV_ERROR( CV_StsNotImplemented,
+ "RGB<->Grayscale conversion is not implemented for images stored in XML/YAML" );
+ /*{
+ IplImage* temp_img = 0;
+ CV_CALL( temp_img = cvCreateImage( cvGetSize(img), img->depth, color > 0 ? 3 : 1 ));
+ cvCvtColor( img, temp_img, color > 0 ? CV_GRAY2BGR : CV_BGR2GRAY );
+ cvReleaseImage( &img );
+ img = temp_img;
+ }*/
+ }
+ else
+ {
+ if( load_image )
+ img = load_image( filename, color );
+ else
+ CV_ERROR( CV_StsNotImplemented,
+ "Loading an image stored in such a format requires HigGUI.\n"
+ "Link it to your program and call any function from it\n" );
+ }
+
+ attach( img );
+
+ __END__;
+
+ return img != 0;
+}
+
+
+bool CvImage::read( CvFileStorage* fs, const char* mapname, const char* imgname )
+{
+ void* obj = 0;
+ IplImage* img = 0;
+
+ if( mapname )
+ {
+ CvFileNode* mapnode = cvGetFileNodeByName( fs, 0, mapname );
+ if( !mapnode )
+ obj = cvReadByName( fs, mapnode, imgname );
+ }
+ else
+ obj = cvReadByName( fs, 0, imgname );
+
+ img = icvRetrieveImage(obj);
+ attach( img );
+ return img != 0;
+}
+
+
+bool CvImage::read( CvFileStorage* fs, const char* seqname, int idx )
+{
+ void* obj = 0;
+ IplImage* img = 0;
+ CvFileNode* seqnode = seqname ?
+ cvGetFileNodeByName( fs, 0, seqname ) : cvGetRootFileNode(fs,0);
+
+ if( seqnode && CV_NODE_IS_SEQ(seqnode->tag) )
+ obj = cvRead( fs, (CvFileNode*)cvGetSeqElem( seqnode->data.seq, idx ));
+ img = icvRetrieveImage(obj);
+ attach( img );
+ return img != 0;
+}
+
+
+void CvImage::save( const char* filename, const char* imgname )
+{
+ CV_FUNCNAME( "CvImage::write" );
+ __BEGIN__;
+
+ if( !image )
+ return;
+ if( icvIsXmlOrYaml( filename ) )
+ cvSave( filename, image, imgname );
+ else
+ {
+ if( save_image )
+ save_image( filename, image );
+ else
+ CV_ERROR( CV_StsNotImplemented,
+ "Saving an image in such a format requires HigGUI.\n"
+ "Link it to your program and call any function from it\n" );
+ }
+
+ __END__;
+}
+
+
+void CvImage::write( CvFileStorage* fs, const char* imgname )
+{
+ if( image )
+ cvWrite( fs, imgname, image );
+}
+
+
+
+/////////////////////////////// CvMatrix implementation //////////////////////////////////
+
+CvMatrix::CvMatrix( int rows, int cols, int type, CvMemStorage* storage, bool alloc_data )
+{
+ if( storage )
+ {
+ matrix = (CvMat*)cvMemStorageAlloc( storage, sizeof(*matrix) );
+ cvInitMatHeader( matrix, rows, cols, type, alloc_data ?
+ cvMemStorageAlloc( storage, rows*cols*CV_ELEM_SIZE(type) ) : 0 );
+ }
+ else
+ matrix = 0;
+}
+
+static CvMat*
+icvRetrieveMatrix( void* obj )
+{
+ CvMat* m = 0;
+
+ CV_FUNCNAME( "icvRetrieveMatrix" );
+
+ __BEGIN__;
+
+ if( CV_IS_MAT(obj) )
+ m = (CvMat*)obj;
+ else if( CV_IS_IMAGE(obj) )
+ {
+ IplImage* img = (IplImage*)obj;
+ CvMat hdr, *src = cvGetMat( img, &hdr );
+ CV_CALL( m = cvCreateMat( src->rows, src->cols, src->type ));
+ CV_CALL( cvCopy( src, m ));
+ cvReleaseImage( &img );
+ }
+ else if( obj )
+ {
+ cvRelease( &obj );
+ CV_ERROR( CV_StsUnsupportedFormat, "The object is neither an image, nor a matrix" );
+ }
+
+ __END__;
+
+ return m;
+}
+
+
+bool CvMatrix::load( const char* filename, const char* matname, int color )
+{
+ CvMat* m = 0;
+
+ CV_FUNCNAME( "CvMatrix::read" );
+
+ __BEGIN__;
+
+ if( icvIsXmlOrYaml(filename) )
+ {
+ m = icvRetrieveMatrix(cvLoad(filename,0,matname));
+
+ if( (CV_MAT_CN(m->type) > 1) != (color == 0) )
+ CV_ERROR( CV_StsNotImplemented,
+ "RGB<->Grayscale conversion is not implemented for matrices stored in XML/YAML" );
+ /*{
+ CvMat* temp_mat;
+ CV_CALL( temp_mat = cvCreateMat( m->rows, m->cols,
+ CV_MAKETYPE(CV_MAT_DEPTH(m->type), color > 0 ? 3 : 1 )));
+ cvCvtColor( m, temp_mat, color > 0 ? CV_GRAY2BGR : CV_BGR2GRAY );
+ cvReleaseMat( &m );
+ m = temp_mat;
+ }*/
+ }
+ else
+ {
+ if( load_image_m )
+ m = load_image_m( filename, color );
+ else
+ CV_ERROR( CV_StsNotImplemented,
+ "Loading an image stored in such a format requires HigGUI.\n"
+ "Link it to your program and call any function from it\n" );
+ }
+
+ set( m, false );
+
+ __END__;
+
+ return m != 0;
+}
+
+
+bool CvMatrix::read( CvFileStorage* fs, const char* mapname, const char* matname )
+{
+ void* obj = 0;
+ CvMat* m = 0;
+
+ if( mapname )
+ {
+ CvFileNode* mapnode = cvGetFileNodeByName( fs, 0, mapname );
+ if( !mapnode )
+ obj = cvReadByName( fs, mapnode, matname );
+ }
+ else
+ obj = cvReadByName( fs, 0, matname );
+
+ m = icvRetrieveMatrix(obj);
+ set( m, false );
+ return m != 0;
+}
+
+
+bool CvMatrix::read( CvFileStorage* fs, const char* seqname, int idx )
+{
+ void* obj = 0;
+ CvMat* m = 0;
+ CvFileNode* seqnode = seqname ?
+ cvGetFileNodeByName( fs, 0, seqname ) : cvGetRootFileNode(fs,0);
+
+ if( seqnode && CV_NODE_IS_SEQ(seqnode->tag) )
+ obj = cvRead( fs, (CvFileNode*)cvGetSeqElem( seqnode->data.seq, idx ));
+ m = icvRetrieveMatrix(obj);
+ set( m, false );
+ return m != 0;
+}
+
+
+void CvMatrix::save( const char* filename, const char* matname )
+{
+ CV_FUNCNAME( "CvMatrix::write" );
+ __BEGIN__;
+
+ if( !matrix )
+ return;
+ if( icvIsXmlOrYaml( filename ) )
+ cvSave( filename, matrix, matname );
+ else
+ {
+ if( save_image )
+ save_image( filename, matrix );
+ else
+ CV_ERROR( CV_StsNotImplemented,
+ "Saving a matrixe in such a format requires HigGUI.\n"
+ "Link it to your program and call any function from it\n" );
+ }
+
+ __END__;
+}
+
+
+void CvMatrix::write( CvFileStorage* fs, const char* matname )
+{
+ if( matrix )
+ cvWrite( fs, matname, matrix );
+}
+
+
+
+CV_IMPL int
+cvSetImageIOFunctions( CvLoadImageFunc _load_image, CvLoadImageMFunc _load_image_m,
+ CvSaveImageFunc _save_image, CvShowImageFunc _show_image=NULL )
+{
+ load_image = _load_image;
+ load_image_m = _load_image_m;
+ save_image = _save_image;
+ show_image = _show_image;
+ return 1;
+}
+
+
+/*void main(void)
+{
+ CvImage a(cvSize(300,200),8,3), b(cvSize(300,200),8,3);
+ CvRNG rng = cvRNG(-1);
+
+ CV_SET_IMAGE_IO_FUNCTIONS();
+
+ cvNamedWindow( "test", 1 );
+ //cvZero( a );
+ cvZero( b );
+ cvRandArr( &rng, a, CV_RAND_UNI, cvScalarAll(0), cvScalarAll(100) );
+ cvCircle( b, cvPoint(100,100), 70, cvScalar(0,255,0), -1, CV_AA, 0 );
+ cvAdd( a, b, a );
+ a.show( "test" );
+
+ cvWaitKey();
+}*/
+
+/* End of file. */
+
diff --git a/cxcore/src/cxjacobieigens.cpp b/cxcore/src/cxjacobieigens.cpp
new file mode 100644
index 0000000..8c07094
--- /dev/null
+++ b/cxcore/src/cxjacobieigens.cpp
@@ -0,0 +1,431 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+
+/*F///////////////////////////////////////////////////////////////////////////////////////
+// Names: icvJacobiEigens_32f, icvJacobiEigens_64d
+// Purpose: Eigenvalues & eigenvectors calculation of a symmetric matrix:
+// A Vi = Ei Vi
+// Context:
+// Parameters: A(n, n) - source symmetric matrix (n - rows & columns number),
+// V(n, n) - matrix of its eigenvectors
+// (i-th row is an eigenvector Vi),
+// E(n) - vector of its eigenvalues
+// (i-th element is an eigenvalue Ei),
+// eps - accuracy of diagonalization.
+//
+// Returns:
+// CV_NO_ERROR or error code
+// Notes:
+// 1. The functions destroy source matrix A, so if you need it further, you
+// have to copy it before the processing.
+// 2. Eigenvalies and eigenvectors are sorted in Ei absolute value descending.
+// 3. Calculation time depends on eps value. If the time isn't very important,
+// we recommend to set eps = 0.
+//F*/
+
+/*=========================== Single precision function ================================*/
+
+static CvStatus CV_STDCALL
+icvJacobiEigens_32f(float *A, float *V, float *E, int n, float eps)
+{
+ int i, j, k, ind, iters = 0;
+ float *AA = A, *VV = V;
+ double Amax, anorm = 0, ax;
+
+ if( A == NULL || V == NULL || E == NULL )
+ return CV_NULLPTR_ERR;
+ if( n <= 0 )
+ return CV_BADSIZE_ERR;
+ if( eps < DBL_EPSILON )
+ eps = DBL_EPSILON;
+
+ /*-------- Prepare --------*/
+ for( i = 0; i < n; i++, VV += n, AA += n )
+ {
+ for( j = 0; j < i; j++ )
+ {
+ double Am = AA[j];
+
+ anorm += Am * Am;
+ }
+ for( j = 0; j < n; j++ )
+ VV[j] = 0.f;
+ VV[i] = 1.f;
+ }
+
+ anorm = sqrt( anorm + anorm );
+ ax = anorm * eps / n;
+ Amax = anorm;
+
+ while( Amax > ax && iters++ < 100 )
+ {
+ Amax /= n;
+ do /* while (ind) */
+ {
+ int p, q;
+ float *V1 = V, *A1 = A;
+
+ ind = 0;
+ for( p = 0; p < n - 1; p++, A1 += n, V1 += n )
+ {
+ float *A2 = A + n * (p + 1), *V2 = V + n * (p + 1);
+
+ for( q = p + 1; q < n; q++, A2 += n, V2 += n )
+ {
+ double x, y, c, s, c2, s2, a;
+ float *A3, Apq = A1[q], App, Aqq, Aip, Aiq, Vpi, Vqi;
+
+ if( fabs( Apq ) < Amax )
+ continue;
+
+ ind = 1;
+
+ /*---- Calculation of rotation angle's sine & cosine ----*/
+ App = A1[p];
+ Aqq = A2[q];
+ y = 5.0e-1 * (App - Aqq);
+ x = -Apq / sqrt( (double)Apq * Apq + (double)y * y );
+ if( y < 0.0 )
+ x = -x;
+ s = x / sqrt( 2.0 * (1.0 + sqrt( 1.0 - (double)x * x )));
+ s2 = s * s;
+ c = sqrt( 1.0 - s2 );
+ c2 = c * c;
+ a = 2.0 * Apq * c * s;
+
+ /*---- Apq annulation ----*/
+ A3 = A;
+ for( i = 0; i < p; i++, A3 += n )
+ {
+ Aip = A3[p];
+ Aiq = A3[q];
+ Vpi = V1[i];
+ Vqi = V2[i];
+ A3[p] = (float) (Aip * c - Aiq * s);
+ A3[q] = (float) (Aiq * c + Aip * s);
+ V1[i] = (float) (Vpi * c - Vqi * s);
+ V2[i] = (float) (Vqi * c + Vpi * s);
+ }
+ for( ; i < q; i++, A3 += n )
+ {
+ Aip = A1[i];
+ Aiq = A3[q];
+ Vpi = V1[i];
+ Vqi = V2[i];
+ A1[i] = (float) (Aip * c - Aiq * s);
+ A3[q] = (float) (Aiq * c + Aip * s);
+ V1[i] = (float) (Vpi * c - Vqi * s);
+ V2[i] = (float) (Vqi * c + Vpi * s);
+ }
+ for( ; i < n; i++ )
+ {
+ Aip = A1[i];
+ Aiq = A2[i];
+ Vpi = V1[i];
+ Vqi = V2[i];
+ A1[i] = (float) (Aip * c - Aiq * s);
+ A2[i] = (float) (Aiq * c + Aip * s);
+ V1[i] = (float) (Vpi * c - Vqi * s);
+ V2[i] = (float) (Vqi * c + Vpi * s);
+ }
+ A1[p] = (float) (App * c2 + Aqq * s2 - a);
+ A2[q] = (float) (App * s2 + Aqq * c2 + a);
+ A1[q] = A2[p] = 0.0f;
+ } /*q */
+ } /*p */
+ }
+ while( ind );
+ Amax /= n;
+ } /* while ( Amax > ax ) */
+
+ for( i = 0, k = 0; i < n; i++, k += n + 1 )
+ E[i] = A[k];
+ /*printf(" M = %d\n", M); */
+
+ /* -------- ordering -------- */
+ for( i = 0; i < n; i++ )
+ {
+ int m = i;
+ float Em = (float) fabs( E[i] );
+
+ for( j = i + 1; j < n; j++ )
+ {
+ float Ej = (float) fabs( E[j] );
+
+ m = (Em < Ej) ? j : m;
+ Em = (Em < Ej) ? Ej : Em;
+ }
+ if( m != i )
+ {
+ int l;
+ float b = E[i];
+
+ E[i] = E[m];
+ E[m] = b;
+ for( j = 0, k = i * n, l = m * n; j < n; j++, k++, l++ )
+ {
+ b = V[k];
+ V[k] = V[l];
+ V[l] = b;
+ }
+ }
+ }
+
+ return CV_NO_ERR;
+}
+
+/*=========================== Double precision function ================================*/
+
+static CvStatus CV_STDCALL
+icvJacobiEigens_64d(double *A, double *V, double *E, int n, double eps)
+{
+ int i, j, k, p, q, ind, iters = 0;
+ double *A1 = A, *V1 = V, *A2 = A, *V2 = V;
+ double Amax = 0.0, anorm = 0.0, ax;
+
+ if( A == NULL || V == NULL || E == NULL )
+ return CV_NULLPTR_ERR;
+ if( n <= 0 )
+ return CV_BADSIZE_ERR;
+ if( eps < DBL_EPSILON )
+ eps = DBL_EPSILON;
+
+ /*-------- Prepare --------*/
+ for( i = 0; i < n; i++, V1 += n, A1 += n )
+ {
+ for( j = 0; j < i; j++ )
+ {
+ double Am = A1[j];
+
+ anorm += Am * Am;
+ }
+ for( j = 0; j < n; j++ )
+ V1[j] = 0.0;
+ V1[i] = 1.0;
+ }
+
+ anorm = sqrt( anorm + anorm );
+ ax = anorm * eps / n;
+ Amax = anorm;
+
+ while( Amax > ax && iters++ < 100 )
+ {
+ Amax /= n;
+ do /* while (ind) */
+ {
+ ind = 0;
+ A1 = A;
+ V1 = V;
+ for( p = 0; p < n - 1; p++, A1 += n, V1 += n )
+ {
+ A2 = A + n * (p + 1);
+ V2 = V + n * (p + 1);
+ for( q = p + 1; q < n; q++, A2 += n, V2 += n )
+ {
+ double x, y, c, s, c2, s2, a;
+ double *A3, Apq, App, Aqq, App2, Aqq2, Aip, Aiq, Vpi, Vqi;
+
+ if( fabs( A1[q] ) < Amax )
+ continue;
+ Apq = A1[q];
+
+ ind = 1;
+
+ /*---- Calculation of rotation angle's sine & cosine ----*/
+ App = A1[p];
+ Aqq = A2[q];
+ y = 5.0e-1 * (App - Aqq);
+ x = -Apq / sqrt( Apq * Apq + (double)y * y );
+ if( y < 0.0 )
+ x = -x;
+ s = x / sqrt( 2.0 * (1.0 + sqrt( 1.0 - (double)x * x )));
+ s2 = s * s;
+ c = sqrt( 1.0 - s2 );
+ c2 = c * c;
+ a = 2.0 * Apq * c * s;
+
+ /*---- Apq annulation ----*/
+ A3 = A;
+ for( i = 0; i < p; i++, A3 += n )
+ {
+ Aip = A3[p];
+ Aiq = A3[q];
+ Vpi = V1[i];
+ Vqi = V2[i];
+ A3[p] = Aip * c - Aiq * s;
+ A3[q] = Aiq * c + Aip * s;
+ V1[i] = Vpi * c - Vqi * s;
+ V2[i] = Vqi * c + Vpi * s;
+ }
+ for( ; i < q; i++, A3 += n )
+ {
+ Aip = A1[i];
+ Aiq = A3[q];
+ Vpi = V1[i];
+ Vqi = V2[i];
+ A1[i] = Aip * c - Aiq * s;
+ A3[q] = Aiq * c + Aip * s;
+ V1[i] = Vpi * c - Vqi * s;
+ V2[i] = Vqi * c + Vpi * s;
+ }
+ for( ; i < n; i++ )
+ {
+ Aip = A1[i];
+ Aiq = A2[i];
+ Vpi = V1[i];
+ Vqi = V2[i];
+ A1[i] = Aip * c - Aiq * s;
+ A2[i] = Aiq * c + Aip * s;
+ V1[i] = Vpi * c - Vqi * s;
+ V2[i] = Vqi * c + Vpi * s;
+ }
+ App2 = App * c2 + Aqq * s2 - a;
+ Aqq2 = App * s2 + Aqq * c2 + a;
+ A1[p] = App2;
+ A2[q] = Aqq2;
+ A1[q] = A2[p] = 0.0;
+ } /*q */
+ } /*p */
+ }
+ while( ind );
+ } /* while ( Amax > ax ) */
+
+ for( i = 0, k = 0; i < n; i++, k += n + 1 )
+ E[i] = A[k];
+
+ /* -------- ordering -------- */
+ for( i = 0; i < n; i++ )
+ {
+ int m = i;
+ double Em = fabs( E[i] );
+
+ for( j = i + 1; j < n; j++ )
+ {
+ double Ej = fabs( E[j] );
+
+ m = (Em < Ej) ? j : m;
+ Em = (Em < Ej) ? Ej : Em;
+ }
+ if( m != i )
+ {
+ int l;
+ double b = E[i];
+
+ E[i] = E[m];
+ E[m] = b;
+ for( j = 0, k = i * n, l = m * n; j < n; j++, k++, l++ )
+ {
+ b = V[k];
+ V[k] = V[l];
+ V[l] = b;
+ }
+ }
+ }
+
+ return CV_NO_ERR;
+}
+
+
+CV_IMPL void
+cvEigenVV( CvArr* srcarr, CvArr* evectsarr, CvArr* evalsarr, double eps )
+{
+
+ CV_FUNCNAME( "cvEigenVV" );
+
+ __BEGIN__;
+
+ CvMat sstub, *src = (CvMat*)srcarr;
+ CvMat estub1, *evects = (CvMat*)evectsarr;
+ CvMat estub2, *evals = (CvMat*)evalsarr;
+
+ if( !CV_IS_MAT( src ))
+ CV_CALL( src = cvGetMat( src, &sstub ));
+
+ if( !CV_IS_MAT( evects ))
+ CV_CALL( evects = cvGetMat( evects, &estub1 ));
+
+ if( !CV_IS_MAT( evals ))
+ CV_CALL( evals = cvGetMat( evals, &estub2 ));
+
+ if( src->cols != src->rows )
+ CV_ERROR( CV_StsUnmatchedSizes, "source is not quadratic matrix" );
+
+ if( !CV_ARE_SIZES_EQ( src, evects) )
+ CV_ERROR( CV_StsUnmatchedSizes, "eigenvectors matrix has inappropriate size" );
+
+ if( (evals->rows != src->rows || evals->cols != 1) &&
+ (evals->cols != src->rows || evals->rows != 1))
+ CV_ERROR( CV_StsBadSize, "eigenvalues vector has inappropriate size" );
+
+ if( !CV_ARE_TYPES_EQ( src, evects ) || !CV_ARE_TYPES_EQ( src, evals ))
+ CV_ERROR( CV_StsUnmatchedFormats,
+ "input matrix, eigenvalues and eigenvectors must have the same type" );
+
+ if( !CV_IS_MAT_CONT( src->type & evals->type & evects->type ))
+ CV_ERROR( CV_BadStep, "all the matrices must be continuous" );
+
+ if( CV_MAT_TYPE(src->type) == CV_32FC1 )
+ {
+ IPPI_CALL( icvJacobiEigens_32f( src->data.fl,
+ evects->data.fl,
+ evals->data.fl, src->cols, (float)eps ));
+
+ }
+ else if( CV_MAT_TYPE(src->type) == CV_64FC1 )
+ {
+ IPPI_CALL( icvJacobiEigens_64d( src->data.db,
+ evects->data.db,
+ evals->data.db, src->cols, eps ));
+ }
+ else
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Only 32fC1 and 64fC1 types are supported" );
+ }
+
+ CV_CHECK_NANS( evects );
+ CV_CHECK_NANS( evals );
+
+ __END__;
+}
+
+/* End of file */
diff --git a/cxcore/src/cxlogic.cpp b/cxcore/src/cxlogic.cpp
new file mode 100644
index 0000000..df23dbf
--- /dev/null
+++ b/cxcore/src/cxlogic.cpp
@@ -0,0 +1,696 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/* ////////////////////////////////////////////////////////////////////
+//
+// CvMat logical operations: &, |, ^ ...
+//
+// */
+
+#include "_cxcore.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// //
+// Macros for logic operations //
+// //
+/////////////////////////////////////////////////////////////////////////////////////////
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ Mat op Mat
+////////////////////////////////////////////////////////////////////////////////////// */
+
+
+#define ICV_DEF_BIN_LOG_OP_2D( __op__, name ) \
+IPCVAPI_IMPL( CvStatus, icv##name##_8u_C1R, \
+( const uchar* src1, int step1, const uchar* src2, int step2, \
+ uchar* dst, int step, CvSize size ), (src1, step1, src2, step2, dst, step, size) )\
+{ \
+ for( ; size.height--; src1 += step1, src2 += step2, dst += step ) \
+ { \
+ int i = 0; \
+ \
+ if( (((size_t)src1 | (size_t)src2 | (size_t)dst) & 3) == 0 ) \
+ { \
+ for( ; i <= size.width - 16; i += 16 ) \
+ { \
+ int t0 = __op__(((const int*)(src1+i))[0], ((const int*)(src2+i))[0]);\
+ int t1 = __op__(((const int*)(src1+i))[1], ((const int*)(src2+i))[1]);\
+ \
+ ((int*)(dst+i))[0] = t0; \
+ ((int*)(dst+i))[1] = t1; \
+ \
+ t0 = __op__(((const int*)(src1+i))[2], ((const int*)(src2+i))[2]); \
+ t1 = __op__(((const int*)(src1+i))[3], ((const int*)(src2+i))[3]); \
+ \
+ ((int*)(dst+i))[2] = t0; \
+ ((int*)(dst+i))[3] = t1; \
+ } \
+ \
+ for( ; i <= size.width - 4; i += 4 ) \
+ { \
+ int t = __op__(*(const int*)(src1+i), *(const int*)(src2+i)); \
+ *(int*)(dst+i) = t; \
+ } \
+ } \
+ \
+ for( ; i < size.width; i++ ) \
+ { \
+ int t = __op__(((const uchar*)src1)[i],((const uchar*)src2)[i]); \
+ dst[i] = (uchar)t; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ Mat op Scalar
+////////////////////////////////////////////////////////////////////////////////////// */
+
+
+#define ICV_DEF_UN_LOG_OP_2D( __op__, name ) \
+static CvStatus CV_STDCALL icv##name##_8u_CnR \
+( const uchar* src0, int step1, uchar* dst0, int step, CvSize size, \
+ const uchar* scalar, int pix_size ) \
+{ \
+ int delta = 12*pix_size; \
+ \
+ for( ; size.height--; src0 += step1, dst0 += step ) \
+ { \
+ const uchar* src = (const uchar*)src0; \
+ uchar* dst = dst0; \
+ int i, len = size.width; \
+ \
+ if( (((size_t)src|(size_t)dst) & 3) == 0 ) \
+ { \
+ while( (len -= delta) >= 0 ) \
+ { \
+ for( i = 0; i < (delta); i += 12 ) \
+ { \
+ int t0 = __op__(((const int*)(src+i))[0], ((const int*)(scalar+i))[0]); \
+ int t1 = __op__(((const int*)(src+i))[1], ((const int*)(scalar+i))[1]); \
+ ((int*)(dst+i))[0] = t0; \
+ ((int*)(dst+i))[1] = t1; \
+ \
+ t0 = __op__(((const int*)(src+i))[2], ((const int*)(scalar+i))[2]); \
+ ((int*)(dst+i))[2] = t0; \
+ } \
+ src += delta; \
+ dst += delta; \
+ } \
+ } \
+ else \
+ { \
+ while( (len -= delta) >= 0 ) \
+ { \
+ for( i = 0; i < (delta); i += 4 ) \
+ { \
+ int t0 = __op__(src[i], scalar[i]); \
+ int t1 = __op__(src[i+1], scalar[i+1]); \
+ dst[i] = (uchar)t0; \
+ dst[i+1] = (uchar)t1; \
+ \
+ t0 = __op__(src[i+2], scalar[i+2]); \
+ t1 = __op__(src[i+3], scalar[i+3]); \
+ dst[i+2] = (uchar)t0; \
+ dst[i+3] = (uchar)t1; \
+ } \
+ src += delta; \
+ dst += delta; \
+ } \
+ } \
+ \
+ for( len += delta, i = 0; i < len; i++ ) \
+ { \
+ int t = __op__(src[i],scalar[i]); \
+ dst[i] = (uchar)t; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// //
+// LOGIC OPERATIONS //
+// //
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static void
+icvLogicS( const void* srcarr, CvScalar* scalar, void* dstarr,
+ const void* maskarr, CvFunc2D_2A1P1I fn_2d )
+{
+ uchar* buffer = 0;
+ int local_alloc = 1;
+
+ CV_FUNCNAME( "icvLogicS" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvMat maskstub, *mask = (CvMat*)maskarr;
+ CvMat dstbuf, *tdst;
+ CvCopyMaskFunc copym_func = 0;
+
+ int y, dy;
+ int coi1 = 0, coi2 = 0;
+ int is_nd = 0, cont_flag = 0;
+ int elem_size, elem_size1, type, depth;
+ double buf[12];
+ CvSize size, tsize;
+ int src_step, dst_step, tdst_step, mask_step;
+
+ if( !CV_IS_MAT(src))
+ {
+ if( CV_IS_MATND(src) )
+ is_nd = 1;
+ else
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
+ }
+
+ if( !CV_IS_MAT(dst))
+ {
+ if( CV_IS_MATND(dst) )
+ is_nd = 1;
+ else
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
+ }
+
+ if( is_nd )
+ {
+ CvArr* arrs[] = { src, dst };
+ CvMatND stubs[2];
+ CvNArrayIterator iterator;
+
+ if( maskarr )
+ CV_ERROR( CV_StsBadMask,
+ "This operation on multi-dimensional arrays does not support mask" );
+
+ CV_CALL( cvInitNArrayIterator( 2, arrs, 0, stubs, &iterator ));
+
+ type = CV_MAT_TYPE(iterator.hdr[0]->type);
+ depth = CV_MAT_DEPTH(type);
+ iterator.size.width *= CV_ELEM_SIZE(type);
+ elem_size1 = CV_ELEM_SIZE1(depth);
+
+ CV_CALL( cvScalarToRawData( scalar, buf, type, 1 ));
+
+ do
+ {
+ IPPI_CALL( fn_2d( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.size, buf, elem_size1 ));
+ }
+ while( cvNextNArraySlice( &iterator ));
+ EXIT;
+ }
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ if( !CV_ARE_TYPES_EQ( src, dst ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ size = cvGetMatSize( src );
+ type = CV_MAT_TYPE(src->type);
+ depth = CV_MAT_DEPTH(type);
+ elem_size = CV_ELEM_SIZE(type);
+ elem_size1 = CV_ELEM_SIZE1(depth);
+
+ if( !mask )
+ {
+ cont_flag = CV_IS_MAT_CONT( src->type & dst->type );
+ dy = size.height;
+ tdst = dst;
+ }
+ else
+ {
+ int buf_size;
+
+ if( !CV_IS_MAT(mask) )
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+
+ if( !CV_IS_MASK_ARR(mask))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !CV_ARE_SIZES_EQ( mask, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ cont_flag = CV_IS_MAT_CONT( src->type & dst->type & mask->type );
+ dy = CV_MAX_LOCAL_SIZE/(elem_size*size.height);
+ dy = MAX(dy,1);
+ dy = MIN(dy,size.height);
+ dstbuf = cvMat( dy, size.width, type );
+ if( !cont_flag )
+ dstbuf.step = cvAlign( dstbuf.step, 8 );
+ buf_size = dstbuf.step ? dstbuf.step*dy : size.width*elem_size;
+ if( buf_size > CV_MAX_LOCAL_SIZE )
+ {
+ CV_CALL( buffer = (uchar*)cvAlloc( buf_size ));
+ local_alloc = 0;
+ }
+ else
+ buffer = (uchar*)cvStackAlloc( buf_size );
+ dstbuf.data.ptr = buffer;
+ tdst = &dstbuf;
+
+ copym_func = icvGetCopyMaskFunc( elem_size );
+ }
+
+ src_step = src->step;
+ dst_step = dst->step;
+ tdst_step = tdst->step;
+ mask_step = mask ? mask->step : 0;
+ CV_CALL( cvScalarToRawData( scalar, buf, type, 1 ));
+
+ for( y = 0; y < size.height; y += dy )
+ {
+ tsize.width = size.width;
+ tsize.height = dy;
+ if( y + dy > size.height )
+ tsize.height = size.height - y;
+ if( cont_flag || tsize.height == 1 )
+ {
+ tsize.width *= tsize.height;
+ tsize.height = 1;
+ src_step = tdst_step = dst_step = mask_step = CV_STUB_STEP;
+ }
+ IPPI_CALL( fn_2d( src->data.ptr + y*src->step, src_step, tdst->data.ptr, tdst_step,
+ cvSize(tsize.width*elem_size, tsize.height), buf, elem_size1 ));
+ if( mask )
+ {
+ IPPI_CALL( copym_func( tdst->data.ptr, tdst_step, dst->data.ptr + y*dst->step,
+ dst_step, tsize, mask->data.ptr + y*mask->step, mask_step ));
+ }
+ }
+
+ __END__;
+
+ if( !local_alloc )
+ cvFree( &buffer );
+}
+
+
+static void
+icvLogic( const void* srcarr1, const void* srcarr2, void* dstarr,
+ const void* maskarr, CvFunc2D_3A fn_2d )
+{
+ uchar* buffer = 0;
+ int local_alloc = 1;
+
+ CV_FUNCNAME( "icvLogic" );
+
+ __BEGIN__;
+
+ int y, dy;
+ int coi1 = 0, coi2 = 0, coi3 = 0;
+ int type, elem_size;
+ int is_nd = 0, cont_flag = 0;
+ CvMat srcstub1, *src1 = (CvMat*)srcarr1;
+ CvMat srcstub2, *src2 = (CvMat*)srcarr2;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvMat maskstub, *mask = (CvMat*)maskarr;
+ CvMat dstbuf, *tdst;
+ int src1_step, src2_step, tdst_step, dst_step, mask_step;
+ CvSize size, tsize;
+ CvCopyMaskFunc copym_func = 0;
+
+ if( !CV_IS_MAT(src1))
+ {
+ if( CV_IS_MATND(src1) )
+ is_nd = 1;
+ else
+ CV_CALL( src1 = cvGetMat( src1, &srcstub1, &coi1 ));
+ }
+
+ if( !CV_IS_MAT(src2))
+ {
+ if( CV_IS_MATND(src2) )
+ is_nd = 1;
+ else
+ CV_CALL( src2 = cvGetMat( src2, &srcstub2, &coi2 ));
+ }
+
+ if( !CV_IS_MAT(dst))
+ {
+ if( CV_IS_MATND(dst) )
+ is_nd = 1;
+ else
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi3 ));
+ }
+
+ if( is_nd )
+ {
+ CvArr* arrs[] = { src1, src2, dst };
+ CvMatND stubs[3];
+ CvNArrayIterator iterator;
+
+ if( maskarr )
+ CV_ERROR( CV_StsBadMask,
+ "This operation on multi-dimensional arrays does not support mask" );
+
+ CV_CALL( cvInitNArrayIterator( 3, arrs, 0, stubs, &iterator ));
+
+ type = CV_MAT_TYPE(iterator.hdr[0]->type);
+ iterator.size.width *= CV_ELEM_SIZE(type);
+
+ do
+ {
+ IPPI_CALL( fn_2d( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.ptr[2], CV_STUB_STEP,
+ iterator.size ));
+ }
+ while( cvNextNArraySlice( &iterator ));
+ EXIT;
+ }
+
+ if( coi1 != 0 || coi2 != 0 || coi3 != 0 )
+ CV_ERROR_FROM_CODE( CV_BadCOI );
+
+ if( !CV_ARE_TYPES_EQ( src1, src2 ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( src1, src2 ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ if( !CV_ARE_TYPES_EQ( src1, dst ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( src1, dst ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ size = cvGetMatSize( src1 );
+ type = CV_MAT_TYPE( src1->type );
+ elem_size = CV_ELEM_SIZE(type);
+
+ if( !mask )
+ {
+ cont_flag = CV_IS_MAT_CONT( src1->type & src2->type & dst->type );
+ dy = size.height;
+ tdst = dst;
+ }
+ else
+ {
+ int buf_size;
+
+ if( !CV_IS_MAT(mask) )
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+
+ if( !CV_IS_MASK_ARR(mask))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !CV_ARE_SIZES_EQ( mask, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ cont_flag = CV_IS_MAT_CONT( src1->type & src2->type & dst->type & mask->type );
+ dy = CV_MAX_LOCAL_SIZE/(elem_size*size.height);
+ dy = MAX(dy,1);
+ dy = MIN(dy,size.height);
+ dstbuf = cvMat( dy, size.width, type );
+ if( !cont_flag )
+ dstbuf.step = cvAlign( dstbuf.step, 8 );
+ buf_size = dstbuf.step ? dstbuf.step*dy : size.width*elem_size;
+ if( buf_size > CV_MAX_LOCAL_SIZE )
+ {
+ CV_CALL( buffer = (uchar*)cvAlloc( buf_size ));
+ local_alloc = 0;
+ }
+ else
+ buffer = (uchar*)cvStackAlloc( buf_size );
+ dstbuf.data.ptr = buffer;
+ tdst = &dstbuf;
+
+ copym_func = icvGetCopyMaskFunc( elem_size );
+ }
+
+ src1_step = src1->step;
+ src2_step = src2->step;
+ dst_step = dst->step;
+ tdst_step = tdst->step;
+ mask_step = mask ? mask->step : 0;
+
+ for( y = 0; y < size.height; y += dy )
+ {
+ tsize.width = size.width;
+ tsize.height = dy;
+ if( y + dy > size.height )
+ tsize.height = size.height - y;
+ if( cont_flag || tsize.height == 1 )
+ {
+ tsize.width *= tsize.height;
+ tsize.height = 1;
+ src1_step = src2_step = tdst_step = dst_step = mask_step = CV_STUB_STEP;
+ }
+ IPPI_CALL( fn_2d( src1->data.ptr + y*src1->step, src1_step,
+ src2->data.ptr + y*src2->step, src2_step,
+ tdst->data.ptr, tdst_step,
+ cvSize(tsize.width*elem_size, tsize.height) ));
+ if( mask )
+ {
+ IPPI_CALL( copym_func( tdst->data.ptr, tdst_step, dst->data.ptr + y*dst->step,
+ dst_step, tsize, mask->data.ptr + y*mask->step, mask_step ));
+ }
+ }
+
+ __END__;
+
+ if( !local_alloc )
+ cvFree( &buffer );
+}
+
+ICV_DEF_BIN_LOG_OP_2D( CV_XOR, Xor )
+ICV_DEF_UN_LOG_OP_2D( CV_XOR, XorC )
+
+ICV_DEF_BIN_LOG_OP_2D( CV_AND, And )
+ICV_DEF_UN_LOG_OP_2D( CV_AND, AndC )
+
+ICV_DEF_BIN_LOG_OP_2D( CV_OR, Or )
+ICV_DEF_UN_LOG_OP_2D( CV_OR, OrC )
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// X O R //
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CV_IMPL void
+cvXorS( const void* src, CvScalar scalar, void* dst, const void* mask )
+{
+ icvLogicS( src, &scalar, dst, mask, (CvFunc2D_2A1P1I)icvXorC_8u_CnR );
+}
+
+
+CV_IMPL void
+cvXor( const void* src1, const void* src2, void* dst, const void* mask )
+{
+ icvLogic( src1, src2, dst, mask, (CvFunc2D_3A)icvXor_8u_C1R );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// A N D //
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CV_IMPL void
+cvAndS( const void* src, CvScalar scalar, void* dst, const void* mask )
+{
+ icvLogicS( src, &scalar, dst, mask, (CvFunc2D_2A1P1I)icvAndC_8u_CnR );
+}
+
+
+CV_IMPL void
+cvAnd( const void* src1, const void* src2, void* dst, const void* mask )
+{
+ icvLogic( src1, src2, dst, mask, (CvFunc2D_3A)icvAnd_8u_C1R );
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// O R //
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CV_IMPL void
+cvOrS( const void* src, CvScalar scalar, void* dst, const void* mask )
+{
+ icvLogicS( src, &scalar, dst, mask, (CvFunc2D_2A1P1I)icvOrC_8u_CnR );
+}
+
+
+CV_IMPL void
+cvOr( const void* src1, const void* src2, void* dst, const void* mask )
+{
+ icvLogic( src1, src2, dst, mask, (CvFunc2D_3A)icvOr_8u_C1R );
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// N O T //
+/////////////////////////////////////////////////////////////////////////////////////////
+
+
+IPCVAPI_IMPL( CvStatus, icvNot_8u_C1R,
+( const uchar* src1, int step1, uchar* dst, int step, CvSize size ),
+ (src1, step1, dst, step, size) )
+{
+ for( ; size.height--; src1 += step1, dst += step )
+ {
+ int i = 0;
+
+ if( (((size_t)src1 | (size_t)dst) & 3) == 0 )
+ {
+ for( ; i <= size.width - 16; i += 16 )
+ {
+ int t0 = ~((const int*)(src1+i))[0];
+ int t1 = ~((const int*)(src1+i))[1];
+
+ ((int*)(dst+i))[0] = t0;
+ ((int*)(dst+i))[1] = t1;
+
+ t0 = ~((const int*)(src1+i))[2];
+ t1 = ~((const int*)(src1+i))[3];
+
+ ((int*)(dst+i))[2] = t0;
+ ((int*)(dst+i))[3] = t1;
+ }
+
+ for( ; i <= size.width - 4; i += 4 )
+ {
+ int t = ~*(const int*)(src1+i);
+ *(int*)(dst+i) = t;
+ }
+ }
+
+ for( ; i < size.width; i++ )
+ {
+ int t = ~((const uchar*)src1)[i];
+ dst[i] = (uchar)t;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+CV_IMPL void
+cvNot( const void* srcarr, void* dstarr )
+{
+ CV_FUNCNAME( "cvNot" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+
+ int coi1 = 0, coi2 = 0;
+ int type, is_nd = 0;
+ CvSize size;
+ int src_step, dst_step;
+
+ if( !CV_IS_MAT(src))
+ {
+ if( CV_IS_MATND(src) )
+ is_nd = 1;
+ else
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
+ }
+
+ if( !CV_IS_MAT(dst))
+ {
+ if( CV_IS_MATND(src) )
+ is_nd = 1;
+ else
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
+ }
+
+ if( is_nd )
+ {
+ CvArr* arrs[] = { src, dst };
+ CvMatND stubs[2];
+ CvNArrayIterator iterator;
+
+ CV_CALL( cvInitNArrayIterator( 2, arrs, 0, stubs, &iterator ));
+
+ type = CV_MAT_TYPE(iterator.hdr[0]->type);
+ iterator.size.width *= CV_ELEM_SIZE(type);
+
+ do
+ {
+ IPPI_CALL( icvNot_8u_C1R( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.size ));
+ }
+ while( cvNextNArraySlice( &iterator ));
+ EXIT;
+ }
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ if( !CV_ARE_TYPES_EQ( src, dst ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ size = cvGetMatSize( src );
+ src_step = src->step;
+ dst_step = dst->step;
+
+ if( CV_IS_MAT_CONT( src->type & dst->type ))
+ {
+ size.width *= size.height;
+ src_step = dst_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+
+ type = CV_MAT_TYPE( src->type );
+ size.width *= CV_ELEM_SIZE(type);
+
+ IPPI_CALL( icvNot_8u_C1R( src->data.ptr, src_step, dst->data.ptr, dst_step, size ));
+
+ __END__;
+}
+
+/* End of file. */
diff --git a/cxcore/src/cxlut.cpp b/cxcore/src/cxlut.cpp
new file mode 100644
index 0000000..589d9b9
--- /dev/null
+++ b/cxcore/src/cxlut.cpp
@@ -0,0 +1,324 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+
+/****************************************************************************************\
+* LUT Transform *
+\****************************************************************************************/
+
+#define ICV_LUT_CASE_C1( type ) \
+ for( i = 0; i <= size.width-4; i += 4 ) \
+ { \
+ type t0 = lut[src[i]]; \
+ type t1 = lut[src[i+1]]; \
+ dst[i] = t0; \
+ dst[i+1] = t1; \
+ \
+ t0 = lut[src[i+2]]; \
+ t1 = lut[src[i+3]]; \
+ dst[i+2] = t0; \
+ dst[i+3] = t1; \
+ } \
+ \
+ for( ; i < size.width; i++ ) \
+ { \
+ type t0 = lut[src[i]]; \
+ dst[i] = t0; \
+ }
+
+
+#define ICV_LUT_CASE_C2( type ) \
+ for( i = 0; i < size.width; i += 2 ) \
+ { \
+ type t0 = lut[src[i]*2]; \
+ type t1 = lut[src[i+1]*2 + 1]; \
+ dst[i] = t0; \
+ dst[i+1] = t1; \
+ }
+
+#define ICV_LUT_CASE_C3( type ) \
+ for( i = 0; i < size.width; i += 3 ) \
+ { \
+ type t0 = lut[src[i]*3]; \
+ type t1 = lut[src[i+1]*3 + 1]; \
+ type t2 = lut[src[i+2]*3 + 2]; \
+ dst[i] = t0; \
+ dst[i+1] = t1; \
+ dst[i+2] = t2; \
+ }
+
+#define ICV_LUT_CASE_C4( type ) \
+ for( i = 0; i < size.width; i += 4 ) \
+ { \
+ type t0 = lut[src[i]*4]; \
+ type t1 = lut[src[i+1]*4 + 1]; \
+ dst[i] = t0; \
+ dst[i+1] = t1; \
+ t0 = lut[src[i+2]*4 + 2]; \
+ t1 = lut[src[i+3]*4 + 3]; \
+ dst[i+2] = t0; \
+ dst[i+3] = t1; \
+ }
+
+
+#define ICV_DEF_LUT_FUNC_8U_CN( flavor, dsttype, cn ) \
+CvStatus CV_STDCALL icvLUT_Transform8u_##flavor##_C##cn##R( \
+ const uchar* src, int srcstep, \
+ dsttype* dst, int dststep, CvSize size, \
+ const dsttype* lut ) \
+{ \
+ size.width *= cn; \
+ dststep /= sizeof(dst[0]); \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ int i; \
+ ICV_LUT_CASE_C##cn( dsttype ) \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_LUT_FUNC_8U_CN( 8u, uchar, 1 )
+ICV_DEF_LUT_FUNC_8U_CN( 16u, ushort, 1 )
+ICV_DEF_LUT_FUNC_8U_CN( 32s, int, 1 )
+ICV_DEF_LUT_FUNC_8U_CN( 64f, double, 1 )
+
+ICV_DEF_LUT_FUNC_8U_CN( 8u, uchar, 2 )
+ICV_DEF_LUT_FUNC_8U_CN( 8u, uchar, 3 )
+ICV_DEF_LUT_FUNC_8U_CN( 8u, uchar, 4 )
+
+
+#define ICV_DEF_LUT_FUNC_8U( flavor, dsttype ) \
+static CvStatus CV_STDCALL \
+icvLUT_Transform8u_##flavor##_CnR( \
+ const uchar* src, int srcstep, \
+ dsttype* dst, int dststep, CvSize size, \
+ const dsttype* _lut, int cn ) \
+{ \
+ int max_block_size = (1 << 10)*cn; \
+ dsttype lutp[1024]; \
+ int i, k; \
+ \
+ size.width *= cn; \
+ dststep /= sizeof(dst[0]); \
+ \
+ if( size.width*size.height < 256 ) \
+ { \
+ for( ; size.height--; src+=srcstep, dst+=dststep ) \
+ for( k = 0; k < cn; k++ ) \
+ for( i = 0; i < size.width; i += cn ) \
+ dst[i+k] = _lut[src[i+k]*cn+k]; \
+ return CV_OK; \
+ } \
+ \
+ /* repack the lut to planar layout */ \
+ for( k = 0; k < cn; k++ ) \
+ for( i = 0; i < 256; i++ ) \
+ lutp[i+k*256] = _lut[i*cn+k]; \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ for( i = 0; i < size.width; ) \
+ { \
+ int j, limit = MIN(size.width,i+max_block_size);\
+ for( k=0; k<cn; k++, src++, dst++ ) \
+ { \
+ const dsttype* lut = lutp + k*256; \
+ for( j = i; j <= limit - cn*2; j += cn*2 ) \
+ { \
+ dsttype t0 = lut[src[j]]; \
+ dsttype t1 = lut[src[j+cn]]; \
+ dst[j] = t0; dst[j+cn] = t1; \
+ } \
+ \
+ for( ; j < limit; j += cn ) \
+ dst[j] = lut[src[j]]; \
+ } \
+ src -= cn; \
+ dst -= cn; \
+ i += limit; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+ICV_DEF_LUT_FUNC_8U( 8u, uchar )
+ICV_DEF_LUT_FUNC_8U( 16u, ushort )
+ICV_DEF_LUT_FUNC_8U( 32s, int )
+ICV_DEF_LUT_FUNC_8U( 64f, double )
+
+#undef icvLUT_Transform8u_8s_C1R
+#undef icvLUT_Transform8u_16s_C1R
+#undef icvLUT_Transform8u_32f_C1R
+
+#define icvLUT_Transform8u_8s_C1R icvLUT_Transform8u_8u_C1R
+#define icvLUT_Transform8u_16s_C1R icvLUT_Transform8u_16u_C1R
+#define icvLUT_Transform8u_32f_C1R icvLUT_Transform8u_32s_C1R
+
+#define icvLUT_Transform8u_8s_CnR icvLUT_Transform8u_8u_CnR
+#define icvLUT_Transform8u_16s_CnR icvLUT_Transform8u_16u_CnR
+#define icvLUT_Transform8u_32f_CnR icvLUT_Transform8u_32s_CnR
+
+CV_DEF_INIT_FUNC_TAB_2D( LUT_Transform8u, C1R )
+CV_DEF_INIT_FUNC_TAB_2D( LUT_Transform8u, CnR )
+
+typedef CvStatus (CV_STDCALL * CvLUT_TransformCnFunc)(
+ const void* src, int srcstep, void* dst,
+ int dststep, CvSize size, const void* lut, int cn );
+
+CV_IMPL void
+cvLUT( const void* srcarr, void* dstarr, const void* lutarr )
+{
+ static CvFuncTable lut_c1_tab, lut_cn_tab;
+ static CvLUT_TransformFunc lut_8u_tab[4];
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvLUT" );
+
+ __BEGIN__;
+
+ int coi1 = 0, coi2 = 0;
+ int depth, cn, lut_cn;
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvMat lutstub, *lut = (CvMat*)lutarr;
+ uchar* lut_data;
+ uchar* shuffled_lut = 0;
+ CvSize size;
+
+ if( !inittab )
+ {
+ icvInitLUT_Transform8uC1RTable( &lut_c1_tab );
+ icvInitLUT_Transform8uCnRTable( &lut_cn_tab );
+ lut_8u_tab[0] = (CvLUT_TransformFunc)icvLUT_Transform8u_8u_C1R;
+ lut_8u_tab[1] = (CvLUT_TransformFunc)icvLUT_Transform8u_8u_C2R;
+ lut_8u_tab[2] = (CvLUT_TransformFunc)icvLUT_Transform8u_8u_C3R;
+ lut_8u_tab[3] = (CvLUT_TransformFunc)icvLUT_Transform8u_8u_C4R;
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(src) )
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
+
+ if( !CV_IS_MAT(dst) )
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
+
+ if( !CV_IS_MAT(lut) )
+ CV_CALL( lut = cvGetMat( lut, &lutstub ));
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( !CV_ARE_CNS_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( CV_MAT_DEPTH( src->type ) > CV_8S )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ depth = CV_MAT_DEPTH( dst->type );
+ cn = CV_MAT_CN( dst->type );
+ lut_cn = CV_MAT_CN( lut->type );
+
+ if( !CV_IS_MAT_CONT(lut->type) || (lut_cn != 1 && lut_cn != cn) ||
+ !CV_ARE_DEPTHS_EQ( dst, lut ) || lut->width*lut->height != 256 )
+ CV_ERROR( CV_StsBadArg, "The LUT must be continuous array \n"
+ "with 256 elements of the same type as destination" );
+
+ size = cvGetMatSize( src );
+ if( lut_cn == 1 )
+ {
+ size.width *= cn;
+ cn = 1;
+ }
+
+ if( CV_IS_MAT_CONT( src->type & dst->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ }
+
+ lut_data = lut->data.ptr;
+
+ if( CV_MAT_DEPTH( src->type ) == CV_8S )
+ {
+ int half_size = CV_ELEM_SIZE1(depth)*cn*128;
+ shuffled_lut = (uchar*)cvStackAlloc(half_size*2);
+
+ // shuffle lut
+ memcpy( shuffled_lut, lut_data + half_size, half_size );
+ memcpy( shuffled_lut + half_size, lut_data, half_size );
+
+ lut_data = shuffled_lut;
+ }
+
+ if( lut_cn == 1 || (lut_cn <= 4 && depth == CV_8U) )
+ {
+ CvLUT_TransformFunc func = depth == CV_8U ? lut_8u_tab[cn-1] :
+ (CvLUT_TransformFunc)(lut_c1_tab.fn_2d[depth]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src->data.ptr, src->step, dst->data.ptr,
+ dst->step, size, lut_data ));
+ }
+ else
+ {
+ CvLUT_TransformCnFunc func =
+ (CvLUT_TransformCnFunc)(lut_cn_tab.fn_2d[depth]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src->data.ptr, src->step, dst->data.ptr,
+ dst->step, size, lut_data, cn ));
+ }
+
+ __END__;
+}
+
+/* End of file. */
diff --git a/cxcore/src/cxmathfuncs.cpp b/cxcore/src/cxmathfuncs.cpp
new file mode 100644
index 0000000..dfac47b
--- /dev/null
+++ b/cxcore/src/cxmathfuncs.cpp
@@ -0,0 +1,1998 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+
+#ifdef HAVE_CONFIG_H
+#include <cvconfig.h>
+#endif
+
+#define ICV_MATH_BLOCK_SIZE 256
+
+#define _CV_SQRT_MAGIC 0xbe6f0000
+
+#define _CV_SQRT_MAGIC_DBL CV_BIG_UINT(0xbfcd460000000000)
+
+#define _CV_ATAN_CF0 (-15.8131890796f)
+#define _CV_ATAN_CF1 (61.0941945596f)
+#define _CV_ATAN_CF2 0.f /*(-0.140500406322f)*/
+
+static const float icvAtanTab[8] = { 0.f + _CV_ATAN_CF2, 90.f - _CV_ATAN_CF2,
+ 180.f - _CV_ATAN_CF2, 90.f + _CV_ATAN_CF2,
+ 360.f - _CV_ATAN_CF2, 270.f + _CV_ATAN_CF2,
+ 180.f + _CV_ATAN_CF2, 270.f - _CV_ATAN_CF2
+};
+
+static const int icvAtanSign[8] =
+ { 0, 0x80000000, 0x80000000, 0, 0x80000000, 0, 0, 0x80000000 };
+
+CV_IMPL float
+cvFastArctan( float y, float x )
+{
+ Cv32suf _x, _y;
+ int ix, iy, ygx, idx;
+ double z;
+
+ _x.f = x; _y.f = y;
+ ix = _x.i; iy = _y.i;
+ idx = (ix < 0) * 2 + (iy < 0) * 4;
+
+ ix &= 0x7fffffff;
+ iy &= 0x7fffffff;
+
+ ygx = (iy <= ix) - 1;
+ idx -= ygx;
+
+ idx &= ((ix == 0) - 1) | ((iy == 0) - 1);
+
+ /* swap ix and iy if ix < iy */
+ ix ^= iy & ygx;
+ iy ^= ix & ygx;
+ ix ^= iy & ygx;
+
+ _y.i = iy ^ icvAtanSign[idx];
+
+ /* ix = ix != 0 ? ix : 1.f */
+ _x.i = ((ix ^ CV_1F) & ((ix == 0) - 1)) ^ CV_1F;
+
+ z = _y.f / _x.f;
+ return (float)((_CV_ATAN_CF0*fabs(z) + _CV_ATAN_CF1)*z + icvAtanTab[idx]);
+}
+
+
+IPCVAPI_IMPL( CvStatus, icvFastArctan_32f,
+ (const float *__y, const float *__x, float *angle, int len ), (__y, __x, angle, len) )
+{
+ int i = 0;
+ const int *y = (const int*)__y, *x = (const int*)__x;
+
+ if( !(y && x && angle && len >= 0) )
+ return CV_BADFACTOR_ERR;
+
+ /* unrolled by 4 loop */
+ for( ; i <= len - 4; i += 4 )
+ {
+ int j, idx[4];
+ float xf[4], yf[4];
+ double d = 1.;
+
+ /* calc numerators and denominators */
+ for( j = 0; j < 4; j++ )
+ {
+ int ix = x[i + j], iy = y[i + j];
+ int ygx, k = (ix < 0) * 2 + (iy < 0) * 4;
+ Cv32suf _x, _y;
+
+ ix &= 0x7fffffff;
+ iy &= 0x7fffffff;
+
+ ygx = (iy <= ix) - 1;
+ k -= ygx;
+
+ k &= ((ix == 0) - 1) | ((iy == 0) - 1);
+
+ /* swap ix and iy if ix < iy */
+ ix ^= iy & ygx;
+ iy ^= ix & ygx;
+ ix ^= iy & ygx;
+
+ _y.i = iy ^ icvAtanSign[k];
+
+ /* ix = ix != 0 ? ix : 1.f */
+ _x.i = ((ix ^ CV_1F) & ((ix == 0) - 1)) ^ CV_1F;
+ idx[j] = k;
+ yf[j] = _y.f;
+ d *= (xf[j] = _x.f);
+ }
+
+ d = 1. / d;
+
+ {
+ double b = xf[2] * xf[3], a = xf[0] * xf[1];
+
+ float z0 = (float) (yf[0] * xf[1] * b * d);
+ float z1 = (float) (yf[1] * xf[0] * b * d);
+ float z2 = (float) (yf[2] * xf[3] * a * d);
+ float z3 = (float) (yf[3] * xf[2] * a * d);
+
+ z0 = (float)((_CV_ATAN_CF0*fabs(z0) + _CV_ATAN_CF1)*z0 + icvAtanTab[idx[0]]);
+ z1 = (float)((_CV_ATAN_CF0*fabs(z1) + _CV_ATAN_CF1)*z1 + icvAtanTab[idx[1]]);
+ z2 = (float)((_CV_ATAN_CF0*fabs(z2) + _CV_ATAN_CF1)*z2 + icvAtanTab[idx[2]]);
+ z3 = (float)((_CV_ATAN_CF0*fabs(z3) + _CV_ATAN_CF1)*z3 + icvAtanTab[idx[3]]);
+
+ angle[i] = z0;
+ angle[i+1] = z1;
+ angle[i+2] = z2;
+ angle[i+3] = z3;
+ }
+ }
+
+ /* process the rest */
+ for( ; i < len; i++ )
+ angle[i] = cvFastArctan( __y[i], __x[i] );
+
+ return CV_OK;
+}
+
+
+/* ************************************************************************** *\
+ Fast cube root by Ken Turkowski
+ (http://www.worldserver.com/turk/computergraphics/papers.html)
+\* ************************************************************************** */
+CV_IMPL float cvCbrt( float value )
+{
+ float fr;
+ Cv32suf v, m;
+ int ix, s;
+ int ex, shx;
+
+ v.f = value;
+ ix = v.i & 0x7fffffff;
+ s = v.i & 0x80000000;
+ ex = (ix >> 23) - 127;
+ shx = ex % 3;
+ shx -= shx >= 0 ? 3 : 0;
+ ex = (ex - shx) / 3; /* exponent of cube root */
+ v.i = (ix & ((1<<23)-1)) | ((shx + 127)<<23);
+ fr = v.f;
+
+ /* 0.125 <= fr < 1.0 */
+ /* Use quartic rational polynomial with error < 2^(-24) */
+ fr = (float)(((((45.2548339756803022511987494 * fr +
+ 192.2798368355061050458134625) * fr +
+ 119.1654824285581628956914143) * fr +
+ 13.43250139086239872172837314) * fr +
+ 0.1636161226585754240958355063)/
+ ((((14.80884093219134573786480845 * fr +
+ 151.9714051044435648658557668) * fr +
+ 168.5254414101568283957668343) * fr +
+ 33.9905941350215598754191872) * fr +
+ 1.0));
+
+ /* fr *= 2^ex * sign */
+ m.f = value;
+ v.f = fr;
+ v.i = (v.i + (ex << 23) + s) & (m.i*2 != 0 ? -1 : 0);
+ return v.f;
+}
+
+//static const double _0_5 = 0.5, _1_5 = 1.5;
+
+IPCVAPI_IMPL( CvStatus, icvInvSqrt_32f, (const float *src, float *dst, int len), (src, dst, len) )
+{
+ int i = 0;
+
+ if( !(src && dst && len >= 0) )
+ return CV_BADFACTOR_ERR;
+
+ for( ; i < len; i++ )
+ dst[i] = (float)(1.f/sqrt(src[i]));
+
+ return CV_OK;
+}
+
+
+IPCVAPI_IMPL( CvStatus, icvSqrt_32f, (const float *src, float *dst, int len), (src, dst, len) )
+{
+ int i = 0;
+
+ if( !(src && dst && len >= 0) )
+ return CV_BADFACTOR_ERR;
+
+ for( ; i < len; i++ )
+ dst[i] = (float)sqrt(src[i]);
+
+ return CV_OK;
+}
+
+
+IPCVAPI_IMPL( CvStatus, icvSqrt_64f, (const double *src, double *dst, int len), (src, dst, len) )
+{
+ int i = 0;
+
+ if( !(src && dst && len >= 0) )
+ return CV_BADFACTOR_ERR;
+
+ for( ; i < len; i++ )
+ dst[i] = sqrt(src[i]);
+
+ return CV_OK;
+}
+
+
+IPCVAPI_IMPL( CvStatus, icvInvSqrt_64f, (const double *src, double *dst, int len), (src, dst, len) )
+{
+ int i = 0;
+
+ if( !(src && dst && len >= 0) )
+ return CV_BADFACTOR_ERR;
+
+ for( ; i < len; i++ )
+ dst[i] = 1./sqrt(src[i]);
+
+ return CV_OK;
+}
+
+
+#define ICV_DEF_SQR_MAGNITUDE_FUNC(flavor, arrtype, magtype)\
+static CvStatus CV_STDCALL \
+icvSqrMagnitude_##flavor(const arrtype* x, const arrtype* y,\
+ magtype* mag, int len) \
+{ \
+ int i; \
+ \
+ for( i = 0; i <= len - 4; i += 4 ) \
+ { \
+ magtype x0 = (magtype)x[i], y0 = (magtype)y[i]; \
+ magtype x1 = (magtype)x[i+1], y1 = (magtype)y[i+1]; \
+ \
+ x0 = x0*x0 + y0*y0; \
+ x1 = x1*x1 + y1*y1; \
+ mag[i] = x0; \
+ mag[i+1] = x1; \
+ x0 = (magtype)x[i+2], y0 = (magtype)y[i+2]; \
+ x1 = (magtype)x[i+3], y1 = (magtype)y[i+3]; \
+ x0 = x0*x0 + y0*y0; \
+ x1 = x1*x1 + y1*y1; \
+ mag[i+2] = x0; \
+ mag[i+3] = x1; \
+ } \
+ \
+ for( ; i < len; i++ ) \
+ { \
+ magtype x0 = (magtype)x[i], y0 = (magtype)y[i]; \
+ mag[i] = x0*x0 + y0*y0; \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_SQR_MAGNITUDE_FUNC( 32f, float, float )
+ICV_DEF_SQR_MAGNITUDE_FUNC( 64f, double, double )
+
+/****************************************************************************************\
+* Cartezian -> Polar *
+\****************************************************************************************/
+
+CV_IMPL void
+cvCartToPolar( const CvArr* xarr, const CvArr* yarr,
+ CvArr* magarr, CvArr* anglearr,
+ int angle_in_degrees )
+{
+ CV_FUNCNAME( "cvCartToPolar" );
+
+ __BEGIN__;
+
+ float* mag_buffer = 0;
+ float* x_buffer = 0;
+ float* y_buffer = 0;
+ int block_size = 0;
+ CvMat xstub, *xmat = (CvMat*)xarr;
+ CvMat ystub, *ymat = (CvMat*)yarr;
+ CvMat magstub, *mag = (CvMat*)magarr;
+ CvMat anglestub, *angle = (CvMat*)anglearr;
+ int coi1 = 0, coi2 = 0, coi3 = 0, coi4 = 0;
+ int depth;
+ CvSize size;
+ int x, y;
+ int cont_flag = CV_MAT_CONT_FLAG;
+
+ if( !CV_IS_MAT(xmat))
+ CV_CALL( xmat = cvGetMat( xmat, &xstub, &coi1 ));
+
+ if( !CV_IS_MAT(ymat))
+ CV_CALL( ymat = cvGetMat( ymat, &ystub, &coi2 ));
+
+ if( !CV_ARE_TYPES_EQ( xmat, ymat ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( xmat, ymat ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ depth = CV_MAT_DEPTH( xmat->type );
+ if( depth < CV_32F )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( mag )
+ {
+ CV_CALL( mag = cvGetMat( mag, &magstub, &coi3 ));
+
+ if( !CV_ARE_TYPES_EQ( mag, xmat ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( mag, xmat ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+ cont_flag = mag->type;
+ }
+
+ if( angle )
+ {
+ CV_CALL( angle = cvGetMat( angle, &anglestub, &coi4 ));
+
+ if( !CV_ARE_TYPES_EQ( angle, xmat ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( angle, xmat ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+ cont_flag &= angle->type;
+ }
+
+ if( coi1 != 0 || coi2 != 0 || coi3 != 0 || coi4 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ size = cvGetMatSize(xmat);
+ size.width *= CV_MAT_CN(xmat->type);
+
+ if( CV_IS_MAT_CONT( xmat->type & ymat->type & cont_flag ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ }
+
+ block_size = MIN( size.width, ICV_MATH_BLOCK_SIZE );
+ if( depth == CV_64F && angle )
+ {
+ x_buffer = (float*)cvStackAlloc( block_size*sizeof(float));
+ y_buffer = (float*)cvStackAlloc( block_size*sizeof(float));
+ }
+ else if( depth == CV_32F && mag )
+ {
+ mag_buffer = (float*)cvStackAlloc( block_size*sizeof(float));
+ }
+
+ if( depth == CV_32F )
+ {
+ for( y = 0; y < size.height; y++ )
+ {
+ float* x_data = (float*)(xmat->data.ptr + xmat->step*y);
+ float* y_data = (float*)(ymat->data.ptr + ymat->step*y);
+ float* mag_data = mag ? (float*)(mag->data.ptr + mag->step*y) : 0;
+ float* angle_data = angle ? (float*)(angle->data.ptr + angle->step*y) : 0;
+
+ for( x = 0; x < size.width; x += block_size )
+ {
+ int len = MIN( size.width - x, block_size );
+
+ if( mag )
+ icvSqrMagnitude_32f( x_data + x, y_data + x, mag_buffer, len );
+
+ if( angle )
+ {
+ icvFastArctan_32f( y_data + x, x_data + x, angle_data + x, len );
+ if( !angle_in_degrees )
+ icvScale_32f( angle_data + x, angle_data + x,
+ len, (float)(CV_PI/180.), 0 );
+ }
+
+ if( mag )
+ icvSqrt_32f( mag_buffer, mag_data + x, len );
+ }
+ }
+ }
+ else
+ {
+ for( y = 0; y < size.height; y++ )
+ {
+ double* x_data = (double*)(xmat->data.ptr + xmat->step*y);
+ double* y_data = (double*)(ymat->data.ptr + ymat->step*y);
+ double* mag_data = mag ? (double*)(mag->data.ptr + mag->step*y) : 0;
+ double* angle_data = angle ? (double*)(angle->data.ptr + angle->step*y) : 0;
+
+ for( x = 0; x < size.width; x += block_size )
+ {
+ int len = MIN( size.width - x, block_size );
+
+ if( angle )
+ {
+ icvCvt_64f32f( x_data + x, x_buffer, len );
+ icvCvt_64f32f( y_data + x, y_buffer, len );
+ }
+
+ if( mag )
+ {
+ icvSqrMagnitude_64f( x_data + x, y_data + x, mag_data + x, len );
+ icvSqrt_64f( mag_data + x, mag_data + x, len );
+ }
+
+ if( angle )
+ {
+ icvFastArctan_32f( y_buffer, x_buffer, x_buffer, len );
+ if( !angle_in_degrees )
+ icvScale_32f( x_buffer, x_buffer, len, (float)(CV_PI/180.), 0 );
+ icvCvt_32f64f( x_buffer, angle_data + x, len );
+ }
+ }
+ }
+ }
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* Polar -> Cartezian *
+\****************************************************************************************/
+
+static CvStatus CV_STDCALL
+icvSinCos_32f( const float *angle,float *sinval, float* cosval,
+ int len, int angle_in_degrees )
+{
+ const int N = 64;
+
+ static const double sin_table[] =
+ {
+ 0.00000000000000000000, 0.09801714032956060400,
+ 0.19509032201612825000, 0.29028467725446233000,
+ 0.38268343236508978000, 0.47139673682599764000,
+ 0.55557023301960218000, 0.63439328416364549000,
+ 0.70710678118654746000, 0.77301045336273699000,
+ 0.83146961230254524000, 0.88192126434835494000,
+ 0.92387953251128674000, 0.95694033573220894000,
+ 0.98078528040323043000, 0.99518472667219682000,
+ 1.00000000000000000000, 0.99518472667219693000,
+ 0.98078528040323043000, 0.95694033573220894000,
+ 0.92387953251128674000, 0.88192126434835505000,
+ 0.83146961230254546000, 0.77301045336273710000,
+ 0.70710678118654757000, 0.63439328416364549000,
+ 0.55557023301960218000, 0.47139673682599786000,
+ 0.38268343236508989000, 0.29028467725446239000,
+ 0.19509032201612861000, 0.09801714032956082600,
+ 0.00000000000000012246, -0.09801714032956059000,
+ -0.19509032201612836000, -0.29028467725446211000,
+ -0.38268343236508967000, -0.47139673682599764000,
+ -0.55557023301960196000, -0.63439328416364527000,
+ -0.70710678118654746000, -0.77301045336273666000,
+ -0.83146961230254524000, -0.88192126434835494000,
+ -0.92387953251128652000, -0.95694033573220882000,
+ -0.98078528040323032000, -0.99518472667219693000,
+ -1.00000000000000000000, -0.99518472667219693000,
+ -0.98078528040323043000, -0.95694033573220894000,
+ -0.92387953251128663000, -0.88192126434835505000,
+ -0.83146961230254546000, -0.77301045336273688000,
+ -0.70710678118654768000, -0.63439328416364593000,
+ -0.55557023301960218000, -0.47139673682599792000,
+ -0.38268343236509039000, -0.29028467725446250000,
+ -0.19509032201612872000, -0.09801714032956050600,
+ };
+
+ static const double k2 = (2*CV_PI)/N;
+
+ static const double sin_a0 = -0.166630293345647*k2*k2*k2;
+ static const double sin_a2 = k2;
+
+ static const double cos_a0 = -0.499818138450326*k2*k2;
+ /*static const double cos_a2 = 1;*/
+
+ double k1;
+ int i;
+
+ if( !angle_in_degrees )
+ k1 = N/(2*CV_PI);
+ else
+ k1 = N/360.;
+
+ for( i = 0; i < len; i++ )
+ {
+ double t = angle[i]*k1;
+ int it = cvRound(t);
+ t -= it;
+ int sin_idx = it & (N - 1);
+ int cos_idx = (N/4 - sin_idx) & (N - 1);
+
+ double sin_b = (sin_a0*t*t + sin_a2)*t;
+ double cos_b = cos_a0*t*t + 1;
+
+ double sin_a = sin_table[sin_idx];
+ double cos_a = sin_table[cos_idx];
+
+ double sin_val = sin_a*cos_b + cos_a*sin_b;
+ double cos_val = cos_a*cos_b - sin_a*sin_b;
+
+ sinval[i] = (float)sin_val;
+ cosval[i] = (float)cos_val;
+ }
+
+ return CV_OK;
+}
+
+
+CV_IMPL void
+cvPolarToCart( const CvArr* magarr, const CvArr* anglearr,
+ CvArr* xarr, CvArr* yarr, int angle_in_degrees )
+{
+ CV_FUNCNAME( "cvPolarToCart" );
+
+ __BEGIN__;
+
+ float* x_buffer = 0;
+ float* y_buffer = 0;
+ int block_size = 0;
+ CvMat xstub, *xmat = (CvMat*)xarr;
+ CvMat ystub, *ymat = (CvMat*)yarr;
+ CvMat magstub, *mag = (CvMat*)magarr;
+ CvMat anglestub, *angle = (CvMat*)anglearr;
+ int coi1 = 0, coi2 = 0, coi3 = 0, coi4 = 0;
+ int depth;
+ CvSize size;
+ int x, y;
+ int cont_flag;
+
+ if( !CV_IS_MAT(angle))
+ CV_CALL( angle = cvGetMat( angle, &anglestub, &coi4 ));
+
+ depth = CV_MAT_DEPTH( angle->type );
+ if( depth < CV_32F )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+ cont_flag = angle->type;
+
+ if( mag )
+ {
+ if( !CV_IS_MAT(mag))
+ CV_CALL( mag = cvGetMat( mag, &magstub, &coi3 ));
+
+ if( !CV_ARE_TYPES_EQ( angle, mag ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( angle, mag ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ cont_flag &= mag->type;
+ }
+
+ if( xmat )
+ {
+ if( !CV_IS_MAT(xmat))
+ CV_CALL( xmat = cvGetMat( xmat, &xstub, &coi1 ));
+
+ if( !CV_ARE_TYPES_EQ( angle, xmat ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( angle, xmat ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ cont_flag &= xmat->type;
+ }
+
+ if( ymat )
+ {
+ if( !CV_IS_MAT(ymat))
+ CV_CALL( ymat = cvGetMat( ymat, &ystub, &coi2 ));
+
+ if( !CV_ARE_TYPES_EQ( angle, ymat ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( angle, ymat ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ cont_flag &= ymat->type;
+ }
+
+ if( coi1 != 0 || coi2 != 0 || coi3 != 0 || coi4 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ size = cvGetMatSize(angle);
+ size.width *= CV_MAT_CN(angle->type);
+
+ if( CV_IS_MAT_CONT( cont_flag ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ }
+
+ block_size = MIN( size.width, ICV_MATH_BLOCK_SIZE );
+ x_buffer = (float*)cvStackAlloc( block_size*sizeof(float));
+ y_buffer = (float*)cvStackAlloc( block_size*sizeof(float));
+
+ if( depth == CV_32F )
+ {
+ for( y = 0; y < size.height; y++ )
+ {
+ float* x_data = (float*)(xmat ? xmat->data.ptr + xmat->step*y : 0);
+ float* y_data = (float*)(ymat ? ymat->data.ptr + ymat->step*y : 0);
+ float* mag_data = (float*)(mag ? mag->data.ptr + mag->step*y : 0);
+ float* angle_data = (float*)(angle->data.ptr + angle->step*y);
+
+ for( x = 0; x < size.width; x += block_size )
+ {
+ int i, len = MIN( size.width - x, block_size );
+
+ icvSinCos_32f( angle_data+x, y_buffer, x_buffer, len, angle_in_degrees );
+
+ for( i = 0; i < len; i++ )
+ {
+ float tx = x_buffer[i];
+ float ty = y_buffer[i];
+
+ if( mag_data )
+ {
+ float magval = mag_data[x+i];
+ tx *= magval;
+ ty *= magval;
+ }
+
+ if( xmat )
+ x_data[x+i] = tx;
+ if( ymat )
+ y_data[x+i] = ty;
+ }
+ }
+ }
+ }
+ else
+ {
+ for( y = 0; y < size.height; y++ )
+ {
+ double* x_data = (double*)(xmat ? xmat->data.ptr + xmat->step*y : 0);
+ double* y_data = (double*)(ymat ? ymat->data.ptr + ymat->step*y : 0);
+ double* mag_data = (double*)(mag ? mag->data.ptr + mag->step*y : 0);
+ double* angle_data = (double*)(angle->data.ptr + angle->step*y);
+ double C = angle_in_degrees ? CV_PI/180. : 1;
+
+ for( x = 0; x < size.width; x++ )
+ {
+ double phi = angle_data[x]*C;
+ double magval = mag_data ? mag_data[x] : 1.;
+ if( xmat )
+ x_data[x] = cos(phi)*magval;
+ if( ymat )
+ y_data[x] = sin(phi)*magval;
+ }
+ }
+ }
+
+ __END__;
+}
+
+/****************************************************************************************\
+* E X P *
+\****************************************************************************************/
+
+typedef union
+{
+ struct {
+#if ( defined( WORDS_BIGENDIAN ) && !defined( OPENCV_UNIVERSAL_BUILD ) ) || defined( __BIG_ENDIAN__ )
+ int hi;
+ int lo;
+#else
+ int lo;
+ int hi;
+#endif
+ } i;
+ double d;
+}
+DBLINT;
+
+#define EXPTAB_SCALE 6
+#define EXPTAB_MASK ((1 << EXPTAB_SCALE) - 1)
+
+#define EXPPOLY_32F_A0 .9670371139572337719125840413672004409288e-2
+
+static const double icvExpTab[] = {
+ 1.0 * EXPPOLY_32F_A0,
+ 1.0108892860517004600204097905619 * EXPPOLY_32F_A0,
+ 1.0218971486541166782344801347833 * EXPPOLY_32F_A0,
+ 1.0330248790212284225001082839705 * EXPPOLY_32F_A0,
+ 1.0442737824274138403219664787399 * EXPPOLY_32F_A0,
+ 1.0556451783605571588083413251529 * EXPPOLY_32F_A0,
+ 1.0671404006768236181695211209928 * EXPPOLY_32F_A0,
+ 1.0787607977571197937406800374385 * EXPPOLY_32F_A0,
+ 1.0905077326652576592070106557607 * EXPPOLY_32F_A0,
+ 1.1023825833078409435564142094256 * EXPPOLY_32F_A0,
+ 1.1143867425958925363088129569196 * EXPPOLY_32F_A0,
+ 1.126521618608241899794798643787 * EXPPOLY_32F_A0,
+ 1.1387886347566916537038302838415 * EXPPOLY_32F_A0,
+ 1.151189229952982705817759635202 * EXPPOLY_32F_A0,
+ 1.1637248587775775138135735990922 * EXPPOLY_32F_A0,
+ 1.1763969916502812762846457284838 * EXPPOLY_32F_A0,
+ 1.1892071150027210667174999705605 * EXPPOLY_32F_A0,
+ 1.2021567314527031420963969574978 * EXPPOLY_32F_A0,
+ 1.2152473599804688781165202513388 * EXPPOLY_32F_A0,
+ 1.2284805361068700056940089577928 * EXPPOLY_32F_A0,
+ 1.2418578120734840485936774687266 * EXPPOLY_32F_A0,
+ 1.2553807570246910895793906574423 * EXPPOLY_32F_A0,
+ 1.2690509571917332225544190810323 * EXPPOLY_32F_A0,
+ 1.2828700160787782807266697810215 * EXPPOLY_32F_A0,
+ 1.2968395546510096659337541177925 * EXPPOLY_32F_A0,
+ 1.3109612115247643419229917863308 * EXPPOLY_32F_A0,
+ 1.3252366431597412946295370954987 * EXPPOLY_32F_A0,
+ 1.3396675240533030053600306697244 * EXPPOLY_32F_A0,
+ 1.3542555469368927282980147401407 * EXPPOLY_32F_A0,
+ 1.3690024229745906119296011329822 * EXPPOLY_32F_A0,
+ 1.3839098819638319548726595272652 * EXPPOLY_32F_A0,
+ 1.3989796725383111402095281367152 * EXPPOLY_32F_A0,
+ 1.4142135623730950488016887242097 * EXPPOLY_32F_A0,
+ 1.4296133383919700112350657782751 * EXPPOLY_32F_A0,
+ 1.4451808069770466200370062414717 * EXPPOLY_32F_A0,
+ 1.4609177941806469886513028903106 * EXPPOLY_32F_A0,
+ 1.476826145939499311386907480374 * EXPPOLY_32F_A0,
+ 1.4929077282912648492006435314867 * EXPPOLY_32F_A0,
+ 1.5091644275934227397660195510332 * EXPPOLY_32F_A0,
+ 1.5255981507445383068512536895169 * EXPPOLY_32F_A0,
+ 1.5422108254079408236122918620907 * EXPPOLY_32F_A0,
+ 1.5590044002378369670337280894749 * EXPPOLY_32F_A0,
+ 1.5759808451078864864552701601819 * EXPPOLY_32F_A0,
+ 1.5931421513422668979372486431191 * EXPPOLY_32F_A0,
+ 1.6104903319492543081795206673574 * EXPPOLY_32F_A0,
+ 1.628027421857347766848218522014 * EXPPOLY_32F_A0,
+ 1.6457554781539648445187567247258 * EXPPOLY_32F_A0,
+ 1.6636765803267364350463364569764 * EXPPOLY_32F_A0,
+ 1.6817928305074290860622509524664 * EXPPOLY_32F_A0,
+ 1.7001063537185234695013625734975 * EXPPOLY_32F_A0,
+ 1.7186192981224779156293443764563 * EXPPOLY_32F_A0,
+ 1.7373338352737062489942020818722 * EXPPOLY_32F_A0,
+ 1.7562521603732994831121606193753 * EXPPOLY_32F_A0,
+ 1.7753764925265212525505592001993 * EXPPOLY_32F_A0,
+ 1.7947090750031071864277032421278 * EXPPOLY_32F_A0,
+ 1.8142521755003987562498346003623 * EXPPOLY_32F_A0,
+ 1.8340080864093424634870831895883 * EXPPOLY_32F_A0,
+ 1.8539791250833855683924530703377 * EXPPOLY_32F_A0,
+ 1.8741676341102999013299989499544 * EXPPOLY_32F_A0,
+ 1.8945759815869656413402186534269 * EXPPOLY_32F_A0,
+ 1.9152065613971472938726112702958 * EXPPOLY_32F_A0,
+ 1.9360617934922944505980559045667 * EXPPOLY_32F_A0,
+ 1.9571441241754002690183222516269 * EXPPOLY_32F_A0,
+ 1.9784560263879509682582499181312 * EXPPOLY_32F_A0,
+};
+
+static const double exp_prescale = 1.4426950408889634073599246810019 * (1 << EXPTAB_SCALE);
+static const double exp_postscale = 1./(1 << EXPTAB_SCALE);
+static const double exp_max_val = 3000.*(1 << EXPTAB_SCALE); // log10(DBL_MAX) < 3000
+
+IPCVAPI_IMPL( CvStatus, icvExp_32f, ( const float *_x, float *y, int n ), (_x, y, n) )
+{
+ static const double
+ EXPPOLY_32F_A4 = 1.000000000000002438532970795181890933776 / EXPPOLY_32F_A0,
+ EXPPOLY_32F_A3 = .6931471805521448196800669615864773144641 / EXPPOLY_32F_A0,
+ EXPPOLY_32F_A2 = .2402265109513301490103372422686535526573 / EXPPOLY_32F_A0,
+ EXPPOLY_32F_A1 = .5550339366753125211915322047004666939128e-1 / EXPPOLY_32F_A0;
+
+ #undef EXPPOLY
+ #define EXPPOLY(x) \
+ (((((x) + EXPPOLY_32F_A1)*(x) + EXPPOLY_32F_A2)*(x) + EXPPOLY_32F_A3)*(x) + EXPPOLY_32F_A4)
+
+ int i = 0;
+ DBLINT buf[4];
+ const Cv32suf* x = (const Cv32suf*)_x;
+
+ if( !x || !y )
+ return CV_NULLPTR_ERR;
+ if( n <= 0 )
+ return CV_BADSIZE_ERR;
+
+ buf[0].i.lo = buf[1].i.lo = buf[2].i.lo = buf[3].i.lo = 0;
+
+ for( ; i <= n - 4; i += 4 )
+ {
+ double x0 = x[i].f * exp_prescale;
+ double x1 = x[i + 1].f * exp_prescale;
+ double x2 = x[i + 2].f * exp_prescale;
+ double x3 = x[i + 3].f * exp_prescale;
+ int val0, val1, val2, val3, t;
+
+ if( ((x[i].i >> 23) & 255) > 127 + 10 )
+ x0 = x[i].i < 0 ? -exp_max_val : exp_max_val;
+
+ if( ((x[i+1].i >> 23) & 255) > 127 + 10 )
+ x1 = x[i+1].i < 0 ? -exp_max_val : exp_max_val;
+
+ if( ((x[i+2].i >> 23) & 255) > 127 + 10 )
+ x2 = x[i+2].i < 0 ? -exp_max_val : exp_max_val;
+
+ if( ((x[i+3].i >> 23) & 255) > 127 + 10 )
+ x3 = x[i+3].i < 0 ? -exp_max_val : exp_max_val;
+
+ val0 = cvRound(x0);
+ val1 = cvRound(x1);
+ val2 = cvRound(x2);
+ val3 = cvRound(x3);
+
+ x0 = (x0 - val0)*exp_postscale;
+ x1 = (x1 - val1)*exp_postscale;
+ x2 = (x2 - val2)*exp_postscale;
+ x3 = (x3 - val3)*exp_postscale;
+
+ t = (val0 >> EXPTAB_SCALE) + 1023;
+ t = (t | ((t < 2047) - 1)) & (((t < 0) - 1) & 2047);
+ buf[0].i.hi = t << 20;
+
+ t = (val1 >> EXPTAB_SCALE) + 1023;
+ t = (t | ((t < 2047) - 1)) & (((t < 0) - 1) & 2047);
+ buf[1].i.hi = t << 20;
+
+ t = (val2 >> EXPTAB_SCALE) + 1023;
+ t = (t | ((t < 2047) - 1)) & (((t < 0) - 1) & 2047);
+ buf[2].i.hi = t << 20;
+
+ t = (val3 >> EXPTAB_SCALE) + 1023;
+ t = (t | ((t < 2047) - 1)) & (((t < 0) - 1) & 2047);
+ buf[3].i.hi = t << 20;
+
+ x0 = buf[0].d * icvExpTab[val0 & EXPTAB_MASK] * EXPPOLY( x0 );
+ x1 = buf[1].d * icvExpTab[val1 & EXPTAB_MASK] * EXPPOLY( x1 );
+
+ y[i] = (float)x0;
+ y[i + 1] = (float)x1;
+
+ x2 = buf[2].d * icvExpTab[val2 & EXPTAB_MASK] * EXPPOLY( x2 );
+ x3 = buf[3].d * icvExpTab[val3 & EXPTAB_MASK] * EXPPOLY( x3 );
+
+ y[i + 2] = (float)x2;
+ y[i + 3] = (float)x3;
+ }
+
+ for( ; i < n; i++ )
+ {
+ double x0 = x[i].f * exp_prescale;
+ int val0, t;
+
+ if( ((x[i].i >> 23) & 255) > 127 + 10 )
+ x0 = x[i].i < 0 ? -exp_max_val : exp_max_val;
+
+ val0 = cvRound(x0);
+ t = (val0 >> EXPTAB_SCALE) + 1023;
+ t = (t | ((t < 2047) - 1)) & (((t < 0) - 1) & 2047);
+
+ buf[0].i.hi = t << 20;
+ x0 = (x0 - val0)*exp_postscale;
+
+ y[i] = (float)(buf[0].d * icvExpTab[val0 & EXPTAB_MASK] * EXPPOLY(x0));
+ }
+
+ return CV_OK;
+}
+
+
+IPCVAPI_IMPL( CvStatus, icvExp_64f, ( const double *_x, double *y, int n ), (_x, y, n) )
+{
+ static const double
+ A5 = .99999999999999999998285227504999 / EXPPOLY_32F_A0,
+ A4 = .69314718055994546743029643825322 / EXPPOLY_32F_A0,
+ A3 = .24022650695886477918181338054308 / EXPPOLY_32F_A0,
+ A2 = .55504108793649567998466049042729e-1 / EXPPOLY_32F_A0,
+ A1 = .96180973140732918010002372686186e-2 / EXPPOLY_32F_A0,
+ A0 = .13369713757180123244806654839424e-2 / EXPPOLY_32F_A0;
+
+ #undef EXPPOLY
+ #define EXPPOLY(x) (((((A0*(x) + A1)*(x) + A2)*(x) + A3)*(x) + A4)*(x) + A5)
+
+ int i = 0;
+ DBLINT buf[4];
+ const Cv64suf* x = (const Cv64suf*)_x;
+
+ if( !x || !y )
+ return CV_NULLPTR_ERR;
+ if( n <= 0 )
+ return CV_BADSIZE_ERR;
+
+ buf[0].i.lo = buf[1].i.lo = buf[2].i.lo = buf[3].i.lo = 0;
+
+ for( ; i <= n - 4; i += 4 )
+ {
+ double x0 = x[i].f * exp_prescale;
+ double x1 = x[i + 1].f * exp_prescale;
+ double x2 = x[i + 2].f * exp_prescale;
+ double x3 = x[i + 3].f * exp_prescale;
+
+ double y0, y1, y2, y3;
+ int val0, val1, val2, val3, t;
+
+ t = (int)(x[i].i >> 52);
+ if( (t & 2047) > 1023 + 10 )
+ x0 = t < 0 ? -exp_max_val : exp_max_val;
+
+ t = (int)(x[i+1].i >> 52);
+ if( (t & 2047) > 1023 + 10 )
+ x1 = t < 0 ? -exp_max_val : exp_max_val;
+
+ t = (int)(x[i+2].i >> 52);
+ if( (t & 2047) > 1023 + 10 )
+ x2 = t < 0 ? -exp_max_val : exp_max_val;
+
+ t = (int)(x[i+3].i >> 52);
+ if( (t & 2047) > 1023 + 10 )
+ x3 = t < 0 ? -exp_max_val : exp_max_val;
+
+ val0 = cvRound(x0);
+ val1 = cvRound(x1);
+ val2 = cvRound(x2);
+ val3 = cvRound(x3);
+
+ x0 = (x0 - val0)*exp_postscale;
+ x1 = (x1 - val1)*exp_postscale;
+ x2 = (x2 - val2)*exp_postscale;
+ x3 = (x3 - val3)*exp_postscale;
+
+ t = (val0 >> EXPTAB_SCALE) + 1023;
+ t = (t | ((t < 2047) - 1)) & (((t < 0) - 1) & 2047);
+ buf[0].i.hi = t << 20;
+
+ t = (val1 >> EXPTAB_SCALE) + 1023;
+ t = (t | ((t < 2047) - 1)) & (((t < 0) - 1) & 2047);
+ buf[1].i.hi = t << 20;
+
+ t = (val2 >> EXPTAB_SCALE) + 1023;
+ t = (t | ((t < 2047) - 1)) & (((t < 0) - 1) & 2047);
+ buf[2].i.hi = t << 20;
+
+ t = (val3 >> EXPTAB_SCALE) + 1023;
+ t = (t | ((t < 2047) - 1)) & (((t < 0) - 1) & 2047);
+ buf[3].i.hi = t << 20;
+
+ y0 = buf[0].d * icvExpTab[val0 & EXPTAB_MASK] * EXPPOLY( x0 );
+ y1 = buf[1].d * icvExpTab[val1 & EXPTAB_MASK] * EXPPOLY( x1 );
+
+ y[i] = y0;
+ y[i + 1] = y1;
+
+ y2 = buf[2].d * icvExpTab[val2 & EXPTAB_MASK] * EXPPOLY( x2 );
+ y3 = buf[3].d * icvExpTab[val3 & EXPTAB_MASK] * EXPPOLY( x3 );
+
+ y[i + 2] = y2;
+ y[i + 3] = y3;
+ }
+
+ for( ; i < n; i++ )
+ {
+ double x0 = x[i].f * exp_prescale;
+ int val0, t;
+
+ t = (int)(x[i].i >> 52);
+ if( (t & 2047) > 1023 + 10 )
+ x0 = t < 0 ? -exp_max_val : exp_max_val;
+
+ val0 = cvRound(x0);
+ t = (val0 >> EXPTAB_SCALE) + 1023;
+ t = (t | ((t < 2047) - 1)) & (((t < 0) - 1) & 2047);
+
+ buf[0].i.hi = t << 20;
+ x0 = (x0 - val0)*exp_postscale;
+
+ y[i] = buf[0].d * icvExpTab[val0 & EXPTAB_MASK] * EXPPOLY( x0 );
+ }
+
+ return CV_OK;
+}
+
+#undef EXPTAB_SCALE
+#undef EXPTAB_MASK
+#undef EXPPOLY_32F_A0
+
+CV_IMPL void cvExp( const CvArr* srcarr, CvArr* dstarr )
+{
+ CV_FUNCNAME( "cvExp" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ int coi1 = 0, coi2 = 0, src_depth, dst_depth;
+ double* buffer = 0;
+ CvSize size;
+ int x, y, dx = 0;
+
+ if( !CV_IS_MAT(src))
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
+
+ if( !CV_IS_MAT(dst))
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ src_depth = CV_MAT_DEPTH(src->type);
+ dst_depth = CV_MAT_DEPTH(dst->type);
+
+ if( !CV_ARE_CNS_EQ( src, dst ) || src_depth < CV_32F || dst_depth < src_depth )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ size = cvGetMatSize(src);
+ size.width *= CV_MAT_CN(src->type);
+
+ if( CV_IS_MAT_CONT( src->type & dst->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ }
+
+ if( !CV_ARE_DEPTHS_EQ( src, dst ))
+ {
+ dx = MIN( 1024, size.width );
+ buffer = (double*)cvStackAlloc( dx*sizeof(buffer[0]) );
+ }
+
+ for( y = 0; y < size.height; y++ )
+ {
+ uchar* src_data = src->data.ptr + src->step*y;
+ uchar* dst_data = dst->data.ptr + dst->step*y;
+
+ if( src_depth == CV_64F )
+ {
+ icvExp_64f( (double*)src_data, (double*)dst_data, size.width );
+ }
+ else if( src_depth == dst_depth )
+ {
+ icvExp_32f( (float*)src_data, (float*)dst_data, size.width );
+ }
+ else
+ {
+ for( x = 0; x < size.width; x += dx )
+ {
+ int len = dx;
+ if( x + len > size.width )
+ len = size.width - x;
+ icvCvt_32f64f( (float*)src_data + x, buffer, len );
+ icvExp_64f( buffer, (double*)dst_data + x, len );
+ }
+ }
+ }
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* L O G *
+\****************************************************************************************/
+
+#define LOGTAB_SCALE 8
+#define LOGTAB_MASK ((1 << LOGTAB_SCALE) - 1)
+#define LOGTAB_MASK2 ((1 << (20 - LOGTAB_SCALE)) - 1)
+#define LOGTAB_MASK2_32F ((1 << (23 - LOGTAB_SCALE)) - 1)
+
+static const double icvLogTab[] = {
+0.0000000000000000000000000000000000000000, 1.000000000000000000000000000000000000000,
+.00389864041565732288852075271279318258166, .9961089494163424124513618677042801556420,
+.00778214044205494809292034119607706088573, .9922480620155038759689922480620155038760,
+.01165061721997527263705585198749759001657, .9884169884169884169884169884169884169884,
+.01550418653596525274396267235488267033361, .9846153846153846153846153846153846153846,
+.01934296284313093139406447562578250654042, .9808429118773946360153256704980842911877,
+.02316705928153437593630670221500622574241, .9770992366412213740458015267175572519084,
+.02697658769820207233514075539915211265906, .9733840304182509505703422053231939163498,
+.03077165866675368732785500469617545604706, .9696969696969696969696969696969696969697,
+.03455238150665972812758397481047722976656, .9660377358490566037735849056603773584906,
+.03831886430213659461285757856785494368522, .9624060150375939849624060150375939849624,
+.04207121392068705056921373852674150839447, .9588014981273408239700374531835205992509,
+.04580953603129420126371940114040626212953, .9552238805970149253731343283582089552239,
+.04953393512227662748292900118940451648088, .9516728624535315985130111524163568773234,
+.05324451451881227759255210685296333394944, .9481481481481481481481481481481481481481,
+.05694137640013842427411105973078520037234, .9446494464944649446494464944649446494465,
+.06062462181643483993820353816772694699466, .9411764705882352941176470588235294117647,
+.06429435070539725460836422143984236754475, .9377289377289377289377289377289377289377,
+.06795066190850773679699159401934593915938, .9343065693430656934306569343065693430657,
+.07159365318700880442825962290953611955044, .9309090909090909090909090909090909090909,
+.07522342123758751775142172846244648098944, .9275362318840579710144927536231884057971,
+.07884006170777602129362549021607264876369, .9241877256317689530685920577617328519856,
+.08244366921107458556772229485432035289706, .9208633093525179856115107913669064748201,
+.08603433734180314373940490213499288074675, .9175627240143369175627240143369175627240,
+.08961215868968712416897659522874164395031, .9142857142857142857142857142857142857143,
+.09317722485418328259854092721070628613231, .9110320284697508896797153024911032028470,
+.09672962645855109897752299730200320482256, .9078014184397163120567375886524822695035,
+.10026945316367513738597949668474029749630, .9045936395759717314487632508833922261484,
+.10379679368164355934833764649738441221420, .9014084507042253521126760563380281690141,
+.10731173578908805021914218968959175981580, .8982456140350877192982456140350877192982,
+.11081436634029011301105782649756292812530, .8951048951048951048951048951048951048951,
+.11430477128005862852422325204315711744130, .8919860627177700348432055749128919860627,
+.11778303565638344185817487641543266363440, .8888888888888888888888888888888888888889,
+.12124924363286967987640707633545389398930, .8858131487889273356401384083044982698962,
+.12470347850095722663787967121606925502420, .8827586206896551724137931034482758620690,
+.12814582269193003360996385708858724683530, .8797250859106529209621993127147766323024,
+.13157635778871926146571524895989568904040, .8767123287671232876712328767123287671233,
+.13499516453750481925766280255629681050780, .8737201365187713310580204778156996587031,
+.13840232285911913123754857224412262439730, .8707482993197278911564625850340136054422,
+.14179791186025733629172407290752744302150, .8677966101694915254237288135593220338983,
+.14518200984449788903951628071808954700830, .8648648648648648648648648648648648648649,
+.14855469432313711530824207329715136438610, .8619528619528619528619528619528619528620,
+.15191604202584196858794030049466527998450, .8590604026845637583892617449664429530201,
+.15526612891112392955683674244937719777230, .8561872909698996655518394648829431438127,
+.15860503017663857283636730244325008243330, .8533333333333333333333333333333333333333,
+.16193282026931324346641360989451641216880, .8504983388704318936877076411960132890365,
+.16524957289530714521497145597095368430010, .8476821192052980132450331125827814569536,
+.16855536102980664403538924034364754334090, .8448844884488448844884488448844884488449,
+.17185025692665920060697715143760433420540, .8421052631578947368421052631578947368421,
+.17513433212784912385018287750426679849630, .8393442622950819672131147540983606557377,
+.17840765747281828179637841458315961062910, .8366013071895424836601307189542483660131,
+.18167030310763465639212199675966985523700, .8338762214983713355048859934853420195440,
+.18492233849401198964024217730184318497780, .8311688311688311688311688311688311688312,
+.18816383241818296356839823602058459073300, .8284789644012944983818770226537216828479,
+.19139485299962943898322009772527962923050, .8258064516129032258064516129032258064516,
+.19461546769967164038916962454095482826240, .8231511254019292604501607717041800643087,
+.19782574332991986754137769821682013571260, .8205128205128205128205128205128205128205,
+.20102574606059073203390141770796617493040, .8178913738019169329073482428115015974441,
+.20421554142869088876999228432396193966280, .8152866242038216560509554140127388535032,
+.20739519434607056602715147164417430758480, .8126984126984126984126984126984126984127,
+.21056476910734961416338251183333341032260, .8101265822784810126582278481012658227848,
+.21372432939771812687723695489694364368910, .8075709779179810725552050473186119873817,
+.21687393830061435506806333251006435602900, .8050314465408805031446540880503144654088,
+.22001365830528207823135744547471404075630, .8025078369905956112852664576802507836991,
+.22314355131420973710199007200571941211830, .8000000000000000000000000000000000000000,
+.22626367865045338145790765338460914790630, .7975077881619937694704049844236760124611,
+.22937410106484582006380890106811420992010, .7950310559006211180124223602484472049689,
+.23247487874309405442296849741978803649550, .7925696594427244582043343653250773993808,
+.23556607131276688371634975283086532726890, .7901234567901234567901234567901234567901,
+.23864773785017498464178231643018079921600, .7876923076923076923076923076923076923077,
+.24171993688714515924331749374687206000090, .7852760736196319018404907975460122699387,
+.24478272641769091566565919038112042471760, .7828746177370030581039755351681957186544,
+.24783616390458124145723672882013488560910, .7804878048780487804878048780487804878049,
+.25088030628580937353433455427875742316250, .7781155015197568389057750759878419452888,
+.25391520998096339667426946107298135757450, .7757575757575757575757575757575757575758,
+.25694093089750041913887912414793390780680, .7734138972809667673716012084592145015106,
+.25995752443692604627401010475296061486000, .7710843373493975903614457831325301204819,
+.26296504550088134477547896494797896593800, .7687687687687687687687687687687687687688,
+.26596354849713793599974565040611196309330, .7664670658682634730538922155688622754491,
+.26895308734550393836570947314612567424780, .7641791044776119402985074626865671641791,
+.27193371548364175804834985683555714786050, .7619047619047619047619047619047619047619,
+.27490548587279922676529508862586226314300, .7596439169139465875370919881305637982196,
+.27786845100345625159121709657483734190480, .7573964497041420118343195266272189349112,
+.28082266290088775395616949026589281857030, .7551622418879056047197640117994100294985,
+.28376817313064456316240580235898960381750, .7529411764705882352941176470588235294118,
+.28670503280395426282112225635501090437180, .7507331378299120234604105571847507331378,
+.28963329258304265634293983566749375313530, .7485380116959064327485380116959064327485,
+.29255300268637740579436012922087684273730, .7463556851311953352769679300291545189504,
+.29546421289383584252163927885703742504130, .7441860465116279069767441860465116279070,
+.29836697255179722709783618483925238251680, .7420289855072463768115942028985507246377,
+.30126133057816173455023545102449133992200, .7398843930635838150289017341040462427746,
+.30414733546729666446850615102448500692850, .7377521613832853025936599423631123919308,
+.30702503529491181888388950937951449304830, .7356321839080459770114942528735632183908,
+.30989447772286465854207904158101882785550, .7335243553008595988538681948424068767908,
+.31275571000389684739317885942000430077330, .7314285714285714285714285714285714285714,
+.31560877898630329552176476681779604405180, .7293447293447293447293447293447293447293,
+.31845373111853458869546784626436419785030, .7272727272727272727272727272727272727273,
+.32129061245373424782201254856772720813750, .7252124645892351274787535410764872521246,
+.32411946865421192853773391107097268104550, .7231638418079096045197740112994350282486,
+.32694034499585328257253991068864706903700, .7211267605633802816901408450704225352113,
+.32975328637246797969240219572384376078850, .7191011235955056179775280898876404494382,
+.33255833730007655635318997155991382896900, .7170868347338935574229691876750700280112,
+.33535554192113781191153520921943709254280, .7150837988826815642458100558659217877095,
+.33814494400871636381467055798566434532400, .7130919220055710306406685236768802228412,
+.34092658697059319283795275623560883104800, .7111111111111111111111111111111111111111,
+.34370051385331840121395430287520866841080, .7091412742382271468144044321329639889197,
+.34646676734620857063262633346312213689100, .7071823204419889502762430939226519337017,
+.34922538978528827602332285096053965389730, .7052341597796143250688705234159779614325,
+.35197642315717814209818925519357435405250, .7032967032967032967032967032967032967033,
+.35471990910292899856770532096561510115850, .7013698630136986301369863013698630136986,
+.35745588892180374385176833129662554711100, .6994535519125683060109289617486338797814,
+.36018440357500774995358483465679455548530, .6975476839237057220708446866485013623978,
+.36290549368936841911903457003063522279280, .6956521739130434782608695652173913043478,
+.36561919956096466943762379742111079394830, .6937669376693766937669376693766937669377,
+.36832556115870762614150635272380895912650, .6918918918918918918918918918918918918919,
+.37102461812787262962487488948681857436900, .6900269541778975741239892183288409703504,
+.37371640979358405898480555151763837784530, .6881720430107526881720430107526881720430,
+.37640097516425302659470730759494472295050, .6863270777479892761394101876675603217158,
+.37907835293496944251145919224654790014030, .6844919786096256684491978609625668449198,
+.38174858149084833769393299007788300514230, .6826666666666666666666666666666666666667,
+.38441169891033200034513583887019194662580, .6808510638297872340425531914893617021277,
+.38706774296844825844488013899535872042180, .6790450928381962864721485411140583554377,
+.38971675114002518602873692543653305619950, .6772486772486772486772486772486772486772,
+.39235876060286384303665840889152605086580, .6754617414248021108179419525065963060686,
+.39499380824086893770896722344332374632350, .6736842105263157894736842105263157894737,
+.39762193064713846624158577469643205404280, .6719160104986876640419947506561679790026,
+.40024316412701266276741307592601515352730, .6701570680628272251308900523560209424084,
+.40285754470108348090917615991202183067800, .6684073107049608355091383812010443864230,
+.40546510810816432934799991016916465014230, .6666666666666666666666666666666666666667,
+.40806588980822172674223224930756259709600, .6649350649350649350649350649350649350649,
+.41065992498526837639616360320360399782650, .6632124352331606217616580310880829015544,
+.41324724855021932601317757871584035456180, .6614987080103359173126614987080103359173,
+.41582789514371093497757669865677598863850, .6597938144329896907216494845360824742268,
+.41840189913888381489925905043492093682300, .6580976863753213367609254498714652956298,
+.42096929464412963239894338585145305842150, .6564102564102564102564102564102564102564,
+.42353011550580327293502591601281892508280, .6547314578005115089514066496163682864450,
+.42608439531090003260516141381231136620050, .6530612244897959183673469387755102040816,
+.42863216738969872610098832410585600882780, .6513994910941475826972010178117048346056,
+.43117346481837132143866142541810404509300, .6497461928934010152284263959390862944162,
+.43370832042155937902094819946796633303180, .6481012658227848101265822784810126582278,
+.43623676677491801667585491486534010618930, .6464646464646464646464646464646464646465,
+.43875883620762790027214350629947148263450, .6448362720403022670025188916876574307305,
+.44127456080487520440058801796112675219780, .6432160804020100502512562814070351758794,
+.44378397241030093089975139264424797147500, .6416040100250626566416040100250626566416,
+.44628710262841947420398014401143882423650, .6400000000000000000000000000000000000000,
+.44878398282700665555822183705458883196130, .6384039900249376558603491271820448877805,
+.45127464413945855836729492693848442286250, .6368159203980099502487562189054726368159,
+.45375911746712049854579618113348260521900, .6352357320099255583126550868486352357320,
+.45623743348158757315857769754074979573500, .6336633663366336633663366336633663366337,
+.45870962262697662081833982483658473938700, .6320987654320987654320987654320987654321,
+.46117571512217014895185229761409573256980, .6305418719211822660098522167487684729064,
+.46363574096303250549055974261136725544930, .6289926289926289926289926289926289926290,
+.46608972992459918316399125615134835243230, .6274509803921568627450980392156862745098,
+.46853771156323925639597405279346276074650, .6259168704156479217603911980440097799511,
+.47097971521879100631480241645476780831830, .6243902439024390243902439024390243902439,
+.47341577001667212165614273544633761048330, .6228710462287104622871046228710462287105,
+.47584590486996386493601107758877333253630, .6213592233009708737864077669902912621359,
+.47827014848147025860569669930555392056700, .6198547215496368038740920096852300242131,
+.48068852934575190261057286988943815231330, .6183574879227053140096618357487922705314,
+.48310107575113581113157579238759353756900, .6168674698795180722891566265060240963855,
+.48550781578170076890899053978500887751580, .6153846153846153846153846153846153846154,
+.48790877731923892879351001283794175833480, .6139088729016786570743405275779376498801,
+.49030398804519381705802061333088204264650, .6124401913875598086124401913875598086124,
+.49269347544257524607047571407747454941280, .6109785202863961813842482100238663484487,
+.49507726679785146739476431321236304938800, .6095238095238095238095238095238095238095,
+.49745538920281889838648226032091770321130, .6080760095011876484560570071258907363420,
+.49982786955644931126130359189119189977650, .6066350710900473933649289099526066350711,
+.50219473456671548383667413872899487614650, .6052009456264775413711583924349881796690,
+.50455601075239520092452494282042607665050, .6037735849056603773584905660377358490566,
+.50691172444485432801997148999362252652650, .6023529411764705882352941176470588235294,
+.50926190178980790257412536448100581765150, .6009389671361502347417840375586854460094,
+.51160656874906207391973111953120678663250, .5995316159250585480093676814988290398126,
+.51394575110223428282552049495279788970950, .5981308411214953271028037383177570093458,
+.51627947444845445623684554448118433356300, .5967365967365967365967365967365967365967,
+.51860776420804555186805373523384332656850, .5953488372093023255813953488372093023256,
+.52093064562418522900344441950437612831600, .5939675174013921113689095127610208816705,
+.52324814376454775732838697877014055848100, .5925925925925925925925925925925925925926,
+.52556028352292727401362526507000438869000, .5912240184757505773672055427251732101617,
+.52786708962084227803046587723656557500350, .5898617511520737327188940092165898617512,
+.53016858660912158374145519701414741575700, .5885057471264367816091954022988505747126,
+.53246479886947173376654518506256863474850, .5871559633027522935779816513761467889908,
+.53475575061602764748158733709715306758900, .5858123569794050343249427917620137299771,
+.53704146589688361856929077475797384977350, .5844748858447488584474885844748858447489,
+.53932196859560876944783558428753167390800, .5831435079726651480637813211845102505695,
+.54159728243274429804188230264117009937750, .5818181818181818181818181818181818181818,
+.54386743096728351609669971367111429572100, .5804988662131519274376417233560090702948,
+.54613243759813556721383065450936555862450, .5791855203619909502262443438914027149321,
+.54839232556557315767520321969641372561450, .5778781038374717832957110609480812641084,
+.55064711795266219063194057525834068655950, .5765765765765765765765765765765765765766,
+.55289683768667763352766542084282264113450, .5752808988764044943820224719101123595506,
+.55514150754050151093110798683483153581600, .5739910313901345291479820627802690582960,
+.55738115013400635344709144192165695130850, .5727069351230425055928411633109619686801,
+.55961578793542265941596269840374588966350, .5714285714285714285714285714285714285714,
+.56184544326269181269140062795486301183700, .5701559020044543429844097995545657015590,
+.56407013828480290218436721261241473257550, .5688888888888888888888888888888888888889,
+.56628989502311577464155334382667206227800, .5676274944567627494456762749445676274945,
+.56850473535266865532378233183408156037350, .5663716814159292035398230088495575221239,
+.57071468100347144680739575051120482385150, .5651214128035320088300220750551876379691,
+.57291975356178548306473885531886480748650, .5638766519823788546255506607929515418502,
+.57511997447138785144460371157038025558000, .5626373626373626373626373626373626373626,
+.57731536503482350219940144597785547375700, .5614035087719298245614035087719298245614,
+.57950594641464214795689713355386629700650, .5601750547045951859956236323851203501094,
+.58169173963462239562716149521293118596100, .5589519650655021834061135371179039301310,
+.58387276558098266665552955601015128195300, .5577342047930283224400871459694989106754,
+.58604904500357812846544902640744112432000, .5565217391304347826086956521739130434783,
+.58822059851708596855957011939608491957200, .5553145336225596529284164859002169197397,
+.59038744660217634674381770309992134571100, .5541125541125541125541125541125541125541,
+.59254960960667157898740242671919986605650, .5529157667386609071274298056155507559395,
+.59470710774669277576265358220553025603300, .5517241379310344827586206896551724137931,
+.59685996110779382384237123915227130055450, .5505376344086021505376344086021505376344,
+.59900818964608337768851242799428291618800, .5493562231759656652360515021459227467811,
+.60115181318933474940990890900138765573500, .5481798715203426124197002141327623126338,
+.60329085143808425240052883964381180703650, .5470085470085470085470085470085470085470,
+.60542532396671688843525771517306566238400, .5458422174840085287846481876332622601279,
+.60755525022454170969155029524699784815300, .5446808510638297872340425531914893617021,
+.60968064953685519036241657886421307921400, .5435244161358811040339702760084925690021,
+.61180154110599282990534675263916142284850, .5423728813559322033898305084745762711864,
+.61391794401237043121710712512140162289150, .5412262156448202959830866807610993657505,
+.61602987721551394351138242200249806046500, .5400843881856540084388185654008438818565,
+.61813735955507864705538167982012964785100, .5389473684210526315789473684210526315789,
+.62024040975185745772080281312810257077200, .5378151260504201680672268907563025210084,
+.62233904640877868441606324267922900617100, .5366876310272536687631027253668763102725,
+.62443328801189346144440150965237990021700, .5355648535564853556485355648535564853556,
+.62652315293135274476554741340805776417250, .5344467640918580375782881002087682672234,
+.62860865942237409420556559780379757285100, .5333333333333333333333333333333333333333,
+.63068982562619868570408243613201193511500, .5322245322245322245322245322245322245322,
+.63276666957103777644277897707070223987100, .5311203319502074688796680497925311203320,
+.63483920917301017716738442686619237065300, .5300207039337474120082815734989648033126,
+.63690746223706917739093569252872839570050, .5289256198347107438016528925619834710744,
+.63897144645792069983514238629140891134750, .5278350515463917525773195876288659793814,
+.64103117942093124081992527862894348800200, .5267489711934156378600823045267489711934,
+.64308667860302726193566513757104985415950, .5256673511293634496919917864476386036961,
+.64513796137358470073053240412264131009600, .5245901639344262295081967213114754098361,
+.64718504499530948859131740391603671014300, .5235173824130879345603271983640081799591,
+.64922794662510974195157587018911726772800, .5224489795918367346938775510204081632653,
+.65126668331495807251485530287027359008800, .5213849287169042769857433808553971486762,
+.65330127201274557080523663898929953575150, .5203252032520325203252032520325203252033,
+.65533172956312757406749369692988693714150, .5192697768762677484787018255578093306288,
+.65735807270835999727154330685152672231200, .5182186234817813765182186234817813765182,
+.65938031808912778153342060249997302889800, .5171717171717171717171717171717171717172,
+.66139848224536490484126716182800009846700, .5161290322580645161290322580645161290323,
+.66341258161706617713093692145776003599150, .5150905432595573440643863179074446680080,
+.66542263254509037562201001492212526500250, .5140562248995983935742971887550200803213,
+.66742865127195616370414654738851822912700, .5130260521042084168336673346693386773547,
+.66943065394262923906154583164607174694550, .5120000000000000000000000000000000000000,
+.67142865660530226534774556057527661323550, .5109780439121756487025948103792415169661,
+.67342267521216669923234121597488410770900, .5099601593625498007968127490039840637450,
+.67541272562017662384192817626171745359900, .5089463220675944333996023856858846918489,
+.67739882359180603188519853574689477682100, .5079365079365079365079365079365079365079,
+.67938098479579733801614338517538271844400, .5069306930693069306930693069306930693069,
+.68135922480790300781450241629499942064300, .5059288537549407114624505928853754940711,
+.68333355911162063645036823800182901322850, .5049309664694280078895463510848126232742,
+.68530400309891936760919861626462079584600, .5039370078740157480314960629921259842520,
+.68727057207096020619019327568821609020250, .5029469548133595284872298624754420432220,
+.68923328123880889251040571252815425395950, .5019607843137254901960784313725490196078,
+.69314718055994530941723212145818, 5.0e-01,
+};
+
+
+
+#define LOGTAB_TRANSLATE(x,h) (((x) - 1.)*icvLogTab[(h)+1])
+static const double ln_2 = 0.69314718055994530941723212145818;
+
+IPCVAPI_IMPL( CvStatus, icvLog_32f, ( const float *_x, float *y, int n ), (_x, y, n) )
+{
+ static const double shift[] = { 0, -1./512 };
+ static const double
+ A0 = 0.3333333333333333333333333,
+ A1 = -0.5,
+ A2 = 1;
+
+ #undef LOGPOLY
+ #define LOGPOLY(x,k) ((x)+=shift[k],((A0*(x) + A1)*(x) + A2)*(x))
+
+ int i = 0;
+ union
+ {
+ int i;
+ float f;
+ }
+ buf[4];
+
+ const int* x = (const int*)_x;
+
+ if( !x || !y )
+ return CV_NULLPTR_ERR;
+ if( n <= 0 )
+ return CV_BADSIZE_ERR;
+
+ for( i = 0; i <= n - 4; i += 4 )
+ {
+ double x0, x1, x2, x3;
+ double y0, y1, y2, y3;
+ int h0, h1, h2, h3;
+
+ h0 = x[i];
+ h1 = x[i+1];
+ buf[0].i = (h0 & LOGTAB_MASK2_32F) | (127 << 23);
+ buf[1].i = (h1 & LOGTAB_MASK2_32F) | (127 << 23);
+
+ y0 = (((h0 >> 23) & 0xff) - 127) * ln_2;
+ y1 = (((h1 >> 23) & 0xff) - 127) * ln_2;
+
+ h0 = (h0 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
+ h1 = (h1 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
+
+ y0 += icvLogTab[h0];
+ y1 += icvLogTab[h1];
+
+ h2 = x[i+2];
+ h3 = x[i+3];
+
+ x0 = LOGTAB_TRANSLATE( buf[0].f, h0 );
+ x1 = LOGTAB_TRANSLATE( buf[1].f, h1 );
+
+ buf[2].i = (h2 & LOGTAB_MASK2_32F) | (127 << 23);
+ buf[3].i = (h3 & LOGTAB_MASK2_32F) | (127 << 23);
+
+ y2 = (((h2 >> 23) & 0xff) - 127) * ln_2;
+ y3 = (((h3 >> 23) & 0xff) - 127) * ln_2;
+
+ h2 = (h2 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
+ h3 = (h3 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
+
+ y2 += icvLogTab[h2];
+ y3 += icvLogTab[h3];
+
+ x2 = LOGTAB_TRANSLATE( buf[2].f, h2 );
+ x3 = LOGTAB_TRANSLATE( buf[3].f, h3 );
+
+ y0 += LOGPOLY( x0, h0 == 510 );
+ y1 += LOGPOLY( x1, h1 == 510 );
+
+ y[i] = (float) y0;
+ y[i + 1] = (float) y1;
+
+ y2 += LOGPOLY( x2, h2 == 510 );
+ y3 += LOGPOLY( x3, h3 == 510 );
+
+ y[i + 2] = (float) y2;
+ y[i + 3] = (float) y3;
+ }
+
+ for( ; i < n; i++ )
+ {
+ int h0 = x[i];
+ double x0, y0;
+
+ y0 = (((h0 >> 23) & 0xff) - 127) * ln_2;
+
+ buf[0].i = (h0 & LOGTAB_MASK2_32F) | (127 << 23);
+ h0 = (h0 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
+
+ y0 += icvLogTab[h0];
+ x0 = LOGTAB_TRANSLATE( buf[0].f, h0 );
+ y0 += LOGPOLY( x0, h0 == 510 );
+
+ y[i] = (float)y0;
+ }
+
+ return CV_OK;
+}
+
+
+IPCVAPI_IMPL( CvStatus, icvLog_64f, ( const double *x, double *y, int n ), (x, y, n) )
+{
+ static const double shift[] = { 0, -1./512 };
+ static const double
+ A0 = -.1666666666666666666666666666666666666666,
+ A1 = +0.2,
+ A2 = -0.25,
+ A3 = +0.3333333333333333333333333333333333333333,
+ A4 = -0.5,
+ A5 = +1.0;
+
+ #undef LOGPOLY
+ #define LOGPOLY(x,k) ((x)+=shift[k], (xq) = (x)*(x),\
+ ((A0*(xq) + A2)*(xq) + A4)*(xq) + ((A1*(xq) + A3)*(xq) + A5)*(x))
+
+ int i = 0;
+ DBLINT buf[4];
+ DBLINT *X = (DBLINT *) x;
+
+ if( !x || !y )
+ return CV_NULLPTR_ERR;
+ if( n <= 0 )
+ return CV_BADSIZE_ERR;
+
+ for( ; i <= n - 4; i += 4 )
+ {
+ double xq;
+ double x0, x1, x2, x3;
+ double y0, y1, y2, y3;
+ int h0, h1, h2, h3;
+
+ h0 = X[i].i.lo;
+ h1 = X[i + 1].i.lo;
+ buf[0].i.lo = h0;
+ buf[1].i.lo = h1;
+
+ h0 = X[i].i.hi;
+ h1 = X[i + 1].i.hi;
+ buf[0].i.hi = (h0 & LOGTAB_MASK2) | (1023 << 20);
+ buf[1].i.hi = (h1 & LOGTAB_MASK2) | (1023 << 20);
+
+ y0 = (((h0 >> 20) & 0x7ff) - 1023) * ln_2;
+ y1 = (((h1 >> 20) & 0x7ff) - 1023) * ln_2;
+
+ h2 = X[i + 2].i.lo;
+ h3 = X[i + 3].i.lo;
+ buf[2].i.lo = h2;
+ buf[3].i.lo = h3;
+
+ h0 = (h0 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
+ h1 = (h1 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
+
+ y0 += icvLogTab[h0];
+ y1 += icvLogTab[h1];
+
+ h2 = X[i + 2].i.hi;
+ h3 = X[i + 3].i.hi;
+
+ x0 = LOGTAB_TRANSLATE( buf[0].d, h0 );
+ x1 = LOGTAB_TRANSLATE( buf[1].d, h1 );
+
+ buf[2].i.hi = (h2 & LOGTAB_MASK2) | (1023 << 20);
+ buf[3].i.hi = (h3 & LOGTAB_MASK2) | (1023 << 20);
+
+ y2 = (((h2 >> 20) & 0x7ff) - 1023) * ln_2;
+ y3 = (((h3 >> 20) & 0x7ff) - 1023) * ln_2;
+
+ h2 = (h2 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
+ h3 = (h3 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
+
+ y2 += icvLogTab[h2];
+ y3 += icvLogTab[h3];
+
+ x2 = LOGTAB_TRANSLATE( buf[2].d, h2 );
+ x3 = LOGTAB_TRANSLATE( buf[3].d, h3 );
+
+ y0 += LOGPOLY( x0, h0 == 510 );
+ y1 += LOGPOLY( x1, h1 == 510 );
+
+ y[i] = y0;
+ y[i + 1] = y1;
+
+ y2 += LOGPOLY( x2, h2 == 510 );
+ y3 += LOGPOLY( x3, h3 == 510 );
+
+ y[i + 2] = y2;
+ y[i + 3] = y3;
+ }
+
+ for( ; i < n; i++ )
+ {
+ int h0 = X[i].i.hi;
+ double xq;
+ double x0, y0 = (((h0 >> 20) & 0x7ff) - 1023) * ln_2;
+
+ buf[0].i.hi = (h0 & LOGTAB_MASK2) | (1023 << 20);
+ buf[0].i.lo = X[i].i.lo;
+ h0 = (h0 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
+
+ y0 += icvLogTab[h0];
+ x0 = LOGTAB_TRANSLATE( buf[0].d, h0 );
+ y0 += LOGPOLY( x0, h0 == 510 );
+ y[i] = y0;
+ }
+
+ return CV_OK;
+}
+
+
+CV_IMPL void cvLog( const CvArr* srcarr, CvArr* dstarr )
+{
+ CV_FUNCNAME( "cvLog" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ int coi1 = 0, coi2 = 0, src_depth, dst_depth;
+ double* buffer = 0;
+ CvSize size;
+ int x, y, dx = 0;
+
+ if( !CV_IS_MAT(src))
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
+
+ if( !CV_IS_MAT(dst))
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ src_depth = CV_MAT_DEPTH(src->type);
+ dst_depth = CV_MAT_DEPTH(dst->type);
+
+ if( !CV_ARE_CNS_EQ( src, dst ) || dst_depth < CV_32F || src_depth < dst_depth )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ size = cvGetMatSize(src);
+ size.width *= CV_MAT_CN(src->type);
+
+ if( CV_IS_MAT_CONT( src->type & dst->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ }
+
+ if( !CV_ARE_DEPTHS_EQ( src, dst ))
+ {
+ dx = MIN( 1024, size.width );
+ buffer = (double*)cvStackAlloc( dx*sizeof(buffer[0]) );
+ }
+
+ for( y = 0; y < size.height; y++ )
+ {
+ uchar* src_data = src->data.ptr + src->step*y;
+ uchar* dst_data = dst->data.ptr + dst->step*y;
+
+ if( dst_depth == CV_64F )
+ {
+ icvLog_64f( (double*)src_data, (double*)dst_data, size.width );
+ }
+ else if( src_depth == dst_depth )
+ {
+ icvLog_32f( (float*)src_data, (float*)dst_data, size.width );
+ }
+ else
+ {
+ for( x = 0; x < size.width; x += dx )
+ {
+ int len = dx;
+ if( x + len > size.width )
+ len = size.width - x;
+ icvLog_64f( (double*)src_data + x, buffer, len );
+ icvCvt_64f32f( buffer, (float*)dst_data + x, len );
+ }
+ }
+ }
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* P O W E R *
+\****************************************************************************************/
+
+#define ICV_DEF_IPOW_OP( flavor, arrtype, worktype, cast_macro ) \
+static CvStatus CV_STDCALL \
+icvIPow_##flavor( const arrtype* src, arrtype* dst, int len, int power ) \
+{ \
+ int i; \
+ \
+ for( i = 0; i < len; i++ ) \
+ { \
+ worktype a = 1, b = src[i]; \
+ int p = power; \
+ while( p > 1 ) \
+ { \
+ if( p & 1 ) \
+ a *= b; \
+ b *= b; \
+ p >>= 1; \
+ } \
+ \
+ a *= b; \
+ dst[i] = cast_macro(a); \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_IPOW_OP( 8u, uchar, int, CV_CAST_8U )
+ICV_DEF_IPOW_OP( 16u, ushort, int, CV_CAST_16U )
+ICV_DEF_IPOW_OP( 16s, short, int, CV_CAST_16S )
+ICV_DEF_IPOW_OP( 32s, int, int, CV_CAST_32S )
+ICV_DEF_IPOW_OP( 32f, float, double, CV_CAST_32F )
+ICV_DEF_IPOW_OP( 64f, double, double, CV_CAST_64F )
+
+#define icvIPow_8s 0
+
+CV_DEF_INIT_FUNC_TAB_1D( IPow )
+
+typedef CvStatus (CV_STDCALL * CvIPowFunc)( const void* src, void* dst, int len, int power );
+typedef CvStatus (CV_STDCALL * CvSqrtFunc)( const void* src, void* dst, int len );
+
+CV_IMPL void cvPow( const CvArr* srcarr, CvArr* dstarr, double power )
+{
+ static CvFuncTable ipow_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvPow" );
+
+ __BEGIN__;
+
+ void* temp_buffer = 0;
+ int block_size = 0;
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ int coi1 = 0, coi2 = 0;
+ int depth;
+ CvSize size;
+ int x, y;
+ int ipower = cvRound( power );
+ int is_ipower = 0;
+
+ if( !CV_IS_MAT(src))
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi1 ));
+
+ if( !CV_IS_MAT(dst))
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
+
+ if( coi1 != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedFormats );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ) )
+ CV_ERROR_FROM_CODE( CV_StsUnmatchedSizes );
+
+ depth = CV_MAT_DEPTH( src->type );
+
+ if( fabs(ipower - power) < DBL_EPSILON )
+ {
+ if( !inittab )
+ {
+ icvInitIPowTable( &ipow_tab );
+ inittab = 1;
+ }
+
+ if( ipower < 0 )
+ {
+ CV_CALL( cvDiv( 0, src, dst ));
+
+ if( ipower == -1 )
+ EXIT;
+ ipower = -ipower;
+ src = dst;
+ }
+
+ switch( ipower )
+ {
+ case 0:
+ cvSet( dst, cvScalarAll(1));
+ EXIT;
+ case 1:
+ cvCopy( src, dst );
+ EXIT;
+ case 2:
+ cvMul( src, src, dst );
+ EXIT;
+ default:
+ is_ipower = 1;
+ }
+ }
+ else if( depth < CV_32F )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Fractional or negative integer power factor can be used "
+ "with floating-point types only");
+
+ size = cvGetMatSize(src);
+ size.width *= CV_MAT_CN(src->type);
+
+ if( CV_IS_MAT_CONT( src->type & dst->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ }
+
+ if( is_ipower )
+ {
+ CvIPowFunc pow_func = (CvIPowFunc)ipow_tab.fn_2d[depth];
+ if( !pow_func )
+ CV_ERROR( CV_StsUnsupportedFormat, "The data type is not supported" );
+
+ for( y = 0; y < size.height; y++ )
+ {
+ uchar* src_data = src->data.ptr + src->step*y;
+ uchar* dst_data = dst->data.ptr + dst->step*y;
+
+ pow_func( src_data, dst_data, size.width, ipower );
+ }
+ }
+ else if( fabs(fabs(power) - 0.5) < DBL_EPSILON )
+ {
+ CvSqrtFunc sqrt_func = power < 0 ?
+ (depth == CV_32F ? (CvSqrtFunc)icvInvSqrt_32f : (CvSqrtFunc)icvInvSqrt_64f) :
+ (depth == CV_32F ? (CvSqrtFunc)icvSqrt_32f : (CvSqrtFunc)icvSqrt_64f);
+
+ for( y = 0; y < size.height; y++ )
+ {
+ uchar* src_data = src->data.ptr + src->step*y;
+ uchar* dst_data = dst->data.ptr + dst->step*y;
+
+ sqrt_func( src_data, dst_data, size.width );
+ }
+ }
+ else
+ {
+ block_size = MIN( size.width, ICV_MATH_BLOCK_SIZE );
+ temp_buffer = cvStackAlloc( block_size*CV_ELEM_SIZE(depth) );
+
+ for( y = 0; y < size.height; y++ )
+ {
+ uchar* src_data = src->data.ptr + src->step*y;
+ uchar* dst_data = dst->data.ptr + dst->step*y;
+
+ for( x = 0; x < size.width; x += block_size )
+ {
+ int len = MIN( size.width - x, block_size );
+ if( depth == CV_32F )
+ {
+ icvLog_32f( (float*)src_data + x, (float*)temp_buffer, len );
+ icvScale_32f( (float*)temp_buffer, (float*)temp_buffer, len, (float)power, 0 );
+ icvExp_32f( (float*)temp_buffer, (float*)dst_data + x, len );
+ }
+ else
+ {
+ icvLog_64f( (double*)src_data + x, (double*)temp_buffer, len );
+ icvScale_64f( (double*)temp_buffer, (double*)temp_buffer, len, power, 0 );
+ icvExp_64f( (double*)temp_buffer, (double*)dst_data + x, len );
+ }
+ }
+ }
+ }
+
+ __END__;
+}
+
+
+/************************** CheckArray for NaN's, Inf's *********************************/
+
+IPCVAPI_IMPL( CvStatus, icvCheckArray_32f_C1R,
+ ( const float* src, int srcstep, CvSize size, int flags, double min_val, double max_val ),
+ (src, srcstep, size, flags, min_val, max_val) )
+{
+ Cv32suf a, b;
+ int ia, ib;
+ const int* isrc = (const int*)src;
+
+ if( !src )
+ return CV_NULLPTR_ERR;
+
+ if( size.width <= 0 || size.height <= 0 )
+ return CV_BADSIZE_ERR;
+
+ if( flags & CV_CHECK_RANGE )
+ {
+ a.f = (float)min_val;
+ b.f = (float)max_val;
+ }
+ else
+ {
+ a.f = -FLT_MAX;
+ b.f = FLT_MAX;
+ }
+
+ ia = CV_TOGGLE_FLT(a.i);
+ ib = CV_TOGGLE_FLT(b.i);
+
+ srcstep /= sizeof(isrc[0]);
+ for( ; size.height--; isrc += srcstep )
+ {
+ int i;
+ for( i = 0; i < size.width; i++ )
+ {
+ int val = isrc[i];
+ val = CV_TOGGLE_FLT(val);
+
+ if( val < ia || val >= ib )
+ return CV_BADRANGE_ERR;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+IPCVAPI_IMPL( CvStatus, icvCheckArray_64f_C1R,
+ ( const double* src, int srcstep, CvSize size, int flags, double min_val, double max_val ),
+ (src, srcstep, size, flags, min_val, max_val) )
+{
+ Cv64suf a, b;
+ int64 ia, ib;
+ const int64* isrc = (const int64*)src;
+
+ if( !src )
+ return CV_NULLPTR_ERR;
+
+ if( size.width <= 0 || size.height <= 0 )
+ return CV_BADSIZE_ERR;
+
+ if( flags & CV_CHECK_RANGE )
+ {
+ a.f = min_val;
+ b.f = max_val;
+ }
+ else
+ {
+ a.f = -DBL_MAX;
+ b.f = DBL_MAX;
+ }
+
+ ia = CV_TOGGLE_DBL(a.i);
+ ib = CV_TOGGLE_DBL(b.i);
+
+ srcstep /= sizeof(isrc[0]);
+ for( ; size.height--; isrc += srcstep )
+ {
+ int i;
+ for( i = 0; i < size.width; i++ )
+ {
+ int64 val = isrc[i];
+ val = CV_TOGGLE_DBL(val);
+
+ if( val < ia || val >= ib )
+ return CV_BADRANGE_ERR;
+ }
+ }
+
+ return CV_OK;
+}
+
+
+CV_IMPL int cvCheckArr( const CvArr* arr, int flags,
+ double minVal, double maxVal )
+{
+ int result = 0;
+
+ CV_FUNCNAME( "cvCheckArr" );
+
+ __BEGIN__;
+
+ if( arr )
+ {
+ CvStatus status = CV_OK;
+ CvMat stub, *mat = (CvMat*)arr;
+ int type;
+ CvSize size;
+
+ if( !CV_IS_MAT( mat ))
+ CV_CALL( mat = cvGetMat( mat, &stub, 0, 1 ));
+
+ type = CV_MAT_TYPE( mat->type );
+ size = cvGetMatSize( mat );
+
+ size.width *= CV_MAT_CN( type );
+
+ if( CV_IS_MAT_CONT( mat->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ }
+
+ if( CV_MAT_DEPTH(type) == CV_32F )
+ {
+ status = icvCheckArray_32f_C1R( mat->data.fl, mat->step, size,
+ flags, minVal, maxVal );
+ }
+ else if( CV_MAT_DEPTH(type) == CV_64F )
+ {
+ status = icvCheckArray_64f_C1R( mat->data.db, mat->step, size,
+ flags, minVal, maxVal );
+ }
+ else
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+ }
+
+ if( status < 0 )
+ {
+ if( status != CV_BADRANGE_ERR || !(flags & CV_CHECK_QUIET))
+ CV_ERROR( CV_StsOutOfRange, "CheckArray failed" );
+ EXIT;
+ }
+ }
+
+ result = 1;
+
+ __END__;
+
+ return result;
+}
+
+
+/* End of file. */
diff --git a/cxcore/src/cxmatmul.cpp b/cxcore/src/cxmatmul.cpp
new file mode 100644
index 0000000..f6d3142
--- /dev/null
+++ b/cxcore/src/cxmatmul.cpp
@@ -0,0 +1,3378 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+
+/****************************************************************************************\
+* cvGEMM *
+\****************************************************************************************/
+
+icvBLAS_GEMM_32f_t icvBLAS_GEMM_32f_p = 0;
+icvBLAS_GEMM_64f_t icvBLAS_GEMM_64f_p = 0;
+icvBLAS_GEMM_32fc_t icvBLAS_GEMM_32fc_p = 0;
+icvBLAS_GEMM_64fc_t icvBLAS_GEMM_64fc_p = 0;
+
+static void
+icvGEMM_CopyBlock( const uchar* src, int src_step,
+ uchar* dst, int dst_step,
+ CvSize size, int pix_size )
+{
+ int j;
+ size.width = size.width * (pix_size / sizeof(int));
+
+ for( ; size.height--; src += src_step, dst += dst_step )
+ {
+ for( j = 0; j <= size.width - 4; j += 4 )
+ {
+ int t0 = ((const int*)src)[j];
+ int t1 = ((const int*)src)[j+1];
+ ((int*)dst)[j] = t0;
+ ((int*)dst)[j+1] = t1;
+ t0 = ((const int*)src)[j+2];
+ t1 = ((const int*)src)[j+3];
+ ((int*)dst)[j+2] = t0;
+ ((int*)dst)[j+3] = t1;
+ }
+
+ for( ; j < size.width; j++ )
+ ((int*)dst)[j] = ((const int*)src)[j];
+ }
+}
+
+
+static void
+icvGEMM_TransposeBlock( const uchar* src, int src_step,
+ uchar* dst, int dst_step,
+ CvSize size, int pix_size )
+{
+ int i, j;
+ for( i = 0; i < size.width; i++, dst += dst_step, src += pix_size )
+ {
+ const uchar* _src = src;
+ switch( pix_size )
+ {
+ case sizeof(int):
+ for( j = 0; j < size.height; j++, _src += src_step )
+ ((int*)dst)[j] = ((int*)_src)[0];
+ break;
+ case sizeof(int)*2:
+ for( j = 0; j < size.height*2; j += 2, _src += src_step )
+ {
+ int t0 = ((int*)_src)[0];
+ int t1 = ((int*)_src)[1];
+ ((int*)dst)[j] = t0;
+ ((int*)dst)[j+1] = t1;
+ }
+ break;
+ case sizeof(int)*4:
+ for( j = 0; j < size.height*4; j += 4, _src += src_step )
+ {
+ int t0 = ((int*)_src)[0];
+ int t1 = ((int*)_src)[1];
+ ((int*)dst)[j] = t0;
+ ((int*)dst)[j+1] = t1;
+ t0 = ((int*)_src)[2];
+ t1 = ((int*)_src)[3];
+ ((int*)dst)[j+2] = t0;
+ ((int*)dst)[j+3] = t1;
+ }
+ break;
+ default:
+ assert(0);
+ return;
+ }
+ }
+}
+
+#define ICV_DEF_GEMM_SINGLE_MUL( flavor, arrtype, worktype ) \
+static CvStatus CV_STDCALL \
+icvGEMMSingleMul_##flavor( const arrtype* a_data, size_t a_step, \
+ const arrtype* b_data, size_t b_step, \
+ const arrtype* c_data, size_t c_step, \
+ arrtype* d_data, size_t d_step, \
+ CvSize a_size, CvSize d_size, \
+ double alpha, double beta, int flags ) \
+{ \
+ int i, j, k, n = a_size.width, m = d_size.width, drows = d_size.height; \
+ const arrtype *_a_data = a_data, *_b_data = b_data, *_c_data = c_data; \
+ arrtype* a_buf = 0; \
+ size_t a_step0, a_step1, c_step0, c_step1, t_step; \
+ \
+ a_step /= sizeof(a_data[0]); \
+ b_step /= sizeof(b_data[0]); \
+ c_step /= sizeof(c_data[0]); \
+ d_step /= sizeof(d_data[0]); \
+ a_step0 = a_step; \
+ a_step1 = 1; \
+ \
+ if( !c_data ) \
+ c_step0 = c_step1 = 0; \
+ else if( !(flags & CV_GEMM_C_T) ) \
+ c_step0 = c_step, c_step1 = 1; \
+ else \
+ c_step0 = 1, c_step1 = c_step; \
+ \
+ if( flags & CV_GEMM_A_T ) \
+ { \
+ CV_SWAP( a_step0, a_step1, t_step ); \
+ n = a_size.height; \
+ if( a_step > 1 && n > 1 ) \
+ a_buf = (arrtype*)cvStackAlloc(n*sizeof(a_data[0])); \
+ } \
+ \
+ if( n == 1 ) /* external product */ \
+ { \
+ arrtype* b_buf = 0; \
+ \
+ if( a_step > 1 ) \
+ { \
+ a_buf = (arrtype*)cvStackAlloc(drows*sizeof(a_data[0])); \
+ for( k = 0; k < drows; k++ ) \
+ a_buf[k] = a_data[a_step*k]; \
+ a_data = a_buf; \
+ } \
+ \
+ if( b_step > 1 ) \
+ { \
+ b_buf = (arrtype*)cvStackAlloc(d_size.width*sizeof(b_buf[0]) ); \
+ for( j = 0; j < d_size.width; j++ ) \
+ b_buf[j] = b_data[j*b_step]; \
+ b_data = b_buf; \
+ } \
+ \
+ for( i = 0; i < drows; i++, _c_data += c_step0, \
+ d_data += d_step ) \
+ { \
+ worktype al = worktype(a_data[i])*alpha; \
+ c_data = _c_data; \
+ for( j = 0; j <= d_size.width - 2; j += 2, c_data += 2*c_step1 )\
+ { \
+ worktype s0 = al*b_data[j]; \
+ worktype s1 = al*b_data[j+1]; \
+ if( !c_data ) \
+ { \
+ d_data[j] = arrtype(s0); \
+ d_data[j+1] = arrtype(s1); \
+ } \
+ else \
+ { \
+ d_data[j] = arrtype(s0 + c_data[0]*beta); \
+ d_data[j+1] = arrtype(s1 + c_data[c_step1]*beta); \
+ } \
+ } \
+ \
+ for( ; j < d_size.width; j++, c_data += c_step1 ) \
+ { \
+ worktype s0 = al*b_data[j]; \
+ if( !c_data ) \
+ d_data[j] = arrtype(s0); \
+ else \
+ d_data[j] = arrtype(s0 + c_data[0]*beta); \
+ } \
+ } \
+ } \
+ else if( flags & CV_GEMM_B_T ) /* A * Bt */ \
+ { \
+ for( i = 0; i < drows; i++, _a_data += a_step0, \
+ _c_data += c_step0, \
+ d_data += d_step ) \
+ { \
+ a_data = _a_data; \
+ b_data = _b_data; \
+ c_data = _c_data; \
+ \
+ if( a_buf ) \
+ { \
+ for( k = 0; k < n; k++ ) \
+ a_buf[k] = a_data[a_step1*k]; \
+ a_data = a_buf; \
+ } \
+ \
+ for( j = 0; j < d_size.width; j++, b_data += b_step, \
+ c_data += c_step1 ) \
+ { \
+ worktype s0(0), s1(0), s2(0), s3(0); \
+ \
+ for( k = 0; k <= n - 4; k += 4 ) \
+ { \
+ s0 += worktype(a_data[k])*b_data[k]; \
+ s1 += worktype(a_data[k+1])*b_data[k+1]; \
+ s2 += worktype(a_data[k+2])*b_data[k+2]; \
+ s3 += worktype(a_data[k+3])*b_data[k+3]; \
+ } \
+ \
+ for( ; k < n; k++ ) \
+ s0 += worktype(a_data[k])*b_data[k]; \
+ s0 = (s0+s1+s2+s3)*alpha; \
+ \
+ if( !c_data ) \
+ d_data[j] = arrtype(s0); \
+ else \
+ d_data[j] = arrtype(s0 + c_data[0]*beta); \
+ } \
+ } \
+ } \
+ else if( d_size.width*sizeof(d_data[0]) <= 1600 ) \
+ { \
+ for( i = 0; i < drows; i++, _a_data += a_step0, \
+ _c_data += c_step0, \
+ d_data += d_step ) \
+ { \
+ a_data = _a_data, c_data = _c_data; \
+ \
+ if( a_buf ) \
+ { \
+ for( k = 0; k < n; k++ ) \
+ a_buf[k] = a_data[a_step1*k]; \
+ a_data = a_buf; \
+ } \
+ \
+ for( j = 0; j <= m - 4; j += 4, c_data += 4*c_step1 ) \
+ { \
+ const arrtype* b = _b_data + j; \
+ worktype s0(0), s1(0), s2(0), s3(0); \
+ \
+ for( k = 0; k < n; k++, b += b_step ) \
+ { \
+ worktype a(a_data[k]); \
+ s0 += a * b[0]; s1 += a * b[1]; \
+ s2 += a * b[2]; s3 += a * b[3]; \
+ } \
+ \
+ if( !c_data ) \
+ { \
+ d_data[j] = arrtype(s0*alpha); \
+ d_data[j+1] = arrtype(s1*alpha); \
+ d_data[j+2] = arrtype(s2*alpha); \
+ d_data[j+3] = arrtype(s3*alpha); \
+ } \
+ else \
+ { \
+ s0 = s0*alpha; s1 = s1*alpha; \
+ s2 = s2*alpha; s3 = s3*alpha; \
+ d_data[j] = arrtype(s0 + c_data[0]*beta); \
+ d_data[j+1] = arrtype(s1 + c_data[c_step1]*beta); \
+ d_data[j+2] = arrtype(s2 + c_data[c_step1*2]*beta); \
+ d_data[j+3] = arrtype(s3 + c_data[c_step1*3]*beta); \
+ } \
+ } \
+ \
+ for( ; j < m; j++, c_data += c_step1 ) \
+ { \
+ const arrtype* b = _b_data + j; \
+ worktype s0(0); \
+ \
+ for( k = 0; k < n; k++, b += b_step ) \
+ s0 += worktype(a_data[k]) * b[0]; \
+ \
+ s0 = s0*alpha; \
+ if( !c_data ) \
+ d_data[j] = arrtype(s0); \
+ else \
+ d_data[j] = arrtype(s0 + c_data[0]*beta); \
+ } \
+ } \
+ } \
+ else \
+ { \
+ worktype* d_buf = (worktype*)cvStackAlloc(m*sizeof(d_buf[0])); \
+ \
+ for( i = 0; i < drows; i++, _a_data += a_step0, \
+ _c_data += c_step0, \
+ d_data += d_step ) \
+ { \
+ a_data = _a_data; \
+ b_data = _b_data; \
+ c_data = _c_data; \
+ \
+ if( a_buf ) \
+ { \
+ for( k = 0; k < n; k++ ) \
+ a_buf[k] = _a_data[a_step1*k]; \
+ a_data = a_buf; \
+ } \
+ \
+ for( j = 0; j < m; j++ ) \
+ d_buf[j] = worktype(0); \
+ \
+ for( k = 0; k < n; k++, b_data += b_step ) \
+ { \
+ worktype al(a_data[k]); \
+ \
+ for( j = 0; j <= m - 4; j += 4 ) \
+ { \
+ worktype t0 = d_buf[j] + b_data[j]*al; \
+ worktype t1 = d_buf[j+1] + b_data[j+1]*al; \
+ d_buf[j] = t0; \
+ d_buf[j+1] = t1; \
+ t0 = d_buf[j+2] + b_data[j+2]*al; \
+ t1 = d_buf[j+3] + b_data[j+3]*al; \
+ d_buf[j+2] = t0; \
+ d_buf[j+3] = t1; \
+ } \
+ \
+ for( ; j < m; j++ ) \
+ d_buf[j] += b_data[j]*al; \
+ } \
+ \
+ if( !c_data ) \
+ for( j = 0; j < m; j++ ) \
+ d_data[j] = arrtype(d_buf[j]*alpha); \
+ else \
+ for( j = 0; j < m; j++, c_data += c_step1 ) \
+ { \
+ worktype t = d_buf[j]*alpha; \
+ d_data[j] = arrtype(t + c_data[0]*beta); \
+ } \
+ } \
+ } \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_GEMM_BLOCK_MUL( flavor, arrtype, worktype ) \
+static CvStatus CV_STDCALL \
+icvGEMMBlockMul_##flavor( const arrtype* a_data, size_t a_step, \
+ const arrtype* b_data, size_t b_step, \
+ worktype* d_data, size_t d_step, \
+ CvSize a_size, CvSize d_size, int flags ) \
+{ \
+ int i, j, k, n = a_size.width, m = d_size.width; \
+ const arrtype *_a_data = a_data, *_b_data = b_data; \
+ arrtype* a_buf = 0; \
+ size_t a_step0, a_step1, t_step; \
+ int do_acc = flags & 16; \
+ \
+ a_step /= sizeof(a_data[0]); \
+ b_step /= sizeof(b_data[0]); \
+ d_step /= sizeof(d_data[0]); \
+ \
+ a_step0 = a_step; \
+ a_step1 = 1; \
+ \
+ if( flags & CV_GEMM_A_T ) \
+ { \
+ CV_SWAP( a_step0, a_step1, t_step ); \
+ n = a_size.height; \
+ a_buf = (arrtype*)cvStackAlloc(n*sizeof(a_data[0])); \
+ } \
+ \
+ if( flags & CV_GEMM_B_T ) \
+ { \
+ /* second operand is transposed */ \
+ for( i = 0; i < d_size.height; i++, _a_data += a_step0, \
+ d_data += d_step ) \
+ { \
+ a_data = _a_data; b_data = _b_data; \
+ \
+ if( a_buf ) \
+ { \
+ for( k = 0; k < n; k++ ) \
+ a_buf[k] = a_data[a_step1*k]; \
+ a_data = a_buf; \
+ } \
+ \
+ for( j = 0; j < d_size.width; j++, b_data += b_step ) \
+ { \
+ worktype s0 = do_acc ? d_data[j]:worktype(0), s1(0);\
+ for( k = 0; k <= n - 2; k += 2 ) \
+ { \
+ s0 += worktype(a_data[k])*b_data[k]; \
+ s1 += worktype(a_data[k+1])*b_data[k+1]; \
+ } \
+ \
+ for( ; k < n; k++ ) \
+ s0 += worktype(a_data[k])*b_data[k]; \
+ \
+ d_data[j] = s0 + s1; \
+ } \
+ } \
+ } \
+ else \
+ { \
+ for( i = 0; i < d_size.height; i++, _a_data += a_step0, \
+ d_data += d_step ) \
+ { \
+ a_data = _a_data, b_data = _b_data; \
+ \
+ if( a_buf ) \
+ { \
+ for( k = 0; k < n; k++ ) \
+ a_buf[k] = a_data[a_step1*k]; \
+ a_data = a_buf; \
+ } \
+ \
+ for( j = 0; j <= m - 4; j += 4 ) \
+ { \
+ worktype s0, s1, s2, s3; \
+ const arrtype* b = b_data + j; \
+ \
+ if( do_acc ) \
+ { \
+ s0 = d_data[j]; s1 = d_data[j+1]; \
+ s2 = d_data[j+2]; s3 = d_data[j+3]; \
+ } \
+ else \
+ s0 = s1 = s2 = s3 = worktype(0); \
+ \
+ for( k = 0; k < n; k++, b += b_step ) \
+ { \
+ worktype a(a_data[k]); \
+ s0 += a * b[0]; s1 += a * b[1]; \
+ s2 += a * b[2]; s3 += a * b[3]; \
+ } \
+ \
+ d_data[j] = s0; d_data[j+1] = s1; \
+ d_data[j+2] = s2; d_data[j+3] = s3; \
+ } \
+ \
+ for( ; j < m; j++ ) \
+ { \
+ const arrtype* b = b_data + j; \
+ worktype s0 = do_acc ? d_data[j] : worktype(0); \
+ \
+ for( k = 0; k < n; k++, b += b_step ) \
+ s0 += worktype(a_data[k]) * b[0]; \
+ \
+ d_data[j] = s0; \
+ } \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_GEMM_STORE( flavor, arrtype, worktype ) \
+static CvStatus CV_STDCALL \
+icvGEMMStore_##flavor( const arrtype* c_data, size_t c_step, \
+ const worktype* d_buf, size_t d_buf_step, \
+ arrtype* d_data, size_t d_step, CvSize d_size,\
+ double alpha, double beta, int flags ) \
+{ \
+ const arrtype* _c_data = c_data; \
+ int j; \
+ size_t c_step0, c_step1; \
+ \
+ c_step /= sizeof(c_data[0]); \
+ d_buf_step /= sizeof(d_buf[0]); \
+ d_step /= sizeof(d_data[0]); \
+ \
+ if( !c_data ) \
+ c_step0 = c_step1 = 0; \
+ else if( !(flags & CV_GEMM_C_T) ) \
+ c_step0 = c_step, c_step1 = 1; \
+ else \
+ c_step0 = 1, c_step1 = c_step; \
+ \
+ for( ; d_size.height--; _c_data += c_step0, \
+ d_buf += d_buf_step, \
+ d_data += d_step ) \
+ { \
+ if( _c_data ) \
+ { \
+ c_data = _c_data; \
+ for( j = 0; j <= d_size.width - 4; j += 4, c_data += 4*c_step1 )\
+ { \
+ worktype t0 = alpha*d_buf[j]; \
+ worktype t1 = alpha*d_buf[j+1]; \
+ t0 += beta*worktype(c_data[0]); \
+ t1 += beta*worktype(c_data[c_step1]); \
+ d_data[j] = arrtype(t0); \
+ d_data[j+1] = arrtype(t1); \
+ t0 = alpha*d_buf[j+2]; \
+ t1 = alpha*d_buf[j+3]; \
+ t0 += beta*worktype(c_data[c_step1*2]); \
+ t1 += beta*worktype(c_data[c_step1*3]); \
+ d_data[j+2] = arrtype(t0); \
+ d_data[j+3] = arrtype(t1); \
+ } \
+ for( ; j < d_size.width; j++, c_data += c_step1 ) \
+ { \
+ worktype t0 = alpha*d_buf[j]; \
+ d_data[j] = arrtype(t0 + beta*c_data[0]); \
+ } \
+ } \
+ else \
+ { \
+ for( j = 0; j <= d_size.width - 4; j += 4 ) \
+ { \
+ worktype t0 = alpha*d_buf[j]; \
+ worktype t1 = alpha*d_buf[j+1]; \
+ d_data[j] = arrtype(t0); \
+ d_data[j+1] = arrtype(t1); \
+ t0 = alpha*d_buf[j+2]; \
+ t1 = alpha*d_buf[j+3]; \
+ d_data[j+2] = arrtype(t0); \
+ d_data[j+3] = arrtype(t1); \
+ } \
+ for( ; j < d_size.width; j++ ) \
+ d_data[j] = arrtype(alpha*d_buf[j]); \
+ } \
+ } \
+ return CV_OK; \
+}
+
+
+ICV_DEF_GEMM_SINGLE_MUL( 32f_C1R, float, double)
+ICV_DEF_GEMM_BLOCK_MUL( 32f_C1R, float, double)
+ICV_DEF_GEMM_STORE( 32f_C1R, float, double)
+
+ICV_DEF_GEMM_SINGLE_MUL( 64f_C1R, double, double)
+ICV_DEF_GEMM_BLOCK_MUL( 64f_C1R, double, double)
+ICV_DEF_GEMM_STORE( 64f_C1R, double, double)
+
+ICV_DEF_GEMM_SINGLE_MUL( 32f_C2R, CvComplex32f, CvComplex64f)
+ICV_DEF_GEMM_BLOCK_MUL( 32f_C2R, CvComplex32f, CvComplex64f)
+ICV_DEF_GEMM_STORE( 32f_C2R, CvComplex32f, CvComplex64f)
+
+ICV_DEF_GEMM_SINGLE_MUL( 64f_C2R, CvComplex64f, CvComplex64f)
+ICV_DEF_GEMM_BLOCK_MUL( 64f_C2R, CvComplex64f, CvComplex64f)
+ICV_DEF_GEMM_STORE( 64f_C2R, CvComplex64f, CvComplex64f)
+
+typedef CvStatus (CV_STDCALL *CvGEMMSingleMulFunc)( const void* src1, size_t step1,
+ const void* src2, size_t step2, const void* src3, size_t step3,
+ void* dst, size_t dststep, CvSize srcsize, CvSize dstsize,
+ double alpha, double beta, int flags );
+
+typedef CvStatus (CV_STDCALL *CvGEMMBlockMulFunc)( const void* src1, size_t step1,
+ const void* src2, size_t step2, void* dst, size_t dststep,
+ CvSize srcsize, CvSize dstsize, int flags );
+
+typedef CvStatus (CV_STDCALL *CvGEMMStoreFunc)( const void* src1, size_t step1,
+ const void* src2, size_t step2, void* dst, size_t dststep,
+ CvSize dstsize, double alpha, double beta, int flags );
+
+
+static void icvInitGEMMTable( CvBigFuncTable* single_mul_tab,
+ CvBigFuncTable* block_mul_tab,
+ CvBigFuncTable* store_tab )
+{
+ single_mul_tab->fn_2d[CV_32FC1] = (void*)icvGEMMSingleMul_32f_C1R;
+ single_mul_tab->fn_2d[CV_64FC1] = (void*)icvGEMMSingleMul_64f_C1R;
+ single_mul_tab->fn_2d[CV_32FC2] = (void*)icvGEMMSingleMul_32f_C2R;
+ single_mul_tab->fn_2d[CV_64FC2] = (void*)icvGEMMSingleMul_64f_C2R;
+ block_mul_tab->fn_2d[CV_32FC1] = (void*)icvGEMMBlockMul_32f_C1R;
+ block_mul_tab->fn_2d[CV_64FC1] = (void*)icvGEMMBlockMul_64f_C1R;
+ block_mul_tab->fn_2d[CV_32FC2] = (void*)icvGEMMBlockMul_32f_C2R;
+ block_mul_tab->fn_2d[CV_64FC2] = (void*)icvGEMMBlockMul_64f_C2R;
+ store_tab->fn_2d[CV_32FC1] = (void*)icvGEMMStore_32f_C1R;
+ store_tab->fn_2d[CV_64FC1] = (void*)icvGEMMStore_64f_C1R;
+ store_tab->fn_2d[CV_32FC2] = (void*)icvGEMMStore_32f_C2R;
+ store_tab->fn_2d[CV_64FC2] = (void*)icvGEMMStore_64f_C2R;
+}
+
+
+CV_IMPL void
+cvGEMM( const CvArr* Aarr, const CvArr* Barr, double alpha,
+ const CvArr* Carr, double beta, CvArr* Darr, int flags )
+{
+ const int block_lin_size = 128;
+ const int block_size = block_lin_size * block_lin_size;
+
+ static CvBigFuncTable single_mul_tab, block_mul_tab, store_tab;
+ static int inittab = 0;
+ static double zero[] = {0,0,0,0};
+ static float zerof[] = {0,0,0,0};
+
+ uchar* buffer = 0;
+ int local_alloc = 0;
+ uchar* block_buffer = 0;
+
+ CV_FUNCNAME( "cvGEMM" );
+
+ __BEGIN__;
+
+ CvMat *A = (CvMat*)Aarr;
+ CvMat *B = (CvMat*)Barr;
+ CvMat *C = (CvMat*)Carr;
+ CvMat *D = (CvMat*)Darr;
+ int len = 0;
+
+ CvMat stub, stub1, stub2, stub3;
+ CvSize a_size, d_size;
+ int type;
+
+ if( !CV_IS_MAT( A ))
+ {
+ int coi = 0;
+ CV_CALL( A = cvGetMat( A, &stub1, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_IS_MAT( B ))
+ {
+ int coi = 0;
+ CV_CALL( B = cvGetMat( B, &stub2, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_IS_MAT( D ))
+ {
+ int coi = 0;
+ CV_CALL( D = cvGetMat( D, &stub, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( beta == 0 )
+ C = 0;
+
+ if( C )
+ {
+ if( !CV_IS_MAT( C ))
+ {
+ int coi = 0;
+ CV_CALL( C = cvGetMat( C, &stub3, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_ARE_TYPES_EQ( C, D ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( ((flags&CV_GEMM_C_T) == 0 && (C->cols != D->cols || C->rows != D->rows)) ||
+ ((flags&CV_GEMM_C_T) != 0 && (C->rows != D->cols || C->cols != D->rows)))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( (flags & CV_GEMM_C_T) != 0 && C->data.ptr == D->data.ptr )
+ {
+ cvTranspose( C, D );
+ C = D;
+ flags &= ~CV_GEMM_C_T;
+ }
+ }
+ else
+ {
+ C = &stub3;
+ C->data.ptr = 0;
+ C->step = 0;
+ C->type = CV_MAT_CONT_FLAG;
+ }
+
+ type = CV_MAT_TYPE(A->type);
+ if( !CV_ARE_TYPES_EQ( A, B ) || !CV_ARE_TYPES_EQ( A, D ) )
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ a_size.width = A->cols;
+ a_size.height = A->rows;
+ d_size.width = D->cols;
+ d_size.height = D->rows;
+
+ switch( flags & (CV_GEMM_A_T|CV_GEMM_B_T) )
+ {
+ case 0:
+ len = B->rows;
+ if( a_size.width != len ||
+ B->cols != d_size.width ||
+ a_size.height != d_size.height )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+ break;
+ case 1:
+ len = B->rows;
+ if( a_size.height != len ||
+ B->cols != d_size.width ||
+ a_size.width != d_size.height )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+ break;
+ case 2:
+ len = B->cols;
+ if( a_size.width != len ||
+ B->rows != d_size.width ||
+ a_size.height != d_size.height )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+ break;
+ case 3:
+ len = B->cols;
+ if( a_size.height != len ||
+ B->rows != d_size.width ||
+ a_size.width != d_size.height )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+ break;
+ }
+
+ if( flags == 0 && 2 <= len && len <= 4 && (len == d_size.width || len == d_size.height) )
+ {
+ int i;
+ if( type == CV_64F )
+ {
+ double* d = D->data.db;
+ const double *a = A->data.db, *b = B->data.db, *c = C->data.db;
+ size_t d_step = D->step/sizeof(d[0]),
+ a_step = A->step/sizeof(a[0]),
+ b_step = B->step/sizeof(b[0]),
+ c_step = C->step/sizeof(c[0]);
+
+ if( !c )
+ c = zero;
+
+ switch( len )
+ {
+ case 2:
+ if( len == d_size.width && b != d )
+ {
+ for( i = 0; i < d_size.height; i++, d += d_step, a += a_step, c += c_step )
+ {
+ double t0 = a[0]*b[0] + a[1]*b[b_step];
+ double t1 = a[0]*b[1] + a[1]*b[b_step+1];
+ d[0] = t0*alpha + c[0]*beta;
+ d[1] = t1*alpha + c[1]*beta;
+ }
+ }
+ else if( a != d )
+ {
+ int c_step0 = 1;
+ if( c == zero )
+ {
+ c_step0 = 0;
+ c_step = 1;
+ }
+
+ for( i = 0; i < d_size.width; i++, d++, b++, c += c_step0 )
+ {
+ double t0 = a[0]*b[0] + a[1]*b[b_step];
+ double t1 = a[a_step]*b[0] + a[a_step+1]*b[b_step];
+ d[0] = t0*alpha + c[0]*beta;
+ d[d_step] = t1*alpha + c[c_step]*beta;
+ }
+ }
+ else
+ break;
+ EXIT;
+ case 3:
+ if( len == d_size.width && b != d )
+ {
+ for( i = 0; i < d_size.height; i++, d += d_step, a += a_step, c += c_step )
+ {
+ double t0 = a[0]*b[0] + a[1]*b[b_step] + a[2]*b[b_step*2];
+ double t1 = a[0]*b[1] + a[1]*b[b_step+1] + a[2]*b[b_step*2+1];
+ double t2 = a[0]*b[2] + a[1]*b[b_step+2] + a[2]*b[b_step*2+2];
+ d[0] = t0*alpha + c[0]*beta;
+ d[1] = t1*alpha + c[1]*beta;
+ d[2] = t2*alpha + c[2]*beta;
+ }
+ }
+ else if( a != d )
+ {
+ int c_step0 = 1;
+ if( c == zero )
+ {
+ c_step0 = 0;
+ c_step = 1;
+ }
+
+ for( i = 0; i < d_size.width; i++, d++, b++, c += c_step0 )
+ {
+ double t0 = a[0]*b[0] + a[1]*b[b_step] + a[2]*b[b_step*2];
+ double t1 = a[a_step]*b[0] + a[a_step+1]*b[b_step] + a[a_step+2]*b[b_step*2];
+ double t2 = a[a_step*2]*b[0] + a[a_step*2+1]*b[b_step] + a[a_step*2+2]*b[b_step*2];
+
+ d[0] = t0*alpha + c[0]*beta;
+ d[d_step] = t1*alpha + c[c_step]*beta;
+ d[d_step*2] = t2*alpha + c[c_step*2]*beta;
+ }
+ }
+ else
+ break;
+ EXIT;
+ case 4:
+ if( len == d_size.width && b != d )
+ {
+ for( i = 0; i < d_size.height; i++, d += d_step, a += a_step, c += c_step )
+ {
+ double t0 = a[0]*b[0] + a[1]*b[b_step] + a[2]*b[b_step*2] + a[3]*b[b_step*3];
+ double t1 = a[0]*b[1] + a[1]*b[b_step+1] + a[2]*b[b_step*2+1] + a[3]*b[b_step*3+1];
+ double t2 = a[0]*b[2] + a[1]*b[b_step+2] + a[2]*b[b_step*2+2] + a[3]*b[b_step*3+2];
+ double t3 = a[0]*b[3] + a[1]*b[b_step+3] + a[2]*b[b_step*2+3] + a[3]*b[b_step*3+3];
+ d[0] = t0*alpha + c[0]*beta;
+ d[1] = t1*alpha + c[1]*beta;
+ d[2] = t2*alpha + c[2]*beta;
+ d[3] = t3*alpha + c[3]*beta;
+ }
+ }
+ else if( d_size.width <= 16 && a != d )
+ {
+ int c_step0 = 1;
+ if( c == zero )
+ {
+ c_step0 = 0;
+ c_step = 1;
+ }
+
+ for( i = 0; i < d_size.width; i++, d++, b++, c += c_step0 )
+ {
+ double t0 = a[0]*b[0] + a[1]*b[b_step] + a[2]*b[b_step*2] + a[3]*b[b_step*3];
+ double t1 = a[a_step]*b[0] + a[a_step+1]*b[b_step] +
+ a[a_step+2]*b[b_step*2] + a[a_step+3]*b[b_step*3];
+ double t2 = a[a_step*2]*b[0] + a[a_step*2+1]*b[b_step] +
+ a[a_step*2+2]*b[b_step*2] + a[a_step*2+3]*b[b_step*3];
+ double t3 = a[a_step*3]*b[0] + a[a_step*3+1]*b[b_step] +
+ a[a_step*3+2]*b[b_step*2] + a[a_step*3+3]*b[b_step*3];
+ d[0] = t0*alpha + c[0]*beta;
+ d[d_step] = t1*alpha + c[c_step]*beta;
+ d[d_step*2] = t2*alpha + c[c_step*2]*beta;
+ d[d_step*3] = t3*alpha + c[c_step*3]*beta;
+ }
+ }
+ else
+ break;
+ EXIT;
+ }
+ }
+
+ if( type == CV_32F )
+ {
+ float* d = D->data.fl;
+ const float *a = A->data.fl, *b = B->data.fl, *c = C->data.fl;
+ size_t d_step = D->step/sizeof(d[0]),
+ a_step = A->step/sizeof(a[0]),
+ b_step = B->step/sizeof(b[0]),
+ c_step = C->step/sizeof(c[0]);
+
+ if( !c )
+ c = zerof;
+
+ switch( len )
+ {
+ case 2:
+ if( len == d_size.width && b != d )
+ {
+ for( i = 0; i < d_size.height; i++, d += d_step, a += a_step, c += c_step )
+ {
+ float t0 = a[0]*b[0] + a[1]*b[b_step];
+ float t1 = a[0]*b[1] + a[1]*b[b_step+1];
+ d[0] = (float)(t0*alpha + c[0]*beta);
+ d[1] = (float)(t1*alpha + c[1]*beta);
+ }
+ }
+ else if( a != d )
+ {
+ int c_step0 = 1;
+ if( c == zerof )
+ {
+ c_step0 = 0;
+ c_step = 1;
+ }
+
+ for( i = 0; i < d_size.width; i++, d++, b++, c += c_step0 )
+ {
+ float t0 = a[0]*b[0] + a[1]*b[b_step];
+ float t1 = a[a_step]*b[0] + a[a_step+1]*b[b_step];
+ d[0] = (float)(t0*alpha + c[0]*beta);
+ d[d_step] = (float)(t1*alpha + c[c_step]*beta);
+ }
+ }
+ else
+ break;
+ EXIT;
+ case 3:
+ if( len == d_size.width && b != d )
+ {
+ for( i = 0; i < d_size.height; i++, d += d_step, a += a_step, c += c_step )
+ {
+ float t0 = a[0]*b[0] + a[1]*b[b_step] + a[2]*b[b_step*2];
+ float t1 = a[0]*b[1] + a[1]*b[b_step+1] + a[2]*b[b_step*2+1];
+ float t2 = a[0]*b[2] + a[1]*b[b_step+2] + a[2]*b[b_step*2+2];
+ d[0] = (float)(t0*alpha + c[0]*beta);
+ d[1] = (float)(t1*alpha + c[1]*beta);
+ d[2] = (float)(t2*alpha + c[2]*beta);
+ }
+ }
+ else if( a != d )
+ {
+ int c_step0 = 1;
+ if( c == zerof )
+ {
+ c_step0 = 0;
+ c_step = 1;
+ }
+
+ for( i = 0; i < d_size.width; i++, d++, b++, c += c_step0 )
+ {
+ float t0 = a[0]*b[0] + a[1]*b[b_step] + a[2]*b[b_step*2];
+ float t1 = a[a_step]*b[0] + a[a_step+1]*b[b_step] + a[a_step+2]*b[b_step*2];
+ float t2 = a[a_step*2]*b[0] + a[a_step*2+1]*b[b_step] + a[a_step*2+2]*b[b_step*2];
+
+ d[0] = (float)(t0*alpha + c[0]*beta);
+ d[d_step] = (float)(t1*alpha + c[c_step]*beta);
+ d[d_step*2] = (float)(t2*alpha + c[c_step*2]*beta);
+ }
+ }
+ else
+ break;
+ EXIT;
+ case 4:
+ if( len == d_size.width && b != d )
+ {
+ for( i = 0; i < d_size.height; i++, d += d_step, a += a_step, c += c_step )
+ {
+ float t0 = a[0]*b[0] + a[1]*b[b_step] + a[2]*b[b_step*2] + a[3]*b[b_step*3];
+ float t1 = a[0]*b[1] + a[1]*b[b_step+1] + a[2]*b[b_step*2+1] + a[3]*b[b_step*3+1];
+ float t2 = a[0]*b[2] + a[1]*b[b_step+2] + a[2]*b[b_step*2+2] + a[3]*b[b_step*3+2];
+ float t3 = a[0]*b[3] + a[1]*b[b_step+3] + a[2]*b[b_step*2+3] + a[3]*b[b_step*3+3];
+ d[0] = (float)(t0*alpha + c[0]*beta);
+ d[1] = (float)(t1*alpha + c[1]*beta);
+ d[2] = (float)(t2*alpha + c[2]*beta);
+ d[3] = (float)(t3*alpha + c[3]*beta);
+ }
+ }
+ else if( len <= 16 && a != d )
+ {
+ int c_step0 = 1;
+ if( c == zerof )
+ {
+ c_step0 = 0;
+ c_step = 1;
+ }
+
+ for( i = 0; i < d_size.width; i++, d++, b++, c += c_step0 )
+ {
+ float t0 = a[0]*b[0] + a[1]*b[b_step] + a[2]*b[b_step*2] + a[3]*b[b_step*3];
+ float t1 = a[a_step]*b[0] + a[a_step+1]*b[b_step] +
+ a[a_step+2]*b[b_step*2] + a[a_step+3]*b[b_step*3];
+ float t2 = a[a_step*2]*b[0] + a[a_step*2+1]*b[b_step] +
+ a[a_step*2+2]*b[b_step*2] + a[a_step*2+3]*b[b_step*3];
+ float t3 = a[a_step*3]*b[0] + a[a_step*3+1]*b[b_step] +
+ a[a_step*3+2]*b[b_step*2] + a[a_step*3+3]*b[b_step*3];
+ d[0] = (float)(t0*alpha + c[0]*beta);
+ d[d_step] = (float)(t1*alpha + c[c_step]*beta);
+ d[d_step*2] = (float)(t2*alpha + c[c_step*2]*beta);
+ d[d_step*3] = (float)(t3*alpha + c[c_step*3]*beta);
+ }
+ }
+ else
+ break;
+ EXIT;
+ }
+ }
+ }
+
+ {
+ int b_step = B->step;
+ CvGEMMSingleMulFunc single_mul_func;
+ CvMat tmat, *D0 = D;
+ icvBLAS_GEMM_32f_t blas_func = 0;
+
+ if( !inittab )
+ {
+ icvInitGEMMTable( &single_mul_tab, &block_mul_tab, &store_tab );
+ inittab = 1;
+ }
+
+ single_mul_func = (CvGEMMSingleMulFunc)single_mul_tab.fn_2d[type];
+ if( !single_mul_func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( D->data.ptr == A->data.ptr || D->data.ptr == B->data.ptr )
+ {
+ int buf_size = d_size.width*d_size.height*CV_ELEM_SIZE(type);
+ if( d_size.width <= CV_MAX_LOCAL_MAT_SIZE )
+ {
+ buffer = (uchar*)cvStackAlloc( buf_size );
+ local_alloc = 1;
+ }
+ else
+ CV_CALL( buffer = (uchar*)cvAlloc( buf_size ));
+
+ tmat = cvMat( d_size.height, d_size.width, type, buffer );
+ D = &tmat;
+ }
+
+ if( (d_size.width == 1 || len == 1) && !(flags & CV_GEMM_B_T) && CV_IS_MAT_CONT(B->type) )
+ {
+ b_step = d_size.width == 1 ? 0 : CV_ELEM_SIZE(type);
+ flags |= CV_GEMM_B_T;
+ }
+
+ if( (d_size.width | d_size.height | len) >= 16 && icvBLAS_GEMM_32f_p != 0 )
+ {
+ blas_func = type == CV_32FC1 ? (icvBLAS_GEMM_32f_t)icvBLAS_GEMM_32f_p :
+ type == CV_64FC1 ? (icvBLAS_GEMM_32f_t)icvBLAS_GEMM_64f_p :
+ type == CV_32FC2 ? (icvBLAS_GEMM_32f_t)icvBLAS_GEMM_32fc_p :
+ type == CV_64FC2 ? (icvBLAS_GEMM_32f_t)icvBLAS_GEMM_64fc_p : 0;
+ }
+
+ if( blas_func )
+ {
+ const char* transa = flags & CV_GEMM_A_T ? "t" : "n";
+ const char* transb = flags & CV_GEMM_B_T ? "t" : "n";
+ int lda, ldb, ldd;
+
+ if( C->data.ptr )
+ {
+ if( C->data.ptr != D->data.ptr )
+ {
+ if( !(flags & CV_GEMM_C_T) )
+ cvCopy( C, D );
+ else
+ cvTranspose( C, D );
+ }
+ }
+
+ if( CV_MAT_DEPTH(type) == CV_32F )
+ {
+ CvComplex32f _alpha, _beta;
+
+ lda = A->step/sizeof(float);
+ ldb = b_step/sizeof(float);
+ ldd = D->step/sizeof(float);
+ _alpha.re = (float)alpha;
+ _alpha.im = 0;
+ _beta.re = C->data.ptr ? (float)beta : 0;
+ _beta.im = 0;
+ if( CV_MAT_CN(type) == 2 )
+ lda /= 2, ldb /= 2, ldd /= 2;
+
+ blas_func( transb, transa, &d_size.width, &d_size.height, &len,
+ &_alpha, B->data.ptr, &ldb, A->data.ptr, &lda,
+ &_beta, D->data.ptr, &ldd );
+ }
+ else
+ {
+ CvComplex64f _alpha, _beta;
+
+ lda = A->step/sizeof(double);
+ ldb = b_step/sizeof(double);
+ ldd = D->step/sizeof(double);
+ _alpha.re = alpha;
+ _alpha.im = 0;
+ _beta.re = C->data.ptr ? beta : 0;
+ _beta.im = 0;
+ if( CV_MAT_CN(type) == 2 )
+ lda /= 2, ldb /= 2, ldd /= 2;
+
+ blas_func( transb, transa, &d_size.width, &d_size.height, &len,
+ &_alpha, B->data.ptr, &ldb, A->data.ptr, &lda,
+ &_beta, D->data.ptr, &ldd );
+ }
+ }
+ else if( ((d_size.height <= block_lin_size/2 || d_size.width <= block_lin_size/2) &&
+ len <= 10000) || len <= 10 ||
+ (d_size.width <= block_lin_size && d_size.height <= block_lin_size && len <= block_lin_size) )
+ {
+ single_mul_func( A->data.ptr, A->step, B->data.ptr, b_step,
+ C->data.ptr, C->step, D->data.ptr, D->step,
+ a_size, d_size, alpha, beta, flags );
+ }
+ else
+ {
+ int is_a_t = flags & CV_GEMM_A_T;
+ int is_b_t = flags & CV_GEMM_B_T;
+ int elem_size = CV_ELEM_SIZE(type);
+ int dk0_1, dk0_2;
+ int a_buf_size = 0, b_buf_size, d_buf_size;
+ uchar* a_buf = 0;
+ uchar* b_buf = 0;
+ uchar* d_buf = 0;
+ int i, j, k, di = 0, dj = 0, dk = 0;
+ int dm0, dn0, dk0;
+ int a_step0, a_step1, b_step0, b_step1, c_step0, c_step1;
+ int work_elem_size = elem_size << (CV_MAT_DEPTH(type) == CV_32F ? 1 : 0);
+ CvGEMMBlockMulFunc block_mul_func = (CvGEMMBlockMulFunc)block_mul_tab.fn_2d[type];
+ CvGEMMStoreFunc store_func = (CvGEMMStoreFunc)store_tab.fn_2d[type];
+
+ assert( block_mul_func && store_func );
+
+ if( !is_a_t )
+ a_step0 = A->step, a_step1 = elem_size;
+ else
+ a_step0 = elem_size, a_step1 = A->step;
+
+ if( !is_b_t )
+ b_step0 = b_step, b_step1 = elem_size;
+ else
+ b_step0 = elem_size, b_step1 = b_step;
+
+ if( !C->data.ptr )
+ {
+ c_step0 = c_step1 = 0;
+ flags &= ~CV_GEMM_C_T;
+ }
+ else if( !(flags & CV_GEMM_C_T) )
+ c_step0 = C->step, c_step1 = elem_size;
+ else
+ c_step0 = elem_size, c_step1 = C->step;
+
+ dm0 = MIN( block_lin_size, d_size.height );
+ dn0 = MIN( block_lin_size, d_size.width );
+ dk0_1 = block_size / dm0;
+ dk0_2 = block_size / dn0;
+ dk0 = MAX( dk0_1, dk0_2 );
+ dk0 = MIN( dk0, len );
+ if( dk0*dm0 > block_size )
+ dm0 = block_size / dk0;
+ if( dk0*dn0 > block_size )
+ dn0 = block_size / dk0;
+
+ dk0_1 = (dn0+dn0/8+2) & -2;
+ b_buf_size = (dk0+dk0/8+1)*dk0_1*elem_size;
+ d_buf_size = (dk0+dk0/8+1)*dk0_1*work_elem_size;
+
+ if( is_a_t )
+ {
+ a_buf_size = (dm0+dm0/8+1)*((dk0+dk0/8+2)&-2)*elem_size;
+ flags &= ~CV_GEMM_A_T;
+ }
+
+ CV_CALL( block_buffer = (uchar*)cvAlloc(a_buf_size + b_buf_size + d_buf_size));
+ d_buf = block_buffer;
+ b_buf = d_buf + d_buf_size;
+
+ if( is_a_t )
+ a_buf = b_buf + b_buf_size;
+
+ for( i = 0; i < d_size.height; i += di )
+ {
+ di = dm0;
+ if( i + di >= d_size.height || 8*(i + di) + di > 8*d_size.height )
+ di = d_size.height - i;
+
+ for( j = 0; j < d_size.width; j += dj )
+ {
+ uchar* _d = D->data.ptr + i*D->step + j*elem_size;
+ const uchar* _c = C->data.ptr + i*c_step0 + j*c_step1;
+ int _d_step = D->step;
+ dj = dn0;
+
+ if( j + dj >= d_size.width || 8*(j + dj) + dj > 8*d_size.width )
+ dj = d_size.width - j;
+
+ flags &= 15;
+ if( dk0 < len )
+ {
+ _d = d_buf;
+ _d_step = dj*work_elem_size;
+ }
+
+ for( k = 0; k < len; k += dk )
+ {
+ const uchar* _a = A->data.ptr + i*a_step0 + k*a_step1;
+ int _a_step = A->step;
+ const uchar* _b = B->data.ptr + k*b_step0 + j*b_step1;
+ int _b_step = b_step;
+ CvSize a_bl_size;
+
+ dk = dk0;
+ if( k + dk >= len || 8*(k + dk) + dk > 8*len )
+ dk = len - k;
+
+ if( !is_a_t )
+ a_bl_size.width = dk, a_bl_size.height = di;
+ else
+ a_bl_size.width = di, a_bl_size.height = dk;
+
+ if( a_buf && is_a_t )
+ {
+ int t;
+ _a_step = dk*elem_size;
+ icvGEMM_TransposeBlock( _a, A->step, a_buf, _a_step, a_bl_size, elem_size );
+ CV_SWAP( a_bl_size.width, a_bl_size.height, t );
+ _a = a_buf;
+ }
+
+ if( dj < d_size.width )
+ {
+ CvSize b_size;
+ if( !is_b_t )
+ b_size.width = dj, b_size.height = dk;
+ else
+ b_size.width = dk, b_size.height = dj;
+
+ _b_step = b_size.width*elem_size;
+ icvGEMM_CopyBlock( _b, b_step, b_buf, _b_step, b_size, elem_size );
+ _b = b_buf;
+ }
+
+ if( dk0 < len )
+ block_mul_func( _a, _a_step, _b, _b_step, _d, _d_step,
+ a_bl_size, cvSize(dj,di), flags );
+ else
+ single_mul_func( _a, _a_step, _b, _b_step, _c, C->step, _d, _d_step,
+ a_bl_size, cvSize(dj,di), alpha, beta, flags );
+ flags |= 16;
+ }
+
+ if( dk0 < len )
+ store_func( _c, C->step, _d, _d_step, D->data.ptr + i*D->step + j*elem_size,
+ D->step, cvSize(dj,di), alpha, beta, flags );
+ }
+ }
+ }
+
+ if( D0 != D )
+ CV_CALL( cvCopy( D, D0 ));
+ }
+
+ __END__;
+
+ if( buffer && !local_alloc )
+ cvFree( &buffer );
+ if( block_buffer )
+ cvFree( &block_buffer );
+}
+
+
+/****************************************************************************************\
+* cvTransform *
+\****************************************************************************************/
+
+#define ICV_DEF_TRANSFORM_CASE_C1( arrtype, temptype, _ld_, \
+ _cast_macro1_, _cast_macro2_ ) \
+{ \
+ for( i = 0; i < size.width; i++, dst += dst_cn ) \
+ { \
+ const double* _mat = mat; \
+ double v0 = _ld_(src[i]); \
+ for( k = 0; k < dst_cn; k++, _mat += 2 ) \
+ { \
+ temptype t0 = _cast_macro1_(_mat[0]*v0 + _mat[1]); \
+ dst[k] = _cast_macro2_(t0); \
+ } \
+ } \
+ src += size.width; \
+}
+
+
+#define ICV_DEF_DIAG_TRANSFORM_CASE_C1( arrtype, temptype, _ld_, \
+ _cast_macro1_, _cast_macro2_ ) \
+ for( i = 0; i < size.width; i++ ) \
+ { \
+ double ft0; \
+ temptype t0; \
+ ft0 = mat[0]*_ld_(src[i]) + mat[1]; \
+ t0 = _cast_macro1_(ft0); \
+ dst[i] = _cast_macro2_(t0); \
+ }
+
+
+#define ICV_DEF_TRANSFORM_CASE_C2( arrtype, temptype, _ld_, \
+ _cast_macro1_, _cast_macro2_ ) \
+if( dst_cn == 2 ) \
+{ \
+ for( i = 0; i < size.width*2; i += 2 ) \
+ { \
+ double ft0, ft1; \
+ temptype t0, t1; \
+ ft0 = mat[0]*_ld_(src[i]) + mat[1]*_ld_(src[i+1]) + mat[2]; \
+ ft1 = mat[3]*_ld_(src[i]) + mat[4]*_ld_(src[i+1]) + mat[5]; \
+ t0 = _cast_macro1_(ft0); \
+ t1 = _cast_macro1_(ft1); \
+ dst[i] = _cast_macro2_(t0); \
+ dst[i+1] = _cast_macro2_(t1); \
+ } \
+ src += size.width*2; dst += size.width*2; \
+} \
+else \
+ for( i = 0; i < size.width; i++, src += 2, dst += dst_cn ) \
+ { \
+ const double* _mat = mat; \
+ double v0 = _ld_(src[0]), v1 = src[1]; \
+ for( k = 0; k < dst_cn; k++, _mat += 3 ) \
+ { \
+ temptype t0 = \
+ _cast_macro1_(_mat[0]*v0 + _mat[1]*v1 + _mat[2]); \
+ dst[k] = _cast_macro2_(t0); \
+ } \
+ }
+
+
+#define ICV_DEF_DIAG_TRANSFORM_CASE_C2( arrtype, temptype, _ld_, \
+ _cast_macro1_, _cast_macro2_ ) \
+ for( i = 0; i < size.width*2; i += 2 ) \
+ { \
+ double ft0, ft1; \
+ temptype t0, t1; \
+ ft0 = mat[0]*_ld_(src[i]) + mat[2]; \
+ ft1 = mat[4]*_ld_(src[i+1]) + mat[5]; \
+ t0 = _cast_macro1_(ft0); \
+ t1 = _cast_macro1_(ft1); \
+ dst[i] = _cast_macro2_(t0); \
+ dst[i+1] = _cast_macro2_(t1); \
+ }
+
+
+#define ICV_DEF_TRANSFORM_CASE_C3( arrtype, temptype, _ld_, \
+ _cast_macro1_, _cast_macro2_ ) \
+if( dst_cn == 3 ) \
+{ \
+ for( i = 0; i < size.width*3; i += 3 ) \
+ { \
+ double ft0, ft1, ft2; \
+ temptype t0, t1, t2; \
+ ft0 = mat[0]*_ld_(src[i]) + mat[1]*_ld_(src[i+1]) + \
+ mat[2]*_ld_(src[i+2]) + mat[3]; \
+ ft1 = mat[4]*_ld_(src[i]) + mat[5]*_ld_(src[i+1]) + \
+ mat[6]*_ld_(src[i+2]) + mat[7]; \
+ ft2 = mat[8]*_ld_(src[i]) + mat[9]*_ld_(src[i+1]) + \
+ mat[10]*_ld_(src[i+2]) + mat[11]; \
+ t0 = _cast_macro1_(ft0); \
+ t1 = _cast_macro1_(ft1); \
+ t2 = _cast_macro1_(ft2); \
+ dst[i] = _cast_macro2_(t0); \
+ dst[i+1] = _cast_macro2_(t1); \
+ dst[i+2] = _cast_macro2_(t2); \
+ } \
+ src += size.width*3; dst += size.width*3; \
+} \
+else if( dst_cn == 1 ) \
+{ \
+ for( i = 0; i < size.width; i++, src += 3 ) \
+ { \
+ temptype t0 = _cast_macro1_(mat[0]*_ld_(src[0]) + \
+ mat[1]*_ld_(src[1]) + mat[2]*_ld_(src[2]) + mat[3]); \
+ dst[i] = _cast_macro2_(t0); \
+ } \
+ dst += size.width; \
+} \
+else \
+ for( i = 0; i < size.width; i++, src += 3, dst += dst_cn ) \
+ { \
+ const double* _mat = mat; \
+ double v0=_ld_(src[0]), v1=_ld_(src[1]), v2=_ld_(src[2]); \
+ for( k = 0; k < dst_cn; k++, _mat += 4 ) \
+ { \
+ temptype t0 = _cast_macro1_(_mat[0]*v0 + \
+ _mat[1]*v1 + _mat[2]*v2 + _mat[3]); \
+ dst[k] = _cast_macro2_(t0); \
+ } \
+ }
+
+
+#define ICV_DEF_DIAG_TRANSFORM_CASE_C3( arrtype, temptype, _ld_, \
+ _cast_macro1_, _cast_macro2_ ) \
+ for( i = 0; i < size.width*3; i += 3 ) \
+ { \
+ double ft0, ft1, ft2; \
+ temptype t0, t1, t2; \
+ ft0 = mat[0]*_ld_(src[i]) + mat[3]; \
+ ft1 = mat[5]*_ld_(src[i+1]) + mat[7]; \
+ ft2 = mat[10]*_ld_(src[i+2]) + mat[11]; \
+ t0 = _cast_macro1_(ft0); \
+ t1 = _cast_macro1_(ft1); \
+ t2 = _cast_macro1_(ft2); \
+ dst[i] = _cast_macro2_(t0); \
+ dst[i+1] = _cast_macro2_(t1); \
+ dst[i+2] = _cast_macro2_(t2); \
+ }
+
+
+#define ICV_DEF_TRANSFORM_CASE_C4( arrtype, temptype, _ld_, \
+ _cast_macro1_, _cast_macro2_ ) \
+for( i = 0; i < size.width; i++, src += 4, dst += dst_cn ) \
+{ \
+ const double* _mat = mat; \
+ double v0 = _ld_(src[0]), v1 = _ld_(src[1]), \
+ v2 = _ld_(src[2]), v3 = _ld_(src[3]); \
+ for( k = 0; k < dst_cn; k++, _mat += 5 ) \
+ { \
+ temptype t0 =_cast_macro1_(_mat[0]*v0+_mat[1]*v1+ \
+ _mat[2]*v2+_mat[3]*v3+_mat[4]); \
+ dst[k] = _cast_macro2_(t0); \
+ } \
+}
+
+
+#define ICV_DEF_DIAG_TRANSFORM_CASE_C4( arrtype, temptype, _ld_, \
+ _cast_macro1_, _cast_macro2_ ) \
+ for( i = 0; i < size.width*4; i += 4 ) \
+ { \
+ double ft0, ft1; \
+ temptype t0, t1; \
+ ft0 = mat[0]*_ld_(src[i]) + mat[4]; \
+ ft1 = mat[6]*_ld_(src[i+1]) + mat[9]; \
+ t0 = _cast_macro1_(ft0); \
+ t1 = _cast_macro1_(ft1); \
+ dst[i] = _cast_macro2_(t0); \
+ dst[i+1] = _cast_macro2_(t1); \
+ ft0 = mat[12]*_ld_(src[i+2]) + mat[14]; \
+ ft1 = mat[18]*_ld_(src[i+3]) + mat[19]; \
+ t0 = _cast_macro1_(ft0); \
+ t1 = _cast_macro1_(ft1); \
+ dst[i+2] = _cast_macro2_(t0); \
+ dst[i+3] = _cast_macro2_(t1); \
+ }
+
+
+
+#define ICV_DEF_TRANSFORM_FUNC( flavor, arrtype, temptype, _ld_, \
+ _cast_macro1_, _cast_macro2_, cn )\
+static CvStatus CV_STDCALL \
+icvTransform_##flavor( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, CvSize size, \
+ const double* mat, int dst_cn ) \
+{ \
+ srcstep = srcstep/sizeof(src[0]) - size.width*cn; \
+ dststep = dststep/sizeof(dst[0]) - size.width*dst_cn; \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ int i, k; \
+ ICV_DEF_TRANSFORM_CASE_C##cn( arrtype, temptype, _ld_, \
+ _cast_macro1_, _cast_macro2_ ) \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_DIAG_TRANSFORM_FUNC( flavor, arrtype, temptype, _ld_, \
+ _cast_macro1_, _cast_macro2_, cn )\
+static CvStatus CV_STDCALL \
+icvDiagTransform_##flavor( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, CvSize size, \
+ const double* mat ) \
+{ \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ int i; \
+ ICV_DEF_DIAG_TRANSFORM_CASE_C##cn( arrtype, temptype, _ld_, \
+ _cast_macro1_, _cast_macro2_ ) \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_TRANSFORM_FUNC( 8u_C1R, uchar, int, CV_8TO32F, cvRound, CV_CAST_8U, 1 )
+ICV_DEF_TRANSFORM_FUNC( 8u_C2R, uchar, int, CV_8TO32F, cvRound, CV_CAST_8U, 2 )
+ICV_DEF_TRANSFORM_FUNC( 8u_C3R, uchar, int, CV_8TO32F, cvRound, CV_CAST_8U, 3 )
+ICV_DEF_TRANSFORM_FUNC( 8u_C4R, uchar, int, CV_8TO32F, cvRound, CV_CAST_8U, 4 )
+
+ICV_DEF_TRANSFORM_FUNC( 16u_C1R, ushort, int, CV_NOP, cvRound, CV_CAST_16U, 1 )
+ICV_DEF_TRANSFORM_FUNC( 16u_C2R, ushort, int, CV_NOP, cvRound, CV_CAST_16U, 2 )
+ICV_DEF_TRANSFORM_FUNC( 16u_C3R, ushort, int, CV_NOP, cvRound, CV_CAST_16U, 3 )
+ICV_DEF_TRANSFORM_FUNC( 16u_C4R, ushort, int, CV_NOP, cvRound, CV_CAST_16U, 4 )
+
+ICV_DEF_TRANSFORM_FUNC( 16s_C1R, short, int, CV_NOP, cvRound, CV_CAST_16S, 1 )
+ICV_DEF_TRANSFORM_FUNC( 16s_C2R, short, int, CV_NOP, cvRound, CV_CAST_16S, 2 )
+ICV_DEF_TRANSFORM_FUNC( 16s_C3R, short, int, CV_NOP, cvRound, CV_CAST_16S, 3 )
+ICV_DEF_TRANSFORM_FUNC( 16s_C4R, short, int, CV_NOP, cvRound, CV_CAST_16S, 4 )
+
+ICV_DEF_TRANSFORM_FUNC( 32s_C1R, int, int, CV_NOP, cvRound, CV_NOP, 1 )
+ICV_DEF_TRANSFORM_FUNC( 32s_C2R, int, int, CV_NOP, cvRound, CV_NOP, 2 )
+ICV_DEF_TRANSFORM_FUNC( 32s_C3R, int, int, CV_NOP, cvRound, CV_NOP, 3 )
+ICV_DEF_TRANSFORM_FUNC( 32s_C4R, int, int, CV_NOP, cvRound, CV_NOP, 4 )
+
+ICV_DEF_TRANSFORM_FUNC( 32f_C1R, float, double, CV_NOP, CV_NOP, CV_CAST_32F, 1 )
+ICV_DEF_TRANSFORM_FUNC( 32f_C2R, float, double, CV_NOP, CV_NOP, CV_CAST_32F, 2 )
+ICV_DEF_TRANSFORM_FUNC( 32f_C3R, float, double, CV_NOP, CV_NOP, CV_CAST_32F, 3 )
+ICV_DEF_TRANSFORM_FUNC( 32f_C4R, float, double, CV_NOP, CV_NOP, CV_CAST_32F, 4 )
+
+ICV_DEF_TRANSFORM_FUNC( 64f_C1R, double, double, CV_NOP, CV_NOP, CV_CAST_64F, 1 )
+ICV_DEF_TRANSFORM_FUNC( 64f_C2R, double, double, CV_NOP, CV_NOP, CV_CAST_64F, 2 )
+ICV_DEF_TRANSFORM_FUNC( 64f_C3R, double, double, CV_NOP, CV_NOP, CV_CAST_64F, 3 )
+ICV_DEF_TRANSFORM_FUNC( 64f_C4R, double, double, CV_NOP, CV_NOP, CV_CAST_64F, 4 )
+
+ICV_DEF_DIAG_TRANSFORM_FUNC( 16u_C1R, ushort, int, CV_NOP, cvRound, CV_CAST_16U, 1 )
+ICV_DEF_DIAG_TRANSFORM_FUNC( 16u_C2R, ushort, int, CV_NOP, cvRound, CV_CAST_16U, 2 )
+ICV_DEF_DIAG_TRANSFORM_FUNC( 16u_C3R, ushort, int, CV_NOP, cvRound, CV_CAST_16U, 3 )
+ICV_DEF_DIAG_TRANSFORM_FUNC( 16u_C4R, ushort, int, CV_NOP, cvRound, CV_CAST_16U, 4 )
+
+ICV_DEF_DIAG_TRANSFORM_FUNC( 16s_C1R, short, int, CV_NOP, cvRound, CV_CAST_16S, 1 )
+ICV_DEF_DIAG_TRANSFORM_FUNC( 16s_C2R, short, int, CV_NOP, cvRound, CV_CAST_16S, 2 )
+ICV_DEF_DIAG_TRANSFORM_FUNC( 16s_C3R, short, int, CV_NOP, cvRound, CV_CAST_16S, 3 )
+ICV_DEF_DIAG_TRANSFORM_FUNC( 16s_C4R, short, int, CV_NOP, cvRound, CV_CAST_16S, 4 )
+
+ICV_DEF_DIAG_TRANSFORM_FUNC( 32s_C1R, int, int, CV_NOP, cvRound, CV_NOP, 1 )
+ICV_DEF_DIAG_TRANSFORM_FUNC( 32s_C2R, int, int, CV_NOP, cvRound, CV_NOP, 2 )
+ICV_DEF_DIAG_TRANSFORM_FUNC( 32s_C3R, int, int, CV_NOP, cvRound, CV_NOP, 3 )
+ICV_DEF_DIAG_TRANSFORM_FUNC( 32s_C4R, int, int, CV_NOP, cvRound, CV_NOP, 4 )
+
+ICV_DEF_DIAG_TRANSFORM_FUNC( 32f_C1R, float, double, CV_NOP, CV_NOP, CV_CAST_32F, 1 )
+ICV_DEF_DIAG_TRANSFORM_FUNC( 32f_C2R, float, double, CV_NOP, CV_NOP, CV_CAST_32F, 2 )
+ICV_DEF_DIAG_TRANSFORM_FUNC( 32f_C3R, float, double, CV_NOP, CV_NOP, CV_CAST_32F, 3 )
+ICV_DEF_DIAG_TRANSFORM_FUNC( 32f_C4R, float, double, CV_NOP, CV_NOP, CV_CAST_32F, 4 )
+
+ICV_DEF_DIAG_TRANSFORM_FUNC( 64f_C1R, double, double, CV_NOP, CV_NOP, CV_CAST_64F, 1 )
+ICV_DEF_DIAG_TRANSFORM_FUNC( 64f_C2R, double, double, CV_NOP, CV_NOP, CV_CAST_64F, 2 )
+ICV_DEF_DIAG_TRANSFORM_FUNC( 64f_C3R, double, double, CV_NOP, CV_NOP, CV_CAST_64F, 3 )
+ICV_DEF_DIAG_TRANSFORM_FUNC( 64f_C4R, double, double, CV_NOP, CV_NOP, CV_CAST_64F, 4 )
+
+#define icvTransform_8s_C1R 0
+#define icvTransform_8s_C2R 0
+#define icvTransform_8s_C3R 0
+#define icvTransform_8s_C4R 0
+
+#define icvDiagTransform_8s_C1R 0
+#define icvDiagTransform_8s_C2R 0
+#define icvDiagTransform_8s_C3R 0
+#define icvDiagTransform_8s_C4R 0
+
+#define icvDiagTransform_8u_C1R 0
+#define icvDiagTransform_8u_C2R 0
+#define icvDiagTransform_8u_C3R 0
+#define icvDiagTransform_8u_C4R 0
+
+CV_DEF_INIT_BIG_FUNC_TAB_2D( Transform, R )
+CV_DEF_INIT_BIG_FUNC_TAB_2D( DiagTransform, R )
+
+typedef CvStatus (CV_STDCALL * CvTransformFunc)(
+ const void* src, int srcstep,
+ void* dst, int dststep, CvSize size,
+ const void* mat, int dst_cn );
+
+typedef CvStatus (CV_STDCALL * CvDiagTransformFunc)(
+ const void* src, int srcstep,
+ void* dst, int dststep, CvSize size,
+ const void* mat );
+
+typedef CvStatus (CV_STDCALL * CvDiagTransformFunc)(
+ const void* src, int srcstep,
+ void* dst, int dststep, CvSize size,
+ const void* mat );
+
+///////////////////// IPP transform functions //////////////////
+
+icvColorTwist_8u_C3R_t icvColorTwist_8u_C3R_p = 0;
+icvColorTwist_16u_C3R_t icvColorTwist_16u_C3R_p = 0;
+icvColorTwist_16s_C3R_t icvColorTwist_16s_C3R_p = 0;
+icvColorTwist_32f_C3R_t icvColorTwist_32f_C3R_p = 0;
+icvColorTwist_32f_C4R_t icvColorTwist_32f_C4R_p = 0;
+
+icvColorToGray_8u_C3C1R_t icvColorToGray_8u_C3C1R_p = 0;
+icvColorToGray_16u_C3C1R_t icvColorToGray_16u_C3C1R_p = 0;
+icvColorToGray_16s_C3C1R_t icvColorToGray_16s_C3C1R_p = 0;
+icvColorToGray_32f_C3C1R_t icvColorToGray_32f_C3C1R_p = 0;
+
+icvColorToGray_8u_AC4C1R_t icvColorToGray_8u_AC4C1R_p = 0;
+icvColorToGray_16u_AC4C1R_t icvColorToGray_16u_AC4C1R_p = 0;
+icvColorToGray_16s_AC4C1R_t icvColorToGray_16s_AC4C1R_p = 0;
+icvColorToGray_32f_AC4C1R_t icvColorToGray_32f_AC4C1R_p = 0;
+
+typedef CvStatus (CV_STDCALL * CvColorTwistIPPFunc)( const void* src, int srcstep,
+ void* dst, int dststep, CvSize size, const float* coeffs );
+
+////////////////////////////////////////////////////////////////
+
+CV_IMPL void
+cvTransform( const CvArr* srcarr, CvArr* dstarr,
+ const CvMat* transmat, const CvMat* shiftvec )
+{
+ static CvBigFuncTable transform_tab, diag_transform_tab;
+ static int inittab = 0;
+ CvMat* lut = 0;
+
+ CV_FUNCNAME( "cvTransform" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src = (CvMat*)srcarr;
+ CvMat dststub, *dst = (CvMat*)dstarr;
+ CvMat rotstub, *rot = (CvMat*)transmat;
+ CvMat shiftstub, *shift = (CvMat*)shiftvec;
+ CvSeq *src_seq = 0, *dst_seq = 0;
+ CvSeq hdr; // need only one copy of stub header & seqblock (either for src or dst)
+ CvSeqBlock block_hdr;
+ int i, j, type, cn, dst_cn;
+ int coi = 0, coi2 = 0;
+ double* buffer = (double*)cvStackAlloc( CV_CN_MAX*(CV_CN_MAX+1)*sizeof(buffer[0]) );
+
+ if( !inittab )
+ {
+ icvInitTransformRTable( &transform_tab );
+ icvInitDiagTransformRTable( &diag_transform_tab );
+ inittab = 1;
+ }
+
+ if( CV_IS_SEQ( src ))
+ {
+ src_seq = (CvSeq*)src;
+ if( CV_ELEM_SIZE(src_seq->flags) != src_seq->elem_size )
+ CV_ERROR( CV_StsUnsupportedFormat, "Unsupported type of sequence elements" );
+ }
+ else
+ CV_CALL( src = cvGetMat( src, &srcstub, &coi ));
+
+ if( CV_IS_SEQ( dst ))
+ {
+ dst_seq = (CvSeq*)dst;
+ if( CV_ELEM_SIZE(dst_seq->flags) != dst_seq->elem_size )
+ CV_ERROR( CV_StsUnsupportedFormat, "Unsupported type of sequence elements" );
+ }
+ else
+ CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 ));
+
+ if( coi != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ if( !CV_ARE_DEPTHS_EQ(src, dst) )
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( src_seq || dst_seq )
+ {
+ if( !src_seq )
+ {
+ if( CV_IS_MAT_CONT(src->type) || (src->rows != 1 && src->cols != 1) )
+ CV_ERROR( CV_StsBadSize, "if eigher the source or destination is a sequence, "
+ "the other array must be also a sequence of continous 1d vector" );
+ src_seq = cvMakeSeqHeaderForArray( CV_MAT_TYPE(src->type), sizeof(hdr),
+ CV_ELEM_SIZE(src->type), src->data.ptr,
+ src->rows + src->cols + 1, &hdr, &block_hdr );
+ }
+
+ if( !dst_seq )
+ {
+ if( CV_IS_MAT_CONT(dst->type) || (dst->rows != 1 && dst->cols != 1) )
+ CV_ERROR( CV_StsBadSize, "if eigher the source or destination is a sequence, "
+ "the other array must be also a sequence of continous 1d vector" );
+ if( dst->rows + dst->cols - 1 != src_seq->total )
+ CV_ERROR( CV_StsUnmatchedFormats,
+ "source sequence and destination vector have different sizes" );
+ dst_seq = cvMakeSeqHeaderForArray( CV_MAT_TYPE(dst->type), sizeof(hdr),
+ CV_ELEM_SIZE(dst->type), dst->data.ptr,
+ dst->rows + dst->cols + 1, &hdr, &block_hdr );
+ }
+ else if( dst_seq->total != src_seq->total )
+ {
+ if( dst_seq->total > src_seq->total )
+ cvSeqPopMulti( dst_seq, 0, dst_seq->total - src_seq->total );
+ else
+ cvSeqPushMulti( dst_seq, 0, src_seq->total - dst_seq->total );
+ }
+ }
+ else if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ type = CV_MAT_TYPE( src->type );
+ cn = CV_MAT_CN( type );
+ dst_cn = CV_MAT_CN( dst->type );
+
+ if( cn > 4 || dst_cn > 4 )
+ CV_ERROR( CV_StsOutOfRange, "Both input and output array must have at most 4 channels" );
+
+ if( !CV_IS_MAT( rot ))
+ CV_CALL( rot = cvGetMat( rot, &rotstub, &coi ));
+
+ if( rot->rows != dst_cn )
+ CV_ERROR( CV_StsBadSize,
+ "The height of transmat matrix must be equal to number of channels" );
+
+ if( rot->cols == cn + 1 || rot->cols == cn )
+ {
+ if( CV_MAT_TYPE( rot->type ) == CV_64FC1 )
+ {
+ for( i = 0; i < dst_cn; i++ )
+ {
+ buffer[i*(cn+1) + cn] = 0;
+ for( j = 0; j < rot->cols; j++ )
+ buffer[i*(cn+1) + j] = ((double*)(rot->data.ptr + rot->step*i))[j];
+ }
+ }
+ else if( CV_MAT_TYPE( rot->type ) == CV_32FC1 )
+ {
+ for( i = 0; i < dst_cn; i++ )
+ {
+ buffer[i*(cn+1) + cn] = 0;
+ for( j = 0; j < rot->cols; j++ )
+ buffer[i*(cn+1) + j] = ((float*)(rot->data.ptr + rot->step*i))[j];
+ }
+ }
+ else
+ CV_ERROR( CV_StsUnsupportedFormat, "Rotation matrix must be 32fC1 or 64fC1" );
+ }
+ else
+ CV_ERROR( CV_StsUnmatchedSizes, "If the source array has <cn> channels, "
+ "the transformation matrix must have <cn> x <cn>+1 or <cn> x <cn> size" );
+
+ if( shift )
+ {
+ if( !CV_IS_MAT( shift ))
+ CV_CALL( shift = cvGetMat( shift, &shiftstub, &coi ));
+
+ if( CV_MAT_CN( shift->type ) * shift->cols * shift->rows == dst_cn &&
+ (shift->rows == 1 || shift->cols == 1) )
+ {
+ if( CV_MAT_DEPTH( shift->type ) == CV_64F )
+ {
+ int step = shift->step ? shift->step/sizeof(double) : 1;
+ for( i = 0; i < dst_cn; i++ )
+ buffer[i*(cn+1) + cn] += shift->data.db[i*step];
+ }
+ else if( CV_MAT_DEPTH( shift->type ) == CV_32F )
+ {
+ int step = shift->step ? shift->step/sizeof(float) : 1;
+ for( i = 0; i < dst_cn; i++ )
+ buffer[i*(cn+1) + cn] += shift->data.fl[i*step];
+ }
+ else
+ CV_ERROR( CV_StsUnsupportedFormat, "Shift vector must be 32f or 64f" );
+ }
+ else
+ {
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Shift (if present) must be 1 dimensional vector with the number "
+ "of elements equal to number of channels in the processed array" );
+ }
+ }
+
+ if( coi != 0 || coi2 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ {
+ CvTransformFunc func = (CvTransformFunc)(transform_tab.fn_2d[type]);
+ CvDiagTransformFunc diag_func = 0;
+ CvLUT_TransformFunc lut_func = 0;
+ int diag_transform = 0;
+ CvColorTwistIPPFunc ipp_func = 0;
+ CvSize size;
+ float* ipp_coeffs = (float*)cvStackAlloc( 16*sizeof(ipp_coeffs[0]) );
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( cn == dst_cn )
+ ipp_func = type == CV_8UC3 ? icvColorTwist_8u_C3R_p :
+ type == CV_16UC3 ? icvColorTwist_16u_C3R_p :
+ type == CV_16SC3 ? icvColorTwist_16s_C3R_p :
+ type == CV_32FC3 ? icvColorTwist_32f_C3R_p :
+ type == CV_32FC4 && fabs(buffer[4]) < DBL_EPSILON &&
+ fabs(buffer[9]) < DBL_EPSILON && fabs(buffer[14]) < DBL_EPSILON &&
+ fabs(buffer[19]) < DBL_EPSILON ? icvColorTwist_32f_C4R_p : 0;
+ else if( dst_cn == 1 && (cn == 3 || cn == 4) &&
+ buffer[0] >= 0 && buffer[1] >= 0 && buffer[2] >= 0 &&
+ buffer[0] + buffer[1] + buffer[2] <= 1.01 &&
+ fabs(buffer[3]) < DBL_EPSILON && (cn == 3 || fabs(buffer[4]) < DBL_EPSILON) )
+ {
+ if( cn == 3 )
+ ipp_func = type == CV_8UC3 ? icvColorToGray_8u_C3C1R_p :
+ type == CV_16UC3 ? icvColorToGray_16u_C3C1R_p :
+ type == CV_16SC3 ? icvColorToGray_16s_C3C1R_p :
+ type == CV_32FC3 ? icvColorToGray_32f_C3C1R_p : 0;
+ else
+ ipp_func = type == CV_8UC4 ? icvColorToGray_8u_AC4C1R_p :
+ type == CV_16UC4 ? icvColorToGray_16u_AC4C1R_p :
+ type == CV_16SC4 ? icvColorToGray_16s_AC4C1R_p :
+ type == CV_32FC4 ? icvColorToGray_32f_AC4C1R_p : 0;
+ }
+
+ if( dst_cn == cn )
+ {
+ diag_transform = 1;
+ for( i = 0; i < dst_cn; i++ )
+ for( j = 0; j < cn; j++ )
+ {
+ if( i != j && fabs(buffer[i*(cn+1) + j]) > DBL_EPSILON )
+ {
+ diag_transform = 0;
+ break;
+ }
+ }
+
+ if( diag_transform )
+ {
+ if( CV_MAT_DEPTH(type) == CV_8U )
+ {
+ CV_CALL( lut = cvCreateMat( 1, 256, type ));
+ for( i = 0; i < cn; i++ )
+ {
+ double a = buffer[i*(cn+1) + i], b = buffer[i*(cn+1) + cn];
+ uchar* ltab = lut->data.ptr;
+ for( j = 0; j < 256; j++ )
+ {
+ int t = cvRound(a*j + b);
+ ltab[j*cn + i] = CV_CAST_8U(t);
+ }
+ }
+ lut_func = cn == 1 ? (CvLUT_TransformFunc)icvLUT_Transform8u_8u_C1R :
+ cn == 2 ? (CvLUT_TransformFunc)icvLUT_Transform8u_8u_C2R :
+ cn == 3 ? (CvLUT_TransformFunc)icvLUT_Transform8u_8u_C3R :
+ (CvLUT_TransformFunc)icvLUT_Transform8u_8u_C4R;
+ }
+ else
+ diag_func = (CvDiagTransformFunc)(diag_transform_tab.fn_2d[type]);
+ }
+ }
+
+ if( ipp_func )
+ {
+ const double* ptr = buffer;
+
+ // fill cn x 4 ipp_coeffs array
+ for( i = 0; i < cn*4; i += 4, ptr += cn+1 )
+ {
+ float t0 = (float)ptr[0];
+ float t1 = (float)ptr[1];
+ ipp_coeffs[i] = t0;
+ ipp_coeffs[i+1] = t1;
+ t0 = (float)ptr[2];
+ t1 = (float)ptr[3];
+ ipp_coeffs[i+2] = t0;
+ ipp_coeffs[i+3] = t1;
+ }
+ }
+
+ if( !src_seq )
+ {
+ int srcstep = src->step;
+ int dststep = dst->step;
+ size = cvGetMatSize( src );
+
+ if( CV_IS_MAT_CONT( src->type & dst->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ srcstep = dststep = CV_STUB_STEP;
+ }
+
+ if( lut_func )
+ lut_func( src->data.ptr, src->step, dst->data.ptr,
+ dst->step, size, lut->data.ptr );
+ else if( ipp_func )
+ {
+ IPPI_CALL( ipp_func( src->data.ptr, srcstep, dst->data.ptr,
+ dststep, size, ipp_coeffs ));
+ }
+ else if( diag_transform )
+ diag_func( src->data.ptr, src->step, dst->data.ptr,
+ dst->step, size, buffer );
+ else
+ func( src->data.ptr, src->step, dst->data.ptr,
+ dst->step, size, buffer, dst_cn );
+ }
+ else
+ {
+ CvSeqBlock* src_block = src_seq->first;
+ CvSeqBlock* dst_block = dst_seq->first;
+ int src_idx = 0, dst_idx = 0;
+ int src_elem_size = CV_ELEM_SIZE(src_seq->flags);
+ int dst_elem_size = CV_ELEM_SIZE(dst_seq->flags);
+
+ for( i = src_seq->total; i > 0; )
+ {
+ int src_len = src_block->count - src_idx;
+ int dst_len = dst_block->count - dst_idx;
+ const void* srcptr = src_block->data + src_idx*src_elem_size;
+ void* dstptr = dst_block->data + dst_idx*dst_elem_size;
+ src_len = MIN(src_len, dst_len);
+
+ if( lut_func )
+ lut_func( srcptr, CV_STUB_STEP, dstptr, CV_STUB_STEP,
+ cvSize( src_len, 1 ), lut->data.ptr );
+ else if( ipp_func )
+ {
+ IPPI_CALL( ipp_func( srcptr, CV_STUB_STEP, dstptr, CV_STUB_STEP,
+ cvSize( src_len, 1 ), ipp_coeffs ));
+ }
+ else if( diag_transform )
+ diag_func( srcptr, CV_STUB_STEP, dstptr, CV_STUB_STEP,
+ cvSize( src_len, 1 ), buffer );
+ else
+ func( srcptr, CV_STUB_STEP, dstptr, CV_STUB_STEP,
+ cvSize( src_len, 1 ), buffer, dst_cn );
+
+ if( (src_idx += src_len) == src_block->count )
+ src_block = src_block->next, src_idx = 0;
+ if( (dst_idx += src_len) == dst_block->count )
+ dst_block = dst_block->next, dst_idx = 0;
+ i -= src_len;
+ }
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &lut );
+}
+
+
+/****************************************************************************************\
+* cvPerspectiveTransform *
+\****************************************************************************************/
+
+#define ICV_PERSPECTIVE_TRANSFORM_FUNC_2( flavor, arrtype ) \
+static CvStatus CV_STDCALL \
+icvPerspectiveTransform_##flavor##_C2R( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, \
+ CvSize size, const double* mat ) \
+{ \
+ int i; \
+ size.width *= 2; \
+ srcstep /= sizeof(src[0]); dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ for( i = 0; i < size.width; i += 2 ) \
+ { \
+ arrtype x = src[i], y = src[i + 1]; \
+ double w = x*mat[6] + y*mat[7] + mat[8]; \
+ \
+ if( fabs(w) > FLT_EPSILON ) \
+ { \
+ w = 1./w; \
+ dst[i] = (arrtype)((x*mat[0] + y*mat[1] + mat[2]) * w); \
+ dst[i+1] = (arrtype)((x*mat[3] + y*mat[4] + mat[5]) * w); \
+ } \
+ else \
+ { \
+ dst[i] = (arrtype)0; \
+ dst[i+1] = (arrtype)0; \
+ } \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_PERSPECTIVE_TRANSFORM_FUNC_3( flavor, arrtype ) \
+static CvStatus CV_STDCALL \
+icvPerspectiveTransform_##flavor##_C3R( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, \
+ CvSize size, const double* mat ) \
+{ \
+ int i; \
+ size.width *= 3; \
+ srcstep /= sizeof(src[0]); dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ for( i = 0; i < size.width; i += 3 ) \
+ { \
+ arrtype x = src[i], y = src[i + 1], z = src[i + 2]; \
+ double w = x*mat[12] + y*mat[13] + z*mat[14] + mat[15]; \
+ \
+ if( fabs(w) > FLT_EPSILON ) \
+ { \
+ w = 1./w; \
+ dst[i] = (arrtype)((x*mat[0] + y*mat[1] + z*mat[2] + mat[3]) * w); \
+ dst[i+1] = (arrtype)((x*mat[4] + y*mat[5] + z*mat[6] + mat[7]) * w); \
+ dst[i+2] = (arrtype)((x*mat[8] + y*mat[9] + z*mat[10] + mat[11]) * w); \
+ } \
+ else \
+ { \
+ dst[i] = (arrtype)0; \
+ dst[i+1] = (arrtype)0; \
+ dst[i+2] = (arrtype)0; \
+ } \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+ICV_PERSPECTIVE_TRANSFORM_FUNC_2( 32f, float )
+ICV_PERSPECTIVE_TRANSFORM_FUNC_2( 64f, double )
+ICV_PERSPECTIVE_TRANSFORM_FUNC_3( 32f, float )
+ICV_PERSPECTIVE_TRANSFORM_FUNC_3( 64f, double )
+
+static void icvInitPerspectiveTransformTable( CvFuncTable* tab2, CvFuncTable* tab3 )\
+{ \
+ tab2->fn_2d[CV_32F] = (void*)icvPerspectiveTransform_32f_C2R; \
+ tab2->fn_2d[CV_64F] = (void*)icvPerspectiveTransform_64f_C2R; \
+ tab3->fn_2d[CV_32F] = (void*)icvPerspectiveTransform_32f_C3R; \
+ tab3->fn_2d[CV_64F] = (void*)icvPerspectiveTransform_64f_C3R; \
+}
+
+
+CV_IMPL void
+cvPerspectiveTransform( const CvArr* srcarr, CvArr* dstarr, const CvMat* mat )
+{
+ static CvFuncTable tab[2];
+ static int inittab = 0;
+ double buffer[16];
+
+ CV_FUNCNAME( "cvPerspectiveProject" );
+
+ __BEGIN__;
+
+ CvMat sstub, *src = (CvMat*)srcarr;
+ CvMat dstub, *dst = (CvMat*)dstarr;
+ int i, j, type, cn;
+ CvFunc2D_2A1P func = 0;
+ CvSize size;
+
+ if( !inittab )
+ {
+ icvInitPerspectiveTransformTable( &tab[0], &tab[1] );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT( src ))
+ {
+ int coi = 0;
+ CV_CALL( src = cvGetMat( src, &sstub, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_IS_MAT( dst ))
+ {
+ int coi = 0;
+ CV_CALL( dst = cvGetMat( dst, &dstub, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ type = CV_MAT_TYPE( src->type );
+ cn = CV_MAT_CN( type );
+
+ if( cn != 2 && cn != 3 )
+ CV_ERROR( CV_BadNumChannels, cvUnsupportedFormat );
+
+ if( !CV_IS_MAT( mat ))
+ CV_ERROR( CV_StsBadArg, "Invalid transformation matrix" );
+
+ if( mat->rows != cn + 1 && mat->cols != mat->rows )
+ CV_ERROR( CV_StsBadSize,
+ "The size of transform matrix must be equal to number of channels" );
+
+ if( CV_MAT_TYPE( mat->type ) == CV_64FC1 )
+ {
+ for( i = 0; i <= cn; i++ )
+ {
+ for( j = 0; j <= cn; j++ )
+ buffer[i*(cn+1) + j] = ((double*)(mat->data.ptr + mat->step*i))[j];
+ }
+ }
+ else if( CV_MAT_TYPE( mat->type ) == CV_32FC1 )
+ {
+ for( i = 0; i <= cn; i++ )
+ {
+ for( j = 0; j <= cn; j++ )
+ buffer[i*(cn+1) + j] = ((float*)(mat->data.ptr + mat->step*i))[j];
+ }
+ }
+ else
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "Rotation matrix must be 32fC1 or 64fC1" );
+ }
+
+ func = (CvFunc2D_2A1P)tab[cn == 3].fn_2d[CV_MAT_DEPTH(type)];
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ size = cvGetMatSize( src );
+
+ if( CV_IS_MAT_CONT( src->type & dst->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ }
+
+ IPPI_CALL( func( src->data.ptr, src->step, dst->data.ptr, dst->step, size, buffer));
+
+ CV_CHECK_NANS( dst );
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* cvScaleAdd *
+\****************************************************************************************/
+
+#define ICV_DEF_MULADDC_CASE_C1( arrtype, temptype, src1, src2, dst, len ) \
+{ \
+ int i; \
+ \
+ for( i = 0; i <= (len) - 4; i += 4 ) \
+ { \
+ temptype t0 = (src1)[i]*s0 + (src2)[i]; \
+ temptype t1 = (src1)[i+1]*s0 + (src2)[i+1]; \
+ \
+ (dst)[i] = (arrtype)t0; \
+ (dst)[i+1] = (arrtype)t1; \
+ \
+ t0 = (src1)[i+2]*s0 + (src2)[i+2]; \
+ t1 = (src1)[i+3]*s0 + (src2)[i+3]; \
+ \
+ (dst)[i+2] = (arrtype)t0; \
+ (dst)[i+3] = (arrtype)t1; \
+ } \
+ \
+ for( ; i < (len); i++ ) \
+ { \
+ temptype t0 = (src1)[i]*s0 + (src2)[i]; \
+ (dst)[i] = (arrtype)t0; \
+ } \
+}
+
+
+#define ICV_DEF_MULADDC_CASE_C2( arrtype, temptype, src1, src2, dst, len ) \
+{ \
+ int i; \
+ \
+ for( i = 0; i <= (len) - 4; i += 4 ) \
+ { \
+ temptype t0 = (src1)[i]*s0 - (src1)[i+1]*s1 + (src2)[i]; \
+ temptype t1 = (src1)[i]*s1 + (src1)[i+1]*s0 + (src2)[i+1]; \
+ \
+ (dst)[i] = (arrtype)t0; \
+ (dst)[i+1] = (arrtype)t1; \
+ \
+ t0 = (src1)[i+2]*s0 - (src1)[i+3]*s1 + (src2)[i+2]; \
+ t1 = (src1)[i+2]*s1 + (src1)[i+3]*s0 + (src2)[i+3]; \
+ \
+ (dst)[i+2] = (arrtype)t0; \
+ (dst)[i+3] = (arrtype)t1; \
+ } \
+ \
+ for( ; i < (len); i += 2 ) \
+ { \
+ temptype t0 = (src1)[i]*s0 - (src1)[i+1]*s1 + (src2)[i]; \
+ temptype t1 = (src1)[i]*s1 + (src1)[i+1]*s0 + (src2)[i+1]; \
+ \
+ (dst)[i] = (arrtype)t0; \
+ (dst)[i+1] = (arrtype)t1; \
+ } \
+}
+
+
+#define ICV_DEF_MULADDS_FUNC( flavor, arrtype, scalartype, entry, cn ) \
+static CvStatus CV_STDCALL \
+icvMulAddC_##flavor( const arrtype* src1, int srcstep1, \
+ const arrtype* src2, int srcstep2, \
+ arrtype* dst, int dststep, CvSize size, \
+ const scalartype* scalar ) \
+{ \
+ entry(scalartype); \
+ size.width *= (cn); \
+ srcstep1 /= sizeof(src1[0]); srcstep2 /= sizeof(src2[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src1+=srcstep1, src2+=srcstep2, dst+=dststep ) \
+ { \
+ ICV_DEF_MULADDC_CASE_C##cn( arrtype, scalartype, src1, src2, \
+ dst, size.width ) \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_MULADDS_FUNC( 32f_C1R, float, double, CV_UN_ENTRY_C1, 1 )
+ICV_DEF_MULADDS_FUNC( 32f_C2R, float, double, CV_UN_ENTRY_C2, 2 )
+ICV_DEF_MULADDS_FUNC( 64f_C1R, double, double, CV_UN_ENTRY_C1, 1 )
+ICV_DEF_MULADDS_FUNC( 64f_C2R, double, double, CV_UN_ENTRY_C2, 2 )
+
+
+static void
+icvInitMulAddCTable( CvBigFuncTable* tab )
+{
+ tab->fn_2d[CV_32FC1] = (void*)icvMulAddC_32f_C1R;
+ tab->fn_2d[CV_32FC2] = (void*)icvMulAddC_32f_C2R;
+ tab->fn_2d[CV_64FC1] = (void*)icvMulAddC_64f_C1R;
+ tab->fn_2d[CV_64FC2] = (void*)icvMulAddC_64f_C2R;
+}
+
+
+CV_IMPL void
+cvScaleAdd( const CvArr* srcarr1, CvScalar scale,
+ const CvArr* srcarr2, CvArr* dstarr )
+{
+ static CvBigFuncTable muladds_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvScaleAdd" );
+
+ __BEGIN__;
+
+ CvMat stub1, *src1 = (CvMat*)srcarr1;
+ CvMat stub2, *src2 = (CvMat*)srcarr2;
+ CvMat stub, *dst = (CvMat*)dstarr;
+ CvSize size;
+ int type;
+
+ if( !CV_IS_MAT( src1 ) || !CV_IS_MAT(src2) || !CV_IS_MAT(dst))
+ {
+ int coi1 = 0, coi2 = 0, coi3 = 0;
+ CV_CALL( src1 = cvGetMat( src1, &stub1, &coi1 ));
+ CV_CALL( src2 = cvGetMat( src2, &stub2, &coi2 ));
+ CV_CALL( dst = cvGetMat( dst, &stub, &coi3 ));
+
+ if( coi1 + coi2 + coi3 != 0 )
+ CV_ERROR( CV_BadCOI, "" );
+ }
+
+ if( !CV_ARE_TYPES_EQ( src1, dst ) || !CV_ARE_TYPES_EQ( src2, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( !CV_ARE_SIZES_EQ( src1, dst ) || !CV_ARE_SIZES_EQ( src2, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ type = CV_MAT_TYPE( src1->type );
+ size = cvGetMatSize( src1 );
+
+ if( CV_IS_MAT_CONT( src1->type & src2->type & dst->type ))
+ {
+ size.width *= size.height;
+
+ if( size.width <= CV_MAX_INLINE_MAT_OP_SIZE )
+ {
+ if( type == CV_32FC1 )
+ {
+ float* mA = src1->data.fl;
+ float* mB = src2->data.fl;
+ float* mC = dst->data.fl;
+
+ do
+ {
+ mC[size.width - 1] = (float)(mA[size.width - 1]*scale.val[0] +
+ mB[size.width - 1]);
+ }
+ while( --size.width );
+
+ EXIT;
+ }
+
+ if( type == CV_64FC1 )
+ {
+ double* mA = src1->data.db;
+ double* mB = src2->data.db;
+ double* mC = dst->data.db;
+
+ do
+ {
+ mC[size.width - 1] = mA[size.width - 1]*scale.val[0] +
+ mB[size.width - 1];
+ }
+ while( --size.width );
+
+ EXIT;
+ }
+ }
+
+ size.height = 1;
+ }
+
+ if( !inittab )
+ {
+ icvInitMulAddCTable( &muladds_tab );
+ inittab = 1;
+ }
+
+ if( CV_MAT_CN(type) > 2 )
+ CV_ERROR( CV_StsOutOfRange, "The function only supports 1- and 2-channel arrays" );
+
+ {
+ CvFunc2D_3A1P func = (CvFunc2D_3A1P)(muladds_tab.fn_2d[type]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src1->data.ptr, src1->step, src2->data.ptr, src2->step,
+ dst->data.ptr, dst->step, size, scale.val ));
+ }
+
+ CV_CHECK_NANS( dst );
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* cvCalcCovarMatrix *
+\****************************************************************************************/
+
+#define ICV_DOT_PRODUCT_CASE( flavor, srctype, avgtype, load_macro ) \
+static CvStatus CV_STDCALL \
+icvDotProductShifted_##flavor##_C1R( const srctype* vec1, int vecstep1, \
+ const srctype* vec2, int vecstep2, \
+ const avgtype* avg, int avgstep, \
+ CvSize size, double* _result ) \
+{ \
+ double result = 0; \
+ vecstep1 /= sizeof(vec1[0]); vecstep2 /= sizeof(vec2[0]); avgstep /= sizeof(avg[0]);\
+ \
+ for( ; size.height--; vec1 += vecstep1, vec2 += vecstep2, avg += avgstep ) \
+ { \
+ int x; \
+ for( x = 0; x <= size.width - 4; x += 4 ) \
+ result += (load_macro(vec1[x]) - avg[x])*(load_macro(vec2[x]) - avg[x]) + \
+ (load_macro(vec1[x+1]) - avg[x+1])*(load_macro(vec2[x+1]) - avg[x+1]) + \
+ (load_macro(vec1[x+2]) - avg[x+2])*(load_macro(vec2[x+2]) - avg[x+2]) + \
+ (load_macro(vec1[x+3]) - avg[x+3])*(load_macro(vec2[x+3]) - avg[x+3]); \
+ for( ; x < size.width; x++ ) \
+ result += (load_macro(vec1[x]) - avg[x])*(load_macro(vec2[x]) - avg[x]); \
+ } \
+ \
+ *_result = result; \
+ return CV_OK; \
+}
+
+
+ICV_DOT_PRODUCT_CASE( 8u32f, uchar, float, CV_8TO32F )
+ICV_DOT_PRODUCT_CASE( 8u64f, uchar, double, CV_8TO32F )
+ICV_DOT_PRODUCT_CASE( 16u32f, ushort, float, CV_NOP )
+ICV_DOT_PRODUCT_CASE( 16u64f, ushort, double, CV_NOP )
+ICV_DOT_PRODUCT_CASE( 16s32f, short, float, CV_NOP )
+ICV_DOT_PRODUCT_CASE( 16s64f, short, double, CV_NOP )
+ICV_DOT_PRODUCT_CASE( 32f, float, float, CV_NOP )
+ICV_DOT_PRODUCT_CASE( 32f64f, float, double, CV_NOP )
+ICV_DOT_PRODUCT_CASE( 64f, double, double, CV_NOP )
+
+static void icvInitDotProductShiftedTable( CvFuncTable* tabfl, CvFuncTable* tabdb )
+{
+ tabfl->fn_2d[CV_8U] = (void*)icvDotProductShifted_8u32f_C1R;
+ tabfl->fn_2d[CV_8S] = 0;
+ tabfl->fn_2d[CV_16U] = (void*)icvDotProductShifted_16u32f_C1R;
+ tabfl->fn_2d[CV_16S] = (void*)icvDotProductShifted_16s32f_C1R;
+ tabfl->fn_2d[CV_32S] = 0;
+ tabfl->fn_2d[CV_32F] = (void*)icvDotProductShifted_32f_C1R;
+ tabfl->fn_2d[CV_64F] = 0;
+
+ tabdb->fn_2d[CV_8U] = (void*)icvDotProductShifted_8u64f_C1R;
+ tabdb->fn_2d[CV_8S] = 0;
+ tabdb->fn_2d[CV_16U] = (void*)icvDotProductShifted_16u64f_C1R;
+ tabdb->fn_2d[CV_16S] = (void*)icvDotProductShifted_16s64f_C1R;
+ tabdb->fn_2d[CV_32S] = 0;
+ tabdb->fn_2d[CV_32F] = (void*)icvDotProductShifted_32f64f_C1R;
+ tabdb->fn_2d[CV_64F] = (void*)icvDotProductShifted_64f_C1R;
+}
+
+#define ICV_EXT_PRODUCT_CASE( flavor, srctype, avgtype, load_macro ) \
+static CvStatus CV_STDCALL \
+icvExtProductShifted_##flavor##_C1R( const srctype* vec, int vecstep, \
+ const avgtype* avg, int avgstep, \
+ avgtype* dst, int dststep, \
+ CvSize size, avgtype* tempbuf ) \
+{ \
+ int x, y, dstsize = size.width * size.height; \
+ \
+ vecstep /= sizeof(vec[0]); avgstep /= sizeof(avg[0]); \
+ for( y = 0; y < size.height; y++, vec += vecstep, avg += avgstep ) \
+ for( x = 0; x < size.width; x++ ) \
+ *tempbuf++ = load_macro(vec[x]) - avg[x]; \
+ tempbuf -= dstsize; \
+ \
+ dststep /= sizeof(dst[0]); \
+ for( y = 0; y < dstsize; y++, dst += dststep ) \
+ { \
+ double ty = tempbuf[y]; \
+ for( x = 0; x <= y - 3; x += 4 ) \
+ { \
+ double t0 = dst[x] + ty*tempbuf[x]; \
+ double t1 = dst[x+1] + ty*tempbuf[x+1]; \
+ dst[x] = (avgtype)t0; \
+ dst[x+1] = (avgtype)t1; \
+ t0 = dst[x+2] + ty*tempbuf[x+2]; \
+ t1 = dst[x+3] + ty*tempbuf[x+3]; \
+ dst[x+2] = (avgtype)t0; \
+ dst[x+3] = (avgtype)t1; \
+ } \
+ for( ; x <= y; x++ ) \
+ dst[x] = (avgtype)(dst[x] + ty*tempbuf[x]); \
+ } \
+ \
+ return CV_OK; \
+}
+
+ICV_EXT_PRODUCT_CASE( 8u32f, uchar, float, CV_8TO32F )
+ICV_EXT_PRODUCT_CASE( 8u64f, uchar, double, CV_8TO32F )
+ICV_EXT_PRODUCT_CASE( 16u32f, ushort, float, CV_NOP )
+ICV_EXT_PRODUCT_CASE( 16u64f, ushort, double, CV_NOP )
+ICV_EXT_PRODUCT_CASE( 16s32f, short, float, CV_NOP )
+ICV_EXT_PRODUCT_CASE( 16s64f, short, double, CV_NOP )
+ICV_EXT_PRODUCT_CASE( 32f, float, float, CV_NOP )
+ICV_EXT_PRODUCT_CASE( 32f64f, float, double, CV_NOP )
+ICV_EXT_PRODUCT_CASE( 64f, double, double, CV_NOP )
+
+
+static void icvInitExtProductShiftedTable( CvFuncTable* tabfl, CvFuncTable* tabdb )
+{
+ tabfl->fn_2d[CV_8U] = (void*)icvExtProductShifted_8u32f_C1R;
+ tabfl->fn_2d[CV_8S] = 0;
+ tabfl->fn_2d[CV_16U] = (void*)icvExtProductShifted_16u32f_C1R;
+ tabfl->fn_2d[CV_16S] = (void*)icvExtProductShifted_16s32f_C1R;
+ tabfl->fn_2d[CV_32S] = 0;
+ tabfl->fn_2d[CV_32F] = (void*)icvExtProductShifted_32f_C1R;
+ tabfl->fn_2d[CV_64F] = 0;
+
+ tabdb->fn_2d[CV_8U] = (void*)icvExtProductShifted_8u64f_C1R;
+ tabdb->fn_2d[CV_8S] = 0;
+ tabdb->fn_2d[CV_16U] = (void*)icvExtProductShifted_16u64f_C1R;
+ tabdb->fn_2d[CV_16S] = (void*)icvExtProductShifted_16s64f_C1R;
+ tabdb->fn_2d[CV_32S] = 0;
+ tabdb->fn_2d[CV_32F] = (void*)icvExtProductShifted_32f64f_C1R;
+ tabdb->fn_2d[CV_64F] = (void*)icvExtProductShifted_64f_C1R;
+}
+
+
+typedef struct vec_data
+{
+ void* ptr;
+ int step;
+}
+vec_data;
+
+CV_IMPL void
+cvCalcCovarMatrix( const CvArr** vecarr, int count,
+ CvArr* covarr, CvArr* avgarr, int flags )
+{
+ static CvFuncTable dot_tab[2];
+ static CvFuncTable ext_tab[2];
+ static int inittab = 0;
+ vec_data* vecdata = 0;
+ CvMat *tempvec = 0;
+
+ CV_FUNCNAME( "cvCalcCovarMatrix" );
+
+ __BEGIN__;
+
+ CvMat covstub, *cov = (CvMat*)covarr;
+ CvMat avgstub, *avg = (CvMat*)avgarr;
+ CvMat vecstub0, *vecmat = 0;
+ CvSize srcsize, contsize;
+ int srctype = 0, dsttype = 0;
+ int i, j;
+ int cont_flag, vec_delta = 0, vec_step = 0;
+ int is_covar_normal = (flags & CV_COVAR_NORMAL) != 0;
+ double scale;
+
+ if( !inittab )
+ {
+ icvInitDotProductShiftedTable( dot_tab + 0, dot_tab + 1 );
+ icvInitExtProductShiftedTable( ext_tab + 0, ext_tab + 1 );
+ inittab = 1;
+ }
+
+ if( !vecarr )
+ CV_ERROR( CV_StsNullPtr, "NULL vec pointer" );
+
+ CV_CALL( cov = cvGetMat( cov, &covstub ));
+ CV_CALL( avg = cvGetMat( avg, &avgstub ));
+
+ if( !CV_ARE_TYPES_EQ( cov, avg ))
+ CV_ERROR( CV_StsUnmatchedFormats,
+ "Covariation matrix and average vector should have the same types" );
+
+ dsttype = CV_MAT_TYPE( cov->type );
+ if( dsttype != CV_32FC1 && dsttype != CV_64FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Covariation matrix must be 32fC1 or 64fC1" );
+
+ if( cov->rows != cov->cols )
+ CV_ERROR( CV_StsBadSize, "Covariation matrix must be square" );
+
+ srcsize = cvGetMatSize( avg );
+ contsize.width = srcsize.width * srcsize.height;
+ contsize.height = 1;
+ cont_flag = avg->type;
+
+ if( flags & (CV_COVAR_ROWS|CV_COVAR_COLS) )
+ {
+ CV_CALL( vecmat = cvGetMat( vecarr[0], &vecstub0 ));
+ srctype = CV_MAT_TYPE(vecmat->type);
+ if( flags & CV_COVAR_COLS )
+ {
+ count = vecmat->cols;
+ if( avg->cols != 1 || avg->rows != vecmat->rows )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The number of input vectors does not match to avg vector size" );
+ cont_flag = 0;
+ vec_delta = CV_ELEM_SIZE(vecmat->type);
+ vec_step = vecmat->step;
+ }
+ else
+ {
+ count = vecmat->rows;
+ if( avg->rows != 1 || avg->cols != vecmat->cols )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The number of input vectors does not match to avg vector size" );
+ vec_delta = vecmat->step;
+ vec_step = CV_STUB_STEP;
+ }
+
+ if( !(flags & CV_COVAR_USE_AVG) )
+ CV_CALL( cvReduce( vecmat, avg, -1, CV_REDUCE_AVG ));
+
+ scale = !(flags & CV_COVAR_SCALE) ? 1. : 1./count;
+
+ cvMulTransposed( vecmat, cov, ((flags & CV_COVAR_ROWS)!=0) ^ ((flags & CV_COVAR_NORMAL)==0), avg, scale );
+ EXIT;
+ }
+
+ scale = !(flags & CV_COVAR_SCALE) ? 1. : 1./count;
+
+ if( is_covar_normal )
+ {
+ if( count <= 0 )
+ CV_ERROR( CV_StsBadSize,
+ "The number of vectors is zero or negative" );
+ if( cov->rows != contsize.width )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The size of input vectors does not match with the size of covariation matrix" );
+
+ CV_CALL( tempvec = cvCreateMat( avg->rows, avg->cols, dsttype ));
+ }
+ else if( count != cov->rows )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The vector count and covariance matrix size do not match" );
+
+ if( !(flags & (CV_COVAR_ROWS|CV_COVAR_COLS)) )
+ {
+ if( !(flags & CV_COVAR_USE_AVG) )
+ cvZero( avg );
+
+ CV_CALL( vecdata = (vec_data*)cvAlloc( count*sizeof(vecdata[0])));
+
+ for( i = 0; i < count; i++ )
+ {
+ CvMat vecstub, *vec = (CvMat*)vecarr[i];
+ CvMat* temp;
+
+ if( !CV_IS_MAT(vec) )
+ CV_CALL( vec = cvGetMat( vec, &vecstub ));
+
+ if( !CV_ARE_SIZES_EQ( vec, avg ))
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "All input vectors and average vector must have the same size" );
+
+ vecdata[i].ptr = vec->data.ptr;
+ vecdata[i].step = vec->step;
+ cont_flag &= vec->type;
+ temp = vec;
+ if( i == 0 )
+ {
+ srctype = CV_MAT_TYPE( vec->type );
+ if( CV_MAT_CN( srctype ) != 1 )
+ CV_ERROR( CV_BadNumChannels, "All vectors must have a single channel" );
+ if( srctype != dsttype && !tempvec && !(flags & CV_COVAR_USE_AVG))
+ CV_CALL( tempvec = cvCreateMat( vec->rows, vec->cols, dsttype ));
+ }
+ else if( CV_MAT_TYPE(vec->type) != srctype )
+ CV_ERROR( CV_StsUnmatchedFormats,
+ "All input vectors must have the same type" );
+
+ if( !(flags & CV_COVAR_USE_AVG) )
+ {
+ if( tempvec )
+ {
+ temp = tempvec;
+ cvConvert( vec, temp );
+ }
+ cvAdd( temp, avg, avg );
+ }
+ }
+
+ if( !(flags & CV_COVAR_USE_AVG) )
+ cvScale( avg, avg, 1./count );
+ }
+
+ cont_flag = CV_IS_MAT_CONT( cont_flag );
+ if( cont_flag )
+ srcsize = contsize;
+
+ if( !is_covar_normal )
+ {
+ CvFunc2D_3A1P dot_func =
+ (CvFunc2D_3A1P)dot_tab[dsttype == CV_64FC1].fn_2d[CV_MAT_DEPTH(srctype)];
+
+ if( !dot_func )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "The format of input vectors is not supported" );
+
+ for( i = 0; i < count; i++ )
+ {
+ int a, b, delta;
+ if( !(i & 1) )
+ a = 0, b = i+1, delta = 1;
+ else
+ a = i, b = -1, delta = -1;
+
+ for( j = a; j != b; j += delta )
+ {
+ double result = 0;
+ void *v_i, *v_j;
+ int step_i, step_j;
+
+ if( !vecmat )
+ {
+ v_i = vecdata[i].ptr;
+ v_j = vecdata[j].ptr;
+ step_i = vecdata[i].step;
+ step_j = vecdata[j].step;
+ }
+ else
+ {
+ v_i = vecmat->data.ptr + vec_delta*i;
+ v_j = vecmat->data.ptr + vec_delta*j;
+ step_i = step_j = vec_step;
+ }
+
+ dot_func( v_i, step_i, v_j, step_j, avg->data.ptr, avg->step, srcsize, &result );
+
+ if( dsttype == CV_64FC1 )
+ {
+ ((double*)(cov->data.ptr + i*cov->step))[j] =
+ ((double*)(cov->data.ptr + j*cov->step))[i] = result*scale;
+ }
+ else
+ {
+ ((float*)(cov->data.ptr + i*cov->step))[j] =
+ ((float*)(cov->data.ptr + j*cov->step))[i] = (float)(result*scale);
+ }
+ }
+ }
+ }
+ else
+ {
+ uchar* cov_ptr = cov->data.ptr;
+ int cov_step = cov->step;
+ int cov_size = cov->rows;
+ CvFunc2D_3A1P ext_func =
+ (CvFunc2D_3A1P)ext_tab[dsttype == CV_64FC1].fn_2d[CV_MAT_DEPTH(srctype)];
+ if( !ext_func )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "The format of input vectors is not supported" );
+
+ cvZero( cov );
+
+ for( i = 0; i < count; i++ )
+ {
+ void* v;
+ int vstep;
+ if( !vecmat )
+ {
+ v = vecdata[i].ptr;
+ vstep = vecdata[i].step;
+ }
+ else
+ {
+ v = vecmat->data.ptr + vec_delta*i;
+ vstep = vec_step;
+ }
+
+ ext_func( v, vstep, avg->data.ptr, avg->step,
+ cov_ptr, cov_step, srcsize, tempvec->data.ptr );
+ }
+
+ if( dsttype == CV_64FC1 )
+ for( i = 0; i < cov_size; i++ )
+ for( j = 0; j <= i; j++ )
+ {
+ double* cov1 = ((double*)(cov_ptr + i*cov_step)) + j;
+ double* cov2 = ((double*)(cov_ptr + j*cov_step)) + i;
+
+ if( flags & CV_COVAR_SCALE )
+ *cov1 = *cov2 = *cov1*scale;
+ else
+ *cov2 = *cov1;
+ }
+ else
+ for( i = 0; i < cov_size; i++ )
+ for( j = 0; j <= i; j++ )
+ {
+ float* cov1 = ((float*)(cov_ptr + i*cov_step)) + j;
+ float* cov2 = ((float*)(cov_ptr + j*cov_step)) + i;
+
+ if( flags & CV_COVAR_SCALE )
+ *cov1 = *cov2 = (float)(*cov1*scale);
+ else
+ *cov2 = *cov1;
+ }
+ }
+
+ __END__;
+
+ cvFree( &vecdata );
+ cvReleaseMat( &tempvec );
+}
+
+/****************************************************************************************\
+* cvMahalanobis *
+\****************************************************************************************/
+
+#define ICV_MAHALANOBIS( flavor, arrtype ) \
+static CvStatus CV_STDCALL \
+icvMahalanobis_##flavor##_C1R( const arrtype* mat, int matstep, \
+ const arrtype* vec, int len, double* _result ) \
+{ \
+ int i, j; \
+ double result = 0; \
+ \
+ matstep /= sizeof(mat[0]); \
+ for( i = 0; i < len; i++, mat += matstep ) \
+ { \
+ double row_sum = 0; \
+ for( j = 0; j <= len - 4; j += 4 ) \
+ row_sum += vec[j]*mat[j] + vec[j+1]*mat[j+1] + \
+ vec[j+2]*mat[j+2] + vec[j+3]*mat[j+3]; \
+ for( ; j < len; j++ ) \
+ row_sum += vec[j]*mat[j]; \
+ result += row_sum * vec[i]; \
+ } \
+ *_result = result; \
+ \
+ return CV_OK; \
+}
+
+ICV_MAHALANOBIS( 32f, float )
+ICV_MAHALANOBIS( 64f, double )
+
+static void icvInitMahalanobisTable( CvFuncTable* tab )
+{
+ tab->fn_2d[CV_32F] = (void*)icvMahalanobis_32f_C1R;
+ tab->fn_2d[CV_64F] = (void*)icvMahalanobis_64f_C1R;
+}
+
+typedef CvStatus (CV_STDCALL * CvMahalanobisFunc)( const void* mat, int matstep,
+ const void* vec, int len, double* _result );
+
+CV_IMPL double
+cvMahalanobis( const CvArr* srcAarr, const CvArr* srcBarr, CvArr* matarr )
+{
+ static CvFuncTable mahal_tab;
+ static int inittab = 0;
+ uchar* buffer = 0;
+ int local_alloc = 0;
+ double dist = 0;
+
+ CV_FUNCNAME( "cvMahalanobis" );
+
+ __BEGIN__;
+
+ int buf_size, elem_size, len;
+ CvMat stubA, *srcA = (CvMat*)srcAarr;
+ CvMat stubB, *srcB = (CvMat*)srcBarr;
+ CvMat stub, *mat = (CvMat*)matarr;
+ CvMat temp;
+ CvMahalanobisFunc func;
+
+ if( !inittab )
+ {
+ icvInitMahalanobisTable( &mahal_tab );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(srcA) )
+ CV_CALL( srcA = cvGetMat( srcA, &stubA ));
+
+ if( !CV_IS_MAT(srcB) )
+ CV_CALL( srcB = cvGetMat( srcB, &stubB ));
+
+ if( !CV_IS_MAT(mat) )
+ CV_CALL( mat = cvGetMat( mat, &stub ));
+
+ if( srcA->rows != 1 && srcA->cols != 1 )
+ CV_ERROR( CV_StsBadSize, "Input matrices must be 1-d vectors" );
+
+ len = srcA->rows + srcA->cols - 1;
+
+ if( !CV_ARE_SIZES_EQ(srcA,srcB) )
+ CV_ERROR( CV_StsUnmatchedSizes, "Input vectors have different sizes" );
+
+ if( mat->rows != len || mat->cols != len )
+ CV_ERROR( CV_StsUnmatchedSizes, "Input vectors and covariation matrix have different sizes" );
+
+ func = (CvMahalanobisFunc)mahal_tab.fn_2d[CV_MAT_DEPTH(srcA->type)];
+
+ if( CV_MAT_CN(srcA->type) > 1 || !func )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Only single-channel floating-point vectors are supported" );
+
+ if( !CV_ARE_TYPES_EQ(srcA,srcB) || !CV_ARE_TYPES_EQ(srcA,mat) )
+ CV_ERROR( CV_StsUnmatchedSizes, "Input vectors have different sizes" );
+
+ elem_size = CV_ELEM_SIZE(srcA->type);
+ buf_size = len*elem_size;
+
+ if( buf_size <= CV_MAX_LOCAL_SIZE )
+ {
+ buffer = (uchar*)cvStackAlloc( buf_size );
+ local_alloc = 1;
+ }
+ else
+ {
+ CV_CALL( buffer = (uchar*)cvAlloc( buf_size ));
+ }
+
+ temp = cvMat( srcA->rows, srcA->cols, srcA->type, buffer );
+ CV_CALL( cvSub( srcA, srcB, &temp ));
+
+ IPPI_CALL( func( mat->data.ptr, mat->step, temp.data.ptr, len, &dist ));
+ dist = sqrt(dist);
+
+ __END__;
+
+ if( buffer && !local_alloc )
+ cvFree( &buffer );
+
+ return dist;
+}
+
+
+/****************************************************************************************\
+* cvMulTransposed *
+\****************************************************************************************/
+
+#define ICV_DEF_MULTRANS_R_FUNC( flavor, srctype, dsttype, load_macro ) \
+static CvStatus CV_STDCALL \
+icvMulTransposedR_##flavor( const srctype* src, int srcstep, \
+ dsttype* dst, int dststep, \
+ const dsttype* delta, int deltastep, \
+ CvSize size, int delta_cols, double scale ) \
+{ \
+ int i, j, k; \
+ dsttype* tdst = dst; \
+ dsttype* col_buf = 0; \
+ dsttype* delta_buf = 0; \
+ int local_alloc = 0; \
+ int buf_size = size.height*sizeof(dsttype); \
+ \
+ if( delta && delta_cols < size.width ) \
+ { \
+ assert( delta_cols == 1 ); \
+ buf_size += 4*buf_size; \
+ } \
+ \
+ if( buf_size <= CV_MAX_LOCAL_SIZE ) \
+ { \
+ col_buf = (dsttype*)cvStackAlloc( buf_size ); \
+ local_alloc = 1; \
+ } \
+ else \
+ { \
+ col_buf = (dsttype*)cvAlloc( buf_size ); \
+ if( !col_buf ) \
+ return CV_OUTOFMEM_ERR; \
+ } \
+ \
+ srcstep /= sizeof(src[0]); dststep /= sizeof(dst[0]); \
+ deltastep /= sizeof(delta[0]); \
+ \
+ if( delta && delta_cols < size.width ) \
+ { \
+ delta_buf = col_buf + size.height; \
+ for( i = 0; i < size.height; i++ ) \
+ delta_buf[i*4] = delta_buf[i*4+1] = \
+ delta_buf[i*4+2] = delta_buf[i*4+3] = delta[i*deltastep]; \
+ delta = delta_buf; \
+ deltastep = deltastep ? 4 : 0; \
+ } \
+ \
+ if( !delta ) \
+ for( i = 0; i < size.width; i++, tdst += dststep ) \
+ { \
+ for( k = 0; k < size.height; k++ ) \
+ col_buf[k] = src[k*srcstep+i]; \
+ \
+ for( j = i; j <= size.width - 4; j += 4 ) \
+ { \
+ double s0 = 0, s1 = 0, s2 = 0, s3 = 0; \
+ const srctype *tsrc = src + j; \
+ \
+ for( k = 0; k < size.height; k++, tsrc += srcstep ) \
+ { \
+ double a = col_buf[k]; \
+ s0 += a * load_macro(tsrc[0]); \
+ s1 += a * load_macro(tsrc[1]); \
+ s2 += a * load_macro(tsrc[2]); \
+ s3 += a * load_macro(tsrc[3]); \
+ } \
+ \
+ tdst[j] = (dsttype)(s0*scale); \
+ tdst[j+1] = (dsttype)(s1*scale); \
+ tdst[j+2] = (dsttype)(s2*scale); \
+ tdst[j+3] = (dsttype)(s3*scale); \
+ } \
+ \
+ for( ; j < size.width; j++ ) \
+ { \
+ double s0 = 0; \
+ const srctype *tsrc = src + j; \
+ \
+ for( k = 0; k < size.height; k++, tsrc += srcstep ) \
+ s0 += col_buf[k] * tsrc[0]; \
+ \
+ tdst[j] = (dsttype)(s0*scale); \
+ } \
+ } \
+ else \
+ for( i = 0; i < size.width; i++, tdst += dststep ) \
+ { \
+ if( !delta_buf ) \
+ for( k = 0; k < size.height; k++ ) \
+ col_buf[k] = load_macro(src[k*srcstep+i]) - delta[k*deltastep+i]; \
+ else \
+ for( k = 0; k < size.height; k++ ) \
+ col_buf[k] = load_macro(src[k*srcstep+i]) - delta_buf[k*deltastep]; \
+ \
+ for( j = i; j <= size.width - 4; j += 4 ) \
+ { \
+ double s0 = 0, s1 = 0, s2 = 0, s3 = 0; \
+ const srctype *tsrc = src + j; \
+ const dsttype *d = delta_buf ? delta_buf : delta + j; \
+ \
+ for( k = 0; k < size.height; k++, tsrc+=srcstep, d+=deltastep ) \
+ { \
+ double a = col_buf[k]; \
+ s0 += a * (load_macro(tsrc[0]) - d[0]); \
+ s1 += a * (load_macro(tsrc[1]) - d[1]); \
+ s2 += a * (load_macro(tsrc[2]) - d[2]); \
+ s3 += a * (load_macro(tsrc[3]) - d[3]); \
+ } \
+ \
+ tdst[j] = (dsttype)(s0*scale); \
+ tdst[j+1] = (dsttype)(s1*scale); \
+ tdst[j+2] = (dsttype)(s2*scale); \
+ tdst[j+3] = (dsttype)(s3*scale); \
+ } \
+ \
+ for( ; j < size.width; j++ ) \
+ { \
+ double s0 = 0; \
+ const srctype *tsrc = src + j; \
+ const dsttype *d = delta_buf ? delta_buf : delta + j; \
+ \
+ for( k = 0; k < size.height; k++, tsrc+=srcstep, d+=deltastep ) \
+ s0 += col_buf[k] * (load_macro(tsrc[0]) - d[0]); \
+ \
+ tdst[j] = (dsttype)(s0*scale); \
+ } \
+ } \
+ \
+ /* fill the lower part of the destination matrix */ \
+ for( i = 1; i < size.width; i++ ) \
+ for( j = 0; j < i; j++ ) \
+ dst[dststep*i + j] = dst[dststep*j + i]; \
+ \
+ if( col_buf && !local_alloc ) \
+ cvFree( &col_buf ); \
+ \
+ return CV_NO_ERR; \
+}
+
+
+#define ICV_DEF_MULTRANS_L_FUNC( flavor, srctype, dsttype, load_macro ) \
+static CvStatus CV_STDCALL \
+icvMulTransposedL_##flavor( const srctype* src, int srcstep, \
+ dsttype* dst, int dststep, \
+ dsttype* delta, int deltastep, \
+ CvSize size, int delta_cols, double scale ) \
+{ \
+ int i, j, k; \
+ dsttype* tdst = dst; \
+ \
+ srcstep /= sizeof(src[0]); dststep /= sizeof(dst[0]); \
+ deltastep /= sizeof(delta[0]); \
+ \
+ if( !delta ) \
+ for( i = 0; i < size.height; i++, tdst += dststep ) \
+ for( j = i; j < size.height; j++ ) \
+ { \
+ double s = 0; \
+ const srctype *tsrc1 = src + i*srcstep; \
+ const srctype *tsrc2 = src + j*srcstep; \
+ \
+ for( k = 0; k <= size.width - 4; k += 4 ) \
+ s += tsrc1[k]*tsrc2[k] + tsrc1[k+1]*tsrc2[k+1] + \
+ tsrc1[k+2]*tsrc2[k+2] + tsrc1[k+3]*tsrc2[k+3]; \
+ for( ; k < size.width; k++ ) \
+ s += tsrc1[k] * tsrc2[k]; \
+ tdst[j] = (dsttype)(s*scale); \
+ } \
+ else \
+ { \
+ dsttype* row_buf = 0; \
+ int local_alloc = 0; \
+ int buf_size = size.width*sizeof(dsttype); \
+ dsttype delta_buf[4]; \
+ int delta_shift = delta_cols == size.width ? 4 : 0; \
+ \
+ if( buf_size <= CV_MAX_LOCAL_SIZE ) \
+ { \
+ row_buf = (dsttype*)cvStackAlloc( buf_size ); \
+ local_alloc = 1; \
+ } \
+ else \
+ { \
+ row_buf = (dsttype*)cvAlloc( buf_size ); \
+ if( !row_buf ) \
+ return CV_OUTOFMEM_ERR; \
+ } \
+ \
+ for( i = 0; i < size.height; i++, tdst += dststep ) \
+ { \
+ const srctype *tsrc1 = src + i*srcstep; \
+ const dsttype *tdelta1 = delta + i*deltastep; \
+ \
+ if( delta_cols < size.width ) \
+ for( k = 0; k < size.width; k++ ) \
+ row_buf[k] = tsrc1[k] - tdelta1[0]; \
+ else \
+ for( k = 0; k < size.width; k++ ) \
+ row_buf[k] = tsrc1[k] - tdelta1[k]; \
+ \
+ for( j = i; j < size.height; j++ ) \
+ { \
+ double s = 0; \
+ const srctype *tsrc2 = src + j*srcstep; \
+ const dsttype *tdelta2 = delta + j*deltastep; \
+ if( delta_cols < size.width ) \
+ { \
+ delta_buf[0] = delta_buf[1] = \
+ delta_buf[2] = delta_buf[3] = tdelta2[0]; \
+ tdelta2 = delta_buf; \
+ } \
+ for( k = 0; k <= size.width-4; k += 4, tdelta2 += delta_shift ) \
+ s += row_buf[k]*(load_macro(tsrc2[k]) - tdelta2[0]) + \
+ row_buf[k+1]*(load_macro(tsrc2[k+1]) - tdelta2[1]) + \
+ row_buf[k+2]*(load_macro(tsrc2[k+2]) - tdelta2[2]) + \
+ row_buf[k+3]*(load_macro(tsrc2[k+3]) - tdelta2[3]); \
+ for( ; k < size.width; k++, tdelta2++ ) \
+ s += row_buf[k]*(load_macro(tsrc2[k]) - tdelta2[0]); \
+ tdst[j] = (dsttype)(s*scale); \
+ } \
+ } \
+ \
+ if( row_buf && !local_alloc ) \
+ cvFree( &row_buf ); \
+ } \
+ \
+ /* fill the lower part of the destination matrix */ \
+ for( j = 0; j < size.height - 1; j++ ) \
+ for( i = j; i < size.height; i++ ) \
+ dst[dststep*i + j] = dst[dststep*j + i]; \
+ \
+ return CV_NO_ERR; \
+}
+
+
+ICV_DEF_MULTRANS_R_FUNC( 8u32f, uchar, float, CV_8TO32F )
+ICV_DEF_MULTRANS_R_FUNC( 8u64f, uchar, double, CV_8TO32F )
+ICV_DEF_MULTRANS_R_FUNC( 32f, float, float, CV_NOP )
+ICV_DEF_MULTRANS_R_FUNC( 32f64f, float, double, CV_NOP )
+ICV_DEF_MULTRANS_R_FUNC( 64f, double, double, CV_NOP )
+ICV_DEF_MULTRANS_R_FUNC( 16u32f, ushort, float, CV_NOP )
+ICV_DEF_MULTRANS_R_FUNC( 16u64f, ushort, double, CV_NOP )
+ICV_DEF_MULTRANS_R_FUNC( 16s32f, short, float, CV_NOP )
+ICV_DEF_MULTRANS_R_FUNC( 16s64f, short, double, CV_NOP )
+
+ICV_DEF_MULTRANS_L_FUNC( 8u32f, uchar, float, CV_8TO32F )
+ICV_DEF_MULTRANS_L_FUNC( 8u64f, uchar, double, CV_8TO32F )
+ICV_DEF_MULTRANS_L_FUNC( 32f, float, float, CV_NOP )
+ICV_DEF_MULTRANS_L_FUNC( 32f64f, float, double, CV_NOP )
+ICV_DEF_MULTRANS_L_FUNC( 64f, double, double, CV_NOP )
+ICV_DEF_MULTRANS_L_FUNC( 16u32f, ushort, float, CV_NOP )
+ICV_DEF_MULTRANS_L_FUNC( 16u64f, ushort, double, CV_NOP )
+ICV_DEF_MULTRANS_L_FUNC( 16s32f, short, float, CV_NOP )
+ICV_DEF_MULTRANS_L_FUNC( 16s64f, short, double, CV_NOP )
+
+
+typedef CvStatus (CV_STDCALL * CvMulTransposedFunc)
+ ( const void* src, int srcstep,
+ void* dst, int dststep, const void* delta,
+ int deltastep, CvSize size, int delta_cols, double scale );
+
+CV_IMPL void
+cvMulTransposed( const CvArr* srcarr, CvArr* dstarr,
+ int order, const CvArr* deltaarr, double scale )
+{
+ const int gemm_level = 100; // boundary above which GEMM is faster.
+ CvMat* src2 = 0;
+
+ CV_FUNCNAME( "cvMulTransposed" );
+
+ __BEGIN__;
+
+ CvMat sstub, *src = (CvMat*)srcarr;
+ CvMat dstub, *dst = (CvMat*)dstarr;
+ CvMat deltastub, *delta = (CvMat*)deltaarr;
+ int stype, dtype;
+
+ if( !CV_IS_MAT( src ))
+ CV_CALL( src = cvGetMat( src, &sstub ));
+
+ if( !CV_IS_MAT( dst ))
+ CV_CALL( dst = cvGetMat( dst, &dstub ));
+
+ if( delta )
+ {
+ if( !CV_IS_MAT( delta ))
+ CV_CALL( delta = cvGetMat( delta, &deltastub ));
+
+ if( !CV_ARE_TYPES_EQ( dst, delta ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( (delta->rows != src->rows && delta->rows != 1) ||
+ (delta->cols != src->cols && delta->cols != 1) )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+ }
+ else
+ {
+ delta = &deltastub;
+ delta->data.ptr = 0;
+ delta->step = 0;
+ delta->rows = delta->cols = 0;
+ }
+
+ stype = CV_MAT_TYPE( src->type );
+ dtype = CV_MAT_TYPE( dst->type );
+
+ if( dst->rows != dst->cols )
+ CV_ERROR( CV_StsBadSize, "The destination matrix must be square" );
+
+ if( (order != 0 && src->cols != dst->cols) ||
+ (order == 0 && src->rows != dst->rows))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( src->data.ptr == dst->data.ptr || (stype == dtype &&
+ (dst->cols >= gemm_level && dst->rows >= gemm_level &&
+ src->cols >= gemm_level && src->rows >= gemm_level)))
+ {
+ if( deltaarr )
+ {
+ CV_CALL( src2 = cvCreateMat( src->rows, src->cols, src->type ));
+ cvRepeat( delta, src2 );
+ cvSub( src, src2, src2 );
+ src = src2;
+ }
+ cvGEMM( src, src, scale, 0, 0, dst, order == 0 ? CV_GEMM_B_T : CV_GEMM_A_T );
+ }
+ else
+ {
+ CvMulTransposedFunc func =
+ stype == CV_8U && dtype == CV_32F ?
+ (order ? (CvMulTransposedFunc)icvMulTransposedR_8u32f :
+ (CvMulTransposedFunc)icvMulTransposedL_8u32f) :
+ stype == CV_8U && dtype == CV_64F ?
+ (order ? (CvMulTransposedFunc)icvMulTransposedR_8u64f :
+ (CvMulTransposedFunc)icvMulTransposedL_8u64f) :
+ stype == CV_16U && dtype == CV_32F ?
+ (order ? (CvMulTransposedFunc)icvMulTransposedR_16u32f :
+ (CvMulTransposedFunc)icvMulTransposedL_16u32f) :
+ stype == CV_16U && dtype == CV_64F ?
+ (order ? (CvMulTransposedFunc)icvMulTransposedR_16u64f :
+ (CvMulTransposedFunc)icvMulTransposedL_16u64f) :
+ stype == CV_16S && dtype == CV_32F ?
+ (order ? (CvMulTransposedFunc)icvMulTransposedR_16s32f :
+ (CvMulTransposedFunc)icvMulTransposedL_16s32f) :
+ stype == CV_16S && dtype == CV_64F ?
+ (order ? (CvMulTransposedFunc)icvMulTransposedR_16s64f :
+ (CvMulTransposedFunc)icvMulTransposedL_16s64f) :
+ stype == CV_32F && dtype == CV_32F ?
+ (order ? (CvMulTransposedFunc)icvMulTransposedR_32f :
+ (CvMulTransposedFunc)icvMulTransposedL_32f) :
+ stype == CV_32F && dtype == CV_64F ?
+ (order ? (CvMulTransposedFunc)icvMulTransposedR_32f64f :
+ (CvMulTransposedFunc)icvMulTransposedL_32f64f) :
+ stype == CV_64F && dtype == CV_64F ?
+ (order ? (CvMulTransposedFunc)icvMulTransposedR_64f :
+ (CvMulTransposedFunc)icvMulTransposedL_64f) : 0;
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src->data.ptr, src->step, dst->data.ptr, dst->step,
+ delta->data.ptr, delta->step, cvGetMatSize( src ),
+ delta->cols, scale ));
+ }
+
+ __END__;
+
+ if( src2 )
+ cvReleaseMat( &src2 );
+}
+
+
+/****************************************************************************************\
+* cvDotProduct *
+\****************************************************************************************/
+
+#define ICV_DEF_DOT_PROD_FUNC_2D( flavor, arrtype, temptype, sumtype ) \
+static CvStatus CV_STDCALL \
+icvDotProduct_##flavor##_C1R( const arrtype* src1, int step1, \
+ const arrtype* src2, int step2, \
+ CvSize size, sumtype* _sum ) \
+{ \
+ sumtype sum = 0; \
+ step1 /= sizeof(src1[0]); step2 /= sizeof(src2[0]); \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2 ) \
+ { \
+ int i; \
+ \
+ for( i = 0; i <= size.width - 4; i += 4 ) \
+ { \
+ temptype t0 = (temptype)src1[i]*src2[i]; \
+ temptype t1 = (temptype)src1[i+1]*src2[i+1]; \
+ t0 += (temptype)src1[i+2]*src2[i+2]; \
+ t1 += (temptype)src1[i+3]*src2[i+3]; \
+ sum += t0 + t1; \
+ } \
+ \
+ for( ; i < size.width; i++ ) \
+ { \
+ sum += (temptype)src1[i]*src2[i]; \
+ } \
+ } \
+ \
+ *_sum = sum; \
+ return CV_OK; \
+}
+
+
+ICV_DEF_DOT_PROD_FUNC_2D( 8u, uchar, int, int64 )
+ICV_DEF_DOT_PROD_FUNC_2D( 16u, ushort, int64, int64 )
+ICV_DEF_DOT_PROD_FUNC_2D( 16s, short, int64, int64 )
+ICV_DEF_DOT_PROD_FUNC_2D( 32s, int, double, double )
+ICV_DEF_DOT_PROD_FUNC_2D( 32f, float, double, double )
+ICV_DEF_DOT_PROD_FUNC_2D( 64f, double, double, double )
+
+#define icvDotProduct_8s_C1R 0
+
+CV_DEF_INIT_FUNC_TAB_2D( DotProduct, C1R )
+
+CV_IMPL double
+cvDotProduct( const CvArr* srcAarr, const CvArr* srcBarr )
+{
+ static CvFuncTable tab_2d;
+ static int inittab = 0;
+
+ Cv64suf result;
+ result.f = 0;
+
+ CV_FUNCNAME( "cvDotProduct" );
+
+ __BEGIN__;
+
+ CvMat stubA, *srcA = (CvMat*)srcAarr;
+ CvMat stubB, *srcB = (CvMat*)srcBarr;
+ CvSize size;
+ int type, depth;
+ CvFunc2D_2A1P func;
+
+ if( !inittab )
+ {
+ icvInitDotProductC1RTable( &tab_2d );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT( srcA ))
+ {
+ int coi = 0;
+ CV_CALL( srcA = cvGetMat( srcA, &stubA, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "coi is not supported" );
+ }
+
+ if( srcBarr == srcAarr )
+ srcB = srcA;
+ else
+ {
+ if( !CV_IS_MAT( srcB ))
+ {
+ int coi = 0;
+ CV_CALL( srcB = cvGetMat( srcB, &stubB, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "coi is not supported" );
+ }
+
+ if( !CV_ARE_TYPES_EQ( srcA, srcB ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( !CV_ARE_SIZES_EQ( srcA, srcB ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+ }
+
+ type = CV_MAT_TYPE( srcA->type );
+ size = cvGetMatSize( srcA );
+
+ size.width *= CV_MAT_CN( type );
+ depth = CV_MAT_DEPTH( type );
+
+ if( CV_IS_MAT_CONT( srcA->type & srcB->type ))
+ {
+ size.width *= size.height;
+
+ if( size.width <= CV_MAX_INLINE_MAT_OP_SIZE )
+ {
+ if( depth == CV_32F )
+ {
+ float* mA = srcA->data.fl;
+ float* mB = srcB->data.fl;
+ double sum = 0;
+ do
+ sum += (double)mA[size.width - 1]*mB[size.width - 1];
+ while( --size.width );
+ result.f = sum;
+ EXIT;
+ }
+
+ if( depth == CV_64F )
+ {
+ double* mA = srcA->data.db;
+ double* mB = srcB->data.db;
+ double sum = 0;
+ do
+ sum += mA[size.width - 1]*mB[size.width - 1];
+ while( --size.width );
+ result.f = sum;
+ EXIT;
+ }
+ }
+ size.height = 1;
+ }
+
+ func = (CvFunc2D_2A1P)(tab_2d.fn_2d[depth]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( srcA->data.ptr, srcA->step,
+ srcB->data.ptr, srcB->step,
+ size, &result ));
+
+ if( depth < CV_32S )
+ result.f = (double)result.i;
+
+ __END__;
+
+ return result.f;
+}
+
+/* End of file. */
diff --git a/cxcore/src/cxmatrix.cpp b/cxcore/src/cxmatrix.cpp
new file mode 100644
index 0000000..3e59428
--- /dev/null
+++ b/cxcore/src/cxmatrix.cpp
@@ -0,0 +1,2006 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+
+/****************************************************************************************\
+* [scaled] Identity matrix initialization *
+\****************************************************************************************/
+
+CV_IMPL void
+cvSetIdentity( CvArr* array, CvScalar value )
+{
+ CV_FUNCNAME( "cvSetIdentity" );
+
+ __BEGIN__;
+
+ CvMat stub, *mat = (CvMat*)array;
+ CvSize size;
+ int i, k, len, step;
+ int type, pix_size;
+ uchar* data = 0;
+ double buf[4];
+
+ if( !CV_IS_MAT( mat ))
+ {
+ int coi = 0;
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "coi is not supported" );
+ }
+
+ size = cvGetMatSize( mat );
+ len = CV_IMIN( size.width, size.height );
+
+ type = CV_MAT_TYPE(mat->type);
+ pix_size = CV_ELEM_SIZE(type);
+ size.width *= pix_size;
+
+ if( CV_IS_MAT_CONT( mat->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ }
+
+ data = mat->data.ptr;
+ step = mat->step;
+ if( step == 0 )
+ step = CV_STUB_STEP;
+ IPPI_CALL( icvSetZero_8u_C1R( data, step, size ));
+ step += pix_size;
+
+ if( type == CV_32FC1 )
+ {
+ float val = (float)value.val[0];
+ float* _data = (float*)data;
+ step /= sizeof(_data[0]);
+ len *= step;
+
+ for( i = 0; i < len; i += step )
+ _data[i] = val;
+ }
+ else if( type == CV_64FC1 )
+ {
+ double val = value.val[0];
+ double* _data = (double*)data;
+ step /= sizeof(_data[0]);
+ len *= step;
+
+ for( i = 0; i < len; i += step )
+ _data[i] = val;
+ }
+ else
+ {
+ uchar* val_ptr = (uchar*)buf;
+ cvScalarToRawData( &value, buf, type, 0 );
+ len *= step;
+
+ for( i = 0; i < len; i += step )
+ for( k = 0; k < pix_size; k++ )
+ data[i+k] = val_ptr[k];
+ }
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* Trace of the matrix *
+\****************************************************************************************/
+
+CV_IMPL CvScalar
+cvTrace( const CvArr* array )
+{
+ CvScalar sum = {{0,0,0,0}};
+
+ CV_FUNCNAME( "cvTrace" );
+
+ __BEGIN__;
+
+ CvMat stub, *mat = 0;
+
+ if( CV_IS_MAT( array ))
+ {
+ mat = (CvMat*)array;
+ int type = CV_MAT_TYPE(mat->type);
+ int size = MIN(mat->rows,mat->cols);
+ uchar* data = mat->data.ptr;
+
+ if( type == CV_32FC1 )
+ {
+ int step = mat->step + sizeof(float);
+
+ for( ; size--; data += step )
+ sum.val[0] += *(float*)data;
+ EXIT;
+ }
+
+ if( type == CV_64FC1 )
+ {
+ int step = mat->step + sizeof(double);
+
+ for( ; size--; data += step )
+ sum.val[0] += *(double*)data;
+ EXIT;
+ }
+ }
+
+ CV_CALL( mat = cvGetDiag( array, &stub ));
+ CV_CALL( sum = cvSum( mat ));
+
+ __END__;
+
+ return sum;
+}
+
+
+/****************************************************************************************\
+* Matrix transpose *
+\****************************************************************************************/
+
+/////////////////// macros for inplace transposition of square matrix ////////////////////
+
+#define ICV_DEF_TRANSP_INP_CASE_C1( \
+ arrtype, len ) \
+{ \
+ arrtype* arr1 = arr; \
+ step /= sizeof(arr[0]); \
+ \
+ while( --len ) \
+ { \
+ arr += step, arr1++; \
+ arrtype* arr2 = arr; \
+ arrtype* arr3 = arr1; \
+ \
+ do \
+ { \
+ arrtype t0 = arr2[0]; \
+ arrtype t1 = arr3[0]; \
+ arr2[0] = t1; \
+ arr3[0] = t0; \
+ \
+ arr2++; \
+ arr3 += step; \
+ } \
+ while( arr2 != arr3 ); \
+ } \
+}
+
+
+#define ICV_DEF_TRANSP_INP_CASE_C3( \
+ arrtype, len ) \
+{ \
+ arrtype* arr1 = arr; \
+ int y; \
+ step /= sizeof(arr[0]); \
+ \
+ for( y = 1; y < len; y++ ) \
+ { \
+ arr += step, arr1 += 3; \
+ arrtype* arr2 = arr; \
+ arrtype* arr3 = arr1; \
+ \
+ for( ; arr2!=arr3; arr2+=3, \
+ arr3+=step )\
+ { \
+ arrtype t0 = arr2[0]; \
+ arrtype t1 = arr3[0]; \
+ arr2[0] = t1; \
+ arr3[0] = t0; \
+ t0 = arr2[1]; \
+ t1 = arr3[1]; \
+ arr2[1] = t1; \
+ arr3[1] = t0; \
+ t0 = arr2[2]; \
+ t1 = arr3[2]; \
+ arr2[2] = t1; \
+ arr3[2] = t0; \
+ } \
+ } \
+}
+
+
+#define ICV_DEF_TRANSP_INP_CASE_C4( \
+ arrtype, len ) \
+{ \
+ arrtype* arr1 = arr; \
+ int y; \
+ step /= sizeof(arr[0]); \
+ \
+ for( y = 1; y < len; y++ ) \
+ { \
+ arr += step, arr1 += 4; \
+ arrtype* arr2 = arr; \
+ arrtype* arr3 = arr1; \
+ \
+ for( ; arr2!=arr3; arr2+=4, \
+ arr3+=step )\
+ { \
+ arrtype t0 = arr2[0]; \
+ arrtype t1 = arr3[0]; \
+ arr2[0] = t1; \
+ arr3[0] = t0; \
+ t0 = arr2[1]; \
+ t1 = arr3[1]; \
+ arr2[1] = t1; \
+ arr3[1] = t0; \
+ t0 = arr2[2]; \
+ t1 = arr3[2]; \
+ arr2[2] = t1; \
+ arr3[2] = t0; \
+ t0 = arr2[3]; \
+ t1 = arr3[3]; \
+ arr2[3] = t1; \
+ arr3[3] = t0; \
+ } \
+ } \
+}
+
+
+//////////////// macros for non-inplace transposition of rectangular matrix //////////////
+
+#define ICV_DEF_TRANSP_CASE_C1( arrtype ) \
+{ \
+ int x, y; \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( y = 0; y <= size.height - 2; y += 2, \
+ src += 2*srcstep, dst += 2 ) \
+ { \
+ const arrtype* src1 = src + srcstep; \
+ arrtype* dst1 = dst; \
+ \
+ for( x = 0; x <= size.width - 2; \
+ x += 2, dst1 += dststep ) \
+ { \
+ arrtype t0 = src[x]; \
+ arrtype t1 = src1[x]; \
+ dst1[0] = t0; \
+ dst1[1] = t1; \
+ dst1 += dststep; \
+ \
+ t0 = src[x + 1]; \
+ t1 = src1[x + 1]; \
+ dst1[0] = t0; \
+ dst1[1] = t1; \
+ } \
+ \
+ if( x < size.width ) \
+ { \
+ arrtype t0 = src[x]; \
+ arrtype t1 = src1[x]; \
+ dst1[0] = t0; \
+ dst1[1] = t1; \
+ } \
+ } \
+ \
+ if( y < size.height ) \
+ { \
+ arrtype* dst1 = dst; \
+ for( x = 0; x <= size.width - 2; \
+ x += 2, dst1 += 2*dststep ) \
+ { \
+ arrtype t0 = src[x]; \
+ arrtype t1 = src[x + 1]; \
+ dst1[0] = t0; \
+ dst1[dststep] = t1; \
+ } \
+ \
+ if( x < size.width ) \
+ { \
+ arrtype t0 = src[x]; \
+ dst1[0] = t0; \
+ } \
+ } \
+}
+
+
+#define ICV_DEF_TRANSP_CASE_C3( arrtype ) \
+{ \
+ size.width *= 3; \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src+=srcstep, dst+=3 )\
+ { \
+ int x; \
+ arrtype* dst1 = dst; \
+ \
+ for( x = 0; x < size.width; x += 3, \
+ dst1 += dststep ) \
+ { \
+ arrtype t0 = src[x]; \
+ arrtype t1 = src[x + 1]; \
+ arrtype t2 = src[x + 2]; \
+ \
+ dst1[0] = t0; \
+ dst1[1] = t1; \
+ dst1[2] = t2; \
+ } \
+ } \
+}
+
+
+#define ICV_DEF_TRANSP_CASE_C4( arrtype ) \
+{ \
+ size.width *= 4; \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src+=srcstep, dst+=4 )\
+ { \
+ int x; \
+ arrtype* dst1 = dst; \
+ \
+ for( x = 0; x < size.width; x += 4, \
+ dst1 += dststep ) \
+ { \
+ arrtype t0 = src[x]; \
+ arrtype t1 = src[x + 1]; \
+ \
+ dst1[0] = t0; \
+ dst1[1] = t1; \
+ \
+ t0 = src[x + 2]; \
+ t1 = src[x + 3]; \
+ \
+ dst1[2] = t0; \
+ dst1[3] = t1; \
+ } \
+ } \
+}
+
+
+#define ICV_DEF_TRANSP_INP_FUNC( flavor, arrtype, cn ) \
+static CvStatus CV_STDCALL \
+icvTranspose_##flavor( arrtype* arr, int step, CvSize size )\
+{ \
+ assert( size.width == size.height ); \
+ \
+ ICV_DEF_TRANSP_INP_CASE_C##cn( arrtype, size.width ) \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_TRANSP_FUNC( flavor, arrtype, cn ) \
+static CvStatus CV_STDCALL \
+icvTranspose_##flavor( const arrtype* src, int srcstep, \
+ arrtype* dst, int dststep, CvSize size )\
+{ \
+ ICV_DEF_TRANSP_CASE_C##cn( arrtype ) \
+ return CV_OK; \
+}
+
+
+ICV_DEF_TRANSP_INP_FUNC( 8u_C1IR, uchar, 1 )
+ICV_DEF_TRANSP_INP_FUNC( 8u_C2IR, ushort, 1 )
+ICV_DEF_TRANSP_INP_FUNC( 8u_C3IR, uchar, 3 )
+ICV_DEF_TRANSP_INP_FUNC( 16u_C2IR, int, 1 )
+ICV_DEF_TRANSP_INP_FUNC( 16u_C3IR, ushort, 3 )
+ICV_DEF_TRANSP_INP_FUNC( 32s_C2IR, int64, 1 )
+ICV_DEF_TRANSP_INP_FUNC( 32s_C3IR, int, 3 )
+ICV_DEF_TRANSP_INP_FUNC( 64s_C2IR, int, 4 )
+ICV_DEF_TRANSP_INP_FUNC( 64s_C3IR, int64, 3 )
+ICV_DEF_TRANSP_INP_FUNC( 64s_C4IR, int64, 4 )
+
+
+ICV_DEF_TRANSP_FUNC( 8u_C1R, uchar, 1 )
+ICV_DEF_TRANSP_FUNC( 8u_C2R, ushort, 1 )
+ICV_DEF_TRANSP_FUNC( 8u_C3R, uchar, 3 )
+ICV_DEF_TRANSP_FUNC( 16u_C2R, int, 1 )
+ICV_DEF_TRANSP_FUNC( 16u_C3R, ushort, 3 )
+ICV_DEF_TRANSP_FUNC( 32s_C2R, int64, 1 )
+ICV_DEF_TRANSP_FUNC( 32s_C3R, int, 3 )
+ICV_DEF_TRANSP_FUNC( 64s_C2R, int, 4 )
+ICV_DEF_TRANSP_FUNC( 64s_C3R, int64, 3 )
+ICV_DEF_TRANSP_FUNC( 64s_C4R, int64, 4 )
+
+CV_DEF_INIT_PIXSIZE_TAB_2D( Transpose, R )
+CV_DEF_INIT_PIXSIZE_TAB_2D( Transpose, IR )
+
+CV_IMPL void
+cvTranspose( const CvArr* srcarr, CvArr* dstarr )
+{
+ static CvBtFuncTable tab, inp_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvTranspose" );
+
+ __BEGIN__;
+
+ CvMat sstub, *src = (CvMat*)srcarr;
+ CvMat dstub, *dst = (CvMat*)dstarr;
+ CvSize size;
+ int type, pix_size;
+
+ if( !inittab )
+ {
+ icvInitTransposeIRTable( &inp_tab );
+ icvInitTransposeRTable( &tab );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT( src ))
+ {
+ int coi = 0;
+ CV_CALL( src = cvGetMat( src, &sstub, &coi ));
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "coi is not supported" );
+ }
+
+ type = CV_MAT_TYPE( src->type );
+ pix_size = CV_ELEM_SIZE(type);
+ size = cvGetMatSize( src );
+
+ if( dstarr == srcarr )
+ {
+ dst = src;
+ }
+ else
+ {
+ if( !CV_IS_MAT( dst ))
+ {
+ int coi = 0;
+ CV_CALL( dst = cvGetMat( dst, &dstub, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "coi is not supported" );
+ }
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( size.width != dst->height || size.height != dst->width )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+ }
+
+ if( src->data.ptr == dst->data.ptr )
+ {
+ if( size.width == size.height )
+ {
+ CvFunc2D_1A func = (CvFunc2D_1A)(inp_tab.fn_2d[pix_size]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src->data.ptr, src->step, size ));
+ }
+ else
+ {
+ if( size.width != 1 && size.height != 1 )
+ CV_ERROR( CV_StsBadSize,
+ "Rectangular matrix can not be transposed inplace" );
+
+ if( !CV_IS_MAT_CONT( src->type & dst->type ))
+ CV_ERROR( CV_StsBadFlag, "In case of inplace column/row transposition "
+ "both source and destination must be continuous" );
+
+ if( dst == src )
+ {
+ int t;
+ CV_SWAP( dst->width, dst->height, t );
+ dst->step = dst->height == 1 ? 0 : pix_size;
+ }
+ }
+ }
+ else
+ {
+ CvFunc2D_2A func = (CvFunc2D_2A)(tab.fn_2d[pix_size]);
+
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ IPPI_CALL( func( src->data.ptr, src->step,
+ dst->data.ptr, dst->step, size ));
+ }
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* LU decomposition/back substitution *
+\****************************************************************************************/
+
+CV_IMPL void
+cvCompleteSymm( CvMat* matrix, int LtoR )
+{
+ CV_FUNCNAME( "cvCompleteSymm" );
+
+ __BEGIN__;
+
+ int i, j, nrows;
+
+ CV_ASSERT( CV_IS_MAT(matrix) && matrix->rows == matrix->cols );
+
+ nrows = matrix->rows;
+
+ if( CV_MAT_TYPE(matrix->type) == CV_32FC1 || CV_MAT_TYPE(matrix->type) == CV_32SC1 )
+ {
+ int* data = matrix->data.i;
+ int step = matrix->step/sizeof(data[0]);
+ int j0 = 0, j1 = nrows;
+ for( i = 0; i < nrows; i++ )
+ {
+ if( !LtoR ) j1 = i; else j0 = i+1;
+ for( j = j0; j < j1; j++ )
+ data[i*step + j] = data[j*step + i];
+ }
+ }
+ else if( CV_MAT_TYPE(matrix->type) == CV_64FC1 )
+ {
+ double* data = matrix->data.db;
+ int step = matrix->step/sizeof(data[0]);
+ int j0 = 0, j1 = nrows;
+ for( i = 0; i < nrows; i++ )
+ {
+ if( !LtoR ) j1 = i; else j0 = i+1;
+ for( j = j0; j < j1; j++ )
+ data[i*step + j] = data[j*step + i];
+ }
+ }
+ else
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* LU decomposition/back substitution *
+\****************************************************************************************/
+
+#define arrtype float
+#define temptype double
+
+typedef CvStatus (CV_STDCALL * CvLUDecompFunc)( double* A, int stepA, CvSize sizeA,
+ void* B, int stepB, CvSize sizeB,
+ double* det );
+
+typedef CvStatus (CV_STDCALL * CvLUBackFunc)( double* A, int stepA, CvSize sizeA,
+ void* B, int stepB, CvSize sizeB );
+
+
+#define ICV_DEF_LU_DECOMP_FUNC( flavor, arrtype ) \
+static CvStatus CV_STDCALL \
+icvLUDecomp_##flavor( double* A, int stepA, CvSize sizeA, \
+ arrtype* B, int stepB, CvSize sizeB, double* _det ) \
+{ \
+ int n = sizeA.width; \
+ int m = 0, i; \
+ double det = 1; \
+ \
+ assert( sizeA.width == sizeA.height ); \
+ \
+ if( B ) \
+ { \
+ assert( sizeA.height == sizeB.height ); \
+ m = sizeB.width; \
+ } \
+ stepA /= sizeof(A[0]); \
+ stepB /= sizeof(B[0]); \
+ \
+ for( i = 0; i < n; i++, A += stepA, B += stepB ) \
+ { \
+ int j, k = i; \
+ double* tA = A; \
+ arrtype* tB = 0; \
+ double kval = fabs(A[i]), tval; \
+ \
+ /* find the pivot element */ \
+ for( j = i + 1; j < n; j++ ) \
+ { \
+ tA += stepA; \
+ tval = fabs(tA[i]); \
+ \
+ if( tval > kval ) \
+ { \
+ kval = tval; \
+ k = j; \
+ } \
+ } \
+ \
+ if( kval == 0 ) \
+ { \
+ det = 0; \
+ break; \
+ } \
+ \
+ /* swap rows */ \
+ if( k != i ) \
+ { \
+ tA = A + stepA*(k - i); \
+ det = -det; \
+ \
+ for( j = i; j < n; j++ ) \
+ { \
+ double t; \
+ CV_SWAP( A[j], tA[j], t ); \
+ } \
+ \
+ if( m > 0 ) \
+ { \
+ tB = B + stepB*(k - i); \
+ \
+ for( j = 0; j < m; j++ ) \
+ { \
+ arrtype t = B[j]; \
+ CV_SWAP( B[j], tB[j], t ); \
+ } \
+ } \
+ } \
+ \
+ tval = 1./A[i]; \
+ det *= A[i]; \
+ tA = A; \
+ tB = B; \
+ A[i] = tval; /* to replace division with multiplication in LUBack */ \
+ \
+ /* update matrix and the right side of the system */ \
+ for( j = i + 1; j < n; j++ ) \
+ { \
+ tA += stepA; \
+ tB += stepB; \
+ double alpha = -tA[i]*tval; \
+ \
+ for( k = i + 1; k < n; k++ ) \
+ tA[k] = tA[k] + alpha*A[k]; \
+ \
+ if( m > 0 ) \
+ for( k = 0; k < m; k++ ) \
+ tB[k] = (arrtype)(tB[k] + alpha*B[k]); \
+ } \
+ } \
+ \
+ if( _det ) \
+ *_det = det; \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_LU_DECOMP_FUNC( 32f, float )
+ICV_DEF_LU_DECOMP_FUNC( 64f, double )
+
+
+#define ICV_DEF_LU_BACK_FUNC( flavor, arrtype ) \
+static CvStatus CV_STDCALL \
+icvLUBack_##flavor( double* A, int stepA, CvSize sizeA, \
+ arrtype* B, int stepB, CvSize sizeB ) \
+{ \
+ int n = sizeA.width; \
+ int m = sizeB.width, i; \
+ \
+ assert( m > 0 && sizeA.width == sizeA.height && \
+ sizeA.height == sizeB.height ); \
+ stepA /= sizeof(A[0]); \
+ stepB /= sizeof(B[0]); \
+ \
+ A += stepA*(n - 1); \
+ B += stepB*(n - 1); \
+ \
+ for( i = n - 1; i >= 0; i--, A -= stepA ) \
+ { \
+ int j, k; \
+ for( j = 0; j < m; j++ ) \
+ { \
+ arrtype* tB = B + j; \
+ double x = 0; \
+ \
+ for( k = n - 1; k > i; k--, tB -= stepB ) \
+ x += A[k]*tB[0]; \
+ \
+ tB[0] = (arrtype)((tB[0] - x)*A[i]); \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_DEF_LU_BACK_FUNC( 32f, float )
+ICV_DEF_LU_BACK_FUNC( 64f, double )
+
+static CvFuncTable lu_decomp_tab, lu_back_tab;
+static int lu_inittab = 0;
+
+static void icvInitLUTable( CvFuncTable* decomp_tab,
+ CvFuncTable* back_tab )
+{
+ decomp_tab->fn_2d[0] = (void*)icvLUDecomp_32f;
+ decomp_tab->fn_2d[1] = (void*)icvLUDecomp_64f;
+ back_tab->fn_2d[0] = (void*)icvLUBack_32f;
+ back_tab->fn_2d[1] = (void*)icvLUBack_64f;
+}
+
+
+
+/****************************************************************************************\
+* Determinant of the matrix *
+\****************************************************************************************/
+
+#define det2(m) (m(0,0)*m(1,1) - m(0,1)*m(1,0))
+#define det3(m) (m(0,0)*(m(1,1)*m(2,2) - m(1,2)*m(2,1)) - \
+ m(0,1)*(m(1,0)*m(2,2) - m(1,2)*m(2,0)) + \
+ m(0,2)*(m(1,0)*m(2,1) - m(1,1)*m(2,0)))
+
+CV_IMPL double
+cvDet( const CvArr* arr )
+{
+ double result = 0;
+ uchar* buffer = 0;
+ int local_alloc = 0;
+
+ CV_FUNCNAME( "cvDet" );
+
+ __BEGIN__;
+
+ CvMat stub, *mat = (CvMat*)arr;
+ int type;
+
+ if( !CV_IS_MAT( mat ))
+ {
+ CV_CALL( mat = cvGetMat( mat, &stub ));
+ }
+
+ type = CV_MAT_TYPE( mat->type );
+
+ if( mat->width != mat->height )
+ CV_ERROR( CV_StsBadSize, "The matrix must be square" );
+
+ #define Mf( y, x ) ((float*)(m + y*step))[x]
+ #define Md( y, x ) ((double*)(m + y*step))[x]
+
+ if( mat->width == 2 )
+ {
+ uchar* m = mat->data.ptr;
+ int step = mat->step;
+
+ if( type == CV_32FC1 )
+ {
+ result = det2(Mf);
+ }
+ else if( type == CV_64FC1 )
+ {
+ result = det2(Md);
+ }
+ else
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+ }
+ }
+ else if( mat->width == 3 )
+ {
+ uchar* m = mat->data.ptr;
+ int step = mat->step;
+
+ if( type == CV_32FC1 )
+ {
+ result = det3(Mf);
+ }
+ else if( type == CV_64FC1 )
+ {
+ result = det3(Md);
+ }
+ else
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+ }
+ }
+ else if( mat->width == 1 )
+ {
+ if( type == CV_32FC1 )
+ {
+ result = mat->data.fl[0];
+ }
+ else if( type == CV_64FC1 )
+ {
+ result = mat->data.db[0];
+ }
+ else
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+ }
+ }
+ else
+ {
+ CvLUDecompFunc decomp_func;
+ CvSize size = cvGetMatSize( mat );
+ const int worktype = CV_64FC1;
+ int buf_size = size.width*size.height*CV_ELEM_SIZE(worktype);
+ CvMat tmat;
+
+ if( !lu_inittab )
+ {
+ icvInitLUTable( &lu_decomp_tab, &lu_back_tab );
+ lu_inittab = 1;
+ }
+
+ if( CV_MAT_CN( type ) != 1 || CV_MAT_DEPTH( type ) < CV_32F )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( size.width <= CV_MAX_LOCAL_MAT_SIZE )
+ {
+ buffer = (uchar*)cvStackAlloc( buf_size );
+ local_alloc = 1;
+ }
+ else
+ {
+ CV_CALL( buffer = (uchar*)cvAlloc( buf_size ));
+ }
+
+ CV_CALL( cvInitMatHeader( &tmat, size.height, size.width, worktype, buffer ));
+ if( type == worktype )
+ {
+ CV_CALL( cvCopy( mat, &tmat ));
+ }
+ else
+ CV_CALL( cvConvert( mat, &tmat ));
+
+ decomp_func = (CvLUDecompFunc)(lu_decomp_tab.fn_2d[CV_MAT_DEPTH(worktype)-CV_32F]);
+ assert( decomp_func );
+
+ IPPI_CALL( decomp_func( tmat.data.db, tmat.step, size, 0, 0, size, &result ));
+ }
+
+ #undef Mf
+ #undef Md
+
+ /*icvCheckVector_64f( &result, 1 );*/
+
+ __END__;
+
+ if( buffer && !local_alloc )
+ cvFree( &buffer );
+
+ return result;
+}
+
+
+
+/****************************************************************************************\
+* Inverse (or pseudo-inverse) of the matrix *
+\****************************************************************************************/
+
+#define Sf( y, x ) ((float*)(srcdata + y*srcstep))[x]
+#define Sd( y, x ) ((double*)(srcdata + y*srcstep))[x]
+#define Df( y, x ) ((float*)(dstdata + y*dststep))[x]
+#define Dd( y, x ) ((double*)(dstdata + y*dststep))[x]
+
+CV_IMPL double
+cvInvert( const CvArr* srcarr, CvArr* dstarr, int method )
+{
+ CvMat* u = 0;
+ CvMat* v = 0;
+ CvMat* w = 0;
+
+ uchar* buffer = 0;
+ int local_alloc = 0;
+ double result = 0;
+
+ CV_FUNCNAME( "cvInvert" );
+
+ __BEGIN__;
+
+ CvMat sstub, *src = (CvMat*)srcarr;
+ CvMat dstub, *dst = (CvMat*)dstarr;
+ int type;
+
+ if( !CV_IS_MAT( src ))
+ CV_CALL( src = cvGetMat( src, &sstub ));
+
+ if( !CV_IS_MAT( dst ))
+ CV_CALL( dst = cvGetMat( dst, &dstub ));
+
+ type = CV_MAT_TYPE( src->type );
+
+ if( method == CV_SVD || method == CV_SVD_SYM )
+ {
+ int n = MIN(src->rows,src->cols);
+ if( method == CV_SVD_SYM && src->rows != src->cols )
+ CV_ERROR( CV_StsBadSize, "CV_SVD_SYM method is used for non-square matrix" );
+
+ CV_CALL( u = cvCreateMat( n, src->rows, src->type ));
+ if( method != CV_SVD_SYM )
+ CV_CALL( v = cvCreateMat( n, src->cols, src->type ));
+ CV_CALL( w = cvCreateMat( n, 1, src->type ));
+ CV_CALL( cvSVD( src, w, u, v, CV_SVD_U_T + CV_SVD_V_T ));
+
+ if( type == CV_32FC1 )
+ result = w->data.fl[0] >= FLT_EPSILON ?
+ w->data.fl[w->rows-1]/w->data.fl[0] : 0;
+ else
+ result = w->data.db[0] >= FLT_EPSILON ?
+ w->data.db[w->rows-1]/w->data.db[0] : 0;
+
+ CV_CALL( cvSVBkSb( w, u, v ? v : u, 0, dst, CV_SVD_U_T + CV_SVD_V_T ));
+ EXIT;
+ }
+ else if( method != CV_LU )
+ CV_ERROR( CV_StsBadArg, "Unknown inversion method" );
+
+ if( !CV_ARE_TYPES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( src->width != src->height )
+ CV_ERROR( CV_StsBadSize, "The matrix must be square" );
+
+ if( !CV_ARE_SIZES_EQ( src, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( type != CV_32FC1 && type != CV_64FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ if( src->width <= 3 )
+ {
+ uchar* srcdata = src->data.ptr;
+ uchar* dstdata = dst->data.ptr;
+ int srcstep = src->step;
+ int dststep = dst->step;
+
+ if( src->width == 2 )
+ {
+ if( type == CV_32FC1 )
+ {
+ double d = det2(Sf);
+ if( d != 0. )
+ {
+ double t0, t1;
+ result = d;
+ d = 1./d;
+ t0 = Sf(0,0)*d;
+ t1 = Sf(1,1)*d;
+ Df(1,1) = (float)t0;
+ Df(0,0) = (float)t1;
+ t0 = -Sf(0,1)*d;
+ t1 = -Sf(1,0)*d;
+ Df(0,1) = (float)t0;
+ Df(1,0) = (float)t1;
+ }
+ }
+ else
+ {
+ double d = det2(Sd);
+ if( d != 0. )
+ {
+ double t0, t1;
+ result = d;
+ d = 1./d;
+ t0 = Sd(0,0)*d;
+ t1 = Sd(1,1)*d;
+ Dd(1,1) = t0;
+ Dd(0,0) = t1;
+ t0 = -Sd(0,1)*d;
+ t1 = -Sd(1,0)*d;
+ Dd(0,1) = t0;
+ Dd(1,0) = t1;
+ }
+ }
+ }
+ else if( src->width == 3 )
+ {
+ if( type == CV_32FC1 )
+ {
+ double d = det3(Sf);
+ if( d != 0. )
+ {
+ float t[9];
+ result = d;
+ d = 1./d;
+
+ t[0] = (float)((Sf(1,1) * Sf(2,2) - Sf(1,2) * Sf(2,1)) * d);
+ t[1] = (float)((Sf(0,2) * Sf(2,1) - Sf(0,1) * Sf(2,2)) * d);
+ t[2] = (float)((Sf(0,1) * Sf(1,2) - Sf(0,2) * Sf(1,1)) * d);
+
+ t[3] = (float)((Sf(1,2) * Sf(2,0) - Sf(1,0) * Sf(2,2)) * d);
+ t[4] = (float)((Sf(0,0) * Sf(2,2) - Sf(0,2) * Sf(2,0)) * d);
+ t[5] = (float)((Sf(0,2) * Sf(1,0) - Sf(0,0) * Sf(1,2)) * d);
+
+ t[6] = (float)((Sf(1,0) * Sf(2,1) - Sf(1,1) * Sf(2,0)) * d);
+ t[7] = (float)((Sf(0,1) * Sf(2,0) - Sf(0,0) * Sf(2,1)) * d);
+ t[8] = (float)((Sf(0,0) * Sf(1,1) - Sf(0,1) * Sf(1,0)) * d);
+
+ Df(0,0) = t[0]; Df(0,1) = t[1]; Df(0,2) = t[2];
+ Df(1,0) = t[3]; Df(1,1) = t[4]; Df(1,2) = t[5];
+ Df(2,0) = t[6]; Df(2,1) = t[7]; Df(2,2) = t[8];
+ }
+ }
+ else
+ {
+ double d = det3(Sd);
+ if( d != 0. )
+ {
+ double t[9];
+ result = d;
+ d = 1./d;
+
+ t[0] = (Sd(1,1) * Sd(2,2) - Sd(1,2) * Sd(2,1)) * d;
+ t[1] = (Sd(0,2) * Sd(2,1) - Sd(0,1) * Sd(2,2)) * d;
+ t[2] = (Sd(0,1) * Sd(1,2) - Sd(0,2) * Sd(1,1)) * d;
+
+ t[3] = (Sd(1,2) * Sd(2,0) - Sd(1,0) * Sd(2,2)) * d;
+ t[4] = (Sd(0,0) * Sd(2,2) - Sd(0,2) * Sd(2,0)) * d;
+ t[5] = (Sd(0,2) * Sd(1,0) - Sd(0,0) * Sd(1,2)) * d;
+
+ t[6] = (Sd(1,0) * Sd(2,1) - Sd(1,1) * Sd(2,0)) * d;
+ t[7] = (Sd(0,1) * Sd(2,0) - Sd(0,0) * Sd(2,1)) * d;
+ t[8] = (Sd(0,0) * Sd(1,1) - Sd(0,1) * Sd(1,0)) * d;
+
+ Dd(0,0) = t[0]; Dd(0,1) = t[1]; Dd(0,2) = t[2];
+ Dd(1,0) = t[3]; Dd(1,1) = t[4]; Dd(1,2) = t[5];
+ Dd(2,0) = t[6]; Dd(2,1) = t[7]; Dd(2,2) = t[8];
+ }
+ }
+ }
+ else
+ {
+ assert( src->width == 1 );
+
+ if( type == CV_32FC1 )
+ {
+ double d = Sf(0,0);
+ if( d != 0. )
+ {
+ result = d;
+ Df(0,0) = (float)(1./d);
+ }
+ }
+ else
+ {
+ double d = Sd(0,0);
+ if( d != 0. )
+ {
+ result = d;
+ Dd(0,0) = 1./d;
+ }
+ }
+ }
+ }
+ else
+ {
+ CvLUDecompFunc decomp_func;
+ CvLUBackFunc back_func;
+ CvSize size = cvGetMatSize( src );
+ const int worktype = CV_64FC1;
+ int buf_size = size.width*size.height*CV_ELEM_SIZE(worktype);
+ CvMat tmat;
+
+ if( !lu_inittab )
+ {
+ icvInitLUTable( &lu_decomp_tab, &lu_back_tab );
+ lu_inittab = 1;
+ }
+
+ if( size.width <= CV_MAX_LOCAL_MAT_SIZE )
+ {
+ buffer = (uchar*)cvStackAlloc( buf_size );
+ local_alloc = 1;
+ }
+ else
+ {
+ CV_CALL( buffer = (uchar*)cvAlloc( buf_size ));
+ }
+
+ CV_CALL( cvInitMatHeader( &tmat, size.height, size.width, worktype, buffer ));
+ if( type == worktype )
+ {
+ CV_CALL( cvCopy( src, &tmat ));
+ }
+ else
+ CV_CALL( cvConvert( src, &tmat ));
+ CV_CALL( cvSetIdentity( dst ));
+
+ decomp_func = (CvLUDecompFunc)(lu_decomp_tab.fn_2d[CV_MAT_DEPTH(type)-CV_32F]);
+ back_func = (CvLUBackFunc)(lu_back_tab.fn_2d[CV_MAT_DEPTH(type)-CV_32F]);
+ assert( decomp_func && back_func );
+
+ IPPI_CALL( decomp_func( tmat.data.db, tmat.step, size,
+ dst->data.ptr, dst->step, size, &result ));
+
+ if( result != 0 )
+ {
+ IPPI_CALL( back_func( tmat.data.db, tmat.step, size,
+ dst->data.ptr, dst->step, size ));
+ }
+ }
+
+ if( !result )
+ CV_CALL( cvSetZero( dst ));
+
+ __END__;
+
+ if( buffer && !local_alloc )
+ cvFree( &buffer );
+
+ if( u || v || w )
+ {
+ cvReleaseMat( &u );
+ cvReleaseMat( &v );
+ cvReleaseMat( &w );
+ }
+
+ return result;
+}
+
+
+/****************************************************************************************\
+* Linear system [least-squares] solution *
+\****************************************************************************************/
+
+static void
+icvLSQ( const CvMat* A, const CvMat* B, CvMat* X )
+{
+ CvMat* AtA = 0;
+ CvMat* AtB = 0;
+ CvMat* W = 0;
+ CvMat* V = 0;
+
+ CV_FUNCNAME( "icvLSQ" );
+
+ __BEGIN__;
+
+ if( !CV_IS_MAT(A) || !CV_IS_MAT(B) || !CV_IS_MAT(X) )
+ CV_ERROR( CV_StsBadArg, "Some of required arguments is not a valid matrix" );
+
+ AtA = cvCreateMat( A->cols, A->cols, A->type );
+ AtB = cvCreateMat( A->cols, 1, A->type );
+ W = cvCreateMat( A->cols, 1, A->type );
+ V = cvCreateMat( A->cols, A->cols, A->type );
+
+ cvMulTransposed( A, AtA, 1 );
+ cvGEMM( A, B, 1, 0, 0, AtB, CV_GEMM_A_T );
+ cvSVD( AtA, W, 0, V, CV_SVD_MODIFY_A + CV_SVD_V_T );
+ cvSVBkSb( W, V, V, AtB, X, CV_SVD_U_T + CV_SVD_V_T );
+
+ __END__;
+
+ cvReleaseMat( &AtA );
+ cvReleaseMat( &AtB );
+ cvReleaseMat( &W );
+ cvReleaseMat( &V );
+}
+
+CV_IMPL int
+cvSolve( const CvArr* A, const CvArr* b, CvArr* x, int method )
+{
+ CvMat* u = 0;
+ CvMat* v = 0;
+ CvMat* w = 0;
+
+ uchar* buffer = 0;
+ int local_alloc = 0;
+ int result = 1;
+
+ CV_FUNCNAME( "cvSolve" );
+
+ __BEGIN__;
+
+ CvMat sstub, *src = (CvMat*)A;
+ CvMat dstub, *dst = (CvMat*)x;
+ CvMat bstub, *src2 = (CvMat*)b;
+ int type;
+
+ if( !CV_IS_MAT( src ))
+ CV_CALL( src = cvGetMat( src, &sstub ));
+
+ if( !CV_IS_MAT( src2 ))
+ CV_CALL( src2 = cvGetMat( src2, &bstub ));
+
+ if( !CV_IS_MAT( dst ))
+ CV_CALL( dst = cvGetMat( dst, &dstub ));
+
+ if( method & CV_LSQ )
+ {
+ icvLSQ( src, src2, dst );
+ EXIT;
+ }
+
+ if( method == CV_SVD || method == CV_SVD_SYM )
+ {
+ int n = MIN(src->rows,src->cols);
+
+ if( method == CV_SVD_SYM && src->rows != src->cols )
+ CV_ERROR( CV_StsBadSize, "CV_SVD_SYM method is used for non-square matrix" );
+
+ CV_CALL( u = cvCreateMat( n, src->rows, src->type ));
+ if( method != CV_SVD_SYM )
+ CV_CALL( v = cvCreateMat( n, src->cols, src->type ));
+ CV_CALL( w = cvCreateMat( n, 1, src->type ));
+ CV_CALL( cvSVD( src, w, u, v, CV_SVD_U_T + CV_SVD_V_T ));
+ CV_CALL( cvSVBkSb( w, u, v ? v : u, src2, dst, CV_SVD_U_T + CV_SVD_V_T ));
+ EXIT;
+ }
+ else if( method != CV_LU )
+ CV_ERROR( CV_StsBadArg, "Unknown inversion method" );
+
+ type = CV_MAT_TYPE( src->type );
+
+ if( !CV_ARE_TYPES_EQ( src, dst ) || !CV_ARE_TYPES_EQ( src, src2 ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( src->width != src->height )
+ CV_ERROR( CV_StsBadSize, "The matrix must be square" );
+
+ if( !CV_ARE_SIZES_EQ( src2, dst ) || src->width != src2->height )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( type != CV_32FC1 && type != CV_64FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ // check case of a single equation and small matrix
+ if( src->width <= 3 && src2->width == 1 )
+ {
+ #define bf(y) ((float*)(bdata + y*src2step))[0]
+ #define bd(y) ((double*)(bdata + y*src2step))[0]
+
+ uchar* srcdata = src->data.ptr;
+ uchar* bdata = src2->data.ptr;
+ uchar* dstdata = dst->data.ptr;
+ int srcstep = src->step;
+ int src2step = src2->step;
+ int dststep = dst->step;
+
+ if( src->width == 2 )
+ {
+ if( type == CV_32FC1 )
+ {
+ double d = det2(Sf);
+ if( d != 0. )
+ {
+ float t;
+ d = 1./d;
+ t = (float)((bf(0)*Sf(1,1) - bf(1)*Sf(0,1))*d);
+ Df(1,0) = (float)((bf(1)*Sf(0,0) - bf(0)*Sf(1,0))*d);
+ Df(0,0) = t;
+ }
+ else
+ result = 0;
+ }
+ else
+ {
+ double d = det2(Sd);
+ if( d != 0. )
+ {
+ double t;
+ d = 1./d;
+ t = (bd(0)*Sd(1,1) - bd(1)*Sd(0,1))*d;
+ Dd(1,0) = (bd(1)*Sd(0,0) - bd(0)*Sd(1,0))*d;
+ Dd(0,0) = t;
+ }
+ else
+ result = 0;
+ }
+ }
+ else if( src->width == 3 )
+ {
+ if( type == CV_32FC1 )
+ {
+ double d = det3(Sf);
+ if( d != 0. )
+ {
+ float t[3];
+ d = 1./d;
+
+ t[0] = (float)(d*
+ (bf(0)*(Sf(1,1)*Sf(2,2) - Sf(1,2)*Sf(2,1)) -
+ Sf(0,1)*(bf(1)*Sf(2,2) - Sf(1,2)*bf(2)) +
+ Sf(0,2)*(bf(1)*Sf(2,1) - Sf(1,1)*bf(2))));
+
+ t[1] = (float)(d*
+ (Sf(0,0)*(bf(1)*Sf(2,2) - Sf(1,2)*bf(2)) -
+ bf(0)*(Sf(1,0)*Sf(2,2) - Sf(1,2)*Sf(2,0)) +
+ Sf(0,2)*(Sf(1,0)*bf(2) - bf(1)*Sf(2,0))));
+
+ t[2] = (float)(d*
+ (Sf(0,0)*(Sf(1,1)*bf(2) - bf(1)*Sf(2,1)) -
+ Sf(0,1)*(Sf(1,0)*bf(2) - bf(1)*Sf(2,0)) +
+ bf(0)*(Sf(1,0)*Sf(2,1) - Sf(1,1)*Sf(2,0))));
+
+ Df(0,0) = t[0];
+ Df(1,0) = t[1];
+ Df(2,0) = t[2];
+ }
+ else
+ result = 0;
+ }
+ else
+ {
+ double d = det3(Sd);
+ if( d != 0. )
+ {
+ double t[9];
+
+ d = 1./d;
+
+ t[0] = ((Sd(1,1) * Sd(2,2) - Sd(1,2) * Sd(2,1))*bd(0) +
+ (Sd(0,2) * Sd(2,1) - Sd(0,1) * Sd(2,2))*bd(1) +
+ (Sd(0,1) * Sd(1,2) - Sd(0,2) * Sd(1,1))*bd(2))*d;
+
+ t[1] = ((Sd(1,2) * Sd(2,0) - Sd(1,0) * Sd(2,2))*bd(0) +
+ (Sd(0,0) * Sd(2,2) - Sd(0,2) * Sd(2,0))*bd(1) +
+ (Sd(0,2) * Sd(1,0) - Sd(0,0) * Sd(1,2))*bd(2))*d;
+
+ t[2] = ((Sd(1,0) * Sd(2,1) - Sd(1,1) * Sd(2,0))*bd(0) +
+ (Sd(0,1) * Sd(2,0) - Sd(0,0) * Sd(2,1))*bd(1) +
+ (Sd(0,0) * Sd(1,1) - Sd(0,1) * Sd(1,0))*bd(2))*d;
+
+ Dd(0,0) = t[0];
+ Dd(1,0) = t[1];
+ Dd(2,0) = t[2];
+ }
+ else
+ result = 0;
+ }
+ }
+ else
+ {
+ assert( src->width == 1 );
+
+ if( type == CV_32FC1 )
+ {
+ double d = Sf(0,0);
+ if( d != 0. )
+ Df(0,0) = (float)(bf(0)/d);
+ else
+ result = 0;
+ }
+ else
+ {
+ double d = Sd(0,0);
+ if( d != 0. )
+ Dd(0,0) = (bd(0)/d);
+ else
+ result = 0;
+ }
+ }
+ }
+ else
+ {
+ CvLUDecompFunc decomp_func;
+ CvLUBackFunc back_func;
+ CvSize size = cvGetMatSize( src );
+ CvSize dstsize = cvGetMatSize( dst );
+ int worktype = CV_64FC1;
+ int buf_size = size.width*size.height*CV_ELEM_SIZE(worktype);
+ double d = 0;
+ CvMat tmat;
+
+ if( !lu_inittab )
+ {
+ icvInitLUTable( &lu_decomp_tab, &lu_back_tab );
+ lu_inittab = 1;
+ }
+
+ if( size.width <= CV_MAX_LOCAL_MAT_SIZE )
+ {
+ buffer = (uchar*)cvStackAlloc( buf_size );
+ local_alloc = 1;
+ }
+ else
+ {
+ CV_CALL( buffer = (uchar*)cvAlloc( buf_size ));
+ }
+
+ CV_CALL( cvInitMatHeader( &tmat, size.height, size.width, worktype, buffer ));
+ if( type == worktype )
+ {
+ CV_CALL( cvCopy( src, &tmat ));
+ }
+ else
+ CV_CALL( cvConvert( src, &tmat ));
+
+ if( src2->data.ptr != dst->data.ptr )
+ {
+ CV_CALL( cvCopy( src2, dst ));
+ }
+
+ decomp_func = (CvLUDecompFunc)(lu_decomp_tab.fn_2d[CV_MAT_DEPTH(type)-CV_32F]);
+ back_func = (CvLUBackFunc)(lu_back_tab.fn_2d[CV_MAT_DEPTH(type)-CV_32F]);
+ assert( decomp_func && back_func );
+
+ IPPI_CALL( decomp_func( tmat.data.db, tmat.step, size,
+ dst->data.ptr, dst->step, dstsize, &d ));
+
+ if( d != 0 )
+ {
+ IPPI_CALL( back_func( tmat.data.db, tmat.step, size,
+ dst->data.ptr, dst->step, dstsize ));
+ }
+ else
+ result = 0;
+ }
+
+ if( !result )
+ CV_CALL( cvSetZero( dst ));
+
+ __END__;
+
+ if( buffer && !local_alloc )
+ cvFree( &buffer );
+
+ if( u || v || w )
+ {
+ cvReleaseMat( &u );
+ cvReleaseMat( &v );
+ cvReleaseMat( &w );
+ }
+
+ return result;
+}
+
+
+
+/****************************************************************************************\
+* 3D vector cross-product *
+\****************************************************************************************/
+
+CV_IMPL void
+cvCrossProduct( const CvArr* srcAarr, const CvArr* srcBarr, CvArr* dstarr )
+{
+ CV_FUNCNAME( "cvCrossProduct" );
+
+ __BEGIN__;
+
+ CvMat stubA, *srcA = (CvMat*)srcAarr;
+ CvMat stubB, *srcB = (CvMat*)srcBarr;
+ CvMat dstub, *dst = (CvMat*)dstarr;
+ int type;
+
+ if( !CV_IS_MAT(srcA))
+ CV_CALL( srcA = cvGetMat( srcA, &stubA ));
+
+ type = CV_MAT_TYPE( srcA->type );
+
+ if( srcA->width*srcA->height*CV_MAT_CN(type) != 3 )
+ CV_ERROR( CV_StsBadArg, "All the input arrays must be continuous 3-vectors" );
+
+ if( !srcB || !dst )
+ CV_ERROR( CV_StsNullPtr, "" );
+
+ if( (srcA->type & ~CV_MAT_CONT_FLAG) == (srcB->type & ~CV_MAT_CONT_FLAG) &&
+ (srcA->type & ~CV_MAT_CONT_FLAG) == (dst->type & ~CV_MAT_CONT_FLAG) )
+ {
+ if( !srcB->data.ptr || !dst->data.ptr )
+ CV_ERROR( CV_StsNullPtr, "" );
+ }
+ else
+ {
+ if( !CV_IS_MAT(srcB))
+ CV_CALL( srcB = cvGetMat( srcB, &stubB ));
+
+ if( !CV_IS_MAT(dst))
+ CV_CALL( dst = cvGetMat( dst, &dstub ));
+
+ if( !CV_ARE_TYPES_EQ( srcA, srcB ) ||
+ !CV_ARE_TYPES_EQ( srcB, dst ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+ }
+
+ if( !CV_ARE_SIZES_EQ( srcA, srcB ) || !CV_ARE_SIZES_EQ( srcB, dst ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( CV_MAT_DEPTH(type) == CV_32F )
+ {
+ float* dstdata = (float*)(dst->data.ptr);
+ const float* src1data = (float*)(srcA->data.ptr);
+ const float* src2data = (float*)(srcB->data.ptr);
+
+ if( CV_IS_MAT_CONT(srcA->type & srcB->type & dst->type) )
+ {
+ dstdata[2] = src1data[0] * src2data[1] - src1data[1] * src2data[0];
+ dstdata[0] = src1data[1] * src2data[2] - src1data[2] * src2data[1];
+ dstdata[1] = src1data[2] * src2data[0] - src1data[0] * src2data[2];
+ }
+ else
+ {
+ int step1 = srcA->step ? srcA->step/sizeof(src1data[0]) : 1;
+ int step2 = srcB->step ? srcB->step/sizeof(src1data[0]) : 1;
+ int step = dst->step ? dst->step/sizeof(src1data[0]) : 1;
+
+ dstdata[2*step] = src1data[0] * src2data[step2] - src1data[step1] * src2data[0];
+ dstdata[0] = src1data[step1] * src2data[step2*2] - src1data[step1*2] * src2data[step2];
+ dstdata[step] = src1data[step1*2] * src2data[0] - src1data[0] * src2data[step2*2];
+ }
+ }
+ else if( CV_MAT_DEPTH(type) == CV_64F )
+ {
+ double* dstdata = (double*)(dst->data.ptr);
+ const double* src1data = (double*)(srcA->data.ptr);
+ const double* src2data = (double*)(srcB->data.ptr);
+
+ if( CV_IS_MAT_CONT(srcA->type & srcB->type & dst->type) )
+ {
+ dstdata[2] = src1data[0] * src2data[1] - src1data[1] * src2data[0];
+ dstdata[0] = src1data[1] * src2data[2] - src1data[2] * src2data[1];
+ dstdata[1] = src1data[2] * src2data[0] - src1data[0] * src2data[2];
+ }
+ else
+ {
+ int step1 = srcA->step ? srcA->step/sizeof(src1data[0]) : 1;
+ int step2 = srcB->step ? srcB->step/sizeof(src1data[0]) : 1;
+ int step = dst->step ? dst->step/sizeof(src1data[0]) : 1;
+
+ dstdata[2*step] = src1data[0] * src2data[step2] - src1data[step1] * src2data[0];
+ dstdata[0] = src1data[step1] * src2data[step2*2] - src1data[step1*2] * src2data[step2];
+ dstdata[step] = src1data[step1*2] * src2data[0] - src1data[0] * src2data[step2*2];
+ }
+ }
+ else
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+ }
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvCalcPCA( const CvArr* data_arr, CvArr* avg_arr, CvArr* eigenvals, CvArr* eigenvects, int flags )
+{
+ CvMat* tmp_avg = 0;
+ CvMat* tmp_avg_r = 0;
+ CvMat* tmp_cov = 0;
+ CvMat* tmp_evals = 0;
+ CvMat* tmp_evects = 0;
+ CvMat* tmp_evects2 = 0;
+ CvMat* tmp_data = 0;
+
+ CV_FUNCNAME( "cvCalcPCA" );
+
+ __BEGIN__;
+
+ CvMat stub, *data = (CvMat*)data_arr;
+ CvMat astub, *avg = (CvMat*)avg_arr;
+ CvMat evalstub, *evals = (CvMat*)eigenvals;
+ CvMat evectstub, *evects = (CvMat*)eigenvects;
+ int covar_flags = CV_COVAR_SCALE;
+ int i, len, in_count, count, out_count;
+
+ if( !CV_IS_MAT(data) )
+ CV_CALL( data = cvGetMat( data, &stub ));
+
+ if( !CV_IS_MAT(avg) )
+ CV_CALL( avg = cvGetMat( avg, &astub ));
+
+ if( !CV_IS_MAT(evals) )
+ CV_CALL( evals = cvGetMat( evals, &evalstub ));
+
+ if( !CV_IS_MAT(evects) )
+ CV_CALL( evects = cvGetMat( evects, &evectstub ));
+
+ if( CV_MAT_CN(data->type) != 1 || CV_MAT_CN(avg->type) != 1 ||
+ CV_MAT_CN(evals->type) != 1 || CV_MAT_CN(evects->type) != 1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "All the input and output arrays must be 1-channel" );
+
+ if( CV_MAT_DEPTH(avg->type) < CV_32F || !CV_ARE_DEPTHS_EQ(avg, evals) ||
+ !CV_ARE_DEPTHS_EQ(avg, evects) )
+ CV_ERROR( CV_StsUnsupportedFormat, "All the output arrays must have the same type, 32fC1 or 64fC1" );
+
+ if( flags & CV_PCA_DATA_AS_COL )
+ {
+ len = data->rows;
+ in_count = data->cols;
+ covar_flags |= CV_COVAR_COLS;
+
+ if( avg->cols != 1 || avg->rows != len )
+ CV_ERROR( CV_StsBadSize,
+ "The mean (average) vector should be data->rows x 1 when CV_PCA_DATA_AS_COL is used" );
+
+ CV_CALL( tmp_avg = cvCreateMat( len, 1, CV_64F ));
+ }
+ else
+ {
+ len = data->cols;
+ in_count = data->rows;
+ covar_flags |= CV_COVAR_ROWS;
+
+ if( avg->rows != 1 || avg->cols != len )
+ CV_ERROR( CV_StsBadSize,
+ "The mean (average) vector should be 1 x data->cols when CV_PCA_DATA_AS_ROW is used" );
+
+ CV_CALL( tmp_avg = cvCreateMat( 1, len, CV_64F ));
+ }
+
+ count = MIN(len, in_count);
+ out_count = evals->cols + evals->rows - 1;
+
+ if( (evals->cols != 1 && evals->rows != 1) || out_count > count )
+ CV_ERROR( CV_StsBadSize,
+ "The array of eigenvalues must be 1d vector containing "
+ "no more than min(data->rows,data->cols) elements" );
+
+ if( evects->cols != len || evects->rows != out_count )
+ CV_ERROR( CV_StsBadSize,
+ "The matrix of eigenvalues must have the same number of columns as the input vector length "
+ "and the same number of rows as the number of eigenvalues" );
+
+ // "scrambled" way to compute PCA (when cols(A)>rows(A)):
+ // B = A'A; B*x=b*x; C = AA'; C*y=c*y -> AA'*y=c*y -> A'A*(A'*y)=c*(A'*y) -> c = b, x=A'*y
+ if( len <= in_count )
+ covar_flags |= CV_COVAR_NORMAL;
+
+ if( flags & CV_PCA_USE_AVG ){
+ covar_flags |= CV_COVAR_USE_AVG;
+ CV_CALL( cvConvert( avg, tmp_avg ) );
+ }
+
+ CV_CALL( tmp_cov = cvCreateMat( count, count, CV_64F ));
+ CV_CALL( tmp_evals = cvCreateMat( 1, count, CV_64F ));
+ CV_CALL( tmp_evects = cvCreateMat( count, count, CV_64F ));
+
+ CV_CALL( cvCalcCovarMatrix( &data_arr, 0, tmp_cov, tmp_avg, covar_flags ));
+ CV_CALL( cvSVD( tmp_cov, tmp_evals, tmp_evects, 0, CV_SVD_MODIFY_A + CV_SVD_U_T ));
+ tmp_evects->rows = out_count;
+ tmp_evals->cols = out_count;
+ cvZero( evects );
+ cvZero( evals );
+
+ if( covar_flags & CV_COVAR_NORMAL )
+ {
+ CV_CALL( cvConvert( tmp_evects, evects ));
+ }
+ else
+ {
+ // CV_PCA_DATA_AS_ROW: cols(A)>rows(A). x=A'*y -> x'=y'*A
+ // CV_PCA_DATA_AS_COL: rows(A)>cols(A). x=A''*y -> x'=y'*A'
+ int block_count = 0;
+
+ CV_CALL( tmp_data = cvCreateMat( count, count, CV_64F ));
+ CV_CALL( tmp_avg_r = cvCreateMat( count, count, CV_64F ));
+ CV_CALL( tmp_evects2 = cvCreateMat( out_count, count, CV_64F ));
+
+ for( i = 0; i < len; i += block_count )
+ {
+ CvMat data_part, tdata_part, part, dst_part, avg_part, tmp_avg_part;
+ int gemm_flags;
+
+ block_count = MIN( count, len - i );
+
+ if( flags & CV_PCA_DATA_AS_COL )
+ {
+ cvGetRows( data, &data_part, i, i + block_count );
+ cvGetRows( tmp_data, &tdata_part, 0, block_count );
+ cvGetRows( tmp_avg, &avg_part, i, i + block_count );
+ cvGetRows( tmp_avg_r, &tmp_avg_part, 0, block_count );
+ gemm_flags = CV_GEMM_B_T;
+ }
+ else
+ {
+ cvGetCols( data, &data_part, i, i + block_count );
+ cvGetCols( tmp_data, &tdata_part, 0, block_count );
+ cvGetCols( tmp_avg, &avg_part, i, i + block_count );
+ cvGetCols( tmp_avg_r, &tmp_avg_part, 0, block_count );
+ gemm_flags = 0;
+ }
+
+ cvGetCols( tmp_evects2, &part, 0, block_count );
+ cvGetCols( evects, &dst_part, i, i + block_count );
+
+ cvConvert( &data_part, &tdata_part );
+ cvRepeat( &avg_part, &tmp_avg_part );
+ cvSub( &tdata_part, &tmp_avg_part, &tdata_part );
+ cvGEMM( tmp_evects, &tdata_part, 1, 0, 0, &part, gemm_flags );
+ cvConvert( &part, &dst_part );
+ }
+
+ // normalize eigenvectors
+ for( i = 0; i < out_count; i++ )
+ {
+ CvMat ei;
+ cvGetRow( evects, &ei, i );
+ cvNormalize( &ei, &ei );
+ }
+ }
+
+ if( tmp_evals->rows != evals->rows )
+ cvReshape( tmp_evals, tmp_evals, 1, evals->rows );
+ cvConvert( tmp_evals, evals );
+ cvConvert( tmp_avg, avg );
+
+ __END__;
+
+ cvReleaseMat( &tmp_avg );
+ cvReleaseMat( &tmp_avg_r );
+ cvReleaseMat( &tmp_cov );
+ cvReleaseMat( &tmp_evals );
+ cvReleaseMat( &tmp_evects );
+ cvReleaseMat( &tmp_evects2 );
+ cvReleaseMat( &tmp_data );
+}
+
+
+CV_IMPL void
+cvProjectPCA( const CvArr* data_arr, const CvArr* avg_arr,
+ const CvArr* eigenvects, CvArr* result_arr )
+{
+ uchar* buffer = 0;
+ int local_alloc = 0;
+
+ CV_FUNCNAME( "cvProjectPCA" );
+
+ __BEGIN__;
+
+ CvMat stub, *data = (CvMat*)data_arr;
+ CvMat astub, *avg = (CvMat*)avg_arr;
+ CvMat evectstub, *evects = (CvMat*)eigenvects;
+ CvMat rstub, *result = (CvMat*)result_arr;
+ CvMat avg_repeated;
+ int i, len, in_count;
+ int gemm_flags, as_cols, convert_data;
+ int block_count0, block_count, buf_size, elem_size;
+ uchar* tmp_data_ptr;
+
+ if( !CV_IS_MAT(data) )
+ CV_CALL( data = cvGetMat( data, &stub ));
+
+ if( !CV_IS_MAT(avg) )
+ CV_CALL( avg = cvGetMat( avg, &astub ));
+
+ if( !CV_IS_MAT(evects) )
+ CV_CALL( evects = cvGetMat( evects, &evectstub ));
+
+ if( !CV_IS_MAT(result) )
+ CV_CALL( result = cvGetMat( result, &rstub ));
+
+ if( CV_MAT_CN(data->type) != 1 || CV_MAT_CN(avg->type) != 1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "All the input and output arrays must be 1-channel" );
+
+ if( (CV_MAT_TYPE(avg->type) != CV_32FC1 && CV_MAT_TYPE(avg->type) != CV_64FC1) ||
+ !CV_ARE_TYPES_EQ(avg, evects) || !CV_ARE_TYPES_EQ(avg, result) )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "All the input and output arrays (except for data) must have the same type, 32fC1 or 64fC1" );
+
+ if( (avg->cols != 1 || avg->rows != data->rows) &&
+ (avg->rows != 1 || avg->cols != data->cols) )
+ CV_ERROR( CV_StsBadSize,
+ "The mean (average) vector should be either 1 x data->cols or data->rows x 1" );
+
+ if( avg->cols == 1 )
+ {
+ len = data->rows;
+ in_count = data->cols;
+
+ gemm_flags = CV_GEMM_A_T + CV_GEMM_B_T;
+ as_cols = 1;
+ }
+ else
+ {
+ len = data->cols;
+ in_count = data->rows;
+
+ gemm_flags = CV_GEMM_B_T;
+ as_cols = 0;
+ }
+
+ if( evects->cols != len )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Eigenvectors must be stored as rows and be of the same size as input vectors" );
+
+ if( result->cols > evects->rows )
+ CV_ERROR( CV_StsOutOfRange,
+ "The output matrix of coefficients must have the number of columns "
+ "less than or equal to the number of eigenvectors (number of rows in eigenvectors matrix)" );
+
+ evects = cvGetRows( evects, &evectstub, 0, result->cols );
+
+ block_count0 = (1 << 16)/len;
+ block_count0 = MAX( block_count0, 4 );
+ block_count0 = MIN( block_count0, in_count );
+ elem_size = CV_ELEM_SIZE(avg->type);
+ convert_data = CV_MAT_DEPTH(data->type) < CV_MAT_DEPTH(avg->type);
+
+ buf_size = block_count0*len*((block_count0 > 1) + 1)*elem_size;
+
+ if( buf_size < CV_MAX_LOCAL_SIZE )
+ {
+ buffer = (uchar*)cvStackAlloc( buf_size );
+ local_alloc = 1;
+ }
+ else
+ CV_CALL( buffer = (uchar*)cvAlloc( buf_size ));
+
+ tmp_data_ptr = buffer;
+ if( block_count0 > 1 )
+ {
+ avg_repeated = cvMat( as_cols ? len : block_count0,
+ as_cols ? block_count0 : len, avg->type, buffer );
+ cvRepeat( avg, &avg_repeated );
+ tmp_data_ptr += block_count0*len*elem_size;
+ }
+ else
+ avg_repeated = *avg;
+
+ for( i = 0; i < in_count; i += block_count )
+ {
+ CvMat data_part, norm_data, avg_part, *src = &data_part, out_part;
+
+ block_count = MIN( block_count0, in_count - i );
+ if( as_cols )
+ {
+ cvGetCols( data, &data_part, i, i + block_count );
+ cvGetCols( &avg_repeated, &avg_part, 0, block_count );
+ norm_data = cvMat( len, block_count, avg->type, tmp_data_ptr );
+ }
+ else
+ {
+ cvGetRows( data, &data_part, i, i + block_count );
+ cvGetRows( &avg_repeated, &avg_part, 0, block_count );
+ norm_data = cvMat( block_count, len, avg->type, tmp_data_ptr );
+ }
+
+ if( convert_data )
+ {
+ cvConvert( src, &norm_data );
+ src = &norm_data;
+ }
+
+ cvSub( src, &avg_part, &norm_data );
+
+ cvGetRows( result, &out_part, i, i + block_count );
+ cvGEMM( &norm_data, evects, 1, 0, 0, &out_part, gemm_flags );
+ }
+
+ __END__;
+
+ if( !local_alloc )
+ cvFree( &buffer );
+}
+
+
+CV_IMPL void
+cvBackProjectPCA( const CvArr* proj_arr, const CvArr* avg_arr,
+ const CvArr* eigenvects, CvArr* result_arr )
+{
+ uchar* buffer = 0;
+ int local_alloc = 0;
+
+ CV_FUNCNAME( "cvProjectPCA" );
+
+ __BEGIN__;
+
+ CvMat pstub, *data = (CvMat*)proj_arr;
+ CvMat astub, *avg = (CvMat*)avg_arr;
+ CvMat evectstub, *evects = (CvMat*)eigenvects;
+ CvMat rstub, *result = (CvMat*)result_arr;
+ CvMat avg_repeated;
+ int i, len, in_count, as_cols;
+ int block_count0, block_count, buf_size, elem_size;
+
+ if( !CV_IS_MAT(data) )
+ CV_CALL( data = cvGetMat( data, &pstub ));
+
+ if( !CV_IS_MAT(avg) )
+ CV_CALL( avg = cvGetMat( avg, &astub ));
+
+ if( !CV_IS_MAT(evects) )
+ CV_CALL( evects = cvGetMat( evects, &evectstub ));
+
+ if( !CV_IS_MAT(result) )
+ CV_CALL( result = cvGetMat( result, &rstub ));
+
+ if( (CV_MAT_TYPE(avg->type) != CV_32FC1 && CV_MAT_TYPE(avg->type) != CV_64FC1) ||
+ !CV_ARE_TYPES_EQ(avg, data) || !CV_ARE_TYPES_EQ(avg, evects) || !CV_ARE_TYPES_EQ(avg, result) )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "All the input and output arrays must have the same type, 32fC1 or 64fC1" );
+
+ if( (avg->cols != 1 || avg->rows != result->rows) &&
+ (avg->rows != 1 || avg->cols != result->cols) )
+ CV_ERROR( CV_StsBadSize,
+ "The mean (average) vector should be either 1 x result->cols or result->rows x 1" );
+
+ if( avg->cols == 1 )
+ {
+ len = result->rows;
+ in_count = result->cols;
+ as_cols = 1;
+ }
+ else
+ {
+ len = result->cols;
+ in_count = result->rows;
+ as_cols = 0;
+ }
+
+ if( evects->cols != len )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Eigenvectors must be stored as rows and be of the same size as the output vectors" );
+
+ if( data->cols > evects->rows )
+ CV_ERROR( CV_StsOutOfRange,
+ "The input matrix of coefficients must have the number of columns "
+ "less than or equal to the number of eigenvectors (number of rows in eigenvectors matrix)" );
+
+ evects = cvGetRows( evects, &evectstub, 0, data->cols );
+
+ block_count0 = (1 << 16)/len;
+ block_count0 = MAX( block_count0, 4 );
+ block_count0 = MIN( block_count0, in_count );
+ elem_size = CV_ELEM_SIZE(avg->type);
+
+ buf_size = block_count0*len*(block_count0 > 1)*elem_size;
+
+ if( buf_size < CV_MAX_LOCAL_SIZE )
+ {
+ buffer = (uchar*)cvStackAlloc( MAX(buf_size,16) );
+ local_alloc = 1;
+ }
+ else
+ CV_CALL( buffer = (uchar*)cvAlloc( buf_size ));
+
+ if( block_count0 > 1 )
+ {
+ avg_repeated = cvMat( as_cols ? len : block_count0,
+ as_cols ? block_count0 : len, avg->type, buffer );
+ cvRepeat( avg, &avg_repeated );
+ }
+ else
+ avg_repeated = *avg;
+
+ for( i = 0; i < in_count; i += block_count )
+ {
+ CvMat data_part, avg_part, out_part;
+
+ block_count = MIN( block_count0, in_count - i );
+ cvGetRows( data, &data_part, i, i + block_count );
+
+ if( as_cols )
+ {
+ cvGetCols( result, &out_part, i, i + block_count );
+ cvGetCols( &avg_repeated, &avg_part, 0, block_count );
+ cvGEMM( evects, &data_part, 1, &avg_part, 1, &out_part, CV_GEMM_A_T + CV_GEMM_B_T );
+ }
+ else
+ {
+ cvGetRows( result, &out_part, i, i + block_count );
+ cvGetRows( &avg_repeated, &avg_part, 0, block_count );
+ cvGEMM( &data_part, evects, 1, &avg_part, 1, &out_part, 0 );
+ }
+ }
+
+ __END__;
+
+ if( !local_alloc )
+ cvFree( &buffer );
+}
+
+
+/* End of file. */
diff --git a/cxcore/src/cxmean.cpp b/cxcore/src/cxmean.cpp
new file mode 100644
index 0000000..6191f04
--- /dev/null
+++ b/cxcore/src/cxmean.cpp
@@ -0,0 +1,481 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+#include <float.h>
+
+/****************************************************************************************\
+* Mean value over the region *
+\****************************************************************************************/
+
+#define ICV_MEAN_CASE_C1( len ) \
+ for( ; x <= (len) - 2; x += 2 ) \
+ { \
+ if( mask[x] ) \
+ s0 += src[x], pix++; \
+ if( mask[x+1] ) \
+ s0 += src[x+1], pix++; \
+ } \
+ \
+ for( ; x < (len); x++ ) \
+ if( mask[x] ) \
+ s0 += src[x], pix++
+
+
+#define ICV_MEAN_CASE_C2( len ) \
+ for( ; x < (len); x++ ) \
+ if( mask[x] ) \
+ { \
+ s0 += src[x*2]; \
+ s1 += src[x*2+1]; \
+ pix++; \
+ }
+
+
+#define ICV_MEAN_CASE_C3( len ) \
+ for( ; x < (len); x++ ) \
+ if( mask[x] ) \
+ { \
+ s0 += src[x*3]; \
+ s1 += src[x*3+1]; \
+ s2 += src[x*3+2]; \
+ pix++; \
+ }
+
+
+#define ICV_MEAN_CASE_C4( len ) \
+ for( ; x < (len); x++ ) \
+ if( mask[x] ) \
+ { \
+ s0 += src[x*4]; \
+ s1 += src[x*4+1]; \
+ s2 += src[x*4+2]; \
+ s3 += src[x*4+3]; \
+ pix++; \
+ }
+
+
+#define ICV_MEAN_COI_CASE( len, cn ) \
+ for( ; x <= (len) - 2; x += 2 ) \
+ { \
+ if( mask[x] ) \
+ s0 += src[x*(cn)], pix++; \
+ if( mask[x+1] ) \
+ s0+=src[(x+1)*(cn)], pix++; \
+ } \
+ \
+ for( ; x < (len); x++ ) \
+ if( mask[x] ) \
+ s0 += src[x*(cn)], pix++;
+
+
+////////////////////////////////////// entry macros //////////////////////////////////////
+
+#define ICV_MEAN_ENTRY_COMMON() \
+ int pix = 0; \
+ step /= sizeof(src[0])
+
+#define ICV_MEAN_ENTRY_C1( sumtype ) \
+ sumtype s0 = 0; \
+ ICV_MEAN_ENTRY_COMMON()
+
+#define ICV_MEAN_ENTRY_C2( sumtype ) \
+ sumtype s0 = 0, s1 = 0; \
+ ICV_MEAN_ENTRY_COMMON()
+
+#define ICV_MEAN_ENTRY_C3( sumtype ) \
+ sumtype s0 = 0, s1 = 0, s2 = 0; \
+ ICV_MEAN_ENTRY_COMMON()
+
+#define ICV_MEAN_ENTRY_C4( sumtype ) \
+ sumtype s0 = 0, s1 = 0, s2 = 0, s3 = 0; \
+ ICV_MEAN_ENTRY_COMMON()
+
+
+#define ICV_MEAN_ENTRY_BLOCK_COMMON( block_size ) \
+ int remaining = block_size; \
+ ICV_MEAN_ENTRY_COMMON()
+
+#define ICV_MEAN_ENTRY_BLOCK_C1( sumtype, worktype, block_size )\
+ sumtype sum0 = 0; \
+ worktype s0 = 0; \
+ ICV_MEAN_ENTRY_BLOCK_COMMON( block_size )
+
+#define ICV_MEAN_ENTRY_BLOCK_C2( sumtype, worktype, block_size )\
+ sumtype sum0 = 0, sum1 = 0; \
+ worktype s0 = 0, s1 = 0; \
+ ICV_MEAN_ENTRY_BLOCK_COMMON( block_size )
+
+#define ICV_MEAN_ENTRY_BLOCK_C3( sumtype, worktype, block_size )\
+ sumtype sum0 = 0, sum1 = 0, sum2 = 0; \
+ worktype s0 = 0, s1 = 0, s2 = 0; \
+ ICV_MEAN_ENTRY_BLOCK_COMMON( block_size )
+
+#define ICV_MEAN_ENTRY_BLOCK_C4( sumtype, worktype, block_size )\
+ sumtype sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0; \
+ worktype s0 = 0, s1 = 0, s2 = 0, s3 = 0; \
+ ICV_MEAN_ENTRY_BLOCK_COMMON( block_size )
+
+
+/////////////////////////////////////// exit macros //////////////////////////////////////
+
+#define ICV_MEAN_EXIT_COMMON() \
+ double scale = pix ? 1./pix : 0
+
+#define ICV_MEAN_EXIT_C1( tmp ) \
+ ICV_MEAN_EXIT_COMMON(); \
+ mean[0] = scale*(double)tmp##0
+
+#define ICV_MEAN_EXIT_C2( tmp ) \
+ ICV_MEAN_EXIT_COMMON(); \
+ double t0 = scale*(double)tmp##0; \
+ double t1 = scale*(double)tmp##1; \
+ mean[0] = t0; \
+ mean[1] = t1
+
+#define ICV_MEAN_EXIT_C3( tmp ) \
+ ICV_MEAN_EXIT_COMMON(); \
+ double t0 = scale*(double)tmp##0; \
+ double t1 = scale*(double)tmp##1; \
+ double t2 = scale*(double)tmp##2; \
+ mean[0] = t0; \
+ mean[1] = t1; \
+ mean[2] = t2
+
+#define ICV_MEAN_EXIT_C4( tmp ) \
+ ICV_MEAN_EXIT_COMMON(); \
+ double t0 = scale*(double)tmp##0; \
+ double t1 = scale*(double)tmp##1; \
+ mean[0] = t0; \
+ mean[1] = t1; \
+ t0 = scale*(double)tmp##2; \
+ t1 = scale*(double)tmp##3; \
+ mean[2] = t0; \
+ mean[3] = t1
+
+#define ICV_MEAN_EXIT_BLOCK_C1() \
+ sum0 += s0; \
+ ICV_MEAN_EXIT_C1( sum )
+
+#define ICV_MEAN_EXIT_BLOCK_C2() \
+ sum0 += s0; sum1 += s1; \
+ ICV_MEAN_EXIT_C2( sum )
+
+#define ICV_MEAN_EXIT_BLOCK_C3() \
+ sum0 += s0; sum1 += s1; \
+ sum2 += s2; \
+ ICV_MEAN_EXIT_C3( sum )
+
+#define ICV_MEAN_EXIT_BLOCK_C4() \
+ sum0 += s0; sum1 += s1; \
+ sum2 += s2; sum3 += s3; \
+ ICV_MEAN_EXIT_C4( sum )
+
+////////////////////////////////////// update macros /////////////////////////////////////
+
+#define ICV_MEAN_UPDATE_COMMON( block_size )\
+ remaining = block_size
+
+#define ICV_MEAN_UPDATE_C1( block_size ) \
+ ICV_MEAN_UPDATE_COMMON( block_size ); \
+ sum0 += s0; \
+ s0 = 0
+
+#define ICV_MEAN_UPDATE_C2( block_size ) \
+ ICV_MEAN_UPDATE_COMMON( block_size ); \
+ sum0 += s0; sum1 += s1; \
+ s0 = s1 = 0
+
+#define ICV_MEAN_UPDATE_C3( block_size ) \
+ ICV_MEAN_UPDATE_COMMON( block_size ); \
+ sum0 += s0; sum1 += s1; sum2 += s2; \
+ s0 = s1 = s2 = 0
+
+#define ICV_MEAN_UPDATE_C4( block_size ) \
+ ICV_MEAN_UPDATE_COMMON( block_size ); \
+ sum0 += s0; sum1 += s1; \
+ sum2 += s2; sum3 += s3; \
+ s0 = s1 = s2 = s3 = 0
+
+
+#define ICV_IMPL_MEAN_BLOCK_FUNC_2D( flavor, cn, \
+ arrtype, sumtype, worktype, block_size ) \
+IPCVAPI_IMPL( CvStatus, icvMean_##flavor##_C##cn##MR, \
+ ( const arrtype* src, int step, \
+ const uchar* mask, int maskstep, \
+ CvSize size, double* mean ), \
+ (src, step, mask, maskstep, size, mean)) \
+{ \
+ ICV_MEAN_ENTRY_BLOCK_C##cn( sumtype, worktype, block_size );\
+ \
+ for( ; size.height--; src += step, mask += maskstep ) \
+ { \
+ int x = 0; \
+ while( x < size.width ) \
+ { \
+ int limit = MIN( remaining, size.width - x ); \
+ remaining -= limit; \
+ limit += x; \
+ ICV_MEAN_CASE_C##cn( limit ); \
+ if( remaining == 0 ) \
+ { \
+ ICV_MEAN_UPDATE_C##cn( block_size ); \
+ } \
+ } \
+ } \
+ \
+ { ICV_MEAN_EXIT_BLOCK_C##cn(); } \
+ return CV_OK; \
+}
+
+
+#define ICV_IMPL_MEAN_FUNC_2D( flavor, cn, \
+ arrtype, sumtype, worktype ) \
+IPCVAPI_IMPL( CvStatus, icvMean_##flavor##_C##cn##MR, \
+ ( const arrtype* src, int step, \
+ const uchar* mask, int maskstep, \
+ CvSize size, double* mean), \
+ (src, step, mask, maskstep, size, mean)) \
+{ \
+ ICV_MEAN_ENTRY_C##cn( sumtype ); \
+ \
+ for( ; size.height--; src += step, mask += maskstep ) \
+ { \
+ int x = 0; \
+ ICV_MEAN_CASE_C##cn( size.width ); \
+ } \
+ \
+ { ICV_MEAN_EXIT_C##cn( s ); } \
+ return CV_OK; \
+}
+
+
+#define ICV_IMPL_MEAN_BLOCK_FUNC_2D_COI( flavor, \
+ arrtype, sumtype, worktype, block_size ) \
+static CvStatus CV_STDCALL \
+icvMean_##flavor##_CnCMR( const arrtype* src, int step, \
+ const uchar* mask, int maskstep, \
+ CvSize size, int cn, \
+ int coi, double* mean ) \
+{ \
+ ICV_MEAN_ENTRY_BLOCK_C1( sumtype, worktype, block_size ); \
+ src += coi - 1; \
+ \
+ for( ; size.height--; src += step, mask += maskstep ) \
+ { \
+ int x = 0; \
+ while( x < size.width ) \
+ { \
+ int limit = MIN( remaining, size.width - x ); \
+ remaining -= limit; \
+ limit += x; \
+ ICV_MEAN_COI_CASE( limit, cn ); \
+ if( remaining == 0 ) \
+ { \
+ ICV_MEAN_UPDATE_C1( block_size ); \
+ } \
+ } \
+ } \
+ \
+ { ICV_MEAN_EXIT_BLOCK_C1(); } \
+ return CV_OK; \
+}
+
+
+#define ICV_IMPL_MEAN_FUNC_2D_COI( flavor, \
+ arrtype, sumtype, worktype ) \
+static CvStatus CV_STDCALL \
+icvMean_##flavor##_CnCMR( const arrtype* src, int step, \
+ const uchar* mask, int maskstep, \
+ CvSize size, int cn, \
+ int coi, double* mean ) \
+{ \
+ ICV_MEAN_ENTRY_C1( sumtype ); \
+ src += coi - 1; \
+ \
+ for( ; size.height--; src += step, mask += maskstep ) \
+ { \
+ int x = 0; \
+ ICV_MEAN_COI_CASE( size.width, cn ); \
+ } \
+ \
+ { ICV_MEAN_EXIT_C1( s ); } \
+ return CV_OK; \
+}
+
+
+#define ICV_IMPL_MEAN_BLOCK_ALL( flavor, arrtype, sumtype, \
+ worktype, block_size ) \
+ ICV_IMPL_MEAN_BLOCK_FUNC_2D( flavor, 1, arrtype, sumtype, \
+ worktype, block_size ) \
+ ICV_IMPL_MEAN_BLOCK_FUNC_2D( flavor, 2, arrtype, sumtype, \
+ worktype, block_size ) \
+ ICV_IMPL_MEAN_BLOCK_FUNC_2D( flavor, 3, arrtype, sumtype, \
+ worktype, block_size ) \
+ ICV_IMPL_MEAN_BLOCK_FUNC_2D( flavor, 4, arrtype, sumtype, \
+ worktype, block_size ) \
+ ICV_IMPL_MEAN_BLOCK_FUNC_2D_COI( flavor, arrtype, sumtype, \
+ worktype, block_size )
+
+#define ICV_IMPL_MEAN_ALL( flavor, arrtype, sumtype, worktype ) \
+ ICV_IMPL_MEAN_FUNC_2D( flavor, 1, arrtype, sumtype, worktype ) \
+ ICV_IMPL_MEAN_FUNC_2D( flavor, 2, arrtype, sumtype, worktype ) \
+ ICV_IMPL_MEAN_FUNC_2D( flavor, 3, arrtype, sumtype, worktype ) \
+ ICV_IMPL_MEAN_FUNC_2D( flavor, 4, arrtype, sumtype, worktype ) \
+ ICV_IMPL_MEAN_FUNC_2D_COI( flavor, arrtype, sumtype, worktype )
+
+ICV_IMPL_MEAN_BLOCK_ALL( 8u, uchar, int64, unsigned, 1 << 24 )
+ICV_IMPL_MEAN_BLOCK_ALL( 16u, ushort, int64, unsigned, 1 << 16 )
+ICV_IMPL_MEAN_BLOCK_ALL( 16s, short, int64, int, 1 << 16 )
+ICV_IMPL_MEAN_ALL( 32s, int, double, double )
+ICV_IMPL_MEAN_ALL( 32f, float, double, double )
+ICV_IMPL_MEAN_ALL( 64f, double, double, double )
+
+#define icvMean_8s_C1MR 0
+#define icvMean_8s_C2MR 0
+#define icvMean_8s_C3MR 0
+#define icvMean_8s_C4MR 0
+#define icvMean_8s_CnCMR 0
+
+CV_DEF_INIT_BIG_FUNC_TAB_2D( Mean, MR )
+CV_DEF_INIT_FUNC_TAB_2D( Mean, CnCMR )
+
+CV_IMPL CvScalar
+cvAvg( const void* img, const void* maskarr )
+{
+ CvScalar mean = {{0,0,0,0}};
+
+ static CvBigFuncTable mean_tab;
+ static CvFuncTable meancoi_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME("cvAvg");
+
+ __BEGIN__;
+
+ CvSize size;
+ double scale;
+
+ if( !maskarr )
+ {
+ CV_CALL( mean = cvSum(img));
+ size = cvGetSize( img );
+ size.width *= size.height;
+ scale = size.width ? 1./size.width : 0;
+
+ mean.val[0] *= scale;
+ mean.val[1] *= scale;
+ mean.val[2] *= scale;
+ mean.val[3] *= scale;
+ }
+ else
+ {
+ int type, coi = 0;
+ int mat_step, mask_step;
+
+ CvMat stub, maskstub, *mat = (CvMat*)img, *mask = (CvMat*)maskarr;
+
+ if( !inittab )
+ {
+ icvInitMeanMRTable( &mean_tab );
+ icvInitMeanCnCMRTable( &meancoi_tab );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(mat) )
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+
+ if( !CV_IS_MAT(mask) )
+ CV_CALL( mask = cvGetMat( mask, &maskstub ));
+
+ if( !CV_IS_MASK_ARR(mask) )
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !CV_ARE_SIZES_EQ( mat, mask ) )
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ type = CV_MAT_TYPE( mat->type );
+ size = cvGetMatSize( mat );
+
+ mat_step = mat->step;
+ mask_step = mask->step;
+
+ if( CV_IS_MAT_CONT( mat->type & mask->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ mat_step = mask_step = CV_STUB_STEP;
+ }
+
+ if( CV_MAT_CN(type) == 1 || coi == 0 )
+ {
+ CvFunc2D_2A1P func;
+
+ if( CV_MAT_CN(type) > 4 )
+ CV_ERROR( CV_StsOutOfRange, "The input array must have at most 4 channels unless COI is set" );
+
+ func = (CvFunc2D_2A1P)(mean_tab.fn_2d[type]);
+
+ if( !func )
+ CV_ERROR( CV_StsBadArg, cvUnsupportedFormat );
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, mask->data.ptr,
+ mask_step, size, mean.val ));
+ }
+ else
+ {
+ CvFunc2DnC_2A1P func = (CvFunc2DnC_2A1P)(
+ meancoi_tab.fn_2d[CV_MAT_DEPTH(type)]);
+
+ if( !func )
+ CV_ERROR( CV_StsBadArg, cvUnsupportedFormat );
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, mask->data.ptr,
+ mask_step, size, CV_MAT_CN(type), coi, mean.val ));
+ }
+ }
+
+ __END__;
+
+ return mean;
+}
+
+/* End of file */
diff --git a/cxcore/src/cxmeansdv.cpp b/cxcore/src/cxmeansdv.cpp
new file mode 100644
index 0000000..cf57638
--- /dev/null
+++ b/cxcore/src/cxmeansdv.cpp
@@ -0,0 +1,799 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+
+/****************************************************************************************\
+* Mean and StdDev calculation *
+\****************************************************************************************/
+
+#define ICV_MEAN_SDV_COI_CASE( worktype, sqsumtype, \
+ sqr_macro, len, cn ) \
+ for( ; x <= (len) - 4*(cn); x += 4*(cn))\
+ { \
+ worktype t0 = src[x]; \
+ worktype t1 = src[x + (cn)]; \
+ \
+ s0 += t0 + t1; \
+ sq0 += (sqsumtype)(sqr_macro(t0)) + \
+ (sqsumtype)(sqr_macro(t1)); \
+ \
+ t0 = src[x + 2*(cn)]; \
+ t1 = src[x + 3*(cn)]; \
+ \
+ s0 += t0 + t1; \
+ sq0 += (sqsumtype)(sqr_macro(t0)) + \
+ (sqsumtype)(sqr_macro(t1)); \
+ } \
+ \
+ for( ; x < (len); x += (cn) ) \
+ { \
+ worktype t0 = src[x]; \
+ \
+ s0 += t0; \
+ sq0 += (sqsumtype)(sqr_macro(t0)); \
+ }
+
+
+#define ICV_MEAN_SDV_CASE_C1( worktype, sqsumtype, sqr_macro, len ) \
+ ICV_MEAN_SDV_COI_CASE( worktype, sqsumtype, sqr_macro, len, 1 )
+
+
+#define ICV_MEAN_SDV_CASE_C2( worktype, sqsumtype, \
+ sqr_macro, len ) \
+ for( ; x < (len); x += 2 ) \
+ { \
+ worktype t0 = (src)[x]; \
+ worktype t1 = (src)[x + 1]; \
+ \
+ s0 += t0; \
+ sq0 += (sqsumtype)(sqr_macro(t0)); \
+ s1 += t1; \
+ sq1 += (sqsumtype)(sqr_macro(t1)); \
+ }
+
+
+#define ICV_MEAN_SDV_CASE_C3( worktype, sqsumtype, \
+ sqr_macro, len ) \
+ for( ; x < (len); x += 3 ) \
+ { \
+ worktype t0 = (src)[x]; \
+ worktype t1 = (src)[x + 1]; \
+ worktype t2 = (src)[x + 2]; \
+ \
+ s0 += t0; \
+ sq0 += (sqsumtype)(sqr_macro(t0)); \
+ s1 += t1; \
+ sq1 += (sqsumtype)(sqr_macro(t1)); \
+ s2 += t2; \
+ sq2 += (sqsumtype)(sqr_macro(t2)); \
+ }
+
+
+#define ICV_MEAN_SDV_CASE_C4( worktype, sqsumtype, \
+ sqr_macro, len ) \
+ for( ; x < (len); x += 4 ) \
+ { \
+ worktype t0 = (src)[x]; \
+ worktype t1 = (src)[x + 1]; \
+ \
+ s0 += t0; \
+ sq0 += (sqsumtype)(sqr_macro(t0)); \
+ s1 += t1; \
+ sq1 += (sqsumtype)(sqr_macro(t1)); \
+ \
+ t0 = (src)[x + 2]; \
+ t1 = (src)[x + 3]; \
+ \
+ s2 += t0; \
+ sq2 += (sqsumtype)(sqr_macro(t0)); \
+ s3 += t1; \
+ sq3 += (sqsumtype)(sqr_macro(t1)); \
+ }
+
+
+#define ICV_MEAN_SDV_MASK_COI_CASE( worktype, sqsumtype, \
+ sqr_macro, len, cn ) \
+ for( ; x <= (len) - 4; x += 4 ) \
+ { \
+ worktype t0; \
+ if( mask[x] ) \
+ { \
+ t0 = src[x*(cn)]; pix++; \
+ s0 += t0; \
+ sq0 += sqsumtype(sqr_macro(t0)); \
+ } \
+ \
+ if( mask[x+1] ) \
+ { \
+ t0 = src[(x+1)*(cn)]; pix++; \
+ s0 += t0; \
+ sq0 += sqsumtype(sqr_macro(t0)); \
+ } \
+ \
+ if( mask[x+2] ) \
+ { \
+ t0 = src[(x+2)*(cn)]; pix++; \
+ s0 += t0; \
+ sq0 += sqsumtype(sqr_macro(t0)); \
+ } \
+ \
+ if( mask[x+3] ) \
+ { \
+ t0 = src[(x+3)*(cn)]; pix++; \
+ s0 += t0; \
+ sq0 += sqsumtype(sqr_macro(t0)); \
+ } \
+ } \
+ \
+ for( ; x < (len); x++ ) \
+ { \
+ if( mask[x] ) \
+ { \
+ worktype t0 = src[x*(cn)]; pix++; \
+ s0 += t0; \
+ sq0 += sqsumtype(sqr_macro(t0)); \
+ } \
+ }
+
+
+#define ICV_MEAN_SDV_MASK_CASE_C1( worktype, sqsumtype, sqr_macro, len ) \
+ ICV_MEAN_SDV_MASK_COI_CASE( worktype, sqsumtype, sqr_macro, len, 1 )
+
+
+#define ICV_MEAN_SDV_MASK_CASE_C2( worktype, sqsumtype,\
+ sqr_macro, len ) \
+ for( ; x < (len); x++ ) \
+ { \
+ if( mask[x] ) \
+ { \
+ worktype t0 = src[x*2]; \
+ worktype t1 = src[x*2+1]; \
+ pix++; \
+ s0 += t0; \
+ sq0 += sqsumtype(sqr_macro(t0)); \
+ s1 += t1; \
+ sq1 += sqsumtype(sqr_macro(t1)); \
+ } \
+ }
+
+
+#define ICV_MEAN_SDV_MASK_CASE_C3( worktype, sqsumtype,\
+ sqr_macro, len ) \
+ for( ; x < (len); x++ ) \
+ { \
+ if( mask[x] ) \
+ { \
+ worktype t0 = src[x*3]; \
+ worktype t1 = src[x*3+1]; \
+ worktype t2 = src[x*3+2]; \
+ pix++; \
+ s0 += t0; \
+ sq0 += sqsumtype(sqr_macro(t0)); \
+ s1 += t1; \
+ sq1 += sqsumtype(sqr_macro(t1)); \
+ s2 += t2; \
+ sq2 += sqsumtype(sqr_macro(t2)); \
+ } \
+ }
+
+
+#define ICV_MEAN_SDV_MASK_CASE_C4( worktype, sqsumtype,\
+ sqr_macro, len ) \
+ for( ; x < (len); x++ ) \
+ { \
+ if( mask[x] ) \
+ { \
+ worktype t0 = src[x*4]; \
+ worktype t1 = src[x*4+1]; \
+ pix++; \
+ s0 += t0; \
+ sq0 += sqsumtype(sqr_macro(t0)); \
+ s1 += t1; \
+ sq1 += sqsumtype(sqr_macro(t1)); \
+ t0 = src[x*4+2]; \
+ t1 = src[x*4+3]; \
+ s2 += t0; \
+ sq2 += sqsumtype(sqr_macro(t0)); \
+ s3 += t1; \
+ sq3 += sqsumtype(sqr_macro(t1)); \
+ } \
+ }
+
+
+////////////////////////////////////// entry macros //////////////////////////////////////
+
+#define ICV_MEAN_SDV_ENTRY_COMMON() \
+ int pix; \
+ double scale, tmp; \
+ step /= sizeof(src[0])
+
+#define ICV_MEAN_SDV_ENTRY_C1( sumtype, sqsumtype ) \
+ sumtype s0 = 0; \
+ sqsumtype sq0 = 0; \
+ ICV_MEAN_SDV_ENTRY_COMMON()
+
+#define ICV_MEAN_SDV_ENTRY_C2( sumtype, sqsumtype ) \
+ sumtype s0 = 0, s1 = 0; \
+ sqsumtype sq0 = 0, sq1 = 0; \
+ ICV_MEAN_SDV_ENTRY_COMMON()
+
+#define ICV_MEAN_SDV_ENTRY_C3( sumtype, sqsumtype ) \
+ sumtype s0 = 0, s1 = 0, s2 = 0; \
+ sqsumtype sq0 = 0, sq1 = 0, sq2 = 0; \
+ ICV_MEAN_SDV_ENTRY_COMMON()
+
+#define ICV_MEAN_SDV_ENTRY_C4( sumtype, sqsumtype ) \
+ sumtype s0 = 0, s1 = 0, s2 = 0, s3 = 0; \
+ sqsumtype sq0 = 0, sq1 = 0, sq2 = 0, sq3 = 0; \
+ ICV_MEAN_SDV_ENTRY_COMMON()
+
+
+#define ICV_MEAN_SDV_ENTRY_BLOCK_COMMON( block_size ) \
+ int remaining = block_size; \
+ ICV_MEAN_SDV_ENTRY_COMMON()
+
+#define ICV_MEAN_SDV_ENTRY_BLOCK_C1( sumtype, sqsumtype, \
+ worktype, sqworktype, block_size ) \
+ sumtype sum0 = 0; \
+ sqsumtype sqsum0 = 0; \
+ worktype s0 = 0; \
+ sqworktype sq0 = 0; \
+ ICV_MEAN_SDV_ENTRY_BLOCK_COMMON( block_size )
+
+#define ICV_MEAN_SDV_ENTRY_BLOCK_C2( sumtype, sqsumtype, \
+ worktype, sqworktype, block_size ) \
+ sumtype sum0 = 0, sum1 = 0; \
+ sqsumtype sqsum0 = 0, sqsum1 = 0; \
+ worktype s0 = 0, s1 = 0; \
+ sqworktype sq0 = 0, sq1 = 0; \
+ ICV_MEAN_SDV_ENTRY_BLOCK_COMMON( block_size )
+
+#define ICV_MEAN_SDV_ENTRY_BLOCK_C3( sumtype, sqsumtype, \
+ worktype, sqworktype, block_size ) \
+ sumtype sum0 = 0, sum1 = 0, sum2 = 0; \
+ sqsumtype sqsum0 = 0, sqsum1 = 0, sqsum2 = 0; \
+ worktype s0 = 0, s1 = 0, s2 = 0; \
+ sqworktype sq0 = 0, sq1 = 0, sq2 = 0; \
+ ICV_MEAN_SDV_ENTRY_BLOCK_COMMON( block_size )
+
+#define ICV_MEAN_SDV_ENTRY_BLOCK_C4( sumtype, sqsumtype, \
+ worktype, sqworktype, block_size ) \
+ sumtype sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0; \
+ sqsumtype sqsum0 = 0, sqsum1 = 0, sqsum2 = 0, sqsum3 = 0; \
+ worktype s0 = 0, s1 = 0, s2 = 0, s3 = 0; \
+ sqworktype sq0 = 0, sq1 = 0, sq2 = 0, sq3 = 0; \
+ ICV_MEAN_SDV_ENTRY_BLOCK_COMMON( block_size )
+
+
+/////////////////////////////////////// exit macros //////////////////////////////////////
+
+#define ICV_MEAN_SDV_EXIT_COMMON() \
+ scale = pix ? 1./pix : 0
+
+#define ICV_MEAN_SDV_EXIT_CN( total, sqtotal, idx ) \
+ ICV_MEAN_SDV_EXIT_COMMON(); \
+ mean[idx] = tmp = scale*(double)total##idx; \
+ tmp = scale*(double)sqtotal##idx - tmp*tmp; \
+ sdv[idx] = sqrt(MAX(tmp,0.))
+
+#define ICV_MEAN_SDV_EXIT_C1( total, sqtotal ) \
+ ICV_MEAN_SDV_EXIT_COMMON(); \
+ ICV_MEAN_SDV_EXIT_CN( total, sqtotal, 0 )
+
+#define ICV_MEAN_SDV_EXIT_C2( total, sqtotal ) \
+ ICV_MEAN_SDV_EXIT_COMMON(); \
+ ICV_MEAN_SDV_EXIT_CN( total, sqtotal, 0 ); \
+ ICV_MEAN_SDV_EXIT_CN( total, sqtotal, 1 )
+
+#define ICV_MEAN_SDV_EXIT_C3( total, sqtotal ) \
+ ICV_MEAN_SDV_EXIT_COMMON(); \
+ ICV_MEAN_SDV_EXIT_CN( total, sqtotal, 0 ); \
+ ICV_MEAN_SDV_EXIT_CN( total, sqtotal, 1 ); \
+ ICV_MEAN_SDV_EXIT_CN( total, sqtotal, 2 )
+
+#define ICV_MEAN_SDV_EXIT_C4( total, sqtotal ) \
+ ICV_MEAN_SDV_EXIT_COMMON(); \
+ ICV_MEAN_SDV_EXIT_CN( total, sqtotal, 0 ); \
+ ICV_MEAN_SDV_EXIT_CN( total, sqtotal, 1 ); \
+ ICV_MEAN_SDV_EXIT_CN( total, sqtotal, 2 ); \
+ ICV_MEAN_SDV_EXIT_CN( total, sqtotal, 3 )
+
+////////////////////////////////////// update macros /////////////////////////////////////
+
+#define ICV_MEAN_SDV_UPDATE_COMMON( block_size )\
+ remaining = block_size
+
+#define ICV_MEAN_SDV_UPDATE_C1( block_size ) \
+ ICV_MEAN_SDV_UPDATE_COMMON( block_size ); \
+ sum0 += s0; sqsum0 += sq0; \
+ s0 = 0; sq0 = 0
+
+#define ICV_MEAN_SDV_UPDATE_C2( block_size ) \
+ ICV_MEAN_SDV_UPDATE_COMMON( block_size ); \
+ sum0 += s0; sqsum0 += sq0; \
+ sum1 += s1; sqsum1 += sq1; \
+ s0 = s1 = 0; sq0 = sq1 = 0
+
+#define ICV_MEAN_SDV_UPDATE_C3( block_size ) \
+ ICV_MEAN_SDV_UPDATE_COMMON( block_size ); \
+ sum0 += s0; sqsum0 += sq0; \
+ sum1 += s1; sqsum1 += sq1; \
+ sum2 += s2; sqsum2 += sq2; \
+ s0 = s1 = s2 = 0; sq0 = sq1 = sq2 = 0
+
+#define ICV_MEAN_SDV_UPDATE_C4( block_size ) \
+ ICV_MEAN_SDV_UPDATE_COMMON( block_size ); \
+ sum0 += s0; sqsum0 += sq0; \
+ sum1 += s1; sqsum1 += sq1; \
+ sum2 += s2; sqsum2 += sq2; \
+ sum3 += s3; sqsum3 += sq3; \
+ s0 = s1 = s2 = s3 = 0; sq0 = sq1 = sq2 = sq3 = 0
+
+
+
+#define ICV_DEF_MEAN_SDV_BLOCK_FUNC_2D( flavor, cn, arrtype, \
+ sumtype, sqsumtype, worktype, \
+ sqworktype, block_size, sqr_macro ) \
+IPCVAPI_IMPL( CvStatus, icvMean_StdDev_##flavor##_C##cn##R, \
+ ( const arrtype* src, int step, \
+ CvSize size, double* mean, double* sdv ), \
+ (src, step, size, mean, sdv) ) \
+{ \
+ ICV_MEAN_SDV_ENTRY_BLOCK_C##cn( sumtype, sqsumtype, \
+ worktype, sqworktype, (block_size)*(cn) ); \
+ pix = size.width * size.height; \
+ size.width *= (cn); \
+ \
+ for( ; size.height--; src += step ) \
+ { \
+ int x = 0; \
+ while( x < size.width ) \
+ { \
+ int limit = MIN( remaining, size.width - x ); \
+ remaining -= limit; \
+ limit += x; \
+ ICV_MEAN_SDV_CASE_C##cn( worktype, sqworktype, \
+ sqr_macro, limit ); \
+ if( remaining == 0 ) \
+ { \
+ ICV_MEAN_SDV_UPDATE_C##cn( (block_size)*(cn) ); \
+ } \
+ } \
+ } \
+ \
+ ICV_MEAN_SDV_UPDATE_C##cn(0); \
+ ICV_MEAN_SDV_EXIT_C##cn( sum, sqsum ); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_MEAN_SDV_FUNC_2D( flavor, cn, arrtype, \
+ sumtype, sqsumtype, worktype ) \
+IPCVAPI_IMPL( CvStatus, icvMean_StdDev_##flavor##_C##cn##R, \
+ ( const arrtype* src, int step, \
+ CvSize size, double* mean, double* sdv ), \
+ (src, step, size, mean, sdv) ) \
+{ \
+ ICV_MEAN_SDV_ENTRY_C##cn( sumtype, sqsumtype ); \
+ pix = size.width * size.height; \
+ size.width *= (cn); \
+ \
+ for( ; size.height--; src += step ) \
+ { \
+ int x = 0; \
+ ICV_MEAN_SDV_CASE_C##cn( worktype, sqsumtype, \
+ CV_SQR, size.width ); \
+ } \
+ \
+ ICV_MEAN_SDV_EXIT_C##cn( s, sq ); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_MEAN_SDV_BLOCK_FUNC_2D_COI( flavor, arrtype, \
+ sumtype, sqsumtype, worktype, \
+ sqworktype, block_size, sqr_macro ) \
+static CvStatus CV_STDCALL icvMean_StdDev_##flavor##_CnCR \
+ ( const arrtype* src, int step, \
+ CvSize size, int cn, int coi, \
+ double* mean, double* sdv ) \
+{ \
+ ICV_MEAN_SDV_ENTRY_BLOCK_C1( sumtype, sqsumtype, \
+ worktype, sqworktype, (block_size)*(cn) ); \
+ pix = size.width * size.height; \
+ size.width *= (cn); \
+ src += coi - 1; \
+ \
+ for( ; size.height--; src += step ) \
+ { \
+ int x = 0; \
+ while( x < size.width ) \
+ { \
+ int limit = MIN( remaining, size.width - x ); \
+ remaining -= limit; \
+ limit += x; \
+ ICV_MEAN_SDV_COI_CASE( worktype, sqworktype, \
+ sqr_macro, limit, cn); \
+ if( remaining == 0 ) \
+ { \
+ ICV_MEAN_SDV_UPDATE_C1( (block_size)*(cn) ); \
+ } \
+ } \
+ } \
+ \
+ ICV_MEAN_SDV_UPDATE_C1(0); \
+ ICV_MEAN_SDV_EXIT_C1( sum, sqsum ); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_MEAN_SDV_FUNC_2D_COI( flavor, arrtype, \
+ sumtype, sqsumtype, worktype )\
+static CvStatus CV_STDCALL icvMean_StdDev_##flavor##_CnCR \
+ ( const arrtype* src, int step, CvSize size,\
+ int cn, int coi, double* mean, double* sdv )\
+{ \
+ ICV_MEAN_SDV_ENTRY_C1( sumtype, sqsumtype ); \
+ pix = size.width * size.height; \
+ size.width *= (cn); \
+ src += coi - 1; \
+ \
+ for( ; size.height--; src += step ) \
+ { \
+ int x = 0; \
+ ICV_MEAN_SDV_COI_CASE( worktype, sqsumtype, \
+ CV_SQR, size.width, cn ); \
+ } \
+ \
+ ICV_MEAN_SDV_EXIT_C1( s, sq ); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_MEAN_SDV_MASK_BLOCK_FUNC_2D( flavor, cn, \
+ arrtype, sumtype, sqsumtype, worktype, \
+ sqworktype, block_size, sqr_macro ) \
+IPCVAPI_IMPL( CvStatus, icvMean_StdDev_##flavor##_C##cn##MR, \
+ ( const arrtype* src, int step, \
+ const uchar* mask, int maskstep, \
+ CvSize size, double* mean, double* sdv ), \
+ (src, step, mask, maskstep, size, mean, sdv))\
+{ \
+ ICV_MEAN_SDV_ENTRY_BLOCK_C##cn( sumtype, sqsumtype, \
+ worktype, sqworktype, block_size ); \
+ pix = 0; \
+ \
+ for( ; size.height--; src += step, mask += maskstep ) \
+ { \
+ int x = 0; \
+ while( x < size.width ) \
+ { \
+ int limit = MIN( remaining, size.width - x ); \
+ remaining -= limit; \
+ limit += x; \
+ ICV_MEAN_SDV_MASK_CASE_C##cn( worktype, sqworktype, \
+ sqr_macro, limit ); \
+ if( remaining == 0 ) \
+ { \
+ ICV_MEAN_SDV_UPDATE_C##cn( block_size ); \
+ } \
+ } \
+ } \
+ \
+ ICV_MEAN_SDV_UPDATE_C##cn(0); \
+ ICV_MEAN_SDV_EXIT_C##cn( sum, sqsum ); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_MEAN_SDV_MASK_FUNC_2D( flavor, cn, arrtype, \
+ sumtype, sqsumtype, worktype)\
+IPCVAPI_IMPL( CvStatus, icvMean_StdDev_##flavor##_C##cn##MR, \
+ ( const arrtype* src, int step, \
+ const uchar* mask, int maskstep, \
+ CvSize size, double* mean, double* sdv ), \
+ (src, step, mask, maskstep, size, mean, sdv))\
+{ \
+ ICV_MEAN_SDV_ENTRY_C##cn( sumtype, sqsumtype ); \
+ pix = 0; \
+ \
+ for( ; size.height--; src += step, mask += maskstep ) \
+ { \
+ int x = 0; \
+ ICV_MEAN_SDV_MASK_CASE_C##cn( worktype, sqsumtype, \
+ CV_SQR, size.width ); \
+ } \
+ \
+ ICV_MEAN_SDV_EXIT_C##cn( s, sq ); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_MEAN_SDV_MASK_BLOCK_FUNC_2D_COI( flavor, \
+ arrtype, sumtype, sqsumtype, worktype, \
+ sqworktype, block_size, sqr_macro ) \
+static CvStatus CV_STDCALL icvMean_StdDev_##flavor##_CnCMR \
+ ( const arrtype* src, int step, \
+ const uchar* mask, int maskstep, \
+ CvSize size, int cn, int coi, \
+ double* mean, double* sdv ) \
+{ \
+ ICV_MEAN_SDV_ENTRY_BLOCK_C1( sumtype, sqsumtype, \
+ worktype, sqworktype, block_size ); \
+ pix = 0; \
+ src += coi - 1; \
+ \
+ for( ; size.height--; src += step, mask += maskstep ) \
+ { \
+ int x = 0; \
+ while( x < size.width ) \
+ { \
+ int limit = MIN( remaining, size.width - x ); \
+ remaining -= limit; \
+ limit += x; \
+ ICV_MEAN_SDV_MASK_COI_CASE( worktype, sqworktype, \
+ sqr_macro, limit, cn ); \
+ if( remaining == 0 ) \
+ { \
+ ICV_MEAN_SDV_UPDATE_C1( block_size ); \
+ } \
+ } \
+ } \
+ \
+ ICV_MEAN_SDV_UPDATE_C1(0); \
+ ICV_MEAN_SDV_EXIT_C1( sum, sqsum ); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_MEAN_SDV_MASK_FUNC_2D_COI( flavor, arrtype, \
+ sumtype, sqsumtype, worktype ) \
+static CvStatus CV_STDCALL icvMean_StdDev_##flavor##_CnCMR \
+ ( const arrtype* src, int step, \
+ const uchar* mask, int maskstep, \
+ CvSize size, int cn, int coi, \
+ double* mean, double* sdv ) \
+{ \
+ ICV_MEAN_SDV_ENTRY_C1( sumtype, sqsumtype ); \
+ pix = 0; \
+ src += coi - 1; \
+ \
+ for( ; size.height--; src += step, mask += maskstep ) \
+ { \
+ int x = 0; \
+ ICV_MEAN_SDV_MASK_COI_CASE( worktype, sqsumtype, \
+ CV_SQR, size.width, cn ); \
+ } \
+ \
+ ICV_MEAN_SDV_EXIT_C1( s, sq ); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_MEAN_SDV_BLOCK_ALL( flavor, arrtype, sumtype, sqsumtype,\
+ worktype, sqworktype, block_size, sqr_macro)\
+ICV_DEF_MEAN_SDV_BLOCK_FUNC_2D( flavor, 1, arrtype, sumtype, sqsumtype, \
+ worktype, sqworktype, block_size, sqr_macro)\
+ICV_DEF_MEAN_SDV_BLOCK_FUNC_2D( flavor, 2, arrtype, sumtype, sqsumtype, \
+ worktype, sqworktype, block_size, sqr_macro)\
+ICV_DEF_MEAN_SDV_BLOCK_FUNC_2D( flavor, 3, arrtype, sumtype, sqsumtype, \
+ worktype, sqworktype, block_size, sqr_macro)\
+ICV_DEF_MEAN_SDV_BLOCK_FUNC_2D( flavor, 4, arrtype, sumtype, sqsumtype, \
+ worktype, sqworktype, block_size, sqr_macro)\
+ICV_DEF_MEAN_SDV_BLOCK_FUNC_2D_COI( flavor, arrtype, sumtype, sqsumtype,\
+ worktype, sqworktype, block_size, sqr_macro)\
+ \
+ICV_DEF_MEAN_SDV_MASK_BLOCK_FUNC_2D( flavor, 1, arrtype, sumtype, \
+ sqsumtype, worktype, sqworktype, block_size, sqr_macro ) \
+ICV_DEF_MEAN_SDV_MASK_BLOCK_FUNC_2D( flavor, 2, arrtype, sumtype, \
+ sqsumtype, worktype, sqworktype, block_size, sqr_macro ) \
+ICV_DEF_MEAN_SDV_MASK_BLOCK_FUNC_2D( flavor, 3, arrtype, sumtype, \
+ sqsumtype, worktype, sqworktype, block_size, sqr_macro ) \
+ICV_DEF_MEAN_SDV_MASK_BLOCK_FUNC_2D( flavor, 4, arrtype, sumtype, \
+ sqsumtype, worktype, sqworktype, block_size, sqr_macro ) \
+ICV_DEF_MEAN_SDV_MASK_BLOCK_FUNC_2D_COI( flavor, arrtype, sumtype, \
+ sqsumtype, worktype, sqworktype, block_size, sqr_macro )
+
+#define ICV_DEF_MEAN_SDV_ALL( flavor, arrtype, sumtype, sqsumtype, worktype ) \
+ICV_DEF_MEAN_SDV_FUNC_2D( flavor, 1, arrtype, sumtype, sqsumtype, worktype ) \
+ICV_DEF_MEAN_SDV_FUNC_2D( flavor, 2, arrtype, sumtype, sqsumtype, worktype ) \
+ICV_DEF_MEAN_SDV_FUNC_2D( flavor, 3, arrtype, sumtype, sqsumtype, worktype ) \
+ICV_DEF_MEAN_SDV_FUNC_2D( flavor, 4, arrtype, sumtype, sqsumtype, worktype ) \
+ICV_DEF_MEAN_SDV_FUNC_2D_COI( flavor, arrtype, sumtype, sqsumtype, worktype ) \
+ \
+ICV_DEF_MEAN_SDV_MASK_FUNC_2D(flavor, 1, arrtype, sumtype, sqsumtype, worktype) \
+ICV_DEF_MEAN_SDV_MASK_FUNC_2D(flavor, 2, arrtype, sumtype, sqsumtype, worktype) \
+ICV_DEF_MEAN_SDV_MASK_FUNC_2D(flavor, 3, arrtype, sumtype, sqsumtype, worktype) \
+ICV_DEF_MEAN_SDV_MASK_FUNC_2D(flavor, 4, arrtype, sumtype, sqsumtype, worktype) \
+ICV_DEF_MEAN_SDV_MASK_FUNC_2D_COI( flavor, arrtype, sumtype, sqsumtype, worktype )
+
+
+ICV_DEF_MEAN_SDV_BLOCK_ALL( 8u, uchar, int64, int64, unsigned, unsigned, 1 << 16, CV_SQR_8U )
+ICV_DEF_MEAN_SDV_BLOCK_ALL( 16u, ushort, int64, int64, unsigned, int64, 1 << 16, CV_SQR )
+ICV_DEF_MEAN_SDV_BLOCK_ALL( 16s, short, int64, int64, int, int64, 1 << 16, CV_SQR )
+
+ICV_DEF_MEAN_SDV_ALL( 32s, int, double, double, double )
+ICV_DEF_MEAN_SDV_ALL( 32f, float, double, double, double )
+ICV_DEF_MEAN_SDV_ALL( 64f, double, double, double, double )
+
+#define icvMean_StdDev_8s_C1R 0
+#define icvMean_StdDev_8s_C2R 0
+#define icvMean_StdDev_8s_C3R 0
+#define icvMean_StdDev_8s_C4R 0
+#define icvMean_StdDev_8s_CnCR 0
+
+#define icvMean_StdDev_8s_C1MR 0
+#define icvMean_StdDev_8s_C2MR 0
+#define icvMean_StdDev_8s_C3MR 0
+#define icvMean_StdDev_8s_C4MR 0
+#define icvMean_StdDev_8s_CnCMR 0
+
+CV_DEF_INIT_BIG_FUNC_TAB_2D( Mean_StdDev, R )
+CV_DEF_INIT_FUNC_TAB_2D( Mean_StdDev, CnCR )
+CV_DEF_INIT_BIG_FUNC_TAB_2D( Mean_StdDev, MR )
+CV_DEF_INIT_FUNC_TAB_2D( Mean_StdDev, CnCMR )
+
+CV_IMPL void
+cvAvgSdv( const CvArr* img, CvScalar* _mean, CvScalar* _sdv, const void* mask )
+{
+ CvScalar mean = {{0,0,0,0}};
+ CvScalar sdv = {{0,0,0,0}};
+
+ static CvBigFuncTable meansdv_tab;
+ static CvFuncTable meansdvcoi_tab;
+ static CvBigFuncTable meansdvmask_tab;
+ static CvFuncTable meansdvmaskcoi_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME("cvMean_StdDev");
+
+ __BEGIN__;
+
+ int type, coi = 0;
+ int mat_step, mask_step = 0;
+ CvSize size;
+ CvMat stub, maskstub, *mat = (CvMat*)img, *matmask = (CvMat*)mask;
+
+ if( !inittab )
+ {
+ icvInitMean_StdDevRTable( &meansdv_tab );
+ icvInitMean_StdDevCnCRTable( &meansdvcoi_tab );
+ icvInitMean_StdDevMRTable( &meansdvmask_tab );
+ icvInitMean_StdDevCnCMRTable( &meansdvmaskcoi_tab );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(mat) )
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+
+ type = CV_MAT_TYPE( mat->type );
+
+ if( CV_MAT_CN(type) > 4 && coi == 0 )
+ CV_ERROR( CV_StsOutOfRange, "The input array must have at most 4 channels unless COI is set" );
+
+ size = cvGetMatSize( mat );
+ mat_step = mat->step;
+
+ if( !mask )
+ {
+ if( CV_IS_MAT_CONT( mat->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ mat_step = CV_STUB_STEP;
+ }
+
+ if( CV_MAT_CN(type) == 1 || coi == 0 )
+ {
+ CvFunc2D_1A2P func = (CvFunc2D_1A2P)(meansdv_tab.fn_2d[type]);
+
+ if( !func )
+ CV_ERROR( CV_StsBadArg, cvUnsupportedFormat );
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, size, mean.val, sdv.val ));
+ }
+ else
+ {
+ CvFunc2DnC_1A2P func = (CvFunc2DnC_1A2P)
+ (meansdvcoi_tab.fn_2d[CV_MAT_DEPTH(type)]);
+
+ if( !func )
+ CV_ERROR( CV_StsBadArg, cvUnsupportedFormat );
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, size,
+ CV_MAT_CN(type), coi, mean.val, sdv.val ));
+ }
+ }
+ else
+ {
+ CV_CALL( matmask = cvGetMat( matmask, &maskstub ));
+
+ mask_step = matmask->step;
+
+ if( !CV_IS_MASK_ARR( matmask ))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !CV_ARE_SIZES_EQ( mat, matmask ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( CV_IS_MAT_CONT( mat->type & matmask->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ mat_step = mask_step = CV_STUB_STEP;
+ }
+
+ if( CV_MAT_CN(type) == 1 || coi == 0 )
+ {
+ CvFunc2D_2A2P func = (CvFunc2D_2A2P)(meansdvmask_tab.fn_2d[type]);
+
+ if( !func )
+ CV_ERROR( CV_StsBadArg, cvUnsupportedFormat );
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, matmask->data.ptr,
+ mask_step, size, mean.val, sdv.val ));
+ }
+ else
+ {
+ CvFunc2DnC_2A2P func = (CvFunc2DnC_2A2P)
+ (meansdvmaskcoi_tab.fn_2d[CV_MAT_DEPTH(type)]);
+
+ if( !func )
+ CV_ERROR( CV_StsBadArg, cvUnsupportedFormat );
+
+ IPPI_CALL( func( mat->data.ptr, mat_step,
+ matmask->data.ptr, mask_step,
+ size, CV_MAT_CN(type), coi, mean.val, sdv.val ));
+ }
+ }
+
+ __END__;
+
+ if( _mean )
+ *_mean = mean;
+
+ if( _sdv )
+ *_sdv = sdv;
+}
+
+
+/* End of file */
diff --git a/cxcore/src/cxminmaxloc.cpp b/cxcore/src/cxminmaxloc.cpp
new file mode 100644
index 0000000..9b98c47
--- /dev/null
+++ b/cxcore/src/cxminmaxloc.cpp
@@ -0,0 +1,452 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+
+/****************************************************************************************\
+* MinMaxLoc *
+\****************************************************************************************/
+
+#define CV_MINMAXLOC_ENTRY( _toggle_, srctype, temptype, cn ) \
+ temptype min_val, max_val; \
+ int min_loc = 0, max_loc = 0; \
+ int x, loc = 0, width = size.width*(cn); \
+ step /= sizeof(src[0]); \
+ \
+ min_val = src[0]; \
+ min_val = max_val = _toggle_( min_val )
+
+
+#define CV_MINMAXLOC_EXIT( _fin_cast_macro_ ) \
+ minLoc->x = min_loc; \
+ maxLoc->x = max_loc; \
+ minLoc->y = maxLoc->y = 0; \
+ *minVal = _fin_cast_macro_(min_val); \
+ *maxVal = _fin_cast_macro_(max_val); \
+ return CV_OK
+
+
+#define ICV_DEF_MINMAXLOC_1D_CASE_COI( _toggle_, temptype, cn ) \
+ for( x = 0; x < width; x += (cn), loc++ ) \
+ { \
+ temptype val = src[x]; \
+ val = _toggle_(val); \
+ \
+ if( val < min_val ) \
+ { \
+ min_val = val; \
+ min_loc = loc; \
+ } \
+ else if( val > max_val ) \
+ { \
+ max_val = val; \
+ max_loc = loc; \
+ } \
+ }
+
+
+#define ICV_DEF_MINMAXLOC_FUNC_2D( _toggle_, _fin_cast_macro_, flavor, \
+ srctype, temptype, extrtype ) \
+IPCVAPI_IMPL( CvStatus, \
+icvMinMaxIndx_##flavor##_C1R,( const srctype* src, int step, CvSize size, \
+ extrtype* minVal, extrtype* maxVal, CvPoint* minLoc, CvPoint* maxLoc ), \
+ (src, step, size, minVal, maxVal, minLoc, maxLoc) ) \
+{ \
+ CV_MINMAXLOC_ENTRY( _toggle_, srctype, temptype, 1 ); \
+ \
+ for( ; size.height--; src += step ) \
+ { \
+ ICV_DEF_MINMAXLOC_1D_CASE_COI( _toggle_, temptype, 1 ); \
+ } \
+ \
+ CV_MINMAXLOC_EXIT( _fin_cast_macro_ ); \
+}
+
+
+#define ICV_DEF_MINMAXLOC_FUNC_2D_COI( _toggle_, _fin_cast_macro_, flavor, \
+ srctype, temptype, extrtype ) \
+static CvStatus CV_STDCALL \
+icvMinMaxIndx_##flavor##_CnCR( const srctype* src, int step, \
+ CvSize size, int cn, int coi, \
+ extrtype* minVal, extrtype* maxVal, \
+ CvPoint* minLoc, CvPoint* maxLoc ) \
+{ \
+ (src) += coi - 1; \
+ CV_MINMAXLOC_ENTRY( _toggle_, srctype, temptype, cn ); \
+ \
+ for( ; size.height--; src += step ) \
+ { \
+ ICV_DEF_MINMAXLOC_1D_CASE_COI( _toggle_, temptype, cn ); \
+ } \
+ \
+ CV_MINMAXLOC_EXIT( _fin_cast_macro_ ); \
+}
+
+
+#define ICV_DEF_MINMAXLOC_ALL_INT( flavor, srctype, \
+ _fin_cast_macro_, extrtype ) \
+ ICV_DEF_MINMAXLOC_FUNC_2D( CV_NOP, _fin_cast_macro_, flavor,\
+ srctype, int, extrtype ) \
+ ICV_DEF_MINMAXLOC_FUNC_2D_COI( CV_NOP, _fin_cast_macro_, \
+ flavor, srctype, int, extrtype )
+
+CV_INLINE float minmax_to_float( int val )
+{
+ Cv32suf v;
+ v.i = CV_TOGGLE_FLT(val);
+ return v.f;
+}
+
+CV_INLINE double minmax_to_double( int64 val )
+{
+ Cv64suf v;
+ v.i = CV_TOGGLE_DBL(val);
+ return v.f;
+}
+
+#define ICV_DEF_MINMAXLOC_ALL_FLT( flavor, srctype, _toggle_, \
+ _fin_cast_macro_, extrtype ) \
+ \
+ ICV_DEF_MINMAXLOC_FUNC_2D( _toggle_, _fin_cast_macro_, flavor, \
+ srctype, srctype, extrtype ) \
+ ICV_DEF_MINMAXLOC_FUNC_2D_COI( _toggle_, _fin_cast_macro_, flavor, \
+ srctype, srctype, extrtype )
+
+ICV_DEF_MINMAXLOC_ALL_INT( 8u, uchar, CV_CAST_32F, float )
+ICV_DEF_MINMAXLOC_ALL_INT( 16u, ushort, CV_CAST_32F, float )
+ICV_DEF_MINMAXLOC_ALL_INT( 16s, short, CV_CAST_32F, float )
+ICV_DEF_MINMAXLOC_ALL_INT( 32s, int, CV_CAST_64F, double )
+ICV_DEF_MINMAXLOC_ALL_FLT( 32f, int, CV_TOGGLE_FLT, minmax_to_float, float )
+ICV_DEF_MINMAXLOC_ALL_FLT( 64f, int64, CV_TOGGLE_DBL, minmax_to_double, double )
+
+
+/****************************************************************************************\
+* MinMaxLoc with mask *
+\****************************************************************************************/
+
+#define CV_MINMAXLOC_MASK_ENTRY( _toggle_, srctype, temptype, cn ) \
+ temptype min_val = 0, max_val = 0; \
+ int min_loc = -1, max_loc = -1; \
+ int x = 0, y, loc = 0, width = size.width; \
+ step /= sizeof(src[0]); \
+ \
+ if( width*(cn) == step && width == maskStep ) \
+ { \
+ width *= size.height; \
+ size.height = 1; \
+ } \
+ \
+ for( y = 0; y < size.height; y++, src += step, \
+ mask += maskStep ) \
+ { \
+ for( x = 0; x < width; x++, loc++ ) \
+ if( mask[x] != 0 ) \
+ { \
+ min_loc = max_loc = loc; \
+ min_val = (src)[x*(cn)]; \
+ min_val = max_val = _toggle_( min_val ); \
+ goto stop_scan; \
+ } \
+ } \
+ \
+ stop_scan:;
+
+
+#define ICV_DEF_MINMAXLOC_1D_MASK_CASE_COI( _toggle_, temptype, cn ) \
+ for( ; x < width; x++, loc++ ) \
+ { \
+ temptype val = src[x*(cn)]; \
+ int m = mask[x] != 0; \
+ val = _toggle_(val); \
+ \
+ if( val < min_val && m ) \
+ { \
+ min_val = val; \
+ min_loc = loc; \
+ } \
+ else if( val > max_val && m ) \
+ { \
+ max_val = val; \
+ max_loc = loc; \
+ } \
+ }
+
+
+#define ICV_DEF_MINMAXLOC_MASK_FUNC_2D( _toggle_, _fin_cast_macro_, flavor, \
+ srctype, temptype, extrtype ) \
+IPCVAPI_IMPL( CvStatus, \
+icvMinMaxIndx_##flavor##_C1MR,( const srctype* src, int step, \
+ const uchar* mask, int maskStep, CvSize size, \
+ extrtype* minVal, extrtype* maxVal, CvPoint* minLoc, CvPoint* maxLoc ), \
+ ( src, step, mask, maskStep, size, minVal, maxVal, minLoc, maxLoc) ) \
+{ \
+ CV_MINMAXLOC_MASK_ENTRY( _toggle_, srctype, temptype, 1 ); \
+ \
+ for( ; y < size.height; y++, src += step, mask += maskStep ) \
+ { \
+ ICV_DEF_MINMAXLOC_1D_MASK_CASE_COI( _toggle_, temptype, 1 ) \
+ x = 0; \
+ } \
+ \
+ CV_MINMAXLOC_EXIT( _fin_cast_macro_ ); \
+}
+
+
+#define ICV_DEF_MINMAXLOC_MASK_FUNC_2D_COI( _toggle_, _fin_cast_macro_, \
+ flavor, srctype, temptype, extrtype ) \
+static CvStatus CV_STDCALL \
+icvMinMaxIndx_##flavor##_CnCMR( const srctype* src, int step, \
+ const uchar* mask, int maskStep, CvSize size, int cn, int coi, \
+ extrtype* minVal, extrtype* maxVal, CvPoint* minLoc, CvPoint* maxLoc ) \
+{ \
+ (src) += coi - 1; \
+ CV_MINMAXLOC_MASK_ENTRY( _toggle_, srctype, temptype, cn ); \
+ \
+ for( ; y < size.height; y++, src += step, mask += maskStep ) \
+ { \
+ ICV_DEF_MINMAXLOC_1D_MASK_CASE_COI( _toggle_, temptype, cn ) \
+ x = 0; \
+ } \
+ \
+ CV_MINMAXLOC_EXIT( _fin_cast_macro_ ); \
+}
+
+
+
+#define ICV_DEF_MINMAXLOC_MASK_ALL_INT( flavor, srctype, \
+ _fin_cast_macro_, extrtype ) \
+ ICV_DEF_MINMAXLOC_MASK_FUNC_2D( CV_NOP, _fin_cast_macro_, flavor, \
+ srctype, int, extrtype ) \
+ ICV_DEF_MINMAXLOC_MASK_FUNC_2D_COI( CV_NOP, _fin_cast_macro_, flavor, \
+ srctype, int, extrtype )
+
+#define ICV_DEF_MINMAXLOC_MASK_ALL_FLT( flavor, srctype, _toggle_, \
+ _fin_cast_macro_, extrtype ) \
+ ICV_DEF_MINMAXLOC_MASK_FUNC_2D( _toggle_, _fin_cast_macro_, flavor, \
+ srctype, srctype, extrtype ) \
+ ICV_DEF_MINMAXLOC_MASK_FUNC_2D_COI( _toggle_, _fin_cast_macro_, flavor, \
+ srctype, srctype, extrtype )
+
+ICV_DEF_MINMAXLOC_MASK_ALL_INT( 8u, uchar, CV_CAST_32F, float )
+ICV_DEF_MINMAXLOC_MASK_ALL_INT( 16u, ushort, CV_CAST_32F, float )
+ICV_DEF_MINMAXLOC_MASK_ALL_INT( 16s, short, CV_CAST_32F, float )
+ICV_DEF_MINMAXLOC_MASK_ALL_INT( 32s, int, CV_CAST_64F, double )
+ICV_DEF_MINMAXLOC_MASK_ALL_FLT( 32f, int, CV_TOGGLE_FLT, minmax_to_float, float )
+ICV_DEF_MINMAXLOC_MASK_ALL_FLT( 64f, int64, CV_TOGGLE_DBL, minmax_to_double, double )
+
+#define icvMinMaxIndx_8s_C1R 0
+#define icvMinMaxIndx_8s_CnCR 0
+#define icvMinMaxIndx_8s_C1MR 0
+#define icvMinMaxIndx_8s_CnCMR 0
+
+CV_DEF_INIT_FUNC_TAB_2D( MinMaxIndx, C1R )
+CV_DEF_INIT_FUNC_TAB_2D( MinMaxIndx, CnCR )
+CV_DEF_INIT_FUNC_TAB_2D( MinMaxIndx, C1MR )
+CV_DEF_INIT_FUNC_TAB_2D( MinMaxIndx, CnCMR )
+
+
+CV_IMPL void
+cvMinMaxLoc( const void* img, double* _minVal, double* _maxVal,
+ CvPoint* _minLoc, CvPoint* _maxLoc, const void* mask )
+{
+ static CvFuncTable minmax_tab, minmaxcoi_tab;
+ static CvFuncTable minmaxmask_tab, minmaxmaskcoi_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME("cvMinMaxLoc");
+
+ __BEGIN__;
+
+ int type, depth, cn, coi = 0;
+ int mat_step, mask_step = 0, cont_flag;
+ CvSize size;
+ CvMat stub, maskstub, *mat = (CvMat*)img, *matmask = (CvMat*)mask;
+ CvPoint minloc, maxloc;
+ double minv = 0, maxv = 0;
+ float minvf = 0.f, maxvf = 0.f;
+ void *pmin = &minvf, *pmax = &maxvf;
+
+ if( !inittab )
+ {
+ icvInitMinMaxIndxC1RTable( &minmax_tab );
+ icvInitMinMaxIndxCnCRTable( &minmaxcoi_tab );
+ icvInitMinMaxIndxC1MRTable( &minmaxmask_tab );
+ icvInitMinMaxIndxCnCMRTable( &minmaxmaskcoi_tab );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(mat) )
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+
+ type = CV_MAT_TYPE( mat->type );
+ depth = CV_MAT_DEPTH( type );
+ cn = CV_MAT_CN( type );
+ size = cvGetMatSize( mat );
+
+ if( cn > 1 && coi == 0 )
+ CV_ERROR( CV_StsBadArg, "" );
+
+ if( depth == CV_32S || depth == CV_64F )
+ pmin = &minv, pmax = &maxv;
+
+ mat_step = mat->step;
+ cont_flag = mat->type;
+
+ if( mask )
+ {
+ CV_CALL( matmask = cvGetMat( matmask, &maskstub ));
+
+ if( !CV_IS_MASK_ARR( matmask ))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !CV_ARE_SIZES_EQ( mat, matmask ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ mask_step = matmask->step;
+ cont_flag &= matmask->type;
+ }
+
+ if( CV_IS_MAT_CONT(cont_flag) )
+ {
+ size.width *= size.height;
+ size.height = 1;
+ }
+
+ if( size.height == 1 )
+ mat_step = mask_step = CV_STUB_STEP;
+
+ if( !mask )
+ {
+ if( CV_MAT_CN(type) == 1 || coi == 0 )
+ {
+ CvFunc2D_1A4P func = (CvFunc2D_1A4P)(minmax_tab.fn_2d[depth]);
+
+ if( !func )
+ CV_ERROR( CV_StsBadArg, cvUnsupportedFormat );
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, size,
+ pmin, pmax, &minloc, &maxloc ));
+ }
+ else
+ {
+ CvFunc2DnC_1A4P func = (CvFunc2DnC_1A4P)(minmaxcoi_tab.fn_2d[depth]);
+
+ if( !func )
+ CV_ERROR( CV_StsBadArg, cvUnsupportedFormat );
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, size, cn, coi,
+ pmin, pmax, &minloc, &maxloc ));
+ }
+ }
+ else
+ {
+ if( CV_MAT_CN(type) == 1 || coi == 0 )
+ {
+ CvFunc2D_2A4P func = (CvFunc2D_2A4P)(minmaxmask_tab.fn_2d[depth]);
+
+ if( !func )
+ CV_ERROR( CV_StsBadArg, cvUnsupportedFormat );
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, matmask->data.ptr,
+ mask_step, size,
+ pmin, pmax, &minloc, &maxloc ));
+ }
+ else
+ {
+ CvFunc2DnC_2A4P func = (CvFunc2DnC_2A4P)(minmaxmaskcoi_tab.fn_2d[depth]);
+
+ if( !func )
+ CV_ERROR( CV_StsBadArg, cvUnsupportedFormat );
+
+ IPPI_CALL( func( mat->data.ptr, mat_step,
+ matmask->data.ptr, mask_step, size, cn, coi,
+ pmin, pmax, &minloc, &maxloc ));
+ }
+ }
+
+ if( matmask || _minLoc || _maxLoc )
+ {
+ if( minloc.x >= mat->cols )
+ {
+ minloc.y = minloc.x / mat->cols;
+ minloc.x -= minloc.y * mat->cols;
+ }
+
+ if( maxloc.x >= mat->cols )
+ {
+ maxloc.y = maxloc.x / mat->cols;
+ maxloc.x -= maxloc.y * mat->cols;
+ }
+
+ if( matmask && ((unsigned)minloc.x >= (unsigned)mat->cols ||
+ (unsigned)minloc.y >= (unsigned)mat->rows ||
+ matmask->data.ptr[minloc.y*matmask->step + minloc.x] == 0 ||
+ (unsigned)maxloc.x >= (unsigned)mat->cols ||
+ (unsigned)maxloc.y >= (unsigned)mat->rows ||
+ matmask->data.ptr[maxloc.y*matmask->step + maxloc.x] == 0) )
+ {
+ minloc.x = minloc.y = maxloc.x = maxloc.y = -1;
+ minv = maxv = minvf = maxvf = 0;
+ }
+
+ if( _minLoc )
+ *_minLoc = minloc;
+
+ if( _maxLoc )
+ *_maxLoc = maxloc;
+ }
+
+ if( depth != CV_32S && depth != CV_64F )
+ {
+ minv = minvf;
+ maxv = maxvf;
+ }
+
+ if( _minVal )
+ *_minVal = minv;
+
+ if( _maxVal )
+ *_maxVal = maxv;
+
+ __END__;
+}
+
+/* End of file */
diff --git a/cxcore/src/cxnorm.cpp b/cxcore/src/cxnorm.cpp
new file mode 100644
index 0000000..2ae29c3
--- /dev/null
+++ b/cxcore/src/cxnorm.cpp
@@ -0,0 +1,1417 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+
+/****************************************************************************************\
+* N o r m *
+\****************************************************************************************/
+
+#define ICV_NORM_CASE( _op_, \
+ _update_op_, worktype, len ) \
+ \
+ for( ; x <= (len) - 4; x += 4 ) \
+ { \
+ worktype t0 = (src)[x]; \
+ worktype t1 = (src)[x+1]; \
+ t0 = _op_(t0); \
+ t1 = _op_(t1); \
+ norm = _update_op_( norm, t0 ); \
+ norm = _update_op_( norm, t1 ); \
+ \
+ t0 = (src)[x+2]; \
+ t1 = (src)[x+3]; \
+ t0 = _op_(t0); \
+ t1 = _op_(t1); \
+ norm = _update_op_( norm, t0 ); \
+ norm = _update_op_( norm, t1 ); \
+ } \
+ \
+ for( ; x < (len); x++ ) \
+ { \
+ worktype t0 = (src)[x]; \
+ t0 = (worktype)_op_(t0); \
+ norm = _update_op_( norm, t0 ); \
+ }
+
+
+#define ICV_NORM_COI_CASE( _op_, \
+ _update_op_, worktype, len, cn ) \
+ \
+ for( ; x < (len); x++ ) \
+ { \
+ worktype t0 = (src)[x*(cn)]; \
+ t0 = (worktype)_op_(t0); \
+ norm = _update_op_( norm, t0 ); \
+ }
+
+
+#define ICV_NORM_DIFF_CASE( _op_, \
+ _update_op_, worktype, len ) \
+ \
+ for( ; x <= (len) - 4; x += 4 ) \
+ { \
+ worktype t0 = (src1)[x] - (src2)[x];\
+ worktype t1 = (src1)[x+1]-(src2)[x+1];\
+ \
+ t0 = _op_(t0); \
+ t1 = _op_(t1); \
+ \
+ norm = _update_op_( norm, t0 ); \
+ norm = _update_op_( norm, t1 ); \
+ \
+ t0 = (src1)[x+2] - (src2)[x+2]; \
+ t1 = (src1)[x+3] - (src2)[x+3]; \
+ \
+ t0 = _op_(t0); \
+ t1 = _op_(t1); \
+ \
+ norm = _update_op_( norm, t0 ); \
+ norm = _update_op_( norm, t1 ); \
+ } \
+ \
+ for( ; x < (len); x++ ) \
+ { \
+ worktype t0 = (src1)[x] - (src2)[x];\
+ t0 = (worktype)_op_(t0); \
+ norm = _update_op_( norm, t0 ); \
+ }
+
+
+#define ICV_NORM_DIFF_COI_CASE( _op_, _update_op_, worktype, len, cn ) \
+ for( ; x < (len); x++ ) \
+ { \
+ worktype t0 = (src1)[x*(cn)] - (src2)[x*(cn)]; \
+ t0 = (worktype)_op_(t0); \
+ norm = _update_op_( norm, t0 ); \
+ }
+
+
+/*
+ The algorithm and its multiple variations below
+ below accumulates the norm by blocks of size "block_size".
+ Each block may span across multiple lines and it is
+ not necessary aligned by row boundaries. Within a block
+ the norm is accumulated to intermediate light-weight
+ type (worktype). It really makes sense for 8u, 16s, 16u types
+ and L1 & L2 norms, where worktype==int and normtype==int64.
+ In other cases a simpler algorithm is used
+*/
+#define ICV_DEF_NORM_NOHINT_BLOCK_FUNC_2D( name, _op_, _update_op_, \
+ post_func, arrtype, normtype, worktype, block_size ) \
+IPCVAPI_IMPL( CvStatus, name, ( const arrtype* src, int step, \
+ CvSize size, double* _norm ), (src, step, size, _norm) ) \
+{ \
+ int remaining = block_size; \
+ normtype total_norm = 0; \
+ worktype norm = 0; \
+ step /= sizeof(src[0]); \
+ \
+ for( ; size.height--; src += step ) \
+ { \
+ int x = 0; \
+ while( x < size.width ) \
+ { \
+ int limit = MIN( remaining, size.width - x ); \
+ remaining -= limit; \
+ limit += x; \
+ ICV_NORM_CASE( _op_, _update_op_, worktype, limit );\
+ if( remaining == 0 ) \
+ { \
+ remaining = block_size; \
+ total_norm += (normtype)norm; \
+ norm = 0; \
+ } \
+ } \
+ } \
+ \
+ total_norm += (normtype)norm; \
+ *_norm = post_func((double)total_norm); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_NORM_NOHINT_FUNC_2D( name, _op_, _update_op_, \
+ post_func, arrtype, normtype, worktype, block_size ) \
+IPCVAPI_IMPL( CvStatus, name, ( const arrtype* src, int step, \
+ CvSize size, double* _norm ), (src, step, size, _norm) ) \
+{ \
+ normtype norm = 0; \
+ step /= sizeof(src[0]); \
+ \
+ for( ; size.height--; src += step ) \
+ { \
+ int x = 0; \
+ ICV_NORM_CASE(_op_, _update_op_, worktype, size.width); \
+ } \
+ \
+ *_norm = post_func((double)norm); \
+ return CV_OK; \
+}
+
+
+/*
+ In IPP only 32f flavors of norm functions are with hint.
+ For float worktype==normtype==double, thus the block algorithm,
+ described above, is not necessary.
+ */
+#define ICV_DEF_NORM_HINT_FUNC_2D( name, _op_, _update_op_, \
+ post_func, arrtype, normtype, worktype, block_size ) \
+IPCVAPI_IMPL( CvStatus, name, ( const arrtype* src, int step, \
+ CvSize size, double* _norm, CvHintAlgorithm /*hint*/ ), \
+ (src, step, size, _norm, cvAlgHintAccurate) ) \
+{ \
+ normtype norm = 0; \
+ step /= sizeof(src[0]); \
+ \
+ for( ; size.height--; src += step ) \
+ { \
+ int x = 0; \
+ ICV_NORM_CASE(_op_, _update_op_, worktype, size.width); \
+ } \
+ \
+ *_norm = post_func((double)norm); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_NORM_NOHINT_BLOCK_FUNC_2D_COI( name, _op_, \
+ _update_op_, post_func, arrtype, \
+ normtype, worktype, block_size ) \
+static CvStatus CV_STDCALL name( const arrtype* src, int step, \
+ CvSize size, int cn, int coi, double* _norm ) \
+{ \
+ int remaining = block_size; \
+ normtype total_norm = 0; \
+ worktype norm = 0; \
+ step /= sizeof(src[0]); \
+ src += coi - 1; \
+ \
+ for( ; size.height--; src += step ) \
+ { \
+ int x = 0; \
+ while( x < size.width ) \
+ { \
+ int limit = MIN( remaining, size.width - x ); \
+ remaining -= limit; \
+ limit += x; \
+ ICV_NORM_COI_CASE( _op_, _update_op_, \
+ worktype, limit, cn ); \
+ if( remaining == 0 ) \
+ { \
+ remaining = block_size; \
+ total_norm += (normtype)norm; \
+ norm = 0; \
+ } \
+ } \
+ } \
+ \
+ total_norm += (normtype)norm; \
+ *_norm = post_func((double)total_norm); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_NORM_NOHINT_FUNC_2D_COI( name, _op_, \
+ _update_op_, post_func, \
+ arrtype, normtype, worktype, block_size ) \
+static CvStatus CV_STDCALL name( const arrtype* src, int step, \
+ CvSize size, int cn, int coi, double* _norm ) \
+{ \
+ normtype norm = 0; \
+ step /= sizeof(src[0]); \
+ src += coi - 1; \
+ \
+ for( ; size.height--; src += step ) \
+ { \
+ int x = 0; \
+ ICV_NORM_COI_CASE( _op_, _update_op_, \
+ worktype, size.width, cn ); \
+ } \
+ \
+ *_norm = post_func((double)norm); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_NORM_DIFF_NOHINT_BLOCK_FUNC_2D( name, _op_, \
+ _update_op_, post_func, arrtype, \
+ normtype, worktype, block_size ) \
+IPCVAPI_IMPL( CvStatus, name,( const arrtype* src1, int step1, \
+ const arrtype* src2, int step2, CvSize size, double* _norm),\
+ (src1, step1, src2, step2, size, _norm)) \
+{ \
+ int remaining = block_size; \
+ normtype total_norm = 0; \
+ worktype norm = 0; \
+ step1 /= sizeof(src1[0]); \
+ step2 /= sizeof(src2[0]); \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2 ) \
+ { \
+ int x = 0; \
+ while( x < size.width ) \
+ { \
+ int limit = MIN( remaining, size.width - x ); \
+ remaining -= limit; \
+ limit += x; \
+ ICV_NORM_DIFF_CASE( _op_, _update_op_, \
+ worktype, limit ); \
+ if( remaining == 0 ) \
+ { \
+ remaining = block_size; \
+ total_norm += (normtype)norm; \
+ norm = 0; \
+ } \
+ } \
+ } \
+ \
+ total_norm += (normtype)norm; \
+ *_norm = post_func((double)total_norm); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_NORM_DIFF_NOHINT_FUNC_2D( name, _op_, \
+ _update_op_, post_func, \
+ arrtype, normtype, worktype, block_size ) \
+IPCVAPI_IMPL( CvStatus, name,( const arrtype* src1, int step1, \
+ const arrtype* src2, int step2, CvSize size, double* _norm),\
+ ( src1, step1, src2, step2, size, _norm )) \
+{ \
+ normtype norm = 0; \
+ step1 /= sizeof(src1[0]); \
+ step2 /= sizeof(src2[0]); \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2 ) \
+ { \
+ int x = 0; \
+ ICV_NORM_DIFF_CASE( _op_, _update_op_, \
+ worktype, size.width ); \
+ } \
+ \
+ *_norm = post_func((double)norm); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_NORM_DIFF_HINT_FUNC_2D( name, _op_, \
+ _update_op_, post_func, \
+ arrtype, normtype, worktype, block_size ) \
+IPCVAPI_IMPL( CvStatus, name,( const arrtype* src1, int step1, \
+ const arrtype* src2, int step2, CvSize size, double* _norm, \
+ CvHintAlgorithm /*hint*/ ), \
+ (src1, step1, src2, step2, size, _norm, cvAlgHintAccurate ))\
+{ \
+ normtype norm = 0; \
+ step1 /= sizeof(src1[0]); \
+ step2 /= sizeof(src2[0]); \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2 ) \
+ { \
+ int x = 0; \
+ ICV_NORM_DIFF_CASE( _op_, _update_op_, \
+ worktype, size.width ); \
+ } \
+ \
+ *_norm = post_func((double)norm); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_NORM_DIFF_NOHINT_BLOCK_FUNC_2D_COI( name, _op_,\
+ _update_op_, post_func, arrtype, \
+ normtype, worktype, block_size ) \
+static CvStatus CV_STDCALL name( const arrtype* src1, int step1,\
+ const arrtype* src2, int step2, CvSize size, \
+ int cn, int coi, double* _norm ) \
+{ \
+ int remaining = block_size; \
+ normtype total_norm = 0; \
+ worktype norm = 0; \
+ step1 /= sizeof(src1[0]); \
+ step2 /= sizeof(src2[0]); \
+ src1 += coi - 1; \
+ src2 += coi - 1; \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2 ) \
+ { \
+ int x = 0; \
+ while( x < size.width ) \
+ { \
+ int limit = MIN( remaining, size.width - x ); \
+ remaining -= limit; \
+ limit += x; \
+ ICV_NORM_DIFF_COI_CASE( _op_, _update_op_, \
+ worktype, limit, cn ); \
+ if( remaining == 0 ) \
+ { \
+ remaining = block_size; \
+ total_norm += (normtype)norm; \
+ norm = 0; \
+ } \
+ } \
+ } \
+ \
+ total_norm += (normtype)norm; \
+ *_norm = post_func((double)total_norm); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_NORM_DIFF_NOHINT_FUNC_2D_COI( name, _op_, \
+ _update_op_, post_func, \
+ arrtype, normtype, worktype, block_size ) \
+static CvStatus CV_STDCALL name( const arrtype* src1, int step1,\
+ const arrtype* src2, int step2, CvSize size, \
+ int cn, int coi, double* _norm ) \
+{ \
+ normtype norm = 0; \
+ step1 /= sizeof(src1[0]); \
+ step2 /= sizeof(src2[0]); \
+ src1 += coi - 1; \
+ src2 += coi - 1; \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2 ) \
+ { \
+ int x = 0; \
+ ICV_NORM_DIFF_COI_CASE( _op_, _update_op_, \
+ worktype, size.width, cn ); \
+ } \
+ \
+ *_norm = post_func((double)norm); \
+ return CV_OK; \
+}
+
+
+/****************************************************************************************\
+* N o r m with M A S K *
+\****************************************************************************************/
+
+#define ICV_NORM_MASK_CASE( _op_, \
+ _update_op_, worktype, len ) \
+{ \
+ for( ; x <= (len) - 2; x += 2 ) \
+ { \
+ worktype t0; \
+ if( mask[x] ) \
+ { \
+ t0 = (src)[x]; \
+ t0 = _op_(t0); \
+ norm = _update_op_( norm, t0 ); \
+ } \
+ if( mask[x+1] ) \
+ { \
+ t0 = (src)[x+1]; \
+ t0 = _op_(t0); \
+ norm = _update_op_( norm, t0 ); \
+ } \
+ } \
+ \
+ for( ; x < (len); x++ ) \
+ if( mask[x] ) \
+ { \
+ worktype t0 = (src)[x]; \
+ t0 = _op_(t0); \
+ norm = _update_op_( norm, t0 ); \
+ } \
+}
+
+
+#define ICV_NORM_DIFF_MASK_CASE( _op_, _update_op_, worktype, len ) \
+{ \
+ for( ; x <= (len) - 2; x += 2 ) \
+ { \
+ worktype t0; \
+ if( mask[x] ) \
+ { \
+ t0 = (src1)[x] - (src2)[x]; \
+ t0 = _op_(t0); \
+ norm = _update_op_( norm, t0 ); \
+ } \
+ if( mask[x+1] ) \
+ { \
+ t0 = (src1)[x+1] - (src2)[x+1]; \
+ t0 = _op_(t0); \
+ norm = _update_op_( norm, t0 ); \
+ } \
+ } \
+ \
+ for( ; x < (len); x++ ) \
+ if( mask[x] ) \
+ { \
+ worktype t0 = (src1)[x] - (src2)[x];\
+ t0 = _op_(t0); \
+ norm = _update_op_( norm, t0 ); \
+ } \
+}
+
+
+#define ICV_NORM_MASK_COI_CASE( _op_, _update_op_, worktype, len, cn ) \
+{ \
+ for( ; x < (len); x++ ) \
+ if( mask[x] ) \
+ { \
+ worktype t0 = (src)[x*(cn)]; \
+ t0 = _op_(t0); \
+ norm = _update_op_( norm, t0 ); \
+ } \
+}
+
+
+#define ICV_NORM_DIFF_MASK_COI_CASE( _op_, _update_op_, worktype, len, cn )\
+{ \
+ for( ; x < (len); x++ ) \
+ if( mask[x] ) \
+ { \
+ worktype t0 = (src1)[x*(cn)] - (src2)[x*(cn)]; \
+ t0 = _op_(t0); \
+ norm = _update_op_( norm, t0 ); \
+ } \
+}
+
+
+#define ICV_DEF_NORM_MASK_NOHINT_BLOCK_FUNC_2D( name, _op_, \
+ _update_op_, post_func, arrtype, \
+ normtype, worktype, block_size ) \
+IPCVAPI_IMPL( CvStatus, name, ( const arrtype* src, int step, \
+ const uchar* mask, int maskstep, CvSize size, double* _norm ),\
+ (src, step, mask, maskstep, size, _norm) ) \
+{ \
+ int remaining = block_size; \
+ normtype total_norm = 0; \
+ worktype norm = 0; \
+ step /= sizeof(src[0]); \
+ \
+ for( ; size.height--; src += step, mask += maskstep ) \
+ { \
+ int x = 0; \
+ while( x < size.width ) \
+ { \
+ int limit = MIN( remaining, size.width - x ); \
+ remaining -= limit; \
+ limit += x; \
+ ICV_NORM_MASK_CASE( _op_, _update_op_, \
+ worktype, limit ); \
+ if( remaining == 0 ) \
+ { \
+ remaining = block_size; \
+ total_norm += (normtype)norm; \
+ norm = 0; \
+ } \
+ } \
+ } \
+ \
+ total_norm += (normtype)norm; \
+ *_norm = post_func((double)total_norm); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_NORM_MASK_NOHINT_FUNC_2D( name, _op_, _update_op_,\
+ post_func, arrtype, normtype, worktype, block_size ) \
+IPCVAPI_IMPL( CvStatus, name, ( const arrtype* src, int step, \
+ const uchar* mask, int maskstep, CvSize size, double* _norm ),\
+ (src, step, mask, maskstep, size, _norm) ) \
+{ \
+ normtype norm = 0; \
+ step /= sizeof(src[0]); \
+ \
+ for( ; size.height--; src += step, mask += maskstep ) \
+ { \
+ int x = 0; \
+ ICV_NORM_MASK_CASE( _op_, _update_op_, \
+ worktype, size.width ); \
+ } \
+ \
+ *_norm = post_func((double)norm); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_NORM_MASK_NOHINT_BLOCK_FUNC_2D_COI( name, _op_,\
+ _update_op_, post_func, arrtype, \
+ normtype, worktype, block_size ) \
+static CvStatus CV_STDCALL name( const arrtype* src, int step, \
+ const uchar* mask, int maskstep, CvSize size, \
+ int cn, int coi, double* _norm ) \
+{ \
+ int remaining = block_size; \
+ normtype total_norm = 0; \
+ worktype norm = 0; \
+ step /= sizeof(src[0]); \
+ src += coi - 1; \
+ \
+ for( ; size.height--; src += step, mask += maskstep ) \
+ { \
+ int x = 0; \
+ while( x < size.width ) \
+ { \
+ int limit = MIN( remaining, size.width - x ); \
+ remaining -= limit; \
+ limit += x; \
+ ICV_NORM_MASK_COI_CASE( _op_, _update_op_, \
+ worktype, limit, cn ); \
+ if( remaining == 0 ) \
+ { \
+ remaining = block_size; \
+ total_norm += (normtype)norm; \
+ norm = 0; \
+ } \
+ } \
+ } \
+ \
+ total_norm += (normtype)norm; \
+ *_norm = post_func((double)total_norm); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_NORM_MASK_NOHINT_FUNC_2D_COI( name, _op_, \
+ _update_op_, post_func, \
+ arrtype, normtype, worktype, block_size ) \
+static CvStatus CV_STDCALL name( const arrtype* src, int step, \
+ const uchar* mask, int maskstep, CvSize size, \
+ int cn, int coi, double* _norm ) \
+{ \
+ normtype norm = 0; \
+ step /= sizeof(src[0]); \
+ src += coi - 1; \
+ \
+ for( ; size.height--; src += step, mask += maskstep ) \
+ { \
+ int x = 0; \
+ ICV_NORM_MASK_COI_CASE( _op_, _update_op_, \
+ worktype, size.width, cn ); \
+ } \
+ \
+ *_norm = post_func((double)norm); \
+ return CV_OK; \
+}
+
+
+
+#define ICV_DEF_NORM_DIFF_MASK_NOHINT_BLOCK_FUNC_2D( name, \
+ _op_, _update_op_, post_func, arrtype, \
+ normtype, worktype, block_size ) \
+IPCVAPI_IMPL( CvStatus, name,( const arrtype* src1, int step1, \
+ const arrtype* src2, int step2, const uchar* mask, \
+ int maskstep, CvSize size, double* _norm ), \
+ (src1, step1, src2, step2, mask, maskstep, size, _norm )) \
+{ \
+ int remaining = block_size; \
+ normtype total_norm = 0; \
+ worktype norm = 0; \
+ step1 /= sizeof(src1[0]); \
+ step2 /= sizeof(src2[0]); \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2, \
+ mask += maskstep ) \
+ { \
+ int x = 0; \
+ while( x < size.width ) \
+ { \
+ int limit = MIN( remaining, size.width - x ); \
+ remaining -= limit; \
+ limit += x; \
+ ICV_NORM_DIFF_MASK_CASE( _op_, _update_op_, \
+ worktype, limit ); \
+ if( remaining == 0 ) \
+ { \
+ remaining = block_size; \
+ total_norm += (normtype)norm; \
+ norm = 0; \
+ } \
+ } \
+ } \
+ \
+ total_norm += (normtype)norm; \
+ *_norm = post_func((double)total_norm); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_NORM_DIFF_MASK_NOHINT_FUNC_2D( name, _op_, \
+ _update_op_, post_func, \
+ arrtype, normtype, worktype, block_size ) \
+IPCVAPI_IMPL( CvStatus, name,( const arrtype* src1, int step1, \
+ const arrtype* src2, int step2, const uchar* mask, \
+ int maskstep, CvSize size, double* _norm ), \
+ (src1, step1, src2, step2, mask, maskstep, size, _norm )) \
+{ \
+ normtype norm = 0; \
+ step1 /= sizeof(src1[0]); \
+ step2 /= sizeof(src2[0]); \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2, \
+ mask += maskstep ) \
+ { \
+ int x = 0; \
+ ICV_NORM_DIFF_MASK_CASE( _op_, _update_op_, \
+ worktype, size.width ); \
+ } \
+ \
+ *_norm = post_func((double)norm); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_NORM_DIFF_MASK_NOHINT_BLOCK_FUNC_2D_COI( name, \
+ _op_, _update_op_, post_func, arrtype, \
+ normtype, worktype, block_size ) \
+static CvStatus CV_STDCALL name( const arrtype* src1, int step1,\
+ const arrtype* src2, int step2, const uchar* mask, \
+ int maskstep, CvSize size, int cn, int coi, double* _norm ) \
+{ \
+ int remaining = block_size; \
+ normtype total_norm = 0; \
+ worktype norm = 0; \
+ step1 /= sizeof(src1[0]); \
+ step2 /= sizeof(src2[0]); \
+ src1 += coi - 1; \
+ src2 += coi - 1; \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2, \
+ mask += maskstep ) \
+ { \
+ int x = 0; \
+ while( x < size.width ) \
+ { \
+ int limit = MIN( remaining, size.width - x ); \
+ remaining -= limit; \
+ limit += x; \
+ ICV_NORM_DIFF_MASK_COI_CASE( _op_, _update_op_, \
+ worktype, limit, cn ); \
+ if( remaining == 0 ) \
+ { \
+ remaining = block_size; \
+ total_norm += (normtype)norm; \
+ norm = 0; \
+ } \
+ } \
+ } \
+ \
+ total_norm += (normtype)norm; \
+ *_norm = post_func((double)total_norm); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_NORM_DIFF_MASK_NOHINT_FUNC_2D_COI( name, _op_, \
+ _update_op_, post_func, \
+ arrtype, normtype, worktype, block_size ) \
+static CvStatus CV_STDCALL name( const arrtype* src1, int step1,\
+ const arrtype* src2, int step2, const uchar* mask, \
+ int maskstep, CvSize size, int cn, int coi, double* _norm ) \
+{ \
+ normtype norm = 0; \
+ step1 /= sizeof(src1[0]); \
+ step2 /= sizeof(src2[0]); \
+ src1 += coi - 1; \
+ src2 += coi - 1; \
+ \
+ for( ; size.height--; src1 += step1, src2 += step2, \
+ mask += maskstep ) \
+ { \
+ int x = 0; \
+ ICV_NORM_DIFF_MASK_COI_CASE( _op_, _update_op_, \
+ worktype, size.width, cn );\
+ } \
+ \
+ *_norm = post_func((double)norm); \
+ return CV_OK; \
+}
+
+
+//////////////////////////////////// The macros expanded /////////////////////////////////
+
+
+#define ICV_DEF_NORM_FUNC_ALL_C(flavor, _abs_, _abs_diff_, arrtype, worktype)\
+ \
+ICV_DEF_NORM_NOHINT_FUNC_2D( icvNorm_Inf_##flavor##_C1R, \
+ _abs_, MAX, CV_NOP, arrtype, worktype, worktype, 0 ) \
+ \
+ICV_DEF_NORM_NOHINT_FUNC_2D_COI( icvNorm_Inf_##flavor##_CnCR, \
+ _abs_, MAX, CV_NOP, arrtype, worktype, worktype, 0 ) \
+ \
+ICV_DEF_NORM_DIFF_NOHINT_FUNC_2D( icvNormDiff_Inf_##flavor##_C1R, \
+ _abs_diff_, MAX, CV_NOP, arrtype, worktype, worktype, 0 ) \
+ \
+ICV_DEF_NORM_DIFF_NOHINT_FUNC_2D_COI( icvNormDiff_Inf_##flavor##_CnCR, \
+ _abs_diff_, MAX, CV_NOP, arrtype, worktype, worktype, 0 ) \
+ \
+ICV_DEF_NORM_MASK_NOHINT_FUNC_2D( icvNorm_Inf_##flavor##_C1MR, \
+ _abs_, MAX, CV_NOP, arrtype, worktype, worktype, 0 ) \
+ \
+ICV_DEF_NORM_MASK_NOHINT_FUNC_2D_COI( icvNorm_Inf_##flavor##_CnCMR, \
+ _abs_, MAX, CV_NOP, arrtype, worktype, worktype, 0 ) \
+ \
+ICV_DEF_NORM_DIFF_MASK_NOHINT_FUNC_2D( icvNormDiff_Inf_##flavor##_C1MR, \
+ _abs_diff_, MAX, CV_NOP, arrtype, worktype, worktype, 0 ) \
+ \
+ICV_DEF_NORM_DIFF_MASK_NOHINT_FUNC_2D_COI( icvNormDiff_Inf_##flavor##_CnCMR,\
+ _abs_diff_, MAX, CV_NOP, arrtype, worktype, worktype, 0 )
+
+
+ICV_DEF_NORM_FUNC_ALL_C( 8u, CV_NOP, CV_IABS, uchar, int )
+ICV_DEF_NORM_FUNC_ALL_C( 16u, CV_NOP, CV_IABS, ushort, int )
+ICV_DEF_NORM_FUNC_ALL_C( 16s, CV_IABS, CV_IABS, short, int )
+// there is no protection from overflow
+// (otherwise we had to do everything in int64's or double's)
+ICV_DEF_NORM_FUNC_ALL_C( 32s, CV_IABS, CV_IABS, int, int )
+ICV_DEF_NORM_FUNC_ALL_C( 32f, fabs, fabs, float, double )
+ICV_DEF_NORM_FUNC_ALL_C( 64f, fabs, fabs, double, double )
+
+#define ICV_DEF_NORM_FUNC_ALL_L1( flavor, _abs_, _abs_diff_, hintp_func, nohint_func,\
+ arrtype, normtype, worktype, block_size ) \
+ \
+ICV_DEF_NORM_##hintp_func##_FUNC_2D( icvNorm_L1_##flavor##_C1R, \
+ _abs_, CV_ADD, CV_NOP, arrtype, normtype, worktype, block_size ) \
+ \
+ICV_DEF_NORM_##nohint_func##_FUNC_2D_COI( icvNorm_L1_##flavor##_CnCR, \
+ _abs_, CV_ADD, CV_NOP, arrtype, normtype, worktype, block_size ) \
+ \
+ICV_DEF_NORM_DIFF_##hintp_func##_FUNC_2D( icvNormDiff_L1_##flavor##_C1R, \
+ _abs_diff_, CV_ADD, CV_NOP, arrtype, normtype, worktype, block_size ) \
+ \
+ICV_DEF_NORM_DIFF_##nohint_func##_FUNC_2D_COI( icvNormDiff_L1_##flavor##_CnCR, \
+ _abs_diff_, CV_ADD, CV_NOP, arrtype, normtype, worktype, block_size ) \
+ \
+ICV_DEF_NORM_MASK_##nohint_func##_FUNC_2D( icvNorm_L1_##flavor##_C1MR, \
+ _abs_, CV_ADD, CV_NOP, arrtype, normtype, worktype, block_size ) \
+ \
+ICV_DEF_NORM_MASK_##nohint_func##_FUNC_2D_COI( icvNorm_L1_##flavor##_CnCMR, \
+ _abs_, CV_ADD, CV_NOP, arrtype, normtype, worktype, block_size ) \
+ \
+ICV_DEF_NORM_DIFF_MASK_##nohint_func##_FUNC_2D( icvNormDiff_L1_##flavor##_C1MR, \
+ _abs_diff_, CV_ADD, CV_NOP, arrtype, normtype, worktype, block_size ) \
+ \
+ICV_DEF_NORM_DIFF_MASK_##nohint_func##_FUNC_2D_COI( icvNormDiff_L1_##flavor##_CnCMR,\
+ _abs_diff_, CV_ADD, CV_NOP, arrtype, normtype, worktype, block_size )
+
+
+ICV_DEF_NORM_FUNC_ALL_L1( 8u, CV_NOP, CV_IABS, NOHINT_BLOCK, NOHINT_BLOCK,
+ uchar, int64, int, 1 << 23 )
+ICV_DEF_NORM_FUNC_ALL_L1( 16u, CV_NOP, CV_IABS, NOHINT_BLOCK, NOHINT_BLOCK,
+ ushort, int64, int, 1 << 15 )
+ICV_DEF_NORM_FUNC_ALL_L1( 16s, CV_IABS, CV_IABS, NOHINT_BLOCK, NOHINT_BLOCK,
+ short, int64, int, 1 << 15 )
+// there is no protection from overflow on abs() stage.
+// (otherwise we had to do everything in int64's or double's)
+ICV_DEF_NORM_FUNC_ALL_L1( 32s, fabs, fabs, NOHINT, NOHINT,
+ int, double, double, INT_MAX )
+ICV_DEF_NORM_FUNC_ALL_L1( 32f, fabs, fabs, HINT, NOHINT,
+ float, double, double, INT_MAX )
+ICV_DEF_NORM_FUNC_ALL_L1( 64f, fabs, fabs, NOHINT, NOHINT,
+ double, double, double, INT_MAX )
+
+
+#define ICV_DEF_NORM_FUNC_ALL_L2( flavor, hintp_func, nohint_func, arrtype, \
+ normtype, worktype, block_size, sqr_macro ) \
+ \
+ICV_DEF_NORM_##hintp_func##_FUNC_2D( icvNorm_L2_##flavor##_C1R, \
+ sqr_macro, CV_ADD, sqrt, arrtype, normtype, worktype, block_size ) \
+ \
+ICV_DEF_NORM_##nohint_func##_FUNC_2D_COI( icvNorm_L2_##flavor##_CnCR, \
+ sqr_macro, CV_ADD, sqrt, arrtype, normtype, worktype, block_size ) \
+ \
+ICV_DEF_NORM_DIFF_##hintp_func##_FUNC_2D( icvNormDiff_L2_##flavor##_C1R, \
+ sqr_macro, CV_ADD, sqrt, arrtype, normtype, worktype, block_size ) \
+ \
+ICV_DEF_NORM_DIFF_##nohint_func##_FUNC_2D_COI( icvNormDiff_L2_##flavor##_CnCR, \
+ sqr_macro, CV_ADD, sqrt, arrtype, normtype, worktype, block_size ) \
+ \
+ICV_DEF_NORM_MASK_##nohint_func##_FUNC_2D( icvNorm_L2_##flavor##_C1MR, \
+ sqr_macro, CV_ADD, sqrt, arrtype, normtype, worktype, block_size ) \
+ \
+ICV_DEF_NORM_MASK_##nohint_func##_FUNC_2D_COI( icvNorm_L2_##flavor##_CnCMR, \
+ sqr_macro, CV_ADD, sqrt, arrtype, normtype, worktype, block_size ) \
+ \
+ICV_DEF_NORM_DIFF_MASK_##nohint_func##_FUNC_2D( icvNormDiff_L2_##flavor##_C1MR, \
+ sqr_macro, CV_ADD, sqrt, arrtype, normtype, worktype, block_size ) \
+ \
+ICV_DEF_NORM_DIFF_MASK_##nohint_func##_FUNC_2D_COI( icvNormDiff_L2_##flavor##_CnCMR,\
+ sqr_macro, CV_ADD, sqrt, arrtype, normtype, worktype, block_size )
+
+
+ICV_DEF_NORM_FUNC_ALL_L2( 8u, NOHINT_BLOCK, NOHINT_BLOCK, uchar,
+ int64, int, 1 << 15, CV_SQR_8U )
+ICV_DEF_NORM_FUNC_ALL_L2( 16u, NOHINT, NOHINT, ushort,
+ double, double, INT_MAX, CV_SQR )
+ICV_DEF_NORM_FUNC_ALL_L2( 16s, NOHINT, NOHINT, short,
+ double, double, INT_MAX, CV_SQR )
+// there is no protection from overflow on abs() stage.
+// (otherwise we had to do everything in int64's or double's)
+ICV_DEF_NORM_FUNC_ALL_L2( 32s, NOHINT, NOHINT, int,
+ double, double, INT_MAX, CV_SQR )
+ICV_DEF_NORM_FUNC_ALL_L2( 32f, HINT, NOHINT, float,
+ double, double, INT_MAX, CV_SQR )
+ICV_DEF_NORM_FUNC_ALL_L2( 64f, NOHINT, NOHINT, double,
+ double, double, INT_MAX, CV_SQR )
+
+
+#define ICV_DEF_INIT_NORM_TAB_2D( FUNCNAME, FLAG ) \
+static void icvInit##FUNCNAME##FLAG##Table( CvFuncTable* tab ) \
+{ \
+ tab->fn_2d[CV_8U] = (void*)icv##FUNCNAME##_8u_##FLAG; \
+ tab->fn_2d[CV_8S] = 0; \
+ tab->fn_2d[CV_16U] = (void*)icv##FUNCNAME##_16u_##FLAG; \
+ tab->fn_2d[CV_16S] = (void*)icv##FUNCNAME##_16s_##FLAG; \
+ tab->fn_2d[CV_32S] = (void*)icv##FUNCNAME##_32s_##FLAG; \
+ tab->fn_2d[CV_32F] = (void*)icv##FUNCNAME##_32f_##FLAG; \
+ tab->fn_2d[CV_64F] = (void*)icv##FUNCNAME##_64f_##FLAG; \
+}
+
+ICV_DEF_INIT_NORM_TAB_2D( Norm_Inf, C1R )
+ICV_DEF_INIT_NORM_TAB_2D( Norm_L1, C1R )
+ICV_DEF_INIT_NORM_TAB_2D( Norm_L2, C1R )
+ICV_DEF_INIT_NORM_TAB_2D( NormDiff_Inf, C1R )
+ICV_DEF_INIT_NORM_TAB_2D( NormDiff_L1, C1R )
+ICV_DEF_INIT_NORM_TAB_2D( NormDiff_L2, C1R )
+
+ICV_DEF_INIT_NORM_TAB_2D( Norm_Inf, CnCR )
+ICV_DEF_INIT_NORM_TAB_2D( Norm_L1, CnCR )
+ICV_DEF_INIT_NORM_TAB_2D( Norm_L2, CnCR )
+ICV_DEF_INIT_NORM_TAB_2D( NormDiff_Inf, CnCR )
+ICV_DEF_INIT_NORM_TAB_2D( NormDiff_L1, CnCR )
+ICV_DEF_INIT_NORM_TAB_2D( NormDiff_L2, CnCR )
+
+ICV_DEF_INIT_NORM_TAB_2D( Norm_Inf, C1MR )
+ICV_DEF_INIT_NORM_TAB_2D( Norm_L1, C1MR )
+ICV_DEF_INIT_NORM_TAB_2D( Norm_L2, C1MR )
+ICV_DEF_INIT_NORM_TAB_2D( NormDiff_Inf, C1MR )
+ICV_DEF_INIT_NORM_TAB_2D( NormDiff_L1, C1MR )
+ICV_DEF_INIT_NORM_TAB_2D( NormDiff_L2, C1MR )
+
+ICV_DEF_INIT_NORM_TAB_2D( Norm_Inf, CnCMR )
+ICV_DEF_INIT_NORM_TAB_2D( Norm_L1, CnCMR )
+ICV_DEF_INIT_NORM_TAB_2D( Norm_L2, CnCMR )
+ICV_DEF_INIT_NORM_TAB_2D( NormDiff_Inf, CnCMR )
+ICV_DEF_INIT_NORM_TAB_2D( NormDiff_L1, CnCMR )
+ICV_DEF_INIT_NORM_TAB_2D( NormDiff_L2, CnCMR )
+
+
+static void icvInitNormTabs( CvFuncTable* norm_tab, CvFuncTable* normmask_tab )
+{
+ icvInitNorm_InfC1RTable( &norm_tab[0] );
+ icvInitNorm_L1C1RTable( &norm_tab[1] );
+ icvInitNorm_L2C1RTable( &norm_tab[2] );
+ icvInitNormDiff_InfC1RTable( &norm_tab[3] );
+ icvInitNormDiff_L1C1RTable( &norm_tab[4] );
+ icvInitNormDiff_L2C1RTable( &norm_tab[5] );
+
+ icvInitNorm_InfCnCRTable( &norm_tab[6] );
+ icvInitNorm_L1CnCRTable( &norm_tab[7] );
+ icvInitNorm_L2CnCRTable( &norm_tab[8] );
+ icvInitNormDiff_InfCnCRTable( &norm_tab[9] );
+ icvInitNormDiff_L1CnCRTable( &norm_tab[10] );
+ icvInitNormDiff_L2CnCRTable( &norm_tab[11] );
+
+ icvInitNorm_InfC1MRTable( &normmask_tab[0] );
+ icvInitNorm_L1C1MRTable( &normmask_tab[1] );
+ icvInitNorm_L2C1MRTable( &normmask_tab[2] );
+ icvInitNormDiff_InfC1MRTable( &normmask_tab[3] );
+ icvInitNormDiff_L1C1MRTable( &normmask_tab[4] );
+ icvInitNormDiff_L2C1MRTable( &normmask_tab[5] );
+
+ icvInitNorm_InfCnCMRTable( &normmask_tab[6] );
+ icvInitNorm_L1CnCMRTable( &normmask_tab[7] );
+ icvInitNorm_L2CnCMRTable( &normmask_tab[8] );
+ icvInitNormDiff_InfCnCMRTable( &normmask_tab[9] );
+ icvInitNormDiff_L1CnCMRTable( &normmask_tab[10] );
+ icvInitNormDiff_L2CnCMRTable( &normmask_tab[11] );
+}
+
+
+CV_IMPL double
+cvNorm( const void* imgA, const void* imgB, int normType, const void* mask )
+{
+ static CvFuncTable norm_tab[12];
+ static CvFuncTable normmask_tab[12];
+ static int inittab = 0;
+
+ double norm = 0, norm_diff = 0;
+
+ CV_FUNCNAME("cvNorm");
+
+ __BEGIN__;
+
+ int type, depth, cn, is_relative;
+ CvSize size;
+ CvMat stub1, *mat1 = (CvMat*)imgB;
+ CvMat stub2, *mat2 = (CvMat*)imgA;
+ int mat2_flag = CV_MAT_CONT_FLAG;
+ int mat1_step, mat2_step, mask_step = 0;
+ int coi = 0, coi2 = 0;
+
+ if( !mat1 )
+ {
+ mat1 = mat2;
+ mat2 = 0;
+ }
+
+ is_relative = mat2 && (normType & CV_RELATIVE);
+ normType &= ~CV_RELATIVE;
+
+ switch( normType )
+ {
+ case CV_C:
+ case CV_L1:
+ case CV_L2:
+ case CV_DIFF_C:
+ case CV_DIFF_L1:
+ case CV_DIFF_L2:
+ normType = (normType & 7) >> 1;
+ break;
+ default:
+ CV_ERROR( CV_StsBadFlag, "" );
+ }
+
+ /* light variant */
+ if( CV_IS_MAT(mat1) && (!mat2 || CV_IS_MAT(mat2)) && !mask )
+ {
+ if( mat2 )
+ {
+ if( !CV_ARE_TYPES_EQ( mat1, mat2 ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( !CV_ARE_SIZES_EQ( mat1, mat2 ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ mat2_flag = mat2->type;
+ }
+
+ size = cvGetMatSize( mat1 );
+ type = CV_MAT_TYPE(mat1->type);
+ depth = CV_MAT_DEPTH(type);
+ cn = CV_MAT_CN(type);
+
+ if( CV_IS_MAT_CONT( mat1->type & mat2_flag ))
+ {
+ size.width *= size.height;
+
+ if( size.width <= CV_MAX_INLINE_MAT_OP_SIZE && normType == 2 /* CV_L2 */ )
+ {
+ if( depth == CV_32F )
+ {
+ const float* src1data = mat1->data.fl;
+ int size0 = size.width *= cn;
+
+ if( !mat2 || is_relative )
+ {
+ do
+ {
+ double t = src1data[size.width-1];
+ norm += t*t;
+ }
+ while( --size.width );
+ }
+
+ if( mat2 )
+ {
+ const float* src2data = mat2->data.fl;
+ size.width = size0;
+
+ do
+ {
+ double t = src1data[size.width-1] - src2data[size.width-1];
+ norm_diff += t*t;
+ }
+ while( --size.width );
+
+ if( is_relative )
+ norm = norm_diff/(norm + DBL_EPSILON);
+ else
+ norm = norm_diff;
+ }
+ norm = sqrt(norm);
+ EXIT;
+ }
+
+ if( depth == CV_64F )
+ {
+ const double* src1data = mat1->data.db;
+ int size0 = size.width *= cn;
+
+ if( !mat2 || is_relative )
+ {
+ do
+ {
+ double t = src1data[size.width-1];
+ norm += t*t;
+ }
+ while( --size.width );
+ }
+
+ if( mat2 )
+ {
+ const double* src2data = mat2->data.db;
+ size.width = size0;
+
+ do
+ {
+ double t = src1data[size.width-1] - src2data[size.width-1];
+ norm_diff += t*t;
+ }
+ while( --size.width );
+
+ if( is_relative )
+ norm = norm_diff/(norm + DBL_EPSILON);
+ else
+ norm = norm_diff;
+ }
+ norm = sqrt(norm);
+ EXIT;
+ }
+ }
+ size.height = 1;
+ mat1_step = mat2_step = CV_STUB_STEP;
+ }
+ else
+ {
+ mat1_step = mat1->step;
+ mat2_step = mat2 ? mat2->step : 0;
+ }
+ }
+ else if( !CV_IS_MATND(mat1) && !CV_IS_MATND(mat2) )
+ {
+ CV_CALL( mat1 = cvGetMat( mat1, &stub1, &coi ));
+
+ if( mat2 )
+ {
+ CV_CALL( mat2 = cvGetMat( mat2, &stub2, &coi2 ));
+
+ if( !CV_ARE_TYPES_EQ( mat1, mat2 ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( !CV_ARE_SIZES_EQ( mat1, mat2 ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ if( coi != coi2 && CV_MAT_CN( mat1->type ) > 1 )
+ CV_ERROR( CV_BadCOI, "" );
+
+ mat2_flag = mat2->type;
+ }
+
+ size = cvGetMatSize( mat1 );
+ type = CV_MAT_TYPE(mat1->type);
+ depth = CV_MAT_DEPTH(type);
+ cn = CV_MAT_CN(type);
+ mat1_step = mat1->step;
+ mat2_step = mat2 ? mat2->step : 0;
+
+ if( !mask && CV_IS_MAT_CONT( mat1->type & mat2_flag ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ mat1_step = mat2_step = CV_STUB_STEP;
+ }
+ }
+ else
+ {
+ CvArr* arrs[] = { mat1, mat2 };
+ CvMatND stubs[2];
+ CvNArrayIterator iterator;
+ int pass_hint;
+
+ if( !inittab )
+ {
+ icvInitNormTabs( norm_tab, normmask_tab );
+ inittab = 1;
+ }
+
+ if( mask )
+ CV_ERROR( CV_StsBadMask,
+ "This operation on multi-dimensional arrays does not support mask" );
+
+ CV_CALL( cvInitNArrayIterator( 1 + (mat2 != 0), arrs, 0, stubs, &iterator ));
+
+ type = CV_MAT_TYPE(iterator.hdr[0]->type);
+ depth = CV_MAT_DEPTH(type);
+ iterator.size.width *= CV_MAT_CN(type);
+
+ pass_hint = normType != 0 && (depth == CV_32F);
+
+ if( !mat2 || is_relative )
+ {
+ if( !pass_hint )
+ {
+ CvFunc2D_1A1P func;
+
+ CV_GET_FUNC_PTR( func, (CvFunc2D_1A1P)norm_tab[normType].fn_2d[depth]);
+
+ do
+ {
+ double temp = 0;
+ IPPI_CALL( func( iterator.ptr[0], CV_STUB_STEP,
+ iterator.size, &temp ));
+ norm += temp;
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ else
+ {
+ CvFunc2D_1A1P1I func;
+
+ CV_GET_FUNC_PTR( func, (CvFunc2D_1A1P1I)norm_tab[normType].fn_2d[depth]);
+
+ do
+ {
+ double temp = 0;
+ IPPI_CALL( func( iterator.ptr[0], CV_STUB_STEP,
+ iterator.size, &temp, cvAlgHintAccurate ));
+ norm += temp;
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ }
+
+ if( mat2 )
+ {
+ if( !pass_hint )
+ {
+ CvFunc2D_2A1P func;
+ CV_GET_FUNC_PTR( func, (CvFunc2D_2A1P)norm_tab[3 + normType].fn_2d[depth]);
+
+ do
+ {
+ double temp = 0;
+ IPPI_CALL( func( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.size, &temp ));
+ norm_diff += temp;
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ else
+ {
+ CvFunc2D_2A1P1I func;
+ CV_GET_FUNC_PTR( func, (CvFunc2D_2A1P1I)norm_tab[3 + normType].fn_2d[depth]);
+
+ do
+ {
+ double temp = 0;
+ IPPI_CALL( func( iterator.ptr[0], CV_STUB_STEP,
+ iterator.ptr[1], CV_STUB_STEP,
+ iterator.size, &temp, cvAlgHintAccurate ));
+ norm_diff += temp;
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+
+ if( is_relative )
+ norm = norm_diff/(norm + DBL_EPSILON);
+ else
+ norm = norm_diff;
+ }
+ EXIT;
+ }
+
+ if( !inittab )
+ {
+ icvInitNormTabs( norm_tab, normmask_tab );
+ inittab = 1;
+ }
+
+ if( !mask )
+ {
+ if( cn == 1 || coi == 0 )
+ {
+ int pass_hint = depth == CV_32F && normType != 0;
+ size.width *= cn;
+
+ if( !mat2 || is_relative )
+ {
+ if( !pass_hint )
+ {
+ CvFunc2D_1A1P func;
+ CV_GET_FUNC_PTR( func, (CvFunc2D_1A1P)norm_tab[normType].fn_2d[depth]);
+
+ IPPI_CALL( func( mat1->data.ptr, mat1_step, size, &norm ));
+ }
+ else
+ {
+ CvFunc2D_1A1P1I func;
+ CV_GET_FUNC_PTR( func, (CvFunc2D_1A1P1I)norm_tab[normType].fn_2d[depth]);
+
+ IPPI_CALL( func( mat1->data.ptr, mat1_step, size, &norm, cvAlgHintAccurate ));
+ }
+ }
+
+ if( mat2 )
+ {
+ if( !pass_hint )
+ {
+ CvFunc2D_2A1P func;
+ CV_GET_FUNC_PTR( func, (CvFunc2D_2A1P)norm_tab[3 + normType].fn_2d[depth]);
+
+ IPPI_CALL( func( mat1->data.ptr, mat1_step, mat2->data.ptr, mat2_step,
+ size, &norm_diff ));
+ }
+ else
+ {
+ CvFunc2D_2A1P1I func;
+ CV_GET_FUNC_PTR( func, (CvFunc2D_2A1P1I)norm_tab[3 + normType].fn_2d[depth]);
+
+ IPPI_CALL( func( mat1->data.ptr, mat1_step, mat2->data.ptr, mat2_step,
+ size, &norm_diff, cvAlgHintAccurate ));
+ }
+
+ if( is_relative )
+ norm = norm_diff/(norm + DBL_EPSILON);
+ else
+ norm = norm_diff;
+ }
+ }
+ else
+ {
+ if( !mat2 || is_relative )
+ {
+ CvFunc2DnC_1A1P func;
+ CV_GET_FUNC_PTR( func, (CvFunc2DnC_1A1P)norm_tab[6 + normType].fn_2d[depth]);
+
+ IPPI_CALL( func( mat1->data.ptr, mat1_step, size, cn, coi, &norm ));
+ }
+
+ if( mat2 )
+ {
+ CvFunc2DnC_2A1P func;
+ CV_GET_FUNC_PTR( func, (CvFunc2DnC_2A1P)norm_tab[9 + normType].fn_2d[depth]);
+
+ IPPI_CALL( func( mat1->data.ptr, mat1_step, mat2->data.ptr, mat2_step,
+ size, cn, coi, &norm_diff ));
+
+ if( is_relative )
+ norm = norm_diff/(norm + DBL_EPSILON);
+ else
+ norm = norm_diff;
+ }
+ }
+ }
+ else
+ {
+ CvMat maskstub, *matmask = (CvMat*)mask;
+
+ if( CV_MAT_CN(type) > 1 && coi == 0 )
+ CV_ERROR( CV_StsBadArg, "" );
+
+ CV_CALL( matmask = cvGetMat( matmask, &maskstub ));
+
+ if( !CV_IS_MASK_ARR( matmask ))
+ CV_ERROR( CV_StsBadMask, "" );
+
+ if( !CV_ARE_SIZES_EQ( mat1, matmask ))
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
+
+ mask_step = matmask->step;
+
+ if( CV_IS_MAT_CONT( mat1->type & mat2_flag & matmask->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ mat1_step = mat2_step = mask_step = CV_STUB_STEP;
+ }
+
+ if( CV_MAT_CN(type) == 1 || coi == 0 )
+ {
+ if( !mat2 || is_relative )
+ {
+ CvFunc2D_2A1P func;
+ CV_GET_FUNC_PTR( func,
+ (CvFunc2D_2A1P)normmask_tab[normType].fn_2d[depth]);
+
+ IPPI_CALL( func( mat1->data.ptr, mat1_step,
+ matmask->data.ptr, mask_step, size, &norm ));
+ }
+
+ if( mat2 )
+ {
+ CvFunc2D_3A1P func;
+ CV_GET_FUNC_PTR( func,
+ (CvFunc2D_3A1P)normmask_tab[3 + normType].fn_2d[depth]);
+
+ IPPI_CALL( func( mat1->data.ptr, mat1_step, mat2->data.ptr, mat2_step,
+ matmask->data.ptr, mask_step, size, &norm_diff ));
+
+ if( is_relative )
+ norm = norm_diff/(norm + DBL_EPSILON);
+ else
+ norm = norm_diff;
+ }
+ }
+ else
+ {
+ if( !mat2 || is_relative )
+ {
+ CvFunc2DnC_2A1P func;
+ CV_GET_FUNC_PTR( func,
+ (CvFunc2DnC_2A1P)normmask_tab[6 + normType].fn_2d[depth]);
+
+ IPPI_CALL( func( mat1->data.ptr, mat1_step,
+ matmask->data.ptr, mask_step,
+ size, cn, coi, &norm ));
+ }
+
+ if( mat2 )
+ {
+ CvFunc2DnC_3A1P func;
+ CV_GET_FUNC_PTR( func,
+ (CvFunc2DnC_3A1P)normmask_tab[9 + normType].fn_2d[depth]);
+
+ IPPI_CALL( func( mat1->data.ptr, mat1_step,
+ mat2->data.ptr, mat2_step,
+ matmask->data.ptr, mask_step,
+ size, cn, coi, &norm_diff ));
+
+ if( is_relative )
+ norm = norm_diff/(norm + DBL_EPSILON);
+ else
+ norm = norm_diff;
+ }
+ }
+ }
+
+ __END__;
+
+ return norm;
+}
+
+/* End of file. */
diff --git a/cxcore/src/cxouttext.cpp b/cxcore/src/cxouttext.cpp
new file mode 100644
index 0000000..52e546d
--- /dev/null
+++ b/cxcore/src/cxouttext.cpp
@@ -0,0 +1,3345 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+
+const char* icvHersheyGlyphs[] = {
+ "",
+ "MWRMNV RMVV PSTS",
+ "MWOMOV OMSMUNUPSQ OQSQURUUSVOV",
+ "MXVNTMRMPNOPOSPURVTVVU",
+ "MWOMOV OMRMTNUPUSTURVOV",
+ "MWOMOV OMUM OQSQ OVUV",
+ "MVOMOV OMUM OQSQ",
+ "MXVNTMRMPNOPOSPURVTVVUVR SRVR",
+ "MWOMOV UMUV OQUQ",
+ "PTRMRV",
+ "NUSMSTRVPVOTOS",
+ "MWOMOV UMOS QQUV",
+ "MVOMOV OVUV",
+ "LXNMNV NMRV VMRV VMVV",
+ "MWOMOV OMUV UMUV",
+ "MXRMPNOPOSPURVSVUUVSVPUNSMRM",
+ "MWOMOV OMSMUNUQSROR",
+ "MXRMPNOPOSPURVSVUUVSVPUNSMRM STVW",
+ "MWOMOV OMSMUNUQSROR RRUV",
+ "MWUNSMQMONOOPPTRUSUUSVQVOU",
+ "MWRMRV NMVM",
+ "MXOMOSPURVSVUUVSVM",
+ "MWNMRV VMRV",
+ "LXNMPV RMPV RMTV VMTV",
+ "MWOMUV UMOV",
+ "MWNMRQRV VMRQ",
+ "MWUMOV OMUM OVUV",
+ "MWRMNV RMVV PSTS",
+ "MWOMOV OMSMUNUPSQ OQSQURUUSVOV",
+ "MVOMOV OMUM",
+ "MWRMNV RMVV NVVV",
+ "MWOMOV OMUM OQSQ OVUV",
+ "MWUMOV OMUM OVUV",
+ "MWOMOV UMUV OQUQ",
+ "MXRMPNOPOSPURVSVUUVSVPUNSMRM QQTR TQQR",
+ "PTRMRV",
+ "MWOMOV UMOS QQUV",
+ "MWRMNV RMVV",
+ "LXNMNV NMRV VMRV VMVV",
+ "MWOMOV OMUV UMUV",
+ "MWOMUM PQTR TQPR OVUV",
+ "MXRMPNOPOSPURVSVUUVSVPUNSMRM",
+ "MWOMOV UMUV OMUM",
+ "MWOMOV OMSMUNUQSROR",
+ "MWOMRQOV OMUM OVUV",
+ "MWRMRV NMVM",
+ "MWNONNOMPMQNRPRV VOVNUMTMSNRP",
+ "LXRMRV PONPNSPTTTVSVPTOPO",
+ "MWOMUV UMOV",
+ "LXRMRV NOOPOSQTSTUSUPVO",
+ "MXOVQVOROPPNRMSMUNVPVRTVVV",
+ "MWSMMV SMUV OSTS",
+ "MWQMNV QMTMVNVPSQPQ SQURUTTURVNV",
+ "LXVPUNTMRMPNOONQNSOUPVRVTUUT",
+ "MXQMNV QMUMVOVQUTTURVNV",
+ "MVQMNV QMVM PQSQ NVSV",
+ "MVQMNV QMVM PQSQ",
+ "LXVPUNTMRMPNOONQNSOUPVRVTUUSRS",
+ "MXQMNV WMTV PQUQ",
+ "PUTMQV",
+ "OVUMSSRUQVPVOUOT",
+ "MVQMNV VMOS RQTV",
+ "NVRMOV OVTV",
+ "LYPMMV PMQV XMQV XMUV",
+ "MXQMNV QMTV WMTV",
+ "LXRMPNOONQNSOUPVRVTUUTVRVPUNTMRM",
+ "MWQMNV QMUMVNVPUQSRPR",
+ "LXRMPNOONQNSOUPVRVTUUTVRVPUNTMRM QVPUPTQSRSSTTVUWVW",
+ "MWQMNV QMUMVNVPUQSRPR QRRUSVTVUU",
+ "MWVNTMRMPNPPQQTRUSUUSVPVNU",
+ "MVSMPV PMVM",
+ "LXPMNSNUOVRVTUUSWM",
+ "MWOMQV WMQV",
+ "KXNMNV SMNV SMSV XMSV",
+ "NWQMTV WMNV",
+ "NWQMSQQV WMSQ",
+ "MWQMWMNVTV",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "LXNMRV VMRV NMVM",
+ "MWNLVX",
+ "LXRONU ROVU",
+ "MWNVVV",
+ "PVRMUQ",
+ "MWMMOKQKTMVMWK",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "NWQPTPUQUV URQSPTPUQVSVUU",
+ "MWOMOV OSPURVTUUSTQRPPQOS",
+ "MWUQSPRPPQOSPURVSVUU",
+ "MWUMUV USTQRPPQOSPURVTUUS",
+ "MWOSUSTQRPPQOSPURVTV",
+ "NVUNTMSMRNRV PPTP",
+ "MWUPUVTXRYPY USTQRPPQOSPURVTUUS",
+ "MWOMOV OSPQRPTQUSUV",
+ "PTRLQMRNSMRL RPRV",
+ "PUSLRMSNTMSL SPSXRYQYPX",
+ "NWPMPV UPPT RSUV",
+ "PTRMRV",
+ "KYMPMV MSNQOPPPQQRSRV RSSQTPUPVQWSWV",
+ "MWOPOV OSPQRPTQUSUV",
+ "MWRPPQOSPURVTUUSTQRP",
+ "MWOPOY OSPURVTUUSTQRPPQOS",
+ "MWUPUY USTQRPPQOSPURVTUUS",
+ "NVPPPV PSQQSPTP",
+ "NWUQTPQPPQPRQSTSUTUUTVQVPU",
+ "NVRMRUSVTVUU PPTP",
+ "MWUPUV OPOSPURVTUUS",
+ "NVOPRV UPRV",
+ "LXNPPV RPPV RPTV VPTV",
+ "MWOPUV UPOV",
+ "MWOPRV UPRVQXPYOY",
+ "MWOPUPOVUV",
+ "MXVPUSTURVPUOSPQRPTQUUVV",
+ "MWOTQVSVTUTSSRPQRQTPUOUNTMRMQNPPOTNY",
+ "MXNQOPQPRQRSQW VPURSTQWPY",
+ "MWTNSMRMQNQORPTQUSTURVPUOSPQRP",
+ "NWUQSPQPPQPRQS SSQSPTPUQVSVUU",
+ "NWTMSNSOTP UPSPQQPSPUQVSWSXRYQY",
+ "LXNQOPPPQQQSPV QSRQTPUPVQVSUVTY",
+ "LXNQOPPPQQQURVSVTUUSVPVNUMTMSNSPTRUSWT",
+ "OVRPQSQURVSVTU",
+ "MWQPOV UPTPRQPS PSQUSVTV",
+ "MWOMPMQNRPUV RPOV",
+ "LYPPMY UPTSSUQVPVOUOS TSTUUVVVWU",
+ "MWNPOPOV UPTSRUOV",
+ "NWTMSNSOTP UPSPQQQRRSTS SSQTPUPVQWSXSYRZQZ",
+ "MWRPPQOSPURVTUUSTQRP",
+ "MXOQQPVP QPQRPV TPTRUV",
+ "MWOSPURVTUUSTQRPPQOSNY",
+ "MXVPRPPQOSPURVTUUSTQRP",
+ "MXOQQPVP SPRV",
+ "KXMQNPOPPQPUQVSVTUUSVP",
+ "MXPPOQOSPURVSVUUVSVQUPTPSQRSQY",
+ "MWOPPPQQSXTYUY UPTRPWOY",
+ "KYTMRY MQNPOPPQPUQVTVUUVSWP",
+ "LXOPNRNTOVQVRTRR UPVRVTUVSVRT",
+ "LWTSSQQPOQNSOUQVSUTS UPTSTUUVVV",
+ "MWQMOSPURVTUUSTQRPPQOS",
+ "MWUQSPRPPQOSPURVTV",
+ "LWTSSQQPOQNSOUQVSUTS VMTSTUUVVV",
+ "MWOSTSURUQSPRPPQOSPURVTV",
+ "OVVMUMTNSPQVPXOYNY QPUP",
+ "MXUSTQRPPQOSPURVTUUS VPTVSXRYPYOX",
+ "MVQMNV OSPQQPSPTQTRSTSUTVUV",
+ "PUSMSNTNTMSM QPRPSQSRRTRUSVTV",
+ "OUSMSNTNTMSM QPRPSQSRRVQXPYOYNX",
+ "NVRMOV UPTPRQPS PSQUSVTV",
+ "OTSMQSQURVSV",
+ "JYKPLPMQMSLV MSNQOPQPRQRSQV RSSQTPVPWQWRVTVUWVXV",
+ "MWNPOPPQPSOV PSQQRPTPUQURTTTUUVVV",
+ "MWRPPQOSPURVTUUSTQRP",
+ "MXNPOPPQPSNY PSQUSVUUVSUQSPQQPS",
+ "MXUSTQRPPQOSPURVTUUS VPSY",
+ "MVOPPPQQQSPV UQTPSPRQQS",
+ "NVTQSPQPPQPRQSRSSTSURVPVOU",
+ "NUSMQSQURVSV PPTP",
+ "MWNPOPPQPROTOUPVRVSUTS UPTSTUUVVV",
+ "MWNPOPPQPROTOUPVRVTUURUP",
+ "KYLPMPNQNRMTMUNVPVQURSSP RSRUSVUVVUWRWP",
+ "MWOQPPQPRQRUSVTVUU VQUPTPSQQUPVOVNU",
+ "MWNPOPPQPROTOUPVRVSUTS UPSVRXQYOYNX",
+ "NVUPOV PQQPSPTQ PUQVSVTU",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "MWUSTQRPPQOSPURVTUUSUPTNRMQM",
+ "MWUQSPRPPQOSPURVSVUU OSSS",
+ "MWRMQNPPOSOVPWRWSVTTUQUNTMRM PRTR",
+ "MWTMQY RPPQOSPURVSVUUVSUQSPRP",
+ "MWUQSPQPOQOSPTRUSVSWRXQX",
+ "",
+ "",
+ "KYTPTSUTVTWSWQVOUNSMQMONNOMQMSNUOVQWSWUV TQSPQPPQPSQTSTTS",
+ "MWUNORUV",
+ "MWONUROV",
+ "OUTKQKQYTY",
+ "OUPKSKSYPY",
+ "OUTKSLRNROSQQRSSRURVSXTY",
+ "OUPKQLRNROQQSRQSRURVQXPY",
+ "LYPMQNQOPPOPNONNOMPMSNUNWMNV USTTTUUVVVWUWTVSUS",
+ "PT",
+ "NV",
+ "MWRMPNOPOSPURVTUUSUPTNRM",
+ "MWPORMRV",
+ "MWONQMSMUNUPTROVUV",
+ "MWONQMSMUNUPSQ RQSQURUUSVQVOU",
+ "MWSMSV SMNSVS",
+ "MWPMOQQPRPTQUSTURVQVOU PMTM",
+ "MWTMRMPNOPOSPURVTUUSTQRPPQOS",
+ "MWUMQV OMUM",
+ "MWQMONOPQQSQUPUNSMQM QQOROUQVSVUUURSQ",
+ "MWUPTRRSPROPPNRMTNUPUSTURVPV",
+ "PURURVSVSURU",
+ "PUSVRVRUSUSWRY",
+ "PURPRQSQSPRP RURVSVSURU",
+ "PURPRQSQSPRP SVRVRUSUSWRY",
+ "PURMRR SMSR RURVSVSURU",
+ "NWPNRMSMUNUPRQRRSRSQUP RURVSVSURU",
+ "PTRMRQ",
+ "NVPMPQ TMTQ",
+ "NVQMPNPPQQSQTPTNSMQM",
+ "MWRKRX UNSMQMONOPQQTRUSUUSVQVOU",
+ "MWVLNX",
+ "OUTKRNQQQSRVTY",
+ "OUPKRNSQSSRVPY",
+ "PTRKRY",
+ "LXNRVR",
+ "LXRNRV NRVR",
+ "LXNPVP NTVT",
+ "MWOOUU UOOU",
+ "MWRORU OPUT UPOT",
+ "PURQRRSRSQRQ",
+ "PUSMRORQSQSPRP",
+ "PUSNRNRMSMSORQ",
+ "LXSOVRSU NRVR",
+ "MXQLQY TLTY OQVQ OTVT",
+ "LXVRURTSSURVOVNUNSORRQSPSNRMPMONOPQSSUUVVV",
+ "LXNNOQOSNV VNUQUSVV NNQOSOVN NVQUSUVV",
+ "LYRQQPOPNQNSOTQTRSSQTPVPWQWSVTTTSSRQ",
+ "",
+ "H\\NRMQLRMSNR VRWQXRWSVR",
+ "H\\MPLQLRMSNSOROQNPMP MQMRNRNQMQ WPVQVRWSXSYRYQXPWP WQWRXRXQWQ",
+ "I[KRYR",
+ "",
+ "H\\RUJPRTZPRU",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "F^ISJQLPNPPQTTVUXUZT[Q ISJPLONOPPTSVTXTZS[Q IYJWLVNVPWTZV[X[ZZ[W IYJVLUNUPVTYVZXZZY[W",
+ "",
+ "F^ISJQLPNPPQTTVUXUZT[Q ISJPLONOPPTSVTXTZS[Q IW[W I[[[",
+ "",
+ "CaGO]OXI L[GU]U",
+ "",
+ "D`F^^^^FFFF^",
+ "",
+ "KYQVOUNSNQOOQNSNUOVQVSUUSVQV SVVS QVVQ OUUO NSSN NQQN",
+ "",
+ "H\\IR[R",
+ "H\\IR[R IQ[Q",
+ "",
+ "LYPFSCSP RDRP OPVP MRXR OVOWNWNVOUQTTTVUWWVYTZQ[O\\N^Na TTUUVWUYTZ N`O_P_S`V`W_ P_SaVaW_W^",
+ "LYPFSCSP RDRP OPVP MRXR OVOWNWNVOUQTTTVUWWVYTZ TTUUVWUYTZ RZTZV[W]W^V`TaQaO`N_N^O^O_ TZU[V]V^U`Ta",
+ "LYPFSCSP RDRP OPVP MRXR VVVWWWWVVUTTRTPUOVNYN^O`QaTaV`W^W\\VZTYQYN[ RTPVOYO^P`Qa TaU`V^V\\UZTY",
+ "LYPFSCSP RDRP OPVP MRXR QTOUNWOYQZTZVYWWVUTTQT QTPUOWPYQZ TZUYVWUUTT QZO[N]N^O`QaTaV`W^W]V[TZ QZP[O]O^P`Qa TaU`V^V]U[TZ",
+ "LYOEOFNFNEODQCTCVDWFVHTIQJOKNMNP TCUDVFUHTI NOONPNSOVOWN PNSPVPWNWM MRXR OVOWNWNVOUQTTTVUWWVYTZ TTUUVWUYTZ RZTZV[W]W^V`TaQaO`N_N^O^O_ TZU[V]V^U`Ta",
+ "LYOEOFNFNEODQCTCVDWFVHTI TCUDVFUHTI RITIVJWLWMVOTPQPOONNNMOMON TIUJVLVMUOTP MRXR QTOUNWOYQZTZVYWWVUTTQT QTPUOWPYQZ TZUYVWUUTT QZO[N]N^O`QaTaV`W^W]V[TZ QZP[O]O^P`Qa TaU`V^V]U[TZ",
+ "LYOCNI OCVC ODSDVC NIOHQGTGVHWJWMVOTPQPOONNNMOMON TGUHVJVMUOTP MRXR QTOUNWOYQZTZVYWWVUTTQT QTPUOWPYQZ TZUYVWUUTT QZO[N]N^O`QaTaV`W^W]V[TZ QZP[O]O^P`Qa TaU`V^V]U[TZ",
+ "LYNCNG VERLPP WCTIQP NEPCRCUE NEPDRDUEVE MRXR QTOUNWOYQZTZVYWWVUTTQT QTPUOWPYQZ TZUYVWUUTT QZO[N]N^O`QaTaV`W^W]V[TZ QZP[O]O^P`Qa TaU`V^V]U[TZ",
+ "LYOCNI OCVC ODSDVC NIOHQGTGVHWJWMVOTPQPOONNNMOMON TGUHVJVMUOTP MRXR VVVWWWWVVUTTRTPUOVNYN^O`QaTaV`W^W\\VZTYQYN[ RTPVOYO^P`Qa TaU`V^V\\UZTY",
+ "LYPFSCSP RDRP OPVP MRXR SVSa TTTa TTM]X] QaVa",
+ "LYOEOFNFNEODQCTCVDWFVHTI TCUDVFUHTI RITIVJWLWMVOTPQPOONNNMOMON TIUJVLVMUOTP MRXR SVSa TTTa TTM]X] QaVa",
+ "F^YXWZU[R[PZMXKWIWHXHZI[K[MZOWPURQTKWGYFZF[G\\H[IZH[G[FZFYFWGVHTLRPPVNZMZ OPUP",
+ "E^P[MZJXHUGRGOHLJIMGPFTFWGYI[L\\O\\R[UYXVZS[P[ NJNW OJOW LJSJVKWMWNVPSQOQ SJUKVMVNUPSQ LWQW SQTRUVVWWWXV SQURVVWW",
+ "E^P[MZJXHUGRGOHLJIMGPFTFWGYI[L\\O\\R[UYXVZS[P[ UKVJVNUKSJPJNKMLLOLRMUNVPWSWUVVT PJNLMOMRNUPW",
+ "E_IM[M IR[R IW[W K[YI",
+ "CaHQGRHSIRHQ RQQRRSSRRQ \\Q[R\\S]R\\Q",
+ "",
+ "E_NWLTIRLPNM LPJRLT JRZR VWXT[RXPVM XPZRXT",
+ "JZWNTLRIPLMN PLRJTL RJRZ WVTXR[PXMV PXRZTX",
+ "F^ZJSJOKMLKNJQJSKVMXOYSZZZ SFS^",
+ "F^JJQJUKWLYNZQZSYVWXUYQZJZ QFQ^",
+ "F^JJQJUKWLYNZQZSYVWXUYQZJZ ORZR",
+ "",
+ "H\\LBL[ RBR[ XBX[",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "I[RFJ[ RFZ[ MTWT",
+ "G\\KFK[ KFTFWGXHYJYLXNWOTP KPTPWQXRYTYWXYWZT[K[",
+ "H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZV",
+ "G\\KFK[ KFRFUGWIXKYNYSXVWXUZR[K[",
+ "H[LFL[ LFYF LPTP L[Y[",
+ "HZLFL[ LFYF LPTP",
+ "H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZVZS USZS",
+ "G]KFK[ YFY[ KPYP",
+ "NVRFR[",
+ "JZVFVVUYTZR[P[NZMYLVLT",
+ "G\\KFK[ YFKT POY[",
+ "HYLFL[ L[X[",
+ "F^JFJ[ JFR[ ZFR[ ZFZ[",
+ "G]KFK[ KFY[ YFY[",
+ "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF",
+ "G\\KFK[ KFTFWGXHYJYMXOWPTQKQ",
+ "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF SWY]",
+ "G\\KFK[ KFTFWGXHYJYLXNWOTPKP RPY[",
+ "H\\YIWGTFPFMGKIKKLMMNOOUQWRXSYUYXWZT[P[MZKX",
+ "JZRFR[ KFYF",
+ "G]KFKULXNZQ[S[VZXXYUYF",
+ "I[JFR[ ZFR[",
+ "F^HFM[ RFM[ RFW[ \\FW[",
+ "H\\KFY[ YFK[",
+ "I[JFRPR[ ZFRP",
+ "H\\YFK[ KFYF K[Y[",
+ "I[RFJ[ RFZ[ MTWT",
+ "G\\KFK[ KFTFWGXHYJYLXNWOTP KPTPWQXRYTYWXYWZT[K[",
+ "HYLFL[ LFXF",
+ "I[RFJ[ RFZ[ J[Z[",
+ "H[LFL[ LFYF LPTP L[Y[",
+ "H\\YFK[ KFYF K[Y[",
+ "G]KFK[ YFY[ KPYP",
+ "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF OPUP",
+ "NVRFR[",
+ "G\\KFK[ YFKT POY[",
+ "I[RFJ[ RFZ[",
+ "F^JFJ[ JFR[ ZFR[ ZFZ[",
+ "G]KFK[ KFY[ YFY[",
+ "I[KFYF OPUP K[Y[",
+ "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF",
+ "G]KFK[ YFY[ KFYF",
+ "G\\KFK[ KFTFWGXHYJYMXOWPTQKQ",
+ "I[KFRPK[ KFYF K[Y[",
+ "JZRFR[ KFYF",
+ "I[KKKILGMFOFPGQIRMR[ YKYIXGWFUFTGSIRM",
+ "H\\RFR[ PKMLLMKOKRLTMUPVTVWUXTYRYOXMWLTKPK",
+ "H\\KFY[ K[YF",
+ "G]RFR[ ILJLKMLQMSNTQUSUVTWSXQYMZL[L",
+ "H\\K[O[LTKPKLLINGQFSFVGXIYLYPXTU[Y[",
+ "G[G[IZLWOSSLVFV[UXSUQSNQLQKRKTLVNXQZT[Y[",
+ "F]SHTITLSPRSQUOXMZK[J[IZIWJRKOLMNJPHRGUFXFZG[I[KZMYNWOTP SPTPWQXRYTYWXYWZU[R[PZOX",
+ "H\\TLTMUNWNYMZKZIYGWFTFQGOIMLLNKRKVLYMZO[Q[TZVXWV",
+ "G^TFRGQIPMOSNVMXKZI[G[FZFXGWIWKXMZP[S[VZXXZT[O[KZHYGWFTFRHRJSMUPWRZT\\U",
+ "H\\VJVKWLYLZKZIYGVFRFOGNINLONPOSPPPMQLRKTKWLYMZP[S[VZXXYV",
+ "H\\RLPLNKMINGQFTFXG[G]F XGVNTTRXPZN[L[JZIXIVJULUNV QPZP",
+ "G^G[IZMVPQQNRJRGQFPFOGNINLONQOUOXNYMZKZQYVXXVZS[O[LZJXIVIT",
+ "F^MMKLJJJIKGMFNFPGQIQKPONULYJ[H[GZGX MRVOXN[L]J^H^G]F\\FZHXLVRUWUZV[W[YZZY\\V",
+ "IZWVUTSQROQLQIRGSFUFVGWIWLVQTVSXQZO[M[KZJXJVKUMUOV",
+ "JYT^R[PVOPOJPGRFTFUGVJVMURR[PaOdNfLgKfKdLaN^P\\SZWX",
+ "F^MMKLJJJIKGMFNFPGQIQKPONULYJ[H[GZGX ^I^G]F\\FZGXIVLTNROPO ROSQSXTZU[V[XZYY[V",
+ "I\\MRORSQVOXMYKYHXFVFUGTISNRSQVPXNZL[J[IZIXJWLWNXQZT[V[YZ[X",
+ "@aEMCLBJBICGEFFFHGIIIKHPGTE[ GTJLLHMGOFPFRGSISKRPQTO[ QTTLVHWGYFZF\\G]I]K\\PZWZZ[[\\[^Z_YaV",
+ "E]JMHLGJGIHGJFKFMGNINKMPLTJ[ LTOLQHRGTFVFXGYIYKXPVWVZW[X[ZZ[Y]V",
+ "H]TFQGOIMLLNKRKVLYMZO[Q[TZVXXUYSZOZKYHXGVFTFRHRKSNUQWSZU\\V",
+ "F_SHTITLSPRSQUOXMZK[J[IZIWJRKOLMNJPHRGUFZF\\G]H^J^M]O\\PZQWQUPTO",
+ "H^ULTNSOQPOPNNNLOIQGTFWFYGZIZMYPWSSWPYNZK[I[HZHXIWKWMXPZS[V[YZ[X",
+ "F_SHTITLSPRSQUOXMZK[J[IZIWJRKOLMNJPHRGUFYF[G\\H]J]M\\O[PYQVQSPTQUSUXVZX[ZZ[Y]V",
+ "H\\H[JZLXOTQQSMTJTGSFRFQGPIPKQMSOVQXSYUYWXYWZT[P[MZKXJVJT",
+ "H[RLPLNKMINGQFTFXG[G]F XGVNTTRXPZN[L[JZIXIVJULUNV",
+ "E]JMHLGJGIHGJFKFMGNINKMOLRKVKXLZN[P[RZSYUUXMZF XMWQVWVZW[X[ZZ[Y]V",
+ "F]KMILHJHIIGKFLFNGOIOKNOMRLVLYM[O[QZTWVTXPYMZIZGYFXFWGVIVKWNYP[Q",
+ "C_HMFLEJEIFGHFIFKGLILLK[ UFK[ UFS[ aF_G\\JYNVTS[",
+ "F^NLLLKKKILGNFPFRGSISLQUQXRZT[V[XZYXYVXUVU ]I]G\\FZFXGVITLPUNXLZJ[H[GZGX",
+ "F]KMILHJHIIGKFLFNGOIOKNOMRLVLXMZN[P[RZTXVUWSYM [FYMVWT]RbPfNgMfMdNaP^S[VY[V",
+ "H]ULTNSOQPOPNNNLOIQGTFWFYGZIZMYPWTTWPZN[K[JZJXKWNWPXQYR[R^QaPcNfLgKfKdLaN^Q[TYZV",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "I[JFR[ ZFR[ JFZF",
+ "G]IL[b",
+ "E_RJIZ RJ[Z",
+ "I[J[Z[",
+ "I[J[Z[ZZJZJ[",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "I\\XMX[ XPVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "H[LFL[ LPNNPMSMUNWPXSXUWXUZS[P[NZLX",
+ "I[XPVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "I\\XFX[ XPVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "I[LSXSXQWOVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "MYWFUFSGRJR[ OMVM",
+ "I\\XMX]W`VaTbQbOa XPVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "I\\MFM[ MQPNRMUMWNXQX[",
+ "NVQFRGSFREQF RMR[",
+ "MWRFSGTFSERF SMS^RaPbNb",
+ "IZMFM[ WMMW QSX[",
+ "NVRFR[",
+ "CaGMG[ GQJNLMOMQNRQR[ RQUNWMZM\\N]Q][",
+ "I\\MMM[ MQPNRMUMWNXQX[",
+ "I\\QMONMPLSLUMXOZQ[T[VZXXYUYSXPVNTMQM",
+ "H[LMLb LPNNPMSMUNWPXSXUWXUZS[P[NZLX",
+ "I\\XMXb XPVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "KXOMO[ OSPPRNTMWM",
+ "J[XPWNTMQMNNMPNRPSUTWUXWXXWZT[Q[NZMX",
+ "MYRFRWSZU[W[ OMVM",
+ "I\\MMMWNZP[S[UZXW XMX[",
+ "JZLMR[ XMR[",
+ "G]JMN[ RMN[ RMV[ ZMV[",
+ "J[MMX[ XMM[",
+ "JZLMR[ XMR[P_NaLbKb",
+ "J[XMM[ MMXM M[X[",
+ "H]QMONMPLRKUKXLZN[P[RZUWWTYPZM QMSMTNUPWXXZY[Z[",
+ "I\\UFSGQIOMNPMTLZKb UFWFYHYKXMWNUORO ROTPVRWTWWVYUZS[Q[OZNYMV",
+ "I\\JPLNNMOMQNROSRSVR[ ZMYPXRR[P_Ob",
+ "I[TMQMONMPLSLVMYNZP[R[TZVXWUWRVOTMRKQIQGRFTFVGXI",
+ "JZWOVNTMQMONOPPRSS SSOTMVMXNZP[S[UZWX",
+ "JYTFRGQHQIRJUKXK XKTMQONRMUMWNYP[S]T_TaSbQbP`",
+ "H\\IQJOLMNMONOPNTL[ NTPPRNTMVMXOXRWWTb",
+ "G\\HQIOKMMMNNNPMUMXNZO[Q[SZUWVUWRXMXJWGUFSFRHRJSMUPWRZT",
+ "LWRMPTOXOZP[R[TYUW",
+ "I[OMK[ YNXMWMUNQROSNS NSPTQUSZT[U[VZ",
+ "JZKFMFOGPHX[ RML[",
+ "H]OMIb NQMVMYO[Q[SZUXWT YMWTVXVZW[Y[[Y\\W",
+ "I[LMOMNSMXL[ YMXPWRUURXOZL[",
+ "JZTFRGQHQIRJUKXK UKRLPMOOOQQSTTVT TTPUNVMXMZO\\S^T_TaRbPb",
+ "J[RMPNNPMSMVNYOZQ[S[UZWXXUXRWOVNTMRM",
+ "G]PML[ UMVSWXX[ IPKNNM[M",
+ "I[MSMVNYOZQ[S[UZWXXUXRWOVNTMRMPNNPMSIb",
+ "I][MQMONMPLSLVMYNZP[R[TZVXWUWRVOUNSM",
+ "H\\SMP[ JPLNOMZM",
+ "H\\IQJOLMNMONOPMVMYO[Q[TZVXXTYPYM",
+ "G]ONMOKQJTJWKYLZN[Q[TZWXYUZRZOXMVMTORSPXMb",
+ "I[KMMMOOU`WbYb ZMYOWRM]K`Jb",
+ "F]VFNb GQHOJMLMMNMPLULXMZO[Q[TZVXXUZP[M",
+ "F]NMLNJQITIWJZK[M[OZQW RSQWRZS[U[WZYWZTZQYNXM",
+ "L\\UUTSRRPRNSMTLVLXMZO[Q[SZTXVRUWUZV[W[YZZY\\V",
+ "M[MVOSRNSLTITGSFQGPIOMNTNZO[P[RZTXUUURVVWWYW[V",
+ "MXTTTSSRQROSNTMVMXNZP[S[VYXV",
+ "L\\UUTSRRPRNSMTLVLXMZO[Q[SZTXZF VRUWUZV[W[YZZY\\V",
+ "NXOYQXRWSUSSRRQROSNUNXOZQ[S[UZVYXV",
+ "OWOVSQUNVLWIWGVFTGSIQQNZKaJdJfKgMfNcOZP[R[TZUYWV",
+ "L[UUTSRRPRNSMTLVLXMZO[Q[SZTY VRTYPdOfMgLfLdMaP^S\\U[XY[V",
+ "M\\MVOSRNSLTITGSFQGPIOMNSM[ M[NXOVQSSRURVSVUUXUZV[W[YZZY\\V",
+ "PWSMSNTNTMSM PVRRPXPZQ[R[TZUYWV",
+ "PWSMSNTNTMSM PVRRLdKfIgHfHdIaL^O\\Q[TYWV",
+ "M[MVOSRNSLTITGSFQGPIOMNSM[ M[NXOVQSSRURVSVUTVQV QVSWTZU[V[XZYY[V",
+ "OWOVQSTNULVIVGUFSGRIQMPTPZQ[R[TZUYWV",
+ "E^EVGSIRJSJTIXH[ IXJVLSNRPRQSQTPXO[ PXQVSSURWRXSXUWXWZX[Y[[Z\\Y^V",
+ "J\\JVLSNROSOTNXM[ NXOVQSSRURVSVUUXUZV[W[YZZY\\V",
+ "LZRRPRNSMTLVLXMZO[Q[SZTYUWUUTSRRQSQURWTXWXYWZV",
+ "KZKVMSNQMUGg MUNSPRRRTSUUUWTYSZQ[ MZO[R[UZWYZV",
+ "L[UUTSRRPRNSMTLVLXMZO[Q[SZ VRUUSZPaOdOfPgRfScS\\U[XY[V",
+ "MZMVOSPQPSSSTTTVSYSZT[U[WZXYZV",
+ "NYNVPSQQQSSVTXTZR[ NZP[T[VZWYYV",
+ "OXOVQSSO VFPXPZQ[S[UZVYXV PNWN",
+ "L[LVNRLXLZM[O[QZSXUU VRTXTZU[V[XZYY[V",
+ "L[LVNRMWMZN[O[RZTXUUUR URVVWWYW[V",
+ "I^LRJTIWIYJ[L[NZPX RRPXPZQ[S[UZWXXUXR XRYVZW\\W^V",
+ "JZJVLSNRPRQSQZR[U[XYZV WSVRTRSSOZN[L[KZ",
+ "L[LVNRLXLZM[O[QZSXUU VRPdOfMgLfLdMaP^S\\U[XY[V",
+ "LZLVNSPRRRTTTVSXQZN[P\\Q^QaPdOfMgLfLdMaP^S\\WYZV",
+ "J\\K[NZQXSVUSWOXKXIWGUFSGRHQJPOPTQXRZT[V[XZYY",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "I[WUWRVOUNSMQMONMPLSLVMYNZP[R[TZVXWUXPXKWHVGTFRFPGNI",
+ "JZWNUMRMPNNPMSMVNYOZQ[T[VZ MTUT",
+ "J[TFRGPJOLNOMTMXNZO[Q[SZUWVUWRXMXIWGVFTF NPWP",
+ "H\\VFNb QMNNLPKSKVLXNZQ[S[VZXXYUYRXPVNSMQM",
+ "I[XOWNTMQMNNMOLQLSMUOWSZT\\T^S_Q_",
+ "",
+ "",
+ "DaWNVLTKQKOLNMMOMRNTOUQVTVVUWS WKWSXUYV[V\\U]S]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYY",
+ "F^ZIJRZ[",
+ "F^JIZRJ[",
+ "KYOBOb OBVB ObVb",
+ "KYUBUb NBUB NbUb",
+ "KYTBQEPHPJQMSOSPORSTSUQWPZP\\Q_Tb",
+ "KYPBSETHTJSMQOQPURQTQUSWTZT\\S_Pb",
+ "F^[FYGVHSHPGNFLFJGIIIKKMMMOLPJPHNF [FI[ YTWTUUTWTYV[X[ZZ[X[VYT",
+ "NV",
+ "JZ",
+ "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF",
+ "H\\NJPISFS[",
+ "H\\LKLJMHNGPFTFVGWHXJXLWNUQK[Y[",
+ "H\\MFXFRNUNWOXPYSYUXXVZS[P[MZLYKW",
+ "H\\UFKTZT UFU[",
+ "H\\WFMFLOMNPMSMVNXPYSYUXXVZS[P[MZLYKW",
+ "H\\XIWGTFRFOGMJLOLTMXOZR[S[VZXXYUYTXQVOSNRNOOMQLT",
+ "H\\YFO[ KFYF",
+ "H\\PFMGLILKMMONSOVPXRYTYWXYWZT[P[MZLYKWKTLRNPQOUNWMXKXIWGTFPF",
+ "H\\XMWPURRSQSNRLPKMKLLINGQFRFUGWIXMXRWWUZR[P[MZLX",
+ "MWRYQZR[SZRY",
+ "MWSZR[QZRYSZS\\R^Q_",
+ "MWRMQNROSNRM RYQZR[SZRY",
+ "MWRMQNROSNRM SZR[QZRYSZS\\R^Q_",
+ "MWRFRT RYQZR[SZRY",
+ "I[LKLJMHNGPFTFVGWHXJXLWNVORQRT RYQZR[SZRY",
+ "NVRFRM",
+ "JZNFNM VFVM",
+ "KYQFOGNINKOMQNSNUMVKVIUGSFQF",
+ "H\\PBP_ TBT_ YIWGTFPFMGKIKKLMMNOOUQWRXSYUYXWZT[P[MZKX",
+ "G][BIb",
+ "KYVBTDRGPKOPOTPYR]T`Vb",
+ "KYNBPDRGTKUPUTTYR]P`Nb",
+ "NVRBRb",
+ "E_IR[R",
+ "E_RIR[ IR[R",
+ "E_IO[O IU[U",
+ "G]KKYY YKKY",
+ "JZRLRX MOWU WOMU",
+ "MWRQQRRSSRRQ",
+ "MWSFRGQIQKRLSKRJ",
+ "MWRHQGRFSGSIRKQL",
+ "E_UMXP[RXTUW IR[R",
+ "G]OFOb UFUb JQZQ JWZW",
+ "E_\\O\\N[MZMYNXPVUTXRZP[L[JZIYHWHUISJRQNRMSKSIRGPFNGMIMKNNPQUXWZY[[[\\Z\\Y",
+ "G]IIJKKOKUJYI[ [IZKYOYUZY[[ IIKJOKUKYJ[I I[KZOYUYYZ[[",
+ "F_\\Q[OYNWNUOTPQTPUNVLVJUISIQJOLNNNPOQPTTUUWVYV[U\\S\\Q",
+ "KYOBO[ UBU[",
+ "F^RBR[ I[[[",
+ "F^[BI[[[",
+ "E_RIQJRKSJRI IYHZI[JZIY [YZZ[[\\Z[Y",
+ "F^RHNLKPJSJUKWMXOXQWRU RHVLYPZSZUYWWXUXSWRU RUQYP\\ RUSYT\\ P\\T\\",
+ "F^RNQKPINHMHKIJKJOKRLTNWR\\ RNSKTIVHWHYIZKZOYRXTVWR\\",
+ "F^RGPJLOIR RGTJXO[R IRLUPZR] [RXUTZR]",
+ "F^RTTWVXXXZW[U[SZQXPVPSQ SQUOVMVKUISHQHOINKNMOOQQ QQNPLPJQISIUJWLXNXPWRT RTQYP\\ RTSYT\\ P\\T\\",
+ "F^RRR[Q\\ RVQ\\ RIQHOHNINKONRR RISHUHVIVKUNRR RRNOLNJNIOIQJR RRVOXNZN[O[QZR RRNULVJVIUISJR RRVUXVZV[U[SZR",
+ "F^ISJSLTMVMXLZ ISIRJQLQMRNTNWMYLZ RGPIOLOOQUQXPZR\\ RGTIULUOSUSXTZR\\ [S[RZQXQWRVTVWWYXZ [SZSXTWVWXXZ KVYV",
+ "",
+ "",
+ "",
+ "PSSRRSQSPRPQQPRPSQSSRUQV QQQRRRRQQQ",
+ "PTQPPQPSQTSTTSTQSPQP RQQRRSSRRQ",
+ "NVPOTU TOPU NRVR",
+ "MWRKQMOPMR RKSMUPWR RMOQ RMUQ ROPQ ROTQ QQSQ MRWR",
+ "MWMRMQNOONQMSMUNVOWQWR PNTN OOUO NPVP NQVQ MRWR",
+ "LRLFLRRRLF LIPQ LLOR LOMQ",
+ "MWRKQMOPMR RKSMUPWR",
+ "MWWRWQVOUNSMQMONNOMQMR",
+ "G]]R]P\\MZJWHTGPGMHJJHMGPGR",
+ "MWMRMSNUOVQWSWUVVUWSWR",
+ "LXLPNRQSSSVRXP",
+ "RURUTTURTPRO",
+ "RVRRUPVNVLUKTK",
+ "NRRROPNNNLOKPK",
+ "MWWHVGTFQFOGNHMJMLNNOOUSVTWVWXVZU[S\\P\\N[MZ",
+ "G]IWHVGTGQHOINKMMMONPOTUUVWWYW[V\\U]S]P\\N[M",
+ "G]RRTUUVWWYW[V\\U]S]Q\\O[NYMWMUNTOPUOVMWKWIVHUGSGQHOINKMMMONPORR",
+ "H\\KFK[ HF[FQP[Z ZV[Y\\[ ZVZY WYZY WYZZ\\[",
+ "KYUARBPCNELHKLKRLUNWQXSXVWXUYR KPLMNKQJSJVKXMYPYVXZV]T_R`Oa",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ">f>RfR",
+ "D`D``D",
+ "RRR>Rf",
+ "D`DD``",
+ "D`DR`R",
+ "F^FY^K",
+ "KYK^YF",
+ "",
+ "KYKFY^",
+ "F^FK^Y",
+ "KYKRYR",
+ "MWMWWM",
+ "",
+ "MWMMWW",
+ "",
+ "",
+ "",
+ "",
+ "D`DOGQKSPTTTYS]Q`O",
+ "PUUDSGQKPPPTQYS]U`",
+ "OTODQGSKTPTTSYQ]O`",
+ "D`DUGSKQPPTPYQ]S`U",
+ "KYRJYNKVRZ",
+ "JZJRNKVYZR",
+ "KYKVKNYVYN",
+ "JZLXJPZTXL",
+ "JZJ]L]O\\Q[TXUVVSVOULTJSIQIPJOLNONSOVPXS[U\\X]Z]",
+ "I]]Z]X\\U[SXPVOSNONLOJPIQISJTLUOVSVVUXT[Q\\O]L]J",
+ "JZZGXGUHSIPLONNQNUOXPZQ[S[TZUXVUVQUNTLQIOHLGJG",
+ "G[GJGLHOIQLTNUQVUVXUZT[S[QZPXOUNQNNOLPISHUGXGZ",
+ "E[EPFRHTJUMVQVUUXSZP[NZLWLSMQNNPLSKVKYL\\M^",
+ "EYETHVKWPWSVVTXQYNYLXKVKSLPNNQMTMYN\\P_",
+ "OUQOOQOSQUSUUSUQSOQO QPPQPSQTSTTSTQSPQP RQQRRSSRRQ",
+ "",
+ "D`DRJR ORUR ZR`R",
+ "D`DUDO`O`U",
+ "JZRDJR RDZR",
+ "D`DR`R JYZY P`T`",
+ "D`DR`R DRRb `RRb",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "KYQKNLLNKQKSLVNXQYSYVXXVYSYQXNVLSKQK",
+ "LXLLLXXXXLLL",
+ "KYRJKVYVRJ",
+ "LXRHLRR\\XRRH",
+ "JZRIPOJOOSMYRUWYUSZOTORI",
+ "KYRKRY KRYR",
+ "MWMMWW WMMW",
+ "MWRLRX MOWU WOMU",
+ "",
+ "",
+ "NVQNOONQNSOUQVSVUUVSVQUOSNQN OQOS PPPT QOQU RORU SOSU TPTT UQUS",
+ "NVNNNVVVVNNN OOOU POPU QOQU RORU SOSU TOTU UOUU",
+ "MWRLMUWURL ROOT ROUT RRQT RRST",
+ "LULRUWUMLR ORTU ORTO RRTS RRTQ",
+ "MWRXWOMORX RUUP RUOP RRSP RRQP",
+ "OXXROMOWXR URPO URPU RRPQ RRPS",
+ "LXRLNWXPLPVWRL RRRL RRLP RRNW RRVW RRXP",
+ "",
+ "",
+ "",
+ "MWRLRX OOUO MUOWQXSXUWWU",
+ "LXRLRX LQMOWOXQ PWTW",
+ "KYMNWX WNMX OLLOKQ ULXOYQ",
+ "I[NII[ VI[[ MM[[ WMI[ NIVI MMWM",
+ "I[RGRV MJWP WJMP IVL\\ [VX\\ IV[V L\\X\\",
+ "G[MJSV KPSL G\\[\\[RG\\",
+ "LXPLPPLPLTPTPXTXTTXTXPTPTLPL",
+ "KYYPXNVLSKQKNLLNKQKSLVNXQYSYVXXVYT YPWNUMSMQNPOOQOSPUQVSWUWWVYT",
+ "KYRJKVYVRJ RZYNKNRZ",
+ "G]PIPGQFSFTGTI GZHXJVKTLPLKMJOIUIWJXKXPYTZV\\X]Z GZ]Z QZP[Q\\S\\T[SZ",
+ "JZRMRS RSQ\\ RSS\\ Q\\S\\ RMQJPHNG QJNG RMSJTHVG SJVG RMNKLKJM PLLLJM RMVKXKZM TLXLZM RMPNOOOR RMPOOR RMTNUOUR RMTOUR",
+ "JZRIRK RNRP RSRU RYQ\\ RYS\\ Q\\S\\ RGQIPJ RGSITJ PJRITJ RKPNNOMN RKTNVOWN NOPORNTOVO RPPSNTLTKRKSLT RPTSVTXTYRYSXT NTPTRSTTVT RUPXOYMZLZKYJWJYLZ RUTXUYWZXZYYZWZYXZ MZOZRYUZWZ",
+ "JZRYQ\\ RYS\\ Q\\S\\ RYUZXZZXZUYTWTYRZOYMWLUMVJUHSGQGOHNJOMMLKMJOKRMTKTJUJXLZOZRY",
+ "JZRYQ\\ RYS\\ Q\\S\\ RYVXVVXUXRZQZLYIXHVHTGPGNHLHKIJLJQLRLUNVNXRY",
+ "I[IPKR LKNP RGRO XKVP [PYR",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "QSRQQRRSSRRQ",
+ "PTQPPQPSQTSTTSTQSPQP",
+ "NVQNOONQNSOUQVSVUUVSVQUOSNQN",
+ "MWQMONNOMQMSNUOVQWSWUVVUWSWQVOUNSMQM",
+ "KYQKNLLNKQKSLVNXQYSYVXXVYSYQXNVLSKQK",
+ "G]PGMHJJHMGPGTHWJZM\\P]T]W\\ZZ\\W]T]P\\MZJWHTGPG",
+ "AcPALBJCGEEGCJBLAPATBXCZE]G_JaLbPcTcXbZa]__]aZbXcTcPbLaJ_G]EZCXBTAPA",
+ "<hP<K=G?DAAD?G=K<P<T=Y?]A`DcGeKgPhThYg]e`cc`e]gYhThPgKeGcD`A]?Y=T<P<",
+ "){O)I*E+@-;073370;-@+E*I)O)U*[+_-d0i3m7q;t@wEyIzO{U{[z_ydwitmqqmtiwdy_z[{U{OzIyEw@t;q7m3i0d-_+[*U)O)",
+ ">fRAPCMDJDGCEA>H@JAMAZB]D_G`M`PaRc RATCWDZD]C_AfHdJcMcZb]`_]`W`TaRc",
+ "AcRAPCMDJDGCEABGAKAPBTDXG\\L`Rc RATCWDZD]C_AbGcKcPbT`X]\\X`Rc BHbH",
+ "H[WPVQWRXQXPVNTMQMNNLPKSKULXNZQ[S[VZXX QMONMPLSLUMXOZQ[ LbXF",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "KYRKMX RNVX RKWX OTTT KXPX TXYX",
+ "JZNKNX OKOX LKSKVLWNVPSQ SKULVNUPSQ OQSQVRWTWUVWSXLX SQURVTVUUWSX",
+ "KYVLWKWOVLTKQKOLNMMPMSNVOWQXTXVWWU QKOMNPNSOVQX",
+ "JZNKNX OKOX LKSKVLWMXPXSWVVWSXLX SKULVMWPWSVVUWSX",
+ "JYNKNX OKOX SOSS LKVKVOUK OQSQ LXVXVTUX",
+ "JXNKNX OKOX SOSS LKVKVOUK OQSQ LXQX",
+ "K[VLWKWOVLTKQKOLNMMPMSNVOWQXTXVW QKOMNPNSOVQX TXUWVU VSVX WSWX TSYS",
+ "J[NKNX OKOX VKVX WKWX LKQK TKYK OQVQ LXQX TXYX",
+ "NWRKRX SKSX PKUK PXUX",
+ "LXSKSURWQX TKTUSWQXPXNWMUNTOUNV QKVK",
+ "JZNKNX OKOX WKOS QQVX RQWX LKQK TKYK LXQX TXYX",
+ "KXOKOX PKPX MKRK MXWXWTVX",
+ "I\\MKMX NNRX NKRU WKRX WKWX XKXX KKNK WKZK KXOX UXZX",
+ "JZNKNX OMVX OKVV VKVX LKOK TKXK LXPX",
+ "KZQKOLNMMPMSNVOWQXTXVWWVXSXPWMVLTKQK QKOMNPNSOVQX TXVVWSWPVMTK",
+ "JYNKNX OKOX LKSKVLWNWOVQSROR SKULVNVOUQSR LXQX",
+ "KZQKOLNMMPMSNVOWQXTXVWWVXSXPWMVLTKQK QKOMNPNSOVQX TXVVWSWPVMTK PWPUQTSTTUUZV[W[XZ TUUXVZW[",
+ "JZNKNX OKOX LKSKVLWNWOVQSROR SKULVNVOUQSR LXQX SRTSUWVXWXXW SRUSVWWX",
+ "KZVMWKWOVMULSKQKOLNMNOOPQQTRVSWT NNOOQPTQVRWSWVVWTXRXPWOVNTNXOV",
+ "KZRKRX SKSX NKMOMKXKXOWK PXUX",
+ "J[NKNUOWQXTXVWWUWK OKOUPWQX LKQK UKYK",
+ "KYMKRX NKRU WKRX KKPK TKYK",
+ "I[LKOX MKOT RKOX RKUX SKUT XKUX JKOK VKZK",
+ "KZNKVX OKWX WKNX LKQK TKYK LXQX TXYX",
+ "LYNKRRRX OKSR WKSRSX LKQK TKYK PXUX",
+ "LYVKNX WKOX OKNONKWK NXWXWTVX",
+ "KYRKMX RNVX RKWX OTTT KXPX TXYX",
+ "JZNKNX OKOX LKSKVLWNVPSQ SKULVNUPSQ OQSQVRWTWUVWSXLX SQURVTVUUWSX",
+ "KXOKOX PKPX MKWKWOVK MXRX",
+ "KYRKLX RMWX RKXX MWVW LXXX",
+ "JYNKNX OKOX SOSS LKVKVOUK OQSQ LXVXVTUX",
+ "LYVKNX WKOX OKNONKWK NXWXWTVX",
+ "J[NKNX OKOX VKVX WKWX LKQK TKYK OQVQ LXQX TXYX",
+ "KZQKOLNMMPMSNVOWQXTXVWWVXSXPWMVLTKQK QKOMNPNSOVQX TXVVWSWPVMTK QOQT TOTT QQTQ QRTR",
+ "NWRKRX SKSX PKUK PXUX",
+ "JZNKNX OKOX WKOS QQVX RQWX LKQK TKYK LXQX TXYX",
+ "KYRKMX RNVX RKWX KXPX TXYX",
+ "I\\MKMX NNRX NKRU WKRX WKWX XKXX KKNK WKZK KXOX UXZX",
+ "JZNKNX OMVX OKVV VKVX LKOK TKXK LXPX",
+ "JZMJLM XJWM PPOS UPTS MVLY XVWY MKWK MLWL PQTQ PRTR MWWW MXWX",
+ "KZQKOLNMMPMSNVOWQXTXVWWVXSXPWMVLTKQK QKOMNPNSOVQX TXVVWSWPVMTK",
+ "J[NKNX OKOX VKVX WKWX LKYK LXQX TXYX",
+ "JYNKNX OKOX LKSKVLWNWOVQSROR SKULVNVOUQSR LXQX",
+ "K[MKRQ NKSQMX MKWKXOVK NWWW MXWXXTVX",
+ "KZRKRX SKSX NKMOMKXKXOWK PXUX",
+ "KZMONLOKPKQLRORX XOWLVKUKTLSOSX MONMOLPLQMRO XOWMVLULTMSO PXUX",
+ "KZRKRX SKSX QNNOMQMRNTQUTUWTXRXQWOTNQN QNOONQNROTQU TUVTWRWQVOTN PKUK PXUX",
+ "KZNKVX OKWX WKNX LKQK TKYK LXQX TXYX",
+ "J[RKRX SKSX LPMONOOSQU TUVSWOXOYP MONROTQUTUVTWRXO PKUK PXUX",
+ "KZMVNXQXMRMONMOLQKTKVLWMXOXRTXWXXV OUNRNOOMQK TKVMWOWRVU NWPW UWWW",
+ "KYTKKX SMTX TKUX NTTT IXNX RXWX",
+ "JYPKLX QKMX NKUKWLWNVPSQ UKVLVNUPSQ OQRQTRUSUUTWQXJX RQTSTUSWQX",
+ "KXVLWLXKWNVLTKRKPLOMNOMRMUNWPXRXTWUU RKPMOONRNVPX",
+ "JYPKLX QKMX NKTKVLWNWQVTUVTWQXJX TKULVNVQUTTVSWQX",
+ "JYPKLX QKMX SORS NKXKWNWK OQRQ JXTXUUSX",
+ "JXPKLX QKMX SORS NKXKWNWK OQRQ JXOX",
+ "KYVLWLXKWNVLTKRKPLOMNOMRMUNWPXRXTWUVVS RKPMOONRNVPX RXTVUS SSXS",
+ "J[PKLX QKMX XKTX YKUX NKSK VK[K OQVQ JXOX RXWX",
+ "NWTKPX UKQX RKWK NXSX",
+ "LXUKRUQWPX VKSURWPXOXMWLUMTNUMV SKXK",
+ "JZPKLX QKMX YKOR RPTX SPUX NKSK VK[K JXOX RXWX",
+ "KXQKMX RKNX OKTK KXUXVUTX",
+ "I\\OKKX OMPX PKQV YKPX YKUX ZKVX MKPK YK\\K IXMX SXXX",
+ "JZPKLX PKTX QKTU XKTX NKQK VKZK JXNX",
+ "KYRKPLOMNOMRMUNWPXRXTWUVVTWQWNVLTKRK RKPMOONRNVPX RXTVUTVQVMTK",
+ "JYPKLX QKMX NKUKWLXMXOWQTROR UKWMWOVQTR JXOX",
+ "KYRKPLOMNOMRMUNWPXRXTWUVVTWQWNVLTKRK RKPMOONRNVPX RXTVUTVQVMTK OWOVPUQURVRZS[T[UZ RVSZT[",
+ "JZPKLX QKMX NKUKWLXMXOWQTROR UKWMWOVQTR SRTWUXVXWW SRTSUWVX JXOX",
+ "KZWLXLYKXNWLUKRKPLOMOOPPUSVT ONPOURVSVVUWSXPXNWMULXMWNW",
+ "KZTKPX UKQX PKNNOKZKYNYK NXSX",
+ "J[PKMUMWOXSXUWVUYK QKNUNWOX NKSK WK[K",
+ "KYOKPX PKQV YKPX MKRK VK[K",
+ "I[NKMX OKNV TKMX TKSX UKTV ZKSX LKQK XK\\K",
+ "KZPKTX QKUX YKLX NKSK VK[K JXOX RXWX",
+ "LYPKRQPX QKSQ YKSQQX NKSK VK[K NXSX",
+ "LYXKLX YKMX QKONPKYK LXUXVUTX",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "KZMHX\\",
+ "JZRMLW RMXW",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "LZQOPPPQOQOPQOTOVQVWWXXX TOUQUWWX URRSPTOUOWPXSXTWUU RSPUPWQX",
+ "JYNKNX OKOX ORPPROTOVPWRWUVWTXRXPWOU TOUPVRVUUWTX LKOK",
+ "LXVQUQURVRVQUPSOQOOPNRNUOWQXSXUWVV QOPPOROUPWQX",
+ "L[VKVX WKWX VRUPSOQOOPNRNUOWQXSXUWVU QOPPOROUPWQX TKWK VXYX",
+ "LXOSVSVRUPSOQOOPNRNUOWQXSXUWVV USUQSO QOPPOROUPWQX",
+ "LWTKULUMVMVLTKRKPMPX RKQMQX NOSO NXSX",
+ "LYQOOQOSQUSUUSUQSOQO QOPQPSQU SUTSTQSO TPUOVO PTOUOXPYTYVZ OWPXTXVYV[T\\P\\N[NYPX",
+ "J[NKNX OKOX ORPPROTOVPWRWX TOUPVRVX LKOK LXQX TXYX",
+ "NWRKRLSLSKRK RORX SOSX POSO PXUX",
+ "NWSKSLTLTKSK SOSZR\\ TOTZR\\P\\O[OZPZP[O[ QOTO",
+ "JZNKNX OKOX WOOU RSVX SSWX LKOK TOYO LXQX TXYX",
+ "NWRKRX SKSX PKSK PXUX",
+ "F_JOJX KOKX KRLPNOPORPSRSX POQPRRRX SRTPVOXOZP[R[X XOYPZRZX HOKO HXMX PXUX XX]X",
+ "J[NONX OOOX ORPPROTOVPWRWX TOUPVRVX LOOO LXQX TXYX",
+ "LYQOOPNRNUOWQXTXVWWUWRVPTOQO QOPPOROUPWQX TXUWVUVRUPTO",
+ "JYNON\\ OOO\\ ORPPROTOVPWRWUVWTXRXPWOU TOUPVRVUUWTX LOOO L\\Q\\",
+ "KYUOU\\ VOV\\ URTPROPONPMRMUNWPXRXTWUU POOPNRNUOWPX S\\X\\",
+ "KXOOOX POPX PRQPSOUOVPVQUQUPVP MOPO MXRX",
+ "LYTOUPUQVQVPTOQOOPORQSTTVU OQQRTSVTVWTXQXOWOVPVPWQX",
+ "LWPKPVRXTXUWUV QKQVRX NOTO",
+ "J[NONUOWQXSXUWVU OOOUPWQX VOVX WOWX LOOO TOWO VXYX",
+ "KYNORX OORV VORX LOQO TOXO",
+ "I[LOOX MOOU ROOX ROUX SOUU XOUX JOOO VOZO",
+ "KYNOUX OOVX VONX LOQO TOXO LXPX SXXX",
+ "KYNORX OORV VORXP[N\\M\\L[LZMZM[L[ LOQO TOXO",
+ "LXUONX VOOX OONQNOVO NXVXVVUX",
+ "K[QOOPNQMSMUNWPXQXSWUUWRXO QOOQNSNUOWPX QOSOUPWWXX SOTPVWXXYX",
+ "KXRKPMOOMUK\\ QLPNNTL\\ RKTKVLVNUPRQ TKULUNTPRQ RQTRUTUVTWRXQXOWNT RQSRTTTVRX",
+ "KYLQNOPORPSSSXR\\ LQNPPPRQSS WOVRSXQ\\",
+ "KYSOQOOPNQMSMUNWPXRXTWUVVTVRUPRNQLQKRJTJUKVM QOOQNSNVPX RXTVUTUQSO QLRKTKVM",
+ "LXVPTOQOOPOQPRRS QOPPPQRS RSOTNUNWPXSXUW RSPTOUOWPX",
+ "LWRKQLQMSNVNVMSNPOOPNRNTOVPWRXSYS[R\\P\\O[ SNQOPPOROTPVRX",
+ "IYJRKPLONOOPOQMX MONPNQLX OQPPROTOVPVRS\\ TOUPURR\\",
+ "IYJSKQLPNPOQOVPX MPNQNUOWPXQXSWTVUTVQVNULTKRKQLQNRPURWS QXSVTTUQUNTK",
+ "NWROPVPWQXSXUWVU SOQVQWRX",
+ "KYOOLX POMX UOVPWPVOTORQOR ORPSRWTXVWWU ORQSSWTX",
+ "LXLKNKPLWX NKOLVX RPMX RPNX",
+ "KZOOK\\ POL\\ NUNWOXQXSWTV VOTVTWUXWXXWYU WOUVUWVX",
+ "JYNOMX OONUMX VRVOWOVRTUQWNXMX LOOO",
+ "MXRKQLQMSNVN TNQOPPPRRSUS TNROQPQRRS SSPTOUOWQXSYTZT[S\\Q\\ SSQTPUPWQX",
+ "KXQOOPNQMSMUNWPXRXTWUVVTVRUPSOQO QOOQNSNVPX RXTVUTUQSO",
+ "IZPPMX PPNX TPSX TPTX KQMOXO KQMPXP",
+ "JXSOQOOPNQMSJ\\ QOOQNSK\\ SOUPVRVTUVTWRXPXNWMU SOUQUTTVRX",
+ "K[YOQOOPNQMSMUNWPXRXTWUVVTVRUPYP QOOQNSNVPX RXTVUTUQSO",
+ "KZSPQX SPRX MQOOXO MQOPXP",
+ "JXKRLPMOOOPPPROUOWPX NOOPORNUNWPXQXSWUUVRVOUOVP",
+ "KZOPNQMSMUNWPXRXUWWUXRXPWOUOTPSRRUO\\ MUNVPWRWUVWTXR XQWPUPSR RUQXP\\",
+ "KXMONOPPS[T\\ NOOPR[T\\U\\ VOTRNYL\\",
+ "I[TKQ\\ UKP\\ JRKPLONOOPOVPWSWUVWT MONPNTOWPXSXUWWTXRYO",
+ "JZNPPPPONPMQLSLUMWNXPXQWRUSR LUNWPWRU RRRWSXUXWVXTXRWPVOVPWP RUSWUWWV",
+ "KZVOTVTWUXWXXWYU WOUVUWVX USUQSOQOOPNQMSMUNWPXRXTV QOOQNSNVPX",
+ "JXOKMR PKNRNVPX NROPQOSOUPVRVTUVTWRXPXNWMUMR SOUQUTTVRX MKPK",
+ "KXUPUQVQUPSOQOOPNQMSMUNWPXRXTWUV QOOQNSNVPX",
+ "KZWKTVTWUXWXXWYU XKUVUWVX USUQSOQOOPNQMSMUNWPXRXTV QOOQNSNVPX UKXK",
+ "KWNURTTSURUPSOQOOPNQMSMUNWPXRXTWUV QOOQNSNVPX",
+ "MXWKXLXKVKTLSNPYO[N\\ VKULTNQYP[N\\L\\L[M\\ POVO",
+ "KYVOTVSYR[ WOUVTYR[P\\M\\L[M[N\\ USUQSOQOOPNQMSMUNWPXRXTV QOOQNSNVPX",
+ "KZPKLX QKMX OQPPROTOVPVRUUUWVX TOUPURTUTWUXWXXWYU NKQK",
+ "MWSKSLTLTKSK NROPPOROSPSRRURWSX QORPRRQUQWRXTXUWVU",
+ "MWTKTLULUKTK ORPPQOSOTPTRRYQ[O\\M\\M[N\\ ROSPSRQYP[O\\",
+ "KXPKLX QKMX VPUQVQVPUOTORQPROR ORPSQWRXTXUWVU ORQSRWSX NKQK",
+ "NVSKPVPWQXSXTWUU TKQVQWRX QKTK",
+ "F^GRHPIOKOLPLQJX JOKPKQIX LQMPOOQOSPSQQX QORPRQPX SQTPVOXOZPZRYUYWZX XOYPYRXUXWYX[X\\W]U",
+ "J[KRLPMOOOPPPQNX NOOPOQMX PQQPSOUOWPWRVUVWWX UOVPVRUUUWVXXXYWZU",
+ "KXQOOPNQMSMUNWPXRXTWUVVTVRUPSOQO QOOQNSNVPX RXTVUTUQSO",
+ "JYKRLPMOOOPPPQM\\ NOOPOQL\\ PQROTOVPWRWTVVUWSXQXOVOT TOVQVTUVSX J\\O\\",
+ "KYVOR\\ WOS\\ USUQSOQOOPNQMSMUNWPXRXTV QOOQNSNVPX P\\U\\",
+ "LXMRNPOOQORPRQPX POQPQQOX RQSPUOVOWPWQVQWP",
+ "LYVPVQWQVPTOQOOPORQSTTVU OQQRTSVTVWTXQXOWNVOVOW",
+ "NWSKPVPWQXSXTWUU TKQVQWRX POUO",
+ "IZJRKPLONOOPORNUNWOX MONPNRMUMWOXQXSWTV VOTVTWUXWXXWYU WOUVUWVX",
+ "JXKRLPMOOOPPPROUOWPX NOOPORNUNWPXQXSWUUVRVOUOVP",
+ "H\\IRJPKOMONPNRMUMWNX LOMPMRLULWNXOXQWRV TORVRWTX UOSVSWTXUXWWYUZRZOYOZP",
+ "JZMRNPPOROSPSR QORPRRQUPWNXMXLWLVMVLW XPWQXQXPWOVOTPSRRURWSX QUQWRXTXVWWU",
+ "IYJRKPLONOOPORNUNWOX MONPNRMUMWOXQXSWTV VOTVSYR[ WOUVTYR[P\\M\\L[M[N\\",
+ "KYWOWPVQNVMWMX NQOOROUQ OPRPUQVQ NVOVRWUW OVRXUXVV",
+ "H[RKSLSMTMTLRKOKMLLNLX OKNLMNMX XKYLYMZMZLXKVKTMTX VKUMUX JOWO JXOX RXWX",
+ "J[UKVLWLWKQKOLNNNX QKPLONOX VOVX WOWX LOWO LXQX TXYX",
+ "J[WKQKOLNNNX QKPLONOX UKVLVX WKWX LOVO LXQX TXYX",
+ "F_PKQLQMRMRLPKMKKLJNJX MKLLKNKX YKZL[L[KUKSLRNRX UKTLSNSX ZOZX [O[X HO[O HXMX PXUX XX]X",
+ "F_PKQLQMRMRLPKMKKLJNJX MKLLKNKX [KUKSLRNRX UKTLSNSX YKZLZX [K[X HOZO HXMX PXUX XX]X",
+ "NWRORX SOSX POSO PXUX",
+ "",
+ "LXVPTOROPPOQNSNUOWQXSXUW ROPQOSOVQX OSSS",
+ "LYSKQLPMOONRNUOWPXRXTWUVVTWQWNVLUKSK SKQMPOOSOVPX RXTVUTVPVMUK OQVQ",
+ "KZTKQ\\ UKP\\ QONPMRMUNWQXTXWWXUXRWPTOQO QOOPNRNUOWQX TXVWWUWRVPTO",
+ "LXUPVRVQUPSOQOOPNRNTOVRX QOOQOTPVRXSYS[R\\P\\",
+ "",
+ "",
+ "",
+ "I[VKWLXLVKSKQLPMOOLYK[J\\ SKQMPOMYL[J\\H\\H[I\\ ZK[L[KYKWLVNSYR[Q\\ YKXLWNTYS[Q\\O\\O[P\\ LOYO",
+ "IZVKWLXLXKSKQLPMOOLYK[J\\ SKQMPOMYL[J\\H\\H[I\\ VOTVTWUXWXXWYU WOUVUWVX LOWO",
+ "IZVKWL XKSKQLPMOOLYK[J\\ SKQMPOMYL[J\\H\\H[I\\ WKTVTWUXWXXWYU XKUVUWVX LOVO",
+ "F^SKTLTM ULSKPKNLMMLOIYH[G\\ PKNMMOJYI[G\\E\\E[F\\ ZK[L\\L\\KWKUL TMSOPYO[N\\ WKUMTOQYP[N\\L\\L[M\\ ZOXVXWYX[X\\W]U [OYVYWZX IO[O",
+ "F^SKTLTM ULSKPKNLMMLOIYH[G\\ PKNMMOJYI[G\\E\\E[F\\ ZK[L \\KWKUL TMSOPYO[N\\ WKUMTOQYP[N\\L\\L[M\\ [KXVXWYX[X\\W]U \\KYVYWZX IOZO",
+ "MWNROPPOROSPSRRURWSX QORPRRQUQWRXTXUWVU",
+ "",
+ "OU",
+ "LX",
+ "LYQKOLNONTOWQXTXVWWTWOVLTKQK QKPLOOOTPWQX TXUWVTVOULTK",
+ "LYPNSKSX RLRX OXVX",
+ "LYOMONNNNMOLQKTKVLWNVPTQQROSNUNX TKULVNUPTQ NWOVPVSWVWWV PVSXVXWVWU",
+ "LYOMONNNNMOLQKTKVLWNVPTQ TKULVNUPTQ RQTQVRWTWUVWTXQXOWNVNUOUOV TQURVTVUUWTX",
+ "LYSMSX TKTX TKMTXT QXVX",
+ "LYOKNQ OKVK OLSLVK NQOPQOTOVPWRWUVWTXQXOWNVNUOUOV TOUPVRVUUWTX",
+ "LYVMVNWNWMVLTKRKPLOMNPNUOWQXTXVWWUWSVQTPQPNR RKPMOPOUPWQX TXUWVUVSUQTP",
+ "LYNKNO VMRTPX WKTQQX NMPKRKUM NMPLRLUMVM",
+ "LYQKOLNNOPQQTQVPWNVLTKQK QKPLONPPQQ TQUPVNULTK QQORNTNUOWQXTXVWWUWTVRTQ QQPROTOUPWQX TXUWVUVTURTQ",
+ "LYOVOUNUNVOWQXSXUWVVWSWNVLTKQKOLNNNPORQSTSWQ SXUVVSVNULTK QKPLONOPPRQS",
+ "NVRVQWRXSWRV",
+ "NVSWRXQWRVSWSYQ[",
+ "NVROQPRQSPRO RVQWRXSWRV",
+ "NVROQPRQSPRO SWRXQWRVSWSYQ[",
+ "NVRKQLRSSLRK RLRO RVQWRXSWRV",
+ "LYNNONOONONNOLQKTKVLWNWOVQSRRSRTST TKVMVPUQSR RWRXSXSWRW",
+ "OVRKRP SKRP",
+ "LXOKOP PKOP UKUP VKUP",
+ "MWQKPLPNQOSOTNTLSKQK",
+ "MWRJRP OKUO UKOO",
+ "KZXHM\\",
+ "MWUHSJQMPPPTQWSZU\\ SJRLQPQTRXSZ",
+ "MWOHQJSMTPTTSWQZO\\ QJRLSPSTRXQZ",
+ "MWPHP\\ QHQ\\ PHUH P\\U\\",
+ "MWSHS\\ THT\\ OHTH O\\T\\",
+ "LWSHRIQKQMRORPPRRTRUQWQYR[S\\ RIQM QKRO RUQY QWR[",
+ "MXQHRISKSMRORPTRRTRUSWSYR[Q\\ RISM SKRO RUSY SWR[",
+ "MWTHPRT\\",
+ "MWPHTRP\\",
+ "OURHR\\",
+ "MWPHP\\ THT\\",
+ "I[LRXR",
+ "I[RLRX LRXR",
+ "JZRMRX MRWR MXWX",
+ "JZRMRX MMWM MRWR",
+ "JZMMWW WMMW",
+ "NVRQQRRSSRRQ",
+ "I[RLQMRNSMRL LRXR RVQWRXSWRV",
+ "I[LPXP LTXT",
+ "I[WLMX LPXP LTXT",
+ "I[LNXN LRXR LVXV",
+ "JZWLMRWX",
+ "JZMLWRMX",
+ "JZWKMOWS MTWT MXWX",
+ "JZMKWOMS MTWT MXWX",
+ "H[YUWUUTTSRPQOONNNLOKQKRLTNUOUQTRSTPUOWNYN",
+ "JZLTLRMPOPUSWSXR LRMQOQUTWTXRXP",
+ "JZMSRPWS MSRQWS",
+ "NVSKPO SKTLPO",
+ "NVQKTO QKPLTO",
+ "LXNKOMQNSNUMVK NKONQOSOUNVK",
+ "NVSLRMQLRKSLSNQP",
+ "NVSKQMQORPSORNQO",
+ "NVQLRMSLRKQLQNSP",
+ "NVQKSMSORPQORNSO",
+ "",
+ "JZWMQMONNOMQMSNUOVQWWW",
+ "JZMMMSNUOVQWSWUVVUWSWM",
+ "JZMMSMUNVOWQWSVUUVSWMW",
+ "JZMWMQNOONQMSMUNVOWQWW",
+ "JZWMQMONNOMQMSNUOVQWWW MRUR",
+ "I[TOUPXRUTTU UPWRUT LRWR",
+ "MWRMRX OPPORLTOUP PORMTO",
+ "I[POOPLROTPU OPMROT MRXR",
+ "MWRLRW OTPURXTUUT PURWTU",
+ "KYVSUPSOQOOPNQMSMUNWPXRXTWUVVTWQWNVLTKQKPLQLRK QOOQNSNVPX RXTVUTVQVNULTK",
+ "JZLKRX MKRV XKRX LKXK NLWL",
+ "G[IOLORW KORX [FRX",
+ "I[XIXJYJYIXHVHTJSLROQUPYO[ UITKSORUQXPZN\\L\\K[KZLZL[",
+ "I[XIXJYJYIXHVHTJSLROQUPYO[ UITKSORUQXPZN\\L\\K[KZLZL[ QNOONQNSOUQVSVUUVSVQUOSNQN",
+ "H\\ZRYTWUVUTTSSQPPONNMNKOJQJRKTMUNUPTQSSPTOVNWNYOZQZR",
+ "JZXKLX OKPLPNOOMOLNLLMKOKSLVLXK UTTUTWUXWXXWXUWTUT",
+ "J[YPXPXQYQYPXOWOVPUTTVSWQXOXMWLVLTMSORRPSNSLRKPKOLONPQUWWXXXYW OXMVMTOR ONPPVWWX",
+ "J[UPSOQOPQPRQTSTUS UOUSVTXTYRYQXNVLSKRKOLMNLQLRMUOWRXSXVW",
+ "KZQHQ\\ THT\\ WLVLVMWMWLUKPKNLNNOPVSWT NNOOVRWTWVVWTXQXOWNVNUOUOVNV",
+ "KYPKP[ TKT[ MQWQ MUWU",
+ "LXTLSLSMTMTLSKQKPLPNQPTRUS PNQOTQUSUUSW QPOROTPVSXTY OTPUSWTYT[S\\Q\\P[PZQZQ[P[",
+ "LXRKQLRMSLRK RMRQ RQQSRVSSRQ RVR\\ POONNOOPPOTOUNVOUPTO",
+ "LXRMSLRKQLRMRQQRSURV RQSRQURVRZQ[R\\S[RZ POONNOOPPOTOUNVOUPTO PXOWNXOYPXTXUWVXUYTX",
+ "LYVKVX NKVK QQVQ NXVX",
+ "",
+ "H\\QKNLLNKQKSLVNXQYSYVXXVYSYQXNVLSKQK RQQRRSSRRQ",
+ "LYQKPLPMQN TKULUMTN RNPOOQORPTRUSUUTVRVQUOSNRN RURY SUSY OWVW",
+ "LYRKPLONOOPQRRSRUQVOVNULSKRK RRRX SRSX OUVU",
+ "H\\QKNLLNKQKSLVNXQYSYVXXVYSYQXNVLSKQK RKRY KRYR",
+ "JYRRPQOQMRLTLUMWOXPXRWSUSTRR WMRR RMWMWR RMVNWR",
+ "JZLLMKOKQLRNRPQRPSNT OKPLQNQQPS VKUX WKTX NTXT",
+ "JYNKNU OKNR NROPQOSOUPVQVTTVTXUYVYWX SOUQUTTV LKOK",
+ "LYONRKRQ VNSKSQ RQPROTOUPWRXSXUWVUVTURSQ RTRUSUSTRT",
+ "JZRKRY MKMPNRPSTSVRWPWK LMMKNM QMRKSM VMWKXM OVUV",
+ "JYNKNX OKOX LKSKVLWNWOVQSROR SKULVNVOUQSR LXVXVUUX",
+ "LYWKTKQLONNQNSOVQXTYWY WKTLRNQQQSRVTXWY",
+ "JZRRPQOQMRLTLUMWOXPXRWSUSTRR SLQQ WMRR XQSS",
+ "KYPMTW TMPW MPWT WPMT",
+ "J[OUMULVLXMYOYPXPVNTMRMONMOLQKTKVLWMXOXRWTUVUXVYXYYXYVXUVU NMPLULWM",
+ "J[OOMOLNLLMKOKPLPNNPMRMUNWOXQYTYVXWWXUXRWPUNULVKXKYLYNXOVO NWPXUXWW",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "F^KHK\\ LHL\\ XHX\\ YHY\\ HH\\H H\\O\\ U\\\\\\",
+ "H]KHRQJ\\ JHQQ JHYHZMXH K[X[ J\\Y\\ZWX\\",
+ "KYVBTDRGPKOPOTPYR]T`Vb TDRHQKPPPTQYR\\T`",
+ "KYNBPDRGTKUPUTTYR]P`Nb PDRHSKTPTTSYR\\P`",
+ "KYOBOb PBPb OBVB ObVb",
+ "KYTBTb UBUb NBUB NbUb",
+ "JYTBQEPHPJQMSOSPORSTSUQWPZP\\Q_Tb RDQGQKRN RVQYQ]R`",
+ "KZPBSETHTJSMQOQPURQTQUSWTZT\\S_Pb RDSGSKRN RVSYS]R`",
+ "KYU@RCPFOIOLPOSVTYT\\S_Ra RCQEPHPKQNTUUXU[T^RaOd",
+ "KYO@RCTFUIULTOQVPYP\\Q_Ra RCSETHTKSNPUOXO[P^RaUd",
+ "AXCRGRR` GSRa FSRb X:Rb",
+ "F^[CZD[E\\D\\C[BYBWCUETGSJRNPZO^N` VDUFTJRVQZP]O_MaKbIbHaH`I_J`Ia",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "H\\RFK[ RFY[ RIX[ MUVU I[O[ U[[[",
+ "G]LFL[ MFM[ IFUFXGYHZJZLYNXOUP UFWGXHYJYLXNWOUP MPUPXQYRZTZWYYXZU[I[ UPWQXRYTYWXYWZU[",
+ "G\\XIYLYFXIVGSFQFNGLIKKJNJSKVLXNZQ[S[VZXXYV QFOGMILKKNKSLVMXOZQ[",
+ "G]LFL[ MFM[ IFSFVGXIYKZNZSYVXXVZS[I[ SFUGWIXKYNYSXVWXUZS[",
+ "G\\LFL[ MFM[ SLST IFYFYLXF MPSP I[Y[YUX[",
+ "G[LFL[ MFM[ SLST IFYFYLXF MPSP I[P[",
+ "G^XIYLYFXIVGSFQFNGLIKKJNJSKVLXNZQ[S[VZXX QFOGMILKKNKSLVMXOZQ[ XSX[ YSY[ US\\S",
+ "F^KFK[ LFL[ XFX[ YFY[ HFOF UF\\F LPXP H[O[ U[\\[",
+ "MXRFR[ SFS[ OFVF O[V[",
+ "KZUFUWTZR[P[NZMXMVNUOVNW TFTWSZR[ QFXF",
+ "F\\KFK[ LFL[ YFLS QOY[ POX[ HFOF UF[F H[O[ U[[[",
+ "I[NFN[ OFO[ KFRF K[Z[ZUY[",
+ "F_KFK[ LFRX KFR[ YFR[ YFY[ ZFZ[ HFLF YF]F H[N[ V[][",
+ "G^LFL[ MFYY MHY[ YFY[ IFMF VF\\F I[O[",
+ "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF QFOGMILKKOKRLVMXOZQ[ S[UZWXXVYRYOXKWIUGSF",
+ "G]LFL[ MFM[ IFUFXGYHZJZMYOXPUQMQ UFWGXHYJYMXOWPUQ I[P[",
+ "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF QFOGMILKKOKRLVMXOZQ[ S[UZWXXVYRYOXKWIUGSF NYNXOVQURUTVUXV_W`Y`Z^Z] UXV\\W^X_Y_Z^",
+ "G]LFL[ MFM[ IFUFXGYHZJZLYNXOUPMP UFWGXHYJYLXNWOUP I[P[ RPTQURXYYZZZ[Y TQUSWZX[Z[[Y[X",
+ "H\\XIYFYLXIVGSFPFMGKIKKLMMNOOUQWRYT KKMMONUPWQXRYTYXWZT[Q[NZLXKUK[LX",
+ "I\\RFR[ SFS[ LFKLKFZFZLYF O[V[",
+ "F^KFKULXNZQ[S[VZXXYUYF LFLUMXOZQ[ HFOF VF\\F",
+ "H\\KFR[ LFRX YFR[ IFOF UF[F",
+ "F^JFN[ KFNV RFN[ RFV[ SFVV ZFV[ GFNF WF]F",
+ "H\\KFX[ LFY[ YFK[ IFOF UF[F I[O[ U[[[",
+ "H]KFRQR[ LFSQS[ ZFSQ IFOF VF\\F O[V[",
+ "H\\XFK[ YFL[ LFKLKFYF K[Y[YUX[",
+ "H\\RFK[ RFY[ RIX[ MUVU I[O[ U[[[",
+ "G]LFL[ MFM[ IFUFXGYHZJZLYNXOUP UFWGXHYJYLXNWOUP MPUPXQYRZTZWYYXZU[I[ UPWQXRYTYWXYWZU[",
+ "I[NFN[ OFO[ KFZFZLYF K[R[",
+ "H\\RFJ[ RFZ[ RIY[ KZYZ J[Z[",
+ "G\\LFL[ MFM[ SLST IFYFYLXF MPSP I[Y[YUX[",
+ "H\\XFK[ YFL[ LFKLKFYF K[Y[YUX[",
+ "F^KFK[ LFL[ XFX[ YFY[ HFOF UF\\F LPXP H[O[ U[\\[",
+ "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF QFOGMILKKOKRLVMXOZQ[ S[UZWXXVYRYOXKWIUGSF OMOT UMUT OPUP OQUQ",
+ "MXRFR[ SFS[ OFVF O[V[",
+ "F\\KFK[ LFL[ YFLS QOY[ POX[ HFOF UF[F H[O[ U[[[",
+ "H\\RFK[ RFY[ RIX[ I[O[ U[[[",
+ "F_KFK[ LFRX KFR[ YFR[ YFY[ ZFZ[ HFLF YF]F H[N[ V[][",
+ "G^LFL[ MFYY MHY[ YFY[ IFMF VF\\F I[O[",
+ "G]KEJJ ZEYJ ONNS VNUS KWJ\\ ZWY\\ KGYG KHYH OPUP OQUQ KYYY KZYZ",
+ "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF QFOGMILKKOKRLVMXOZQ[ S[UZWXXVYRYOXKWIUGSF",
+ "F^KFK[ LFL[ XFX[ YFY[ HF\\F H[O[ U[\\[",
+ "G]LFL[ MFM[ IFUFXGYHZJZMYOXPUQMQ UFWGXHYJYMXOWPUQ I[P[",
+ "H]KFRPJ[ JFQP JFYFZLXF KZXZ J[Y[ZUX[",
+ "I\\RFR[ SFS[ LFKLKFZFZLYF O[V[",
+ "I\\KKKILGMFOFPGQIRMR[ KIMGOGQI ZKZIYGXFVFUGTISMS[ ZIXGVGTI O[V[",
+ "H]RFR[ SFS[ PKMLLMKOKRLTMUPVUVXUYTZRZOYMXLUKPK PKNLMMLOLRMTNUPV UVWUXTYRYOXMWLUK OFVF O[V[",
+ "H\\KFX[ LFY[ YFK[ IFOF UF[F I[O[ U[[[",
+ "G^RFR[ SFS[ IMJLLMMQNSOTQU JLKMLQMSNTQUTUWTXSYQZM[L TUVTWSXQYM[L\\M OFVF O[V[",
+ "G]JXK[O[MWKSJPJLKIMGPFTFWGYIZLZPYSWWU[Y[ZX MWLTKPKLLINGPF TFVGXIYLYPXTWW KZNZ VZYZ",
+ "H\\UFH[ UFV[ THU[ LUUU F[L[ R[X[",
+ "F^OFI[ PFJ[ LFWFZG[I[KZNYOVP WFYGZIZKYNXOVP MPVPXQYSYUXXVZR[F[ VPWQXSXUWXUZR[",
+ "H]ZH[H\\F[L[JZHYGWFTFQGOIMLLOKSKVLYMZP[S[UZWXXV TFRGPINLMOLSLVMYNZP[",
+ "F]OFI[ PFJ[ LFUFXGYHZKZOYSWWUYSZO[F[ UFWGXHYKYOXSVWTYRZO[",
+ "F]OFI[ PFJ[ TLRT LF[FZLZF MPSP F[U[WVT[",
+ "F\\OFI[ PFJ[ TLRT LF[FZLZF MPSP F[M[",
+ "H^ZH[H\\F[L[JZHYGWFTFQGOIMLLOKSKVLYMZP[R[UZWXYT TFRGPINLMOLSLVMYNZP[ R[TZVXXT UT\\T",
+ "E_NFH[ OFI[ [FU[ \\FV[ KFRF XF_F LPXP E[L[ R[Y[",
+ "LYUFO[ VFP[ RFYF L[S[",
+ "I[XFSWRYQZO[M[KZJXJVKULVKW WFRWQYO[ TF[F",
+ "F]OFI[ PFJ[ ]FLS SOW[ ROV[ LFSF YF_F F[M[ S[Y[",
+ "H\\QFK[ RFL[ NFUF H[W[YUV[",
+ "E`NFH[ NFO[ OFPY \\FO[ \\FV[ ]FW[ KFOF \\F`F E[K[ S[Z[",
+ "F_OFI[ OFVX OIV[ \\FV[ LFOF YF_F F[L[",
+ "G]SFPGNILLKOJSJVKYLZN[Q[TZVXXUYRZNZKYHXGVFSF SFQGOIMLLOKSKVLYN[ Q[SZUXWUXRYNYKXHVF",
+ "F]OFI[ PFJ[ LFXF[G\\I\\K[NYPUQMQ XFZG[I[KZNXPUQ F[M[",
+ "G]SFPGNILLKOJSJVKYLZN[Q[TZVXXUYRZNZKYHXGVFSF SFQGOIMLLOKSKVLYN[ Q[SZUXWUXRYNYKXHVF LYLXMVOUPURVSXS_T`V`W^W] SXT^U_V_W^",
+ "F^OFI[ PFJ[ LFWFZG[I[KZNYOVPMP WFYGZIZKYNXOVP RPTQURVZW[Y[ZYZX URWYXZYZZY F[M[",
+ "G^ZH[H\\F[L[JZHYGVFRFOGMIMKNMONVRXT MKOMVQWRXTXWWYVZS[O[LZKYJWJUI[JYKY",
+ "H]UFO[ VFP[ OFLLNF]F\\L\\F L[S[",
+ "F_NFKQJUJXKZN[R[UZWXXU\\F OFLQKUKXLZN[ KFRF YF_F",
+ "H\\NFO[ OFPY \\FO[ LFRF XF^F",
+ "E_MFK[ NFLY UFK[ UFS[ VFTY ]FS[ JFQF ZF`F",
+ "G]NFU[ OFV[ \\FH[ LFRF XF^F F[L[ R[X[",
+ "H]NFRPO[ OFSPP[ ]FSP LFRF YF_F L[S[",
+ "G][FH[ \\FI[ OFLLNF\\F H[V[XUU[",
+ "H\\KILKXWYYY[ LLXX KIKKLMXYY[ PPLTKVKXLZK[ KVMZ LTLVMXMZK[ SSXN VIVLWNYNYLWKVI VIWLYN",
+ "H\\QIK[ SIY[ RIX[ MUVU I[O[ U[[[ QBOCNENGOIQJSJUIVGVEUCSBQB",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "G]IB[b",
+ "F^RJIZ RJ[Z",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "I]NONPMPMONNPMTMVNWOXQXXYZZ[ WOWXXZZ[[[ WQVRPSMTLVLXMZP[S[UZWX PSNTMVMXNZP[",
+ "G\\LFL[ MFM[ MPONQMSMVNXPYSYUXXVZS[Q[OZMX SMUNWPXSXUWXUZS[ IFMF",
+ "H[WPVQWRXQXPVNTMQMNNLPKSKULXNZQ[S[VZXX QMONMPLSLUMXOZQ[",
+ "H]WFW[ XFX[ WPUNSMQMNNLPKSKULXNZQ[S[UZWX QMONMPLSLUMXOZQ[ TFXF W[[[",
+ "H[LSXSXQWOVNTMQMNNLPKSKULXNZQ[S[VZXX WSWPVN QMONMPLSLUMXOZQ[",
+ "KXUGTHUIVHVGUFSFQGPIP[ SFRGQIQ[ MMUM M[T[",
+ "I\\QMONNOMQMSNUOVQWSWUVVUWSWQVOUNSMQM ONNPNTOV UVVTVPUN VOWNYMYNWN NUMVLXLYM[P\\U\\X]Y^ LYMZP[U[X\\Y^Y_XaUbObLaK_K^L\\O[",
+ "G]LFL[ MFM[ MPONRMTMWNXPX[ TMVNWPW[ IFMF I[P[ T[[[",
+ "MXRFQGRHSGRF RMR[ SMS[ OMSM O[V[",
+ "MXSFRGSHTGSF TMT_SaQbObNaN`O_P`Oa SMS_RaQb PMTM",
+ "G\\LFL[ MFM[ WMMW RSX[ QSW[ IFMF TMZM I[P[ T[Z[",
+ "MXRFR[ SFS[ OFSF O[V[",
+ "BcGMG[ HMH[ HPJNMMOMRNSPS[ OMQNRPR[ SPUNXMZM]N^P^[ ZM\\N]P][ DMHM D[K[ O[V[ Z[a[",
+ "G]LML[ MMM[ MPONRMTMWNXPX[ TMVNWPW[ IMMM I[P[ T[[[",
+ "H\\QMNNLPKSKULXNZQ[S[VZXXYUYSXPVNSMQM QMONMPLSLUMXOZQ[ S[UZWXXUXSWPUNSM",
+ "G\\LMLb MMMb MPONQMSMVNXPYSYUXXVZS[Q[OZMX SMUNWPXSXUWXUZS[ IMMM IbPb",
+ "H\\WMWb XMXb WPUNSMQMNNLPKSKULXNZQ[S[UZWX QMONMPLSLUMXOZQ[ Tb[b",
+ "IZNMN[ OMO[ OSPPRNTMWMXNXOWPVOWN KMOM K[R[",
+ "J[WOXMXQWOVNTMPMNNMOMQNRPSUUWVXW MPNQPRUTWUXVXYWZU[Q[OZNYMWM[NY",
+ "KZPFPWQZS[U[WZXX QFQWRZS[ MMUM",
+ "G]LMLXMZP[R[UZWX MMMXNZP[ WMW[ XMX[ IMMM TMXM W[[[",
+ "I[LMR[ MMRY XMR[ JMPM TMZM",
+ "F^JMN[ KMNX RMN[ RMV[ SMVX ZMV[ GMNM WM]M",
+ "H\\LMW[ MMX[ XML[ JMPM TMZM J[P[ T[Z[",
+ "H[LMR[ MMRY XMR[P_NaLbKbJaK`La JMPM TMZM",
+ "I[WML[ XMM[ MMLQLMXM L[X[XWW[",
+ "G^QMNNLPKRJUJXKZN[P[RZUWWTYPZM QMONMPLRKUKXLZN[ QMSMUNVPXXYZZ[ SMTNUPWXXZZ[[[",
+ "G\\TFQGOIMMLPKTJZIb TFRGPINMMPLTKZJb TFVFXGYHYKXMWNTOPO VFXHXKWMVNTO POTPVRWTWWVYUZR[P[NZMYLV POSPURVTVWUYTZR[",
+ "H\\IPKNMMOMQNROSRSVRZOb JOLNPNRO ZMYPXRSYP^Nb YMXPWRSY",
+ "I\\VNTMRMONMQLTLWMYNZP[R[UZWWXTXQWOSJRHRFSEUEWFYH RMPNNQMTMXNZ R[TZVWWTWPVNTKSISGTFVFYH",
+ "I[XPVNTMPMNNNPPRSS PMONOPQRSS SSNTLVLXMZP[S[UZWX SSOTMVMXNZP[",
+ "I[TFRGQHQIRJUKZKZJWKSMPOMRLULWMYP[S]T_TaSbQbPa ULQONRMUMWNYP[",
+ "G]HQIOKMNMONOPNTL[ MMNNNPMTK[ NTPPRNTMVMXNYOYRXWUb VMXOXRWWTb",
+ "F]GQHOJMMMNNNPMUMXNZO[ LMMNMPLULXMZO[Q[SZUXWUXRYMYIXGVFTFRHRJSMUPWRZT SZUWVUWRXMXIWGVF",
+ "LXRMPTOXOZP[S[UYVW SMQTPXPZQ[",
+ "H\\NMJ[ OMK[ XMYNZNYMWMUNQROSMS OSQTSZT[ OSPTRZS[U[WZYW",
+ "H\\KFMFOGPHQJWXXZY[ MFOHPJVXWZY[Z[ RMJ[ RMK[",
+ "F]MMGb NMHb MPLVLYN[P[RZTXVU XMUXUZV[Y[[Y\\W YMVXVZW[",
+ "H\\NML[ OMNSMXL[ YMXQVU ZMYPXRVUTWQYOZL[ KMOM",
+ "IZTFRGQHQIRJUKXK UKQLOMNONQPSSTVT UKRLPMOOOQQSST STOUMVLXLZN\\S^T_TaRbPb STPUNVMXMZO\\S^",
+ "I[RMONMQLTLWMYNZP[R[UZWWXTXQWOVNTMRM RMPNNQMTMXNZ R[TZVWWTWPVN",
+ "G]PNL[ PNM[ VNV[ VNW[ IPKNNM[M IPKONN[N",
+ "H[LVMYNZP[R[UZWWXTXQWOVNTMRMONMQLTHb R[TZVWWTWPVN RMPNNQMTIb",
+ "H][MQMNNLQKTKWLYMZO[Q[TZVWWTWQVOUNSM QMONMQLTLXMZ Q[SZUWVTVPUN UN[N",
+ "H\\SNP[ SNQ[ JPLNOMZM JPLOONZN",
+ "H\\IQJOLMOMPNPPNVNYP[ NMONOPMVMYNZP[Q[TZVXXUYRYOXMWNXOYR XUYO",
+ "G]ONMOKQJTJWKYLZN[Q[TZWXYUZRZOXMVMTORSPXMb JWLYNZQZTYWWYU ZOXNVNTPRSPYNb",
+ "I[KMMMONPPU_VaWb MMNNOPT_UaWbYb ZMYOWRM]K`Jb",
+ "F]UFOb VFNb GQHOJMMMNNNPMUMXOZRZTYWVYS LMMNMPLULXMZO[R[TZVXXUYS[M",
+ "F]JQLOONNMLNJQITIWJZK[M[OZQWRT IWJYKZMZOYQW QTQWRZS[U[WZYWZTZQYNXMWNYOZQ QWRYSZUZWYYW",
+ "H]XMVTUXUZV[Y[[Y\\W YMWTVXVZW[ VTVQUNSMQMNNLQKTKWLYMZO[Q[SZUWVT QMONMQLTLXMZ",
+ "H[PFLSLVMYNZ QFMS MSNPPNRMTMVNWOXQXTWWUZR[P[NZMWMS VNWPWTVWTZR[ MFQF",
+ "I[WPWQXQXPWNUMRMONMQLTLWMYNZP[R[UZWW RMPNNQMTMXNZ",
+ "H]ZFVTUXUZV[Y[[Y\\W [FWTVXVZW[ VTVQUNSMQMNNLQKTKWLYMZO[Q[SZUWVT QMONMQLTLXMZ WF[F",
+ "I[MVQUTTWRXPWNUMRMONMQLTLWMYNZP[R[UZWX RMPNNQMTMXNZ",
+ "KZZGYHZI[H[GZFXFVGUHTJSMP[O_Na XFVHUJTNRWQ[P^O`NaLbJbIaI`J_K`Ja OMYM",
+ "H\\YMU[T^RaObLbJaI`I_J^K_J` XMT[S^QaOb VTVQUNSMQMNNLQKTKWLYMZO[Q[SZUWVT QMONMQLTLXMZ",
+ "H]PFJ[ QFK[ MTOPQNSMUMWNXOXQVWVZW[ UMWOWQUWUZV[Y[[Y\\W MFQF",
+ "LYUFTGUHVGUF MQNOPMSMTNTQRWRZS[ RMSNSQQWQZR[U[WYXW",
+ "LYVFUGVHWGVF NQOOQMTMUNUQR[Q^P`OaMbKbJaJ`K_L`Ka SMTNTQQ[P^O`Mb",
+ "H\\PFJ[ QFK[ XNWOXPYOYNXMWMUNQROSMS OSQTSZT[ OSPTRZS[U[WZYW MFQF",
+ "MYUFQTPXPZQ[T[VYWW VFRTQXQZR[ RFVF",
+ "AbBQCOEMHMINIPHTF[ GMHNHPGTE[ HTJPLNNMPMRNSOSQP[ PMRORQO[ RTTPVNXMZM\\N]O]Q[W[Z\\[ ZM\\O\\QZWZZ[[^[`YaW",
+ "F]GQHOJMMMNNNPMTK[ LMMNMPLTJ[ MTOPQNSMUMWNXOXQVWVZW[ UMWOWQUWUZV[Y[[Y\\W",
+ "I[RMONMQLTLWMYNZP[R[UZWWXTXQWOVNTMRM RMPNNQMTMXNZ R[TZVWWTWPVN",
+ "G\\HQIOKMNMONOPNTJb MMNNNPMTIb NTOQQNSMUMWNXOYQYTXWVZS[Q[OZNWNT WNXPXTWWUZS[ FbMb",
+ "H\\XMRb YMSb VTVQUNSMQMNNLQKTKWLYMZO[Q[SZUWVT QMONMQLTLXMZ ObVb",
+ "IZJQKOMMPMQNQPPTN[ OMPNPPOTM[ PTRPTNVMXMYNYOXPWOXN",
+ "J[XOXPYPYOXNUMRMONNONQORVVWW NPOQVUWVWYVZS[P[MZLYLXMXMY",
+ "KYTFPTOXOZP[S[UYVW UFQTPXPZQ[ NMWM",
+ "F]GQHOJMMMNNNQLWLYN[ LMMNMQKWKYLZN[P[RZTXVT XMVTUXUZV[Y[[Y\\W YMWTVXVZW[",
+ "H\\IQJOLMOMPNPQNWNYP[ NMONOQMWMYNZP[Q[TZVXXUYQYMXMYO",
+ "C`DQEOGMJMKNKQIWIYK[ IMJNJQHWHYIZK[M[OZQXRV TMRVRYSZU[W[YZ[X\\V]R]M\\M]O UMSVSYU[",
+ "H\\KQMNOMRMSOSR QMRORRQVPXNZL[K[JZJYKXLYKZ QVQYR[U[WZYW YNXOYPZOZNYMXMVNTPSRRVRYS[",
+ "G\\HQIOKMNMONOQMWMYO[ MMNNNQLWLYMZO[Q[SZUXWT ZMV[U^SaPbMbKaJ`J_K^L_K` YMU[T^RaPb",
+ "H\\YMXOVQNWLYK[ LQMOOMRMVO MOONRNVOXO LYNYRZUZWY NYR[U[WYXW",
+ "G^VGUHVIWHWGUFRFOGMILLL[ RFPGNIMLM[ \\G[H\\I]H]G\\FZFXGWIW[ ZFYGXIX[ IM[M I[P[ T[[[",
+ "G]WGVHWIXHWGUFRFOGMILLL[ RFPGNIMLM[ WMW[ XMX[ IMXM I[P[ T[[[",
+ "G]VGUHVIWHWGUF XFRFOGMILLL[ RFPGNIMLM[ WHW[ XFX[ IMWM I[P[ T[[[",
+ "BcRGQHRISHRGPFMFJGHIGLG[ MFKGIIHLH[ ]G\\H]I^H]G[FXFUGSIRLR[ XFVGTISLS[ ]M][ ^M^[ DM^M D[K[ O[V[ Z[a[",
+ "BcRGQHRISHRGPFMFJGHIGLG[ MFKGIIHLH[ \\G[H\\I]H]G[F ^FXFUGSIRLR[ XFVGTISLS[ ]H][ ^F^[ DM]M D[K[ O[V[ Z[a[",
+ "MXRMR[ SMS[ OMSM O[V[",
+ "",
+ "IZWNUMRMONMPLSLVMYNZQ[T[VZ RMPNNPMSMVNYOZQ[ MTUT",
+ "I\\TFQGOJNLMOLTLXMZO[Q[TZVWWUXRYMYIXGVFTF TFRGPJOLNOMTMXNZO[ Q[SZUWVUWRXMXIWGVF NPWP",
+ "G]UFOb VFNb QMMNKPJSJVKXMZP[S[WZYXZUZRYPWNTMQM QMNNLPKSKVLXNZP[ S[VZXXYUYRXPVNTM",
+ "I[TMVNXPXOWNTMQMNNMOLQLSMUOWSZ QMONNOMQMSNUSZT\\T^S_Q_",
+ "",
+ "",
+ "G]LMKNJPJRKUOYP[ JRKTOXP[P]O`MbLbKaJ_J\\KXMTOQRNTMVMYNZPZTYXWZU[T[SZSXTWUXTY VMXNYPYTXXWZ",
+ "E_YGXHYIZHYGWFTFQGOINKMNLRJ[I_Ha TFRGPIOKNNLWK[J^I`HaFbDbCaC`D_E`Da _G^H_I`H`G_F]F[GZHYJXMU[T_Sa ]F[HZJYNWWV[U^T`SaQbObNaN`O_P`Oa IM^M",
+ "F^[GZH[I\\H[GXFUFRGPIOKNNMRK[J_Ia UFSGQIPKONMWL[K^J`IaGbEbDaD`E_F`Ea YMWTVXVZW[Z[\\Y]W ZMXTWXWZX[ JMZM",
+ "F^YGXHYIZHZGXF \\FUFRGPIOKNNMRK[J_Ia UFSGQIPKONMWL[K^J`IaGbEbDaD`E_F`Ea [FWTVXVZW[Z[\\Y]W \\FXTWXWZX[ JMYM",
+ "@cTGSHTIUHTGRFOFLGJIIKHNGRE[D_Ca OFMGKIJKINGWF[E^D`CaAb?b>a>`?_@`?a `G_H`IaH`G]FZFWGUITKSNRRP[O_Na ZFXGVIUKTNRWQ[P^O`NaLbJbIaI`J_K`Ja ^M\\T[X[Z\\[_[aYbW _M]T\\X\\Z][ DM_M",
+ "@cTGSHTIUHTGRFOFLGJIIKHNGRE[D_Ca OFMGKIJKINGWF[E^D`CaAb?b>a>`?_@`?a ^G]H^I_H_G]F aFZFWGUITKSNRRP[O_Na ZFXGVIUKTNRWQ[P^O`NaLbJbIaI`J_K`Ja `F\\T[X[Z\\[_[aYbW aF]T\\X\\Z][ DM^M",
+ "LYMQNOPMSMTNTQRWRZS[ RMSNSQQWQZR[U[WYXW",
+ "",
+ "NV",
+ "JZ",
+ "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF QFOGNHMJLOLRMWNYOZQ[ S[UZVYWWXRXOWJVHUGSF",
+ "H\\NJPISFS[ RGR[ N[W[",
+ "H\\LJMKLLKKKJLHMGPFTFWGXHYJYLXNUPPRNSLUKXK[ TFVGWHXJXLWNTPPR KYLXNXSZVZXYYX NXS[W[XZYXYV",
+ "H\\LJMKLLKKKJLHMGPFTFWGXIXLWNTOQO TFVGWIWLVNTO TOVPXRYTYWXYWZT[P[MZLYKWKVLUMVLW WQXTXWWYVZT[",
+ "H\\THT[ UFU[ UFJUZU Q[X[",
+ "H\\MFKP KPMNPMSMVNXPYSYUXXVZS[P[MZLYKWKVLUMVLW SMUNWPXSXUWXUZS[ MFWF MGRGWF",
+ "H\\WIVJWKXJXIWGUFRFOGMILKKOKULXNZQ[S[VZXXYUYTXQVOSNRNOOMQLT RFPGNIMKLOLUMXOZQ[ S[UZWXXUXTWQUOSN",
+ "H\\KFKL KJLHNFPFUIWIXHYF LHNGPGUI YFYIXLTQSSRVR[ XLSQRSQVQ[",
+ "H\\PFMGLILLMNPOTOWNXLXIWGTFPF PFNGMIMLNNPO TOVNWLWIVGTF POMPLQKSKWLYMZP[T[WZXYYWYSXQWPTO PONPMQLSLWMYNZP[ T[VZWYXWXSWQVPTO",
+ "H\\XMWPURRSQSNRLPKMKLLINGQFSFVGXIYLYRXVWXUZR[O[MZLXLWMVNWMX QSORMPLMLLMIOGQF SFUGWIXLXRWVVXTZR[",
+ "MWRYQZR[SZRY",
+ "MWR[QZRYSZS\\R^Q_",
+ "MWRMQNROSNRM RYQZR[SZRY",
+ "MWRMQNROSNRM R[QZRYSZS\\R^Q_",
+ "MWRFQHRTSHRF RHRN RYQZR[SZRY",
+ "I[MJNKMLLKLJMHNGPFSFVGWHXJXLWNVORQRT SFUGVHWJWLVNTP RYQZR[SZRY",
+ "NVRFQM SFQM",
+ "JZNFMM OFMM VFUM WFUM",
+ "KYQFOGNINKOMQNSNUMVKVIUGSFQF",
+ "JZRFRR MIWO WIMO",
+ "G][BIb",
+ "KYVBTDRGPKOPOTPYR]T`Vb TDRHQKPPPTQYR\\T`",
+ "KYNBPDRGTKUPUTTYR]P`Nb PDRHSKTPTTSYR\\P`",
+ "KYOBOb PBPb OBVB ObVb",
+ "KYTBTb UBUb NBUB NbUb",
+ "JYTBQEPHPJQMSOSPORSTSUQWPZP\\Q_Tb RDQGQKRN RVQYQ]R`",
+ "KZPBSETHTJSMQOQPURQTQUSWTZT\\S_Pb RDSGSKRN RVSYS]R`",
+ "KYUBNRUb",
+ "KYOBVROb",
+ "NVRBRb",
+ "KYOBOb UBUb",
+ "E_IR[R",
+ "E_RIR[ IR[R",
+ "F^RJR[ JRZR J[Z[",
+ "F^RJR[ JJZJ JRZR",
+ "G]KKYY YKKY",
+ "MWQQQSSSSQQQ RQRS QRSR",
+ "E_RIQJRKSJRI IR[R RYQZR[SZRY",
+ "E_IO[O IU[U",
+ "E_YIK[ IO[O IU[U",
+ "E_IM[M IR[R IW[W",
+ "F^ZIJRZ[",
+ "F^JIZRJ[",
+ "F^ZFJMZT JVZV J[Z[",
+ "F^JFZMJT JVZV J[Z[",
+ "F_[WYWWVUTRPQOONMNKOJQJSKUMVOVQURTUPWNYM[M",
+ "F^IUISJPLONOPPTSVTXTZS[Q ISJQLPNPPQTTVUXUZT[Q[O",
+ "G]JTROZT JTRPZT",
+ "LXTFOL TFUGOL",
+ "LXPFUL PFOGUL",
+ "H\\KFLHNJQKSKVJXHYF KFLINKQLSLVKXIYF",
+ "MWRHQGRFSGSIRKQL",
+ "MWSFRGQIQKRLSKRJ",
+ "MWRHSGRFQGQIRKSL",
+ "MWQFRGSISKRLQKRJ",
+ "E[HMLMRY KMR[ [BR[",
+ "F^ZJSJOKMLKNJQJSKVMXOYSZZZ",
+ "F^JJJQKULWNYQZSZVYXWYUZQZJ",
+ "F^JJQJUKWLYNZQZSYVWXUYQZJZ",
+ "F^JZJSKOLMNKQJSJVKXMYOZSZZ",
+ "F^ZJSJOKMLKNJQJSKVMXOYSZZZ JRVR",
+ "E_XP[RXT UMZRUW IRZR",
+ "JZPLRITL MORJWO RJR[",
+ "E_LPIRLT OMJROW JR[R",
+ "JZPXR[TX MURZWU RIRZ",
+ "I\\XRWOVNTMRMONMQLTLWMYNZP[R[UZWXXUYPYKXHWGUFRFPGOHOIPIPH RMPNNQMTMXNZ R[TZVXWUXPXKWHUF",
+ "H\\JFR[ KFRY ZFR[ JFZF KGYG",
+ "AbDMIMRY HNR[ b:R[",
+ "F^[CZD[E\\D\\C[BYBWCUETGSJRNPZO^N` VDUFTJRVQZP]O_MaKbIbHaH`I_J`Ia",
+ "F^[CZD[E\\D\\C[BYBWCUETGSJRNPZO^N` VDUFTJRVQZP]O_MaKbIbHaH`I_J`Ia QKNLLNKQKSLVNXQYSYVXXVYSYQXNVLSKQK",
+ "F_\\S[UYVWVUUTTQPPONNLNJOIQISJULVNVPUQTTPUOWNYN[O\\Q\\S",
+ "F^[FI[ NFPHPJOLMMKMIKIIJGLFNFPGSHVHYG[F WTUUTWTYV[X[ZZ[X[VYTWT",
+ "F_[NZO[P\\O\\N[MZMYNXPVUTXRZP[M[JZIXIUJSPORMSKSIRGPFNGMIMKNNPQUXWZZ[[[\\Z\\Y M[KZJXJUKSMQ MKNMVXXZZ[",
+ "E`WNVLTKQKOLNMMPMSNUPVSVUUVS QKOMNPNSOUPV WKVSVUXVZV\\T]Q]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYYZX XKWSWUXV",
+ "H\\PBP_ TBT_ XIWJXKYJYIWGTFPFMGKIKKLMMNOOUQWRYT KKMMONUPWQXRYTYXWZT[P[MZKXKWLVMWLX",
+ "G]OFOb UFUb JQZQ JWZW",
+ "JZUITJUKVJVIUGSFQFOGNINKOMQOVR OMTPVRWTWVVXTZ PNNPMRMTNVPXU[ NVSYU[V]V_UaSbQbOaN_N^O]P^O_",
+ "JZRFQHRJSHRF RFRb RQQTRbSTRQ LMNNPMNLLM LMXM TMVNXMVLTM",
+ "JZRFQHRJSHRF RFRT RPQRSVRXQVSRRP RTRb R^Q`RbS`R^ LMNNPMNLLM LMXM TMVNXMVLTM L[N\\P[NZL[ L[X[ T[V\\X[VZT[",
+ "I\\XFX[ KFXF PPXP K[X[",
+ "",
+ "E`QFNGKIILHOHRIUKXNZQ[T[WZZX\\U]R]O\\LZIWGTFQF ROQPQQRRSRTQTPSORO RPRQSQSPRP",
+ "J[PFNGOIQJ PFOGOI UFWGVITJ UFVGVI QJOKNLMNMQNSOTQUTUVTWSXQXNWLVKTJQJ RUR[ SUS[ NXWX",
+ "I\\RFOGMILLLMMPORRSSSVRXPYMYLXIVGSFRF RSR[ SSS[ NWWW",
+ "D`PFMGJIHLGOGSHVJYM[P\\T\\W[ZY\\V]S]O\\LZIWGTFPF RFR\\ GQ]Q",
+ "G`PMMNKPJSJTKWMYPZQZTYVWWTWSVPTNQMPM ]GWG[HUN ]G]M\\IVO \\HVN",
+ "F\\IIJGLFOFQGRIRLQOPQNSKU OFPGQIQMPPNS VFT[ WFS[ KUYU",
+ "I\\MFMU NFMQ MQNOONQMTMWNXPXRWTUV TMVNWPWRTXTZU[W[YY KFNF",
+ "I\\RNOOMQLTLUMXOZR[S[VZXXYUYTXQVOSNRN RHNJRFRN SHWJSFSN RSQTQURVSVTUTTSSRS RTRUSUSTRT",
+ "G^QHRFR[ THSFS[ JHKFKMLPNRQSRS MHLFLNMQ [HZFZMYPWRTSSS XHYFYNXQ NWWW",
+ "G]LFL[ MFM[ IFUFXGYHZJZMYOXPUQMQ UFWGXHYJYMXOWPUQ I[Y[YVX[",
+ "H[YGUGQHNJLMKPKSLVNYQ[U\\Y\\ YGVHSJQMPPPSQVSYV[Y\\",
+ "F_OQMQKRJSIUIWJYKZM[O[QZRYSWSURSQROQ SHPQ ZJRR \\QST",
+ "H\\OKUY UKOY KOYU YOKU",
+ "F^NVLUKUIVHXHYI[K\\L\\N[OYOXNVKRJOJMKJMHPGTGWHYJZMZOYRVVUXUYV[X\\Y\\[[\\Y\\X[VYUXUVV JMKKMIPHTHWIYKZM",
+ "F^NMLNKNIMHKHJIHKGLGNHOJOKNMKQJTJVKYM[P\\T\\W[YYZVZTYQVMUKUJVHXGYG[H\\J\\K[MYNXNVM JVKXMZP[T[WZYXZV",
+ "I[KYYK QLULYKXOXS ULXLXO",
+ "I[YKKY LQLUKYOXSX LULXOX",
+ "I[YYKK SLOLKKLOLS OLLLLO",
+ "I[KKYY QXUXYYXUXQ UXXXXU",
+ "",
+ "F_JMILIJJHLGNGPHQIRKSP IJKHMHOIPJQLRPR[ [M\\L\\J[HYGWGUHTISKRP \\JZHXHVIUJTLSPS[",
+ "F^IGJKKMMOPPTPWOYMZK[G IGJJKLMNPOTOWNYLZJ[G PONPMQLSLVMXOZQ[S[UZWXXVXSWQVPTO PPNQMSMVNY VYWVWSVQTP",
+ "F^MJMV NKNU VKVU WJWV IGKIMJPKTKWJYI[G IYKWMVPUTUWVYW[Y",
+ "F^[ILIJJILINJPLQNQPPQNQLPJ[J IMJOKPMQ QMPKOJMI IXXXZW[U[SZQXPVPTQSSSUTWIW [TZRYQWP STTVUWWX",
+ "F]OUMTLTJUIWIXJZL[M[OZPXPWOUJPINIKJILHOGSGWHYJZLZOYRVUUWUYV[X[YZZX MSKPJNJKKILH SGVHXJYLYOXRVU",
+ "G_HKKHMKMV JILLLV MKPHRKRU OIQLQU RKUHWKW[ TIVLV[ WKZH[J\\M\\P[SZUXWUYP[ YIZJ[M[PZSYUWWTYP[",
+ "F^ISMSLRKOKMLJNHQGSGVHXJYMYOXRWS[S ITOTMRLOLMMJOHQG SGUHWJXMXOWRUT[T KXYX KYYY",
+ "F_GLJIMLMX IJLMLX MLPISLSX OJRMRX SLVIYLYW[Y UJXMXXZZ]W",
+ "G]ZIJY ZIWJQJ XKUKQJ ZIYLYR XKXNYR QRJR PSMSJR QRQY PSPVQY",
+ "F^HOJKOU JMOWRPWPZO[M[KZIXHWHUITKTMUPVRWUWXUZ WHVIUKUMWQXTXWWYUZ",
+ "F^IOLLPN KMOORLUN QMTOWLYN VMXO[L IULRPT KSOURRUT QSTUWRYT VSXU[R",
+ "F^JHNJPLQOQRPUNWJY JHMIOJQLRO RRQUOWMXJY ZHWIUJSLRO RRSUUWWXZY ZHVJTLSOSRTUVWZY IP[P IQ[Q",
+ "",
+ "",
+ "",
+ "",
+ "NVQQQSSSSQQQ QQSS SQQS",
+ "JZMPQRTTVVWYW[V]U^ MQST MRPSTUVWWY",
+ "JZWKVMTOPQMR SPMS UFVGWIWKVNTPQRMT",
+ "H\\SMONLPKRKTLVNWQWUVXTYRYPXNVMSM XNSM VMQNLP ONKR LVQW NWSVXT UVYR",
+ "H\\SMONLPKRKTLVNWQWUVXTYRYPXNVMSM XNSM VMQNLP ONKR LVQW NWSVXT UVYR",
+ "J[SMPNNPMRMTNVPWRWUVWTXRXPWNUMSM OPUM NRVN MTWO NUXP OVWR PWVT",
+ "JZOGO^ UFU] MNWL MOWM MWWU MXWV",
+ "JZNFNX VLV^ NNVL NOVM NWVU NXVV",
+ "JZNBNW NNQLTLVMWOWQVSSUQVNW NNQMTMVN UMVOVQUSSU",
+ "E_HIHL \\I\\L HI\\I HJ\\J HK\\K HL\\L",
+ "JZMNMQ WNWQ MNWN MOWO MPWP MQWQ",
+ "JZMLWX MLONQOTOVNWMWKUKUMTO ONTO QOWM VKVN ULWL WXUVSUPUNVMWMYOYOWPU UVPU SUMW NVNY MXOX",
+ "JZPOOMOKMKMMNNPOSOUNWL NKNN MLOL MMSO POUN WLWY",
+ "A^GfHfIeIdHcGcFdFfGhIiKiNhPfQdR`RUQ;Q4R/S-U,V,X-Y/Y3X6W8U;P?JCHEFHEJDNDREVGYJ[N\\R\\V[XZZW[T[PZMYKWITHPHMIKKJNJRKUMW GdGeHeHdGd U;Q?LCIFGIFKENERFVGXJ[ R\\U[WZYWZTZPYMXKVITH",
+ "EfNSOUQVSVUUVSVQUOSNQNOONPMSMVNYP[S\\V\\Y[[Y\\W]T]P\\MZJXIUHRHOIMJKLIOHSHXI]KaMcPeTfYf]e`cba KLJNIRIXJ\\L`NbQdUeYe]d_cba POTO OPUP NQVQ NRVR NSVS OTUT PUTU aLaNcNcLaL bLbN aMcM aVaXcXcVaV bVbX aWcW",
+ "D`H@Hd M@Md W@Wd \\@\\d MMWK MNWL MOWM MWWU MXWV MYWW",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "NVQQQSSSSQQQ QQSS SQQS",
+ "JZMPQRTTVVWYW[V]U^ MQST MRPSTUVWWY",
+ "JZWKVMTOPQMR SPMS UFVGWIWKVNTPQRMT",
+ "H\\PMMNLOKQKSLUMVPWTWWVXUYSYQXOWNTMPM MNLPLSMUNVPW WVXTXQWOVNTM",
+ "H\\SMONLPKRKTLVNWQWUVXTYRYPXNVMSM XNSM VMQNLP ONKR LVQW NWSVXT UVYR",
+ "J[SMPNNPMRMTNVPWRWUVWTXRXPWNUMSM OPUM NRVN MTWO NUXP OVWR PWVT",
+ "JZOGO^ UFU] MNWL MOWM MWWU MXWV",
+ "JZNFNX VLV^ NNVL NOVM NWVU NXVV",
+ "JZNBNW NNQLTLVMWOWQVSSUQVNW NNQMTMVN UMVOVQUSSU",
+ "E_HIHL \\I\\L HI\\I HJ\\J HK\\K HL\\L",
+ "JZMNMQ WNWQ MNWN MOWO MPWP MQWQ",
+ "JZQCVMRTRU ULQS TITKPRRUUY W\\UYSXQXOYN[N]O_Ra W\\UZSYOYO]P_Ra SXPZN]",
+ "JZPOOMOKMKMMNNPOSOUNWL NKNN MLOL MMSO POUN WLSY",
+ "A^GfHfIeIdHcGcFdFfGhIiKiNhPfQdR`RUQ;Q4R/S-U,V,X-Y/Y3X6W8U;P?JCHEFHEJDNDREVGYJ[N\\R\\V[XZZW[T[PZMYKWITHPHMIKKJNJRKUMW GdGeHeHdGd U;Q?LCIFGIFKENERFVGXJ[ R\\U[WZYWZTZPYMXKVITH",
+ "IjNQOOQNSNUOVQVSUUSVQVOUNTMQMNNKPISHWH[I^K`NaRaW`[_]]`ZcVfQiMk WHZI]K_N`R`W_[^]\\`YcTgQi POTO OPUP NQVQ NRVR NSVS OTUT PUTU eLeNgNgLeL fLfN eMgM eVeXgXgVeV fVfX eWgW",
+ "D`H>Hf I>If M>Mf QBSBSDQDQAR?T>W>Y?[A\\D\\I[LYNWOUOSNRLQNOQNROSQVRXSVUUWUYV[X\\[\\`[cYeWfTfReQcQ`S`SbQb RBRD QCSC Y?ZA[D[IZLYN RLRNPQNRPSRVRX YVZX[[[`ZcYe R`Rb QaSa",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "AcHBHb IBIb [B[b \\B\\b DB`B DbMb Wb`b",
+ "BaGBQPFb FBPP EBPQ EB\\B^I[B Ga\\a Fb\\b^[[b",
+ "I[X+U1R8P=OANFMNMVN^OcPgRlUsXy U1S6Q<P@OFNNNVO^PdQhSnUs",
+ "I[L+O1R8T=UAVFWNWVV^UcTgRlOsLy O1Q6S<T@UFVNVVU^TdShQnOs",
+ "I[M+MRMy N+NRNy M+X+ MyXy",
+ "I[V+VRVy W+WRWy L+W+ LyWy",
+ "H[V+R1P5O:O>PBTJTLSNROMRRUSVTXTZPbOfOjPoRsVy T.R2Q5P:P>QCRF R^QaPfPjQoRrTv",
+ "I\\N+R1T5U:U>TBPJPLQNROWRRUQVPXPZTbUfUjToRsNy P.R2S5T:T>SCRF R^SaTfTjSoRrPv",
+ "I[V.S1Q4O8N=NCOIPMSXT\\UbUgTlSoQs S1Q5P8O=OBPHQLTWU[VaVgUlSpQsNv",
+ "I[N.Q1S4U8V=VCUITMQXP\\ObOgPlQoSs Q1S5T8U=UBTHSLPWO[NaNgOlQpSsVv",
+ "7Z:RARRo @RQo ?RRr Z\"VJRr",
+ "Ca].\\.[/[0\\1]1^0^.],[+Y+W,U.T0S3R:QJQjPsOv \\/\\0]0]/\\/ R:Rj U.T1S:SZRjQqPtOvMxKyIyGxFvFtGsHsItIuHvGv GtGuHuHtGt",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "H\\RFJ[ RIK[J[ RIY[Z[ RFZ[ MUWU LVXV",
+ "H\\LFL[ MGMZ LFTFWGXHYJYMXOWPTQ MGTGWHXJXMWOTP MPTPWQXRYTYWXYWZT[L[ MQTQWRXTXWWYTZMZ",
+ "H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZV ZKYKXIWHUGQGOHMKLNLSMVOYQZUZWYXXYVZV",
+ "H]LFL[ MGMZ LFSFVGXIYKZNZSYVXXVZS[L[ MGSGVHWIXKYNYSXVWXVYSZMZ",
+ "I\\MFM[ NGNZ MFYF NGYGYF NPTPTQ NQTQ NZYZY[ M[Y[",
+ "I[MFM[ NGN[M[ MFYF NGYGYF NPTPTQ NQTQ",
+ "H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZVZRUR ZKYKXIWHUGQGOHNIMKLNLSMVNXOYQZUZWYXXYVYSUSUR",
+ "G]KFK[ KFLFL[K[ YFXFX[Y[ YFY[ LPXP LQXQ",
+ "NWRFR[S[ RFSFS[",
+ "J[VFVVUYSZQZOYNVMV VFWFWVVYUZS[Q[OZNYMV",
+ "H]LFL[M[ LFMFM[ ZFYFMR ZFMS POY[Z[ QOZ[",
+ "IZMFM[ MFNFNZ NZYZY[ M[Y[",
+ "F^JFJ[ KKK[J[ KKR[ JFRX ZFRX YKR[ YKY[Z[ ZFZ[",
+ "G]KFK[ LIL[K[ LIY[ KFXX XFXX XFYFY[",
+ "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF QGNHLKKNKSLVNYQZSZVYXVYSYNXKVHSGQG",
+ "H\\LFL[ MGM[L[ LFUFWGXHYJYMXOWPUQMQ MGUGWHXJXMWOUPMP",
+ "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF QGNHLKKNKSLVNYQZSZVYXVYSYNXKVHSGQG SXX]Y] SXTXY]",
+ "H\\LFL[ MGM[L[ LFTFWGXHYJYMXOWPTQMQ MGTGWHXJXMWOTPMP RQX[Y[ SQY[",
+ "H\\YIWGTFPFMGKIKKLMMNOOTQVRWSXUXXWYTZPZNYMXKX YIWIVHTGPGMHLILKMMONTPVQXSYUYXWZT[P[MZKX",
+ "J[RGR[ SGS[R[ LFYFYG LFLGYG",
+ "G]KFKULXNZQ[S[VZXXYUYF KFLFLUMXNYQZSZVYWXXUXFYF",
+ "H\\JFR[ JFKFRX ZFYFRX ZFR[",
+ "E_GFM[ GFHFMX RFMX RIM[ RIW[ RFWX ]F\\FWX ]FW[",
+ "H\\KFX[Y[ KFLFY[ YFXFK[ YFL[K[",
+ "I\\KFRPR[S[ KFLFSP ZFYFRP ZFSPS[",
+ "H\\XFK[ YFL[ KFYF KFKGXG LZYZY[ K[Y[",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "E\\XFVHTKQPOSLWIZG[E[DZDXEWFXEY XFWJUTT[ XFU[ T[TYSVRTPRNQLQKRKTLWOZR[V[XZ",
+ "F^UGTHSJQOOUNWLZJ[ THSKQSPVOXMZJ[H[GZGXHWIXHY OLNNMOKOJNJLKJMHOGRFXFZG[I[KZMXNTORO XFYGZIZKYMXN TOWPXQYSYVXYWZU[S[RZRXSU TOVPWQXSXVWYU[",
+ "H]KHJJJLKNNOQOUNWMYKZIZGYFWFTGQJOMMQLULXMZP[R[UZWXXVXTWRURSSRU WFUGRJPMNQMUMXNZP[",
+ "F]UGTHSJQOOUNWLZJ[ THSKQSPVOXMZJ[H[GZGXHWJWLXNZP[S[UZWXYTZOZLYIWGUFPFMGKIJKJMKNMNNMOK",
+ "I\\WIVJVLWMYMZKZIYGWFTFRGQHPJPLQNSO TFRHQJQMSO SOQONPLRKTKWLYMZO[R[UZWXXVXTWRURSSRU QOOPMRLTLXMZ",
+ "G\\WHVJTORUQWOZM[ QLPNNOLOKMKKLINGQF[FXGWHVKTSSVRXPZM[K[IZHYHXIWJXIY SFWGXG OSPRRQVQXPZMXT",
+ "G]JIIKIMJOLPOPROTNWKXHXGWFVFTGRIQKPNPQQSSTUTWSYQZO WFUGSIRKQNQRST ZOYSWWUYSZO[L[JZIXIWJVKWJX YSWVUXRZO[",
+ "F^LLKKKILGOFRFOQMWLYKZI[G[FZFXGWHXGY RFOONRLWKYI[ JTKSMRVOXN[L]J^H^G]F\\FZGXJWLURTVTYV[W[YZ[X \\FZHXLVRUVUYV[",
+ "IYWHUKSPQUPWNZL[ YLWNTOQOONNLNJOHQGUFYFWHVJTPRVQXOZL[J[IZIXJWKXJY",
+ "IZYFWHUKSPPYN] YMWOTPQPOONMNKOIQGUFYFWIVKSTQXPZN]M^K_J^J\\KZMXOWRVVU",
+ "F^LLKKKIMGPFRFOQMWLYKZI[G[FZFXGWHXGY RFOONRLWKYI[ ZGWKUMSNPO ]G\\H]I^H^G]F\\FZGWLVMTNPO POSPTRUYV[ PORPSRTYV[W[YZ[X",
+ "I[MILKLMMOOPRPUOWNZK[H[GZFYFWGVHTKPUOWMZK[ VHTLRSQVPXNZK[I[HZHXIWKWMXPZR[U[WZYX",
+ "D`RFNOKUIXGZE[C[BZBXCWDXCY RFPMOQNVNZP[ RFQJPOOVOZP[ [FWORXP[ [FYMXQWVWZY[Z[\\Z^X [FZJYOXVXZY[",
+ "G^RFQJOPMULWJZH[F[EZEXFWGXFY RFRKSVT[ RFSKTVT[ `G_H`IaHaG`F^F\\GZJYLWQUWT[",
+ "H]SFQGOIMLLNKRKVLYMZO[Q[TZVXXUYSZOZKYHXGWGUHSJQNPSPV QGOJMNLRLVMYO[",
+ "F]UGTHSJQOOUNWLZJ[ THSKQSPVOXMZJ[H[GZGXHWIXHY OLNNMOKOJNJLKJMHOGRFVFYGZH[J[MZOYPVQTQRP VFXGYHZJZMYOXPVQ",
+ "H]UJULTNSOQPOPNNNLOIQGTFWFYGZIZMYPWSSWPYNZK[I[HZHXIWKWMXPZS[V[XZZX WFXGYIYMXPVSSVOYK[",
+ "F^UGTHSJQOOUNWLZJ[ THSKQSPVOXMZJ[H[GZGXHWIXHY OLNNMOKOJNJLKJMHOGRFWFZG[I[KZMYNVORO WFYGZIZKYMXNVO ROUPVRWYX[ ROTPURVYX[Y[[Z]X",
+ "H\\NIMKMMNOPPSPVOXN[K\\H\\G[FZFXGWHVJUMSTRWPZN[ VJUNTUSXQZN[K[IZHXHWIVJWIX",
+ "I[YHXJVOTUSWQZO[ SLRNPONOMMMKNIPGSF\\FZGYHXKVSUVTXRZO[M[KZJYJXKWLXKY UFYGZG",
+ "G]HJJGLFMFOHOKNNKVKYL[ MFNHNKKSJVJYL[N[PZSWUTVR ZFVRUVUYW[X[ZZ\\X [FWRVVVYW[",
+ "G\\HJJGLFMFOHOKNOLVLYM[ MFNHNKLRKVKYM[N[QZTWVTXPYMZIZGYFXFWGVIVLWNYP[Q]Q",
+ "F]ILHLGKGIHGJFNFMHLLKUJ[ LLLUK[ VFTHRLOUMYK[ VFUHTLSUR[ TLTUS[ `F^G\\IZLWUUYS[",
+ "H\\PKOLMLLKLIMGOFQFSGTITLSPQUOXMZJ[H[GZGXHWIXHY QFRGSISLRPPUNXLZJ[ ]G\\H]I^H^G]F[FYGWIULSPRURXSZT[U[WZYX",
+ "G]JJLGNFOFQGQIOOORPT OFPGPINONRPTRTUSWQYNZL \\FZLWTUX ]F[LYQWUUXSZP[L[JZIXIWJVKWJX",
+ "G\\ZHYJWOVRUTSWQYOZL[ SLRNPONOMMMKNIPGSF]F[GZHYKXOVUTXQZL[H[GZGXHWJWLXOZQ[T[WZYX VFZG[G",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "H\\WMW[X[ WMXMX[ WPUNSMPMNNLPKSKULXNZP[S[UZWX WPSNPNNOMPLSLUMXNYPZSZWX",
+ "H\\LFL[M[ LFMFM[ MPONQMTMVNXPYSYUXXVZT[Q[OZMX MPQNTNVOWPXSXUWXVYTZQZMX",
+ "I[XPVNTMQMONMPLSLUMXOZQ[T[VZXX XPWQVOTNQNOONPMSMUNXOYQZTZVYWWXX",
+ "H\\WFW[X[ WFXFX[ WPUNSMPMNNLPKSKULXNZP[S[UZWX WPSNPNNOMPLSLUMXNYPZSZWX",
+ "I[MTXTXQWOVNTMQMONMPLSLUMXOZQ[T[VZXX MSWSWQVOTNQNOONPMSMUNXOYQZTZVYWWXX",
+ "LZWFUFSGRJR[S[ WFWGUGSH TGSJS[ OMVMVN OMONVN",
+ "H\\XMWMW\\V_U`SaQaO`N_L_ XMX\\W_UaSbPbNaL_ WPUNSMPMNNLPKSKULXNZP[S[UZWX WPSNPNNOMPLSLUMXNYPZSZWX",
+ "H\\LFL[M[ LFMFM[ MQPNRMUMWNXQX[ MQPORNTNVOWQW[X[",
+ "NWRFQGQHRISITHTGSFRF RGRHSHSGRG RMR[S[ RMSMS[",
+ "NWRFQGQHRISITHTGSFRF RGRHSHSGRG RMRbSb RMSMSb",
+ "H[LFL[M[ LFMFM[ XMWMMW XMMX PTV[X[ QSX[",
+ "NWRFR[S[ RFSFS[",
+ "CbGMG[H[ GMHMH[ HQKNMMPMRNSQS[ HQKOMNONQORQR[S[ SQVNXM[M]N^Q^[ SQVOXNZN\\O]Q][^[",
+ "H\\LML[M[ LMMMM[ MQPNRMUMWNXQX[ MQPORNTNVOWQW[X[",
+ "I\\QMONMPLSLUMXOZQ[T[VZXXYUYSXPVNTMQM QNOONPMSMUNXOYQZTZVYWXXUXSWPVOTNQN",
+ "H\\LMLbMb LMMMMb MPONQMTMVNXPYSYUXXVZT[Q[OZMX MPQNTNVOWPXSXUWXVYTZQZMX",
+ "H\\WMWbXb WMXMXb WPUNSMPMNNLPKSKULXNZP[S[UZWX WPSNPNNOMPLSLUMXNYPZSZWX",
+ "KYOMO[P[ OMPMP[ PSQPSNUMXM PSQQSOUNXNXM",
+ "J[XPWNTMQMNNMPNRPSUUWV VUWWWXVZ WYTZQZNY OZNXMX XPWPVN WOTNQNNO ONNPOR NQPRUTWUXWXXWZT[Q[NZMX",
+ "MXRFR[S[ RFSFS[ OMVMVN OMONVN",
+ "H\\LMLWMZO[R[TZWW LMMMMWNYPZRZTYWW WMW[X[ WMXMX[",
+ "JZLMR[ LMMMRY XMWMRY XMR[",
+ "F^IMN[ IMJMNX RMNX RPN[ RPV[ RMVX [MZMVX [MV[",
+ "I[LMW[X[ LMMMX[ XMWML[ XMM[L[",
+ "JZLMR[ LMMMRY XMWMRYNb XMR[ObNb",
+ "I[VNL[ XMNZ LMXM LMLNVN NZXZX[ L[X[",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "K[UUTSRRPRNSMTLVLXMZO[Q[SZTX PRNTMVMYO[ VRTXTZV[XZYY[V WRUXUZV[",
+ "LZLVNSPO SFMXMZO[P[RZTXUUURVVWWXWZV TFNXNZO[",
+ "LXTSSTTTTSSRQROSNTMVMXNZP[S[VYXV QROTNVNYP[",
+ "K[UUTSRRPRNSMTLVLXMZO[Q[SZTX PRNTMVMYO[ ZFTXTZV[XZYY[V [FUXUZV[",
+ "LXOYQXRWSUSSRRQROSNTMVMXNZP[S[VYXV QROTNVNYP[",
+ "OXRRUOWLXIXGWFUGTIKdKfLgNfOcPZQ[S[UZVYXV TISNRRO[M`Kd",
+ "K[UUTSRRPRNSMTLVLXMZO[Q[SZTX PRNTMVMYO[ VRPd WRT[R`PdOfMgLfLdMaO_R]V[YY[V",
+ "L[LVNSPO SFL[ TFM[ OUQSSRTRVSVUUXUZV[ TRUSUUTXTZV[XZYY[V",
+ "NVSLRMSNTMSL QROXOZQ[SZTYVV RRPXPZQ[",
+ "NVSLRMSNTMSL QRKd RRO[M`KdJfHgGfGdHaJ_M]Q[TYVV",
+ "LZLVNSPO SFL[ TFM[ URUSVSURTRRTOU OURVSZT[ OUQVRZT[U[XYZV",
+ "NVNVPSRO UFOXOZQ[SZTYVV VFPXPZQ[",
+ "E^EVGSIRKSKUI[ IRJSJUH[ KUMSORPRRSRUP[ PRQSQUO[ RUTSVRWRYSYUXXXZY[ WRXSXUWXWZY[[Z\\Y^V",
+ "I[IVKSMROSOUM[ MRNSNUL[ OUQSSRTRVSVUUXUZV[ TRUSUUTXTZV[XZYY[V",
+ "KYRRPRNSMTLVLXMZO[Q[SZTYUWUUTSRRQSQURWTXVXXWYV PRNTMVMYO[",
+ "L[LVNSPO QLHg RLIg OUQSSRTRVSVUUXUZV[ TRUSUUTXTZV[XZYY[V",
+ "K[UUTSRRPRNSMTLVLXMZO[Q[SZ PRNTMVMYO[ VRPdPfQgSfTcT[V[YY[V WRT[R`Pd",
+ "LZLVNSPRRSRUP[ PRQSQUO[ RUTSVRWRVU VRVUWWXWZV",
+ "NZNVPSQQQSTUUWUYTZR[ QSSUTWTYR[ NZP[U[XYZV",
+ "NVNVPSRO UFOXOZQ[SZTYVV VFPXPZQ[ PNVN",
+ "K[NRLXLZN[O[QZSXUU ORMXMZN[ VRTXTZV[XZYY[V WRUXUZV[",
+ "KZNRMTLWLZN[O[RZTXUUUR ORNTMWMZN[ URVVWWXWZV",
+ "H]LRJTIWIZK[L[NZPX MRKTJWJZK[ RRPXPZR[S[UZWXXUXR SRQXQZR[ XRYVZW[W]V",
+ "JZJVLSNRPRQSQUPXOZM[L[KZKYLYKZ WSVTWTWSVRURSSRUQXQZR[U[XYZV QSRU SSQU PXQZ QXOZ",
+ "K[NRLXLZN[O[QZSXUU ORMXMZN[ VRPd WRT[R`PdOfMgLfLdMaO_R]V[YY[V",
+ "LYLVNSPRRRTSTVSXPZN[ RRSSSVRXPZ N[P\\Q^QaPdNfLgKfKdLaO^R\\VYYV N[O\\P^PaOdNf",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "NV",
+ "JZ",
+ "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF OGMJLOLRMWOZ NYQZSZVY UZWWXRXOWJUG VHSGQGNH",
+ "H\\NJPISFS[ NJNKPJRHR[S[",
+ "H\\LKLJMHNGPFTFVGWHXJXLWNUQL[ LKMKMJNHPGTGVHWJWLVNTQK[ LZYZY[ K[Y[",
+ "H\\MFXFQO MFMGWG WFPO QNSNVOXQYTYUXXVZS[P[MZLYKWLW POSOVPXS TOWQXTXUWXTZ XVVYSZPZMYLW OZLX",
+ "H\\UIU[V[ VFV[ VFKVZV UILV LUZUZV",
+ "H\\MFLO NGMN MFWFWG NGWG MNPMSMVNXPYSYUXXVZS[P[MZLYKWLW LOMOONSNVOXR TNWPXSXUWXTZ XVVYSZPZMYLW OZLX",
+ "H\\VGWIXIWGTFRFOGMJLOLTMXOZR[S[VZXXYUYTXQVOSNRNOOMQ WHTGRGOH PGNJMOMTNXQZ MVOYRZSZVYXV TZWXXUXTWQTO XSVPSOROOPMS QONQMT",
+ "H\\KFYFO[ KFKGXG XFN[O[",
+ "H\\PFMGLILKMMNNPOTPVQWRXTXWWYTZPZMYLWLTMRNQPPTOVNWMXKXIWGTFPF NGMIMKNMPNTOVPXRYTYWXYWZT[P[MZLYKWKTLRNPPOTNVMWKWIVG WHTGPGMH LXOZ UZXX",
+ "H\\WPURRSQSNRLPKMKLLINGQFRFUGWIXMXRWWUZR[P[MZLXMXNZ WMVPSR WNUQRRQRNQLN PRMPLMLLMIPG LKNHQGRGUHWK SGVIWMWRVWTZ UYRZPZMY",
+ "MXRXQYQZR[S[TZTYSXRX RYRZSZSYRY",
+ "MXTZS[R[QZQYRXSXTYT\\S^Q_ RYRZSZSYRY S[T\\ TZS^",
+ "MXRMQNQORPSPTOTNSMRM RNROSOSNRN RXQYQZR[S[TZTYSXRX RYRZSZSYRY",
+ "MXRMQNQORPSPTOTNSMRM RNROSOSNRN TZS[R[QZQYRXSXTYT\\S^Q_ RYRZSZSYRY S[T\\ TZS^",
+ "MXRFRTST RFSFST RXQYQZR[S[TZTYSXRX RYRZSZSYRY",
+ "I\\LKLJMHNGQFTFWGXHYJYLXNWOUPRQ LKMKMJNHQGTGWHXJXLWNUORP MIPG UGXI XMTP RPRTSTSP RXQYQZR[S[TZTYSXRX RYRZSZSYRY",
+ "MXTFRGQIQLRMSMTLTKSJRJQK RKRLSLSKRK RGQK QIRJ",
+ "MXTHSIRIQHQGRFSFTGTJSLQM RGRHSHSGRG SITJ THSL",
+ "F_\\MZMXNWPUVTXSYQZMZKYJWJUKSLRQOSMTKTISGQFPFNGMIMKNNPQUWXZZ[\\[ \\M\\NZNWP ZMXPVVUXSZQ[M[KZJYIWIUJSLQQNRMSKSIRG SHQGPGNH OGNINKONQQVWXYZZ\\Z\\[",
+ "I\\RBR_S_ RBSBS_ WIYIWGTFQFNGLILKMMNNVRWSXUXWWYTZQZOYNX WIVHTGQGNHMIMKNMVQXSYUYWXYWZT[Q[NZLXNX XXUZ",
+ "G^[BIbJb [B\\BJb",
+ "KYUBSDQGOKNPNTOYQ]S`UbVb UBVBTDRGPKOPOTPYR]T`Vb",
+ "KYNBPDRGTKUPUTTYR]P`NbOb NBOBQDSGUKVPVTUYS]Q`Ob",
+ "JZRFQGSQRR RFRR RFSGQQRR MINIVOWO MIWO MIMJWNWO WIVINOMO WIMO WIWJMNMO",
+ "F_JQ[Q[R JQJR[R",
+ "F_RIRZSZ RISISZ JQ[Q[R JQJR[R",
+ "F_JM[M[N JMJN[N JU[U[V JUJV[V",
+ "NWSFRGRM SGRM SFTGRM",
+ "I[NFMGMM NGMM NFOGMM WFVGVM WGVM WFXGVM",
+ "KYQFOGNINKOMQNSNUMVKVIUGSFQF QFNIOMSNVKUGQF SFOGNKQNUMVISF",
+ "F^ZIJRZ[ ZIZJLRZZZ[",
+ "F^JIZRJ[ JIJJXRJZJ[",
+ "G^OFObPb OFPFPb UFUbVb UFVFVb JP[P[Q JPJQ[Q JW[W[X JWJX[X",
+ "F^[FYGVHSHPGNFLFJGIIIKKMMMOLPJPHNF [FH[I[ [F\\FI[ YTWTUUTWTYV[X[ZZ[X[VYT NFJGIKMMPJNF LFIIKMOLPHLF YTUUTYX[[XYT WTTWV[ZZ[VWT",
+ "E`WMTKQKOLNMMOMRNTOUQVTVWT WMTLQLOMNONROTQUTUWT VKVSWUYVZV\\U]S]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[U[YZ VKWKWSXUZV YV[U\\S\\O[LZJYIWHTGQGNHLIKJJLIOIRJUKWLXNYQZUZYYYZ",
+ "E_JPLONOPPSTTUVVXVZU[S[QZOXNVNTOSPPTNULUJT ZPXOVOTPQTPUNVLVJUISIQJOLNNNPOQPTTVUXUZT KOJQJSKU YUZSZQYO",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "NV",
+ "JZ",
+ "H]TFQGOIMLLOKSKVLYMZO[Q[TZVXXUYRZNZKYHXGVFTF TFRGPINLMOLSLVMYO[ Q[SZUXWUXRYNYKXHVF",
+ "H]TJO[ VFP[ VFSIPKNL UIQKNL",
+ "H]OJPKOLNKNJOHPGSFVFYGZIZKYMWOTQPSMUKWI[ VFXGYIYKXMVOPS JYKXMXRZUZWYXW MXR[U[WZXW",
+ "H]OJPKOLNKNJOHPGSFVFYGZIZKYMVOSP VFXGYIYKXMVO QPSPVQWRXTXWWYVZS[O[LZKYJWJVKULVKW SPUQVRWTWWVYUZS[",
+ "H]XGR[ YFS[ YFJUZU",
+ "H]QFLP QF[F QGVG[F LPMOPNSNVOWPXRXUWXUZR[O[LZKYJWJVKULVKW SNUOVPWRWUVXTZR[",
+ "H]YIXJYKZJZIYGWFTFQGOIMLLOKSKWLYMZO[R[UZWXXVXSWQVPTOQOOPMRLT TFRGPINLMOLSLXMZ R[TZVXWVWRVP",
+ "H]NFLL [FZIXLSRQUPWO[ XLRRPUOWN[ MIPFRFWI NHPGRGWIYIZH[F",
+ "H]SFPGOHNJNMOOQPTPXOYNZLZIYGVFSF SFQGPHOJOMPOQP TPWOXNYLYIXGVF QPMQKSJUJXKZN[R[VZWYXWXTWRVQTP QPNQLSKUKXLZN[ R[UZVYWWWSVQ",
+ "H]YMXOVQTRQROQNPMNMKNIPGSFVFXGYHZJZNYRXUVXTZQ[N[LZKXKWLVMWLX OQNONKOIQGSF XGYIYNXRWUUXSZQ[",
+ "MXPYOZP[QZPY",
+ "MXP[OZPYQZQ[P]N_",
+ "MXSMRNSOTNSM PYOZP[QZ",
+ "MXSMRNSOTNSM P[OZPYQZQ[P]N_",
+ "MXUFTGRS UGRS UFVGRS PYOZP[QZPY",
+ "H]OJPKOLNKNJOHPGSFWFZG[I[KZMYNSPQQQSRTTT WFYGZIZKYMXNVO PYOZP[QZPY",
+ "MXVFTHSJSKTLUKTJ",
+ "MXUHTGUFVGVHUJSL",
+ "E_\\N[O\\P]O]N\\M[MYNWPRXPZN[K[HZGXGVHTISKRPPROTMUKUITGRFPGOIOLPRQUSXUZW[Y[ZYZX K[IZHXHVITJSPP OLPQQTSWUYWZYZZY",
+ "H]TBL_ YBQ_ ZJYKZL[K[JZHYGVFRFOGMIMKNMONVRXT MKOMVQWRXTXWWYVZS[O[LZKYJWJVKULVKW",
+ "G]_BEb",
+ "KZZBVESHQKOONTNXO]P`Qb VESIQMPPOUOZP_Qb",
+ "JYSBTDUGVLVPUUSYQ\\N_Jb SBTEUJUOTTSWQ[N_",
+ "J[TFTR OIYO YIOO",
+ "E_IR[R",
+ "E_RIR[ IR[R",
+ "E_IO[O IU[U",
+ "NWUFSM VFSM",
+ "I[PFNM QFNM YFWM ZFWM",
+ "KZSFQGPIPKQMSNUNWMXKXIWGUFSF",
+ "F^ZIJRZ[",
+ "F^JIZRJ[",
+ "H]SFLb YFRb LQZQ KWYW",
+ "E_^F\\GXHUHQGOFMFKGJIJKLMNMPLQJQHOF ^FF[ XTVTTUSWSYU[W[YZZXZVXT",
+ "E`WNVLTKQKOLNMMPMSNUPVSVUUVS QKOMNPNSOUPV WKVSVUXVZV\\T]Q]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYYZX XKWSWUXV",
+ "F_\\S[UYVWVUUTTQPPONNLNJOIQISJULVNVPUQTTPUOWNYN[O\\Q\\S",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "H\\RFK[ RFY[ RIX[ MUVU I[O[ U[[[",
+ "G]LFL[ MFM[ IFYFYLXF MPUPXQYRZTZWYYXZU[I[ UPWQXRYTYWXYWZU[",
+ "G]LFL[ MFM[ IFUFXGYHZJZLYNXOUP UFWGXHYJYLXNWOUP MPUPXQYRZTZWYYXZU[I[ UPWQXRYTYWXYWZU[",
+ "I[NFN[ OFO[ KFZFZLYF K[R[",
+ "F^NFNLMTLXKZJ[ XFX[ YFY[ KF\\F G[\\[ G[Gb H[Gb [[\\b \\[\\b",
+ "G\\LFL[ MFM[ SLST IFYFYLXF MPSP I[Y[YUX[",
+ "CbRFR[ SFS[ OFVF GGHHGIFHFGGFHFIGJIKMLONPWPYOZM[I\\G]F^F_G_H^I]H^G NPLQKSJXIZH[ NPMQLSKXJZI[G[FZEX WPYQZS[X\\Z][ WPXQYSZX[Z\\[^[_Z`X O[V[",
+ "H\\LIKFKLLINGPFTFWGXIXLWNTOQO TFVGWIWLVNTO TOVPXRYTYWXYWZT[O[MZLYKWKVLUMVLW WQXTXWWYVZT[",
+ "F^KFK[ LFL[ XFX[ YFY[ HFOF UF\\F XHLY H[O[ U[\\[",
+ "F^KFK[ LFL[ XFX[ YFY[ HFOF UF\\F XHLY H[O[ U[\\[ N@N?M?M@NBPCTCVBW@",
+ "F^KFK[ LFL[ HFOF LPSPUOVMWIXGYFZF[G[HZIYHZG SPUQVSWXXZY[ SPTQUSVXWZX[Z[[Z\\X H[O[",
+ "E^MFMLLTKXJZI[H[GZGYHXIYHZ XFX[ YFY[ JF\\F U[\\[",
+ "F_KFK[ LFRX KFR[ YFR[ YFY[ ZFZ[ HFLF YF]F H[N[ V[][",
+ "F^KFK[ LFL[ XFX[ YFY[ HFOF UF\\F LPXP H[O[ U[\\[",
+ "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF QFOGMILKKOKRLVMXOZQ[ S[UZWXXVYRYOXKWIUGSF",
+ "F^KFK[ LFL[ XFX[ YFY[ HF\\F H[O[ U[\\[",
+ "G]LFL[ MFM[ IFUFXGYHZJZMYOXPUQMQ UFWGXHYJYMXOWPUQ I[P[",
+ "G\\XIYLYFXIVGSFQFNGLIKKJNJSKVLXNZQ[S[VZXXYV QFOGMILKKNKSLVMXOZQ[",
+ "I\\RFR[ SFS[ LFKLKFZFZLYF O[V[",
+ "H]KFRV LFSV ZFSVQYPZN[M[LZLYMXNYMZ IFOF VF\\F",
+ "F_RFR[ SFS[ OFVF PILJJLIOIRJULWPXUXYW[U\\R\\O[LYJUIPI PIMJKLJOJRKUMWPX UXXWZU[R[OZLXJUI O[V[",
+ "H\\KFX[ LFY[ YFK[ IFOF UF[F I[O[ U[[[",
+ "F^KFK[ LFL[ XFX[ YFY[ HFOF UF\\F H[\\[ [[\\b \\[\\b",
+ "F]KFKQLSOTRTUSWQ LFLQMSOT WFW[ XFX[ HFOF TF[F T[[[",
+ "BcGFG[ HFH[ RFR[ SFS[ ]F][ ^F^[ DFKF OFVF ZFaF D[a[",
+ "BcGFG[ HFH[ RFR[ SFS[ ]F][ ^F^[ DFKF OFVF ZFaF D[a[ `[ab a[ab",
+ "F`PFP[ QFQ[ IFHLHFTF QPXP[Q\\R]T]W\\Y[ZX[M[ XPZQ[R\\T\\W[YZZX[",
+ "CaHFH[ IFI[ EFLF IPPPSQTRUTUWTYSZP[E[ PPRQSRTTTWSYRZP[ [F[[ \\F\\[ XF_F X[_[",
+ "H]MFM[ NFN[ JFQF NPUPXQYRZTZWYYXZU[J[ UPWQXRYTYWXYWZU[",
+ "H]LIKFKLLINGQFSFVGXIYKZNZSYVXXVZS[P[MZLYKWKVLUMVLW SFUGWIXKYNYSXVWXUZS[ PPYP",
+ "CbHFH[ IFI[ EFLF E[L[ VFSGQIPKOOORPVQXSZV[X[[Z]X^V_R_O^K]I[GXFVF VFTGRIQKPOPRQVRXTZV[ X[ZZ\\X]V^R^O]K\\IZGXF IPOP",
+ "G]WFW[ XFX[ [FOFLGKHJJJLKNLOOPWP OFMGLHKJKLLNMOOP RPPQORLYKZJZIY PQOSMZL[J[IYIX T[[[",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "I]NONPMPMONNPMTMVNWOXQXXYZZ[ WOWXXZZ[[[ WQVRPSMTLVLXMZP[S[UZWX PSNTMVMXNZP[",
+ "H\\XFWGQINKLNKQKULXNZQ[S[VZXXYUYSXPVNSMQMNNLPKS XFWHUIQJNLLN QMONMPLSLUMXOZQ[ S[UZWXXUXSWPUNSM",
+ "H\\MMM[ NMN[ JMUMXNYPYQXSUT UMWNXPXQWSUT NTUTXUYWYXXZU[J[ UTWUXWXXWZU[",
+ "HZMMM[ NMN[ JMXMXRWM J[Q[",
+ "F]NMNQMWLZK[ WMW[ XMX[ KM[M I[H`H[[[[`Z[",
+ "H[LSXSXQWOVNTMQMNNLPKSKULXNZQ[S[VZXX WSWPVN QMONMPLSLUMXOZQ[",
+ "E`RMR[ SMS[ OMVM JNIOHNIMJMKNMRNSPTUTWSXRZN[M\\M]N\\O[N PTNUMVKZJ[ PTNVLZK[I[HZGX UTWUXVZZ[[ UTWVYZZ[\\[]Z^X O[V[",
+ "I[MOLMLQMONNPMTMWNXPXQWSTT TMVNWPWQVSTT QTTTWUXWXXWZT[P[MZLXLWMVNWMX TTVUWWWXVZT[",
+ "G]LML[ MMM[ WMW[ XMX[ IMPM TM[M I[P[ T[[[ WNMZ",
+ "G]LML[ MMM[ WMW[ XMX[ IMPM TM[M I[P[ T[[[ WNMZ OGOFNFNGOIQJSJUIVG",
+ "H\\MMM[ NMN[ JMQM NTPTSSTRVNWMXMYNXOWN PTSUTVVZW[ PTRUSVUZV[X[YZZX J[Q[",
+ "G]NMNQMWLZK[J[IZJYKZ WMW[ XMX[ KM[M T[[[",
+ "G^LML[ LMR[ MMRY XMR[ XMX[ YMY[ IMMM XM\\M I[O[ U[\\[",
+ "G]LML[ MMM[ WMW[ XMX[ IMPM TM[M MTWT I[P[ T[[[",
+ "H\\QMNNLPKSKULXNZQ[S[VZXXYUYSXPVNSMQM QMONMPLSLUMXOZQ[ S[UZWXXUXSWPUNSM",
+ "G]LML[ MMM[ WMW[ XMX[ IM[M I[P[ T[[[",
+ "G\\LMLb MMMb MPONQMSMVNXPYSYUXXVZS[Q[OZMX SMUNWPXSXUWXUZS[ IMMM IbPb",
+ "H[WPVQWRXQXPVNTMQMNNLPKSKULXNZQ[S[VZXX QMONMPLSLUMXOZQ[",
+ "I\\RMR[ SMS[ MMLRLMYMYRXM O[V[",
+ "I[LMR[ MMRY XMR[P_NaLbKbJaK`La JMPM TMZM",
+ "H]RFRb SFSb OFSF RPQNPMNMLNKQKWLZN[P[QZRX NMMNLQLWMZN[ WMXNYQYWXZW[ SPTNUMWMYNZQZWYZW[U[TZSX ObVb",
+ "H\\LMW[ MMX[ XML[ JMPM TMZM J[P[ T[Z[",
+ "G]LML[ MMM[ WMW[ XMX[ IMPM TM[M I[[[[`Z[",
+ "G]LMLTMVPWRWUVWT MMMTNVPW WMW[ XMX[ IMPM TM[M T[[[",
+ "CbHMH[ IMI[ RMR[ SMS[ \\M\\[ ]M][ EMLM OMVM YM`M E[`[",
+ "CbHMH[ IMI[ RMR[ SMS[ \\M\\[ ]M][ EMLM OMVM YM`M E[`[``_[",
+ "H]QMQ[ RMR[ LMKRKMUM RTVTYUZWZXYZV[N[ VTXUYWYXXZV[",
+ "E_JMJ[ KMK[ GMNM KTOTRUSWSXRZO[G[ OTQURWRXQZO[ YMY[ ZMZ[ VM]M V[][",
+ "J[OMO[ PMP[ LMSM PTTTWUXWXXWZT[L[ TTVUWWWXVZT[",
+ "I\\MOLMLQMONNPMSMVNXPYSYUXXVZS[P[NZLXLWMVNWMX SMUNWPXSXUWXUZS[ RTXT",
+ "DaIMI[ JMJ[ FMMM F[M[ VMSNQPPSPUQXSZV[X[[Z]X^U^S]P[NXMVM VMTNRPQSQURXTZV[ X[ZZ\\X]U]S\\PZNXM JTPT",
+ "G\\VMV[ WMW[ ZMOMLNKPKQLSOTVT OMMNLPLQMSOT TTQUPVNZM[ TTRUQVOZN[L[KZJX S[Z[",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "H\\RFKZ QIW[ RIX[ RFY[ MUVU I[O[ T[[[ KZJ[ KZM[ WZU[ WYV[ XYZ[",
+ "G]LFL[ MGMZ NFN[ IFUFXGYHZJZLYNXOUP XHYJYLXN UFWGXIXMWOUP NPUPXQYRZTZWYYXZU[I[ XRYTYWXY UPWQXSXXWZU[ JFLG KFLH OFNH PFNG LZJ[ LYK[ NYO[ NZP[",
+ "G\\XIYFYLXIVGTFQFNGLIKKJNJSKVLXNZQ[T[VZXXYV MILKKNKSLVMX QFOGMJLNLSMWOZQ[",
+ "G]LFL[ MGMZ NFN[ IFSFVGXIYKZNZSYVXXVZS[I[ WIXKYNYSXVWX SFUGWJXNXSWWUZS[ JFLG KFLH OFNH PFNG LZJ[ LYK[ NYO[ NZP[",
+ "G\\LFL[ MGMZ NFN[ IFYFYL NPTP TLTT I[Y[YU JFLG KFLH OFNH PFNG TFYG VFYH WFYI XFYL TLSPTT TNRPTR TOPPTQ LZJ[ LYK[ NYO[ NZP[ T[YZ V[YY W[YX X[YU",
+ "G[LFL[ MGMZ NFN[ IFYFYL NPTP TLTT I[Q[ JFLG KFLH OFNH PFNG TFYG VFYH WFYI XFYL TLSPTT TNRPTR TOPPTQ LZJ[ LYK[ NYO[ NZP[",
+ "G^XIYFYLXIVGTFQFNGLIKKJNJSKVLXNZQ[T[VZXZY[YS MILKKNKSLVMX QFOGMJLNLSMWOZQ[ XTXY WSWYVZ TS\\S USWT VSWU ZSYU [SYT",
+ "F^KFK[ LGLZ MFM[ WFW[ XGXZ YFY[ HFPF TF\\F MPWP H[P[ T[\\[ IFKG JFKH NFMH OFMG UFWG VFWH ZFYH [FYG KZI[ KYJ[ MYN[ MZO[ WZU[ WYV[ YYZ[ YZ[[",
+ "LXQFQ[ RGRZ SFS[ NFVF N[V[ OFQG PFQH TFSH UFSG QZO[ QYP[ SYT[ SZU[",
+ "JZSFSWRZQ[ TGTWSZ UFUWTZQ[O[MZLXLVMUNUOVOWNXMX MVMWNWNVMV PFXF QFSG RFSH VFUH WFUG",
+ "F\\KFK[ LGLZ MFM[ XGMR PPW[ QPX[ QNY[ HFPF UF[F H[P[ T[[[ IFKG JFKH NFMH OFMG WFXG ZFXG KZI[ KYJ[ MYN[ MZO[ WYU[ WYZ[",
+ "I[NFN[ OGOZ PFP[ KFSF K[Z[ZU LFNG MFNH QFPH RFPG NZL[ NYM[ PYQ[ PZR[ U[ZZ W[ZY X[ZX Y[ZU",
+ "E_JFJZ JFQ[ KFQX LFRX XFQ[ XFX[ YGYZ ZFZ[ GFLF XF]F G[M[ U[][ HFJG [FZH \\FZG JZH[ JZL[ XZV[ XYW[ ZY[[ ZZ\\[",
+ "F^KFKZ KFY[ LFXX MFYX YGY[ HFMF VF\\F H[N[ IFKG WFYG [FYG KZI[ KZM[",
+ "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF MILKKNKSLVMX WXXVYSYNXKWI QFOGMJLNLSMWOZQ[ S[UZWWXSXNWJUGSF",
+ "G]LFL[ MGMZ NFN[ IFUFXGYHZJZMYOXPUQNQ XHYJYMXO UFWGXIXNWPUQ I[Q[ JFLG KFLH OFNH PFNG LZJ[ LYK[ NYO[ NZP[",
+ "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF MILKKNKSLVMX WXXVYSYNXKWI QFOGMJLNLSMWOZQ[ S[UZWWXSXNWJUGSF NXOVQURUTVUXV^W`Y`Z^Z\\ V\\W^X_Y_ UXW]X^Y^Z]",
+ "G]LFL[ MGMZ NFN[ IFUFXGYHZJZLYNXOUPNP XHYJYLXN UFWGXIXMWOUP RPTQUSWYX[Z[[Y[W WWXYYZZZ TQURXXYYZY[X I[Q[ JFLG KFLH OFNH PFNG LZJ[ LYK[ NYO[ NZP[",
+ "H\\XIYFYLXIVGSFPFMGKIKLLNOPURWSXUXXWZ LLMNOOUQWRXT MGLILKMMONUPXRYTYWXYWZT[Q[NZLXKUK[LX",
+ "H\\JFJL QFQ[ RGRZ SFS[ ZFZL JFZF N[V[ KFJL LFJI MFJH OFJG UFZG WFZH XFZI YFZL QZO[ QYP[ SYT[ SZU[",
+ "F^KFKULXNZQ[S[VZXXYUYG LGLVMX MFMVNYOZQ[ HFPF VF\\F IFKG JFKH NFMH OFMG WFYG [FYG",
+ "H\\KFR[ LFRXR[ MFSX YGR[ IFPF UF[F JFLH NFMH OFMG WFYG ZFYG",
+ "F^JFN[ KFNVN[ LFOV RFOVN[ RFV[ SFVVV[ TFWV ZGWVV[ GFOF RFTF WF]F HFKG IFKH MFLH NFLG XFZG \\FZG",
+ "H\\KFW[ LFX[ MFY[ XGLZ IFPF UF[F I[O[ T[[[ JFMH NFMH OFMG VFXG ZFXG LZJ[ LZN[ WZU[ WYV[ WYZ[",
+ "G]JFQQQ[ KFRQRZ LFSQS[ YGSQ HFOF VF\\F N[V[ IFKG NFLG WFYG [FYG QZO[ QYP[ SYT[ SZU[",
+ "H\\YFKFKL WFK[ XFL[ YFM[ K[Y[YU LFKL MFKI NFKH PFKG T[YZ V[YY W[YX X[YU",
+ "H\\RFKZ QIW[ RIX[ RFY[ MUVU I[O[ T[[[ KZJ[ KZM[ WZU[ WYV[ XYZ[",
+ "G]LFL[ MGMZ NFN[ IFUFXGYHZJZLYNXOUP XHYJYLXN UFWGXIXMWOUP NPUPXQYRZTZWYYXZU[I[ XRYTYWXY UPWQXSXXWZU[ JFLG KFLH OFNH PFNG LZJ[ LYK[ NYO[ NZP[",
+ "I[NFN[ OGOZ PFP[ KFZFZL K[S[ LFNG MFNH QFPH RFPG UFZG WFZH XFZI YFZL NYM[ NZL[ PYQ[ PZR[",
+ "H\\RFJ[ QIX[ RIY[ RFZ[ KYXY KZXZ J[Z[",
+ "G\\LFL[ MGMZ NFN[ IFYFYL NPTP TLTT I[Y[YU JFLG KFLH OFNH PFNG TFYG VFYH WFYI XFYL TLSPTT TNRPTR TOPPTQ LZJ[ LYK[ NYO[ NZP[ T[YZ V[YY W[YX X[YU",
+ "H\\YFKFKL WFK[ XFL[ YFM[ K[Y[YU LFKL MFKI NFKH PFKG T[YZ V[YY W[YX X[YU",
+ "F^KFK[ LGLZ MFM[ WFW[ XGXZ YFY[ HFPF TF\\F MPWP H[P[ T[\\[ IFKG JFKH NFMH OFMG UFWG VFWH ZFYH [FYG KZI[ KYJ[ MYN[ MZO[ WZU[ WYV[ YYZ[ YZ[[",
+ "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF MILKKNKSLVMX WXXVYSYNXKWI QFOGMJLNLSMWOZQ[ S[UZWWXSXNWJUGSF OMOT UMUT OPUP OQUQ ONPP OOQP UNTP UOSP PQOS QQOR SQUR TQUS",
+ "LXQFQ[ RGRZ SFS[ NFVF N[V[ OFQG PFQH TFSH UFSG QZO[ QYP[ SYT[ SZU[",
+ "F\\KFK[ LGLZ MFM[ XGMR PPW[ QPX[ QNY[ HFPF UF[F H[P[ T[[[ IFKG JFKH NFMH OFMG WFXG ZFXG KZI[ KYJ[ MYN[ MZO[ WYU[ WYZ[",
+ "H\\RFKZ QIW[ RIX[ RFY[ I[O[ T[[[ KZJ[ KZM[ WZU[ WYV[ XYZ[",
+ "E_JFJZ JFQ[ KFQX LFRX XFQ[ XFX[ YGYZ ZFZ[ GFLF XF]F G[M[ U[][ HFJG [FZH \\FZG JZH[ JZL[ XZV[ XYW[ ZY[[ ZZ\\[",
+ "F^KFKZ KFY[ LFXX MFYX YGY[ HFMF VF\\F H[N[ IFKG WFYG [FYG KZI[ KZM[",
+ "G]JEJL ZEZL OMOT UMUT JUJ\\ ZUZ\\ JGZG JHZH JIZI OPUP OQUQ JXZX JYZY JZZZ JFMH ZFWH KIJK LIJJ XIZJ YIZK ONPP OOQP UNTP UOSP PQOS QQOR SQUR TQUS JVKX JWLX ZWXX ZVYX MYJ[ WYZ[",
+ "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF MILKKNKSLVMX WXXVYSYNXKWI QFOGMJLNLSMWOZQ[ S[UZWWXSXNWJUGSF",
+ "F^KFK[ LGLZ MFM[ WFW[ XGXZ YFY[ HF\\F H[P[ T[\\[ IFKG JFKH NFMH OFMG UFWG VFWH ZFYH [FYG KZI[ KYJ[ MYN[ MZO[ WZU[ WYV[ YYZ[ YZ[[",
+ "G]LFL[ MGMZ NFN[ IFUFXGYHZJZMYOXPUQNQ XHYJYMXO UFWGXIXNWPUQ I[Q[ JFLG KFLH OFNH PFNG LZJ[ LYK[ NYO[ NZP[",
+ "G]IFPPQQ JFQP KFRPI[ IFYFZLYIWF VFYH TFYG KYYY JZYZ I[Y[ZUYXWY",
+ "H\\JFJL QFQ[ RGRZ SFS[ ZFZL JFZF N[V[ KFJL LFJI MFJH OFJG UFZG WFZH XFZI YFZL QZO[ QYP[ SYT[ SZU[",
+ "H\\JMKILGMFOFPGQIRM LHMGOGPH JMKJMHOHPIQMQ[ RMR[ ZMYJWHUHTISMS[ XHWGUGTH ZMYIXGWFUFTGSIRM N[V[ QYP[ QZO[ SZU[ SYT[",
+ "G]QFQ[ RGRZ SFS[ NFVF N[V[ OFQG PFQH TFSH UFSG QZO[ QYP[ SYT[ SZU[ OKLLKMJOJRKTLUOVUVXUYTZRZOYMXLUKOK LMKOKRLT XTYRYOXM OKMLLOLRMUOV UVWUXRXOWLUK",
+ "H\\KFW[ LFX[ MFY[ XGLZ IFPF UF[F I[O[ T[[[ JFMH NFMH OFMG VFXG ZFXG LZJ[ LZN[ WZU[ WYV[ WYZ[",
+ "F^QFQ[ RGRZ SFS[ NFVF N[V[ OFQG PFQH TFSH UFSG QZO[ QYP[ SYT[ SZU[ HMIMJNKQLSMTPUTUWTXSYQZN[M\\M LRKNJLILKN HMIKJKKLLPMSNTPU YN[LZLYNXR TUVTWSXPYLZK[K\\M",
+ "G]NYKYJWK[O[MVKRJOJLKIMGPFTFWGYIZLZOYRWVU[Y[ZWYYVY LSKOKLLI XIYLYOXS O[MULPLKMHNGPF TFVGWHXKXPWUU[ KZNZ VZYZ",
+ "H\\UFIZ SJT[ THUZ UFUHVYV[ LUTU F[L[ Q[X[ IZG[ IZK[ TZR[ TYS[ VYW[",
+ "F^OFI[ PFJ[ QFK[ LFWFZG[I[KZNYOVP YGZIZKYNXO WFXGYIYKXNVP NPVPXQYSYUXXVZR[F[ WQXSXUWXUZ VPWRWUVXTZR[ MFPG NFOH RFPH SFPG JZG[ JYH[ KYL[ JZM[",
+ "H]ZH[H\\F[L[JZHYGWFTFQGOIMLLOKSKVLYMZP[S[UZWXXV QHOJNLMOLSLWMY TFRGPJOLNOMSMXNZP[",
+ "F]OFI[ PFJ[ QFK[ LFUFXGYHZKZOYSWWUYSZO[F[ WGXHYKYOXSVWTY UFWHXKXOWSUWRZO[ MFPG NFOH RFPH SFPG JZG[ JYH[ KYL[ JZM[",
+ "F]OFI[ PFJ[ QFK[ ULST LF[FZL NPTP F[U[WV MFPG NFOH RFPH SFPG WFZG XFZH YFZI ZFZL ULSPST TNRPSR TOQPSQ JZG[ JYH[ KYL[ JZM[ P[UZ R[UY UYWV",
+ "F\\OFI[ PFJ[ QFK[ ULST LF[FZL NPTP F[N[ MFPG NFOH RFPH SFPG WFZG XFZH YFZI ZFZL ULSPST TNRPSR TOQPSQ JZG[ JYH[ KYL[ JZM[",
+ "H^ZH[H\\F[L[JZHYGWFTFQGOIMLLOKSKVLYMZP[R[UZWXYT QHOJNLMOLSLWMY VXWWXT TFRGPJOLNOMSMXNZP[ R[TZVWWT TT\\T UTWU VTWW ZTXV [TXU",
+ "E_NFH[ OFI[ PFJ[ ZFT[ [FU[ \\FV[ KFSF WF_F LPXP E[M[ Q[Y[ LFOG MFNH QFOH RFOG XF[G YFZH ]F[H ^F[G IZF[ IYG[ JYK[ IZL[ UZR[ UYS[ VYW[ UZX[",
+ "KYTFN[ UFO[ VFP[ QFYF K[S[ RFUG SFTH WFUH XFUG OZL[ OYM[ PYQ[ OZR[",
+ "I\\WFRWQYO[ XFTSSVRX YFUSSXQZO[M[KZJXJVKULUMVMWLXKX KVKWLWLVKV TF\\F UFXG VFWH ZFXH [FXG",
+ "F]OFI[ PFJ[ QFK[ \\GMR QOU[ ROV[ SNWZ LFTF YF_F F[N[ R[Y[ MFPG NFOH RFPH SFPG ZF\\G ^F\\G JZG[ JYH[ KYL[ JZM[ UZS[ UYT[ VYX[",
+ "H\\QFK[ RFL[ SFM[ NFVF H[W[YU OFRG PFQH TFRH UFRG LZI[ LYJ[ MYN[ LZO[ R[WZ T[XX V[YU",
+ "D`MFGZ MGNYN[ NFOY OFPX [FPXN[ [FU[ \\FV[ ]FW[ JFOF [F`F D[J[ R[Z[ KFMG LFMH ^F\\H _F\\G GZE[ GZI[ VZS[ VYT[ WYX[ VZY[",
+ "F_OFIZ OFV[ PFVX QFWX \\GWXV[ LFQF YF_F F[L[ MFPG NFPH ZF\\G ^F\\G IZG[ IZK[",
+ "G]SFPGNILLKOJSJVKYLZN[Q[TZVXXUYRZNZKYHXGVFSF OIMLLOKSKWLY UXWUXRYNYJXH SFQGOJNLMOLSLXMZN[ Q[SZUWVUWRXNXIWGVF",
+ "F]OFI[ PFJ[ QFK[ LFXF[G\\I\\K[NYPUQMQ ZG[I[KZNXP XFYGZIZKYNWPUQ F[N[ MFPG NFOH RFPH SFPG JZG[ JYH[ KYL[ JZM[",
+ "G]SFPGNILLKOJSJVKYLZN[Q[TZVXXUYRZNZKYHXGVFSF OIMLLOKSKWLY UXWUXRYNYJXH SFQGOJNLMOLSLXMZN[ Q[SZUWVUWRXNXIWGVF LXMVOUPURVSXT]U^V^W] T^U_V_ SXS_T`V`W]W\\",
+ "F^OFI[ PFJ[ QFK[ LFWFZG[I[KZNYOVPNP YGZIZKYNXO WFXGYIYKXNVP RPTQURWXXYYYZX WYXZYZ URVZW[Y[ZXZW F[N[ MFPG NFOH RFPH SFPG JZG[ JYH[ KYL[ JZM[",
+ "G^ZH[H\\F[L[JZHYGVFRFOGMIMLNNPPVSWUWXVZ NLONVRWT OGNINKOMUPWRXTXWWYVZS[O[LZKYJWJUI[JYKY",
+ "G]TFN[ UFO[ VFP[ MFKL ]F\\L MF]F K[S[ NFKL PFLI RFMG YF\\G ZF\\H [F\\I \\F\\L OZL[ OYM[ PYQ[ OZR[",
+ "F_NFKQJUJXKZN[R[UZWXXU\\G OFLQKUKYLZ PFMQLULYN[ KFSF YF_F LFOG MFNH QFOH RFOG ZF\\G ^F\\G",
+ "H\\NFNHOYO[ OGPX PFQW [GO[ LFSF XF^F MFNH QFPH RFOG YF[G ]F[G",
+ "E_MFMHKYK[ NGLX OFMW UFMWK[ UFUHSYS[ VGTX WFUW ]GUWS[ JFRF UFWF ZF`F KFNG LFMH PFNI QFNG [F]G _F]G",
+ "G]NFT[ OFU[ PFV[ [GIZ LFSF XF^F F[L[ Q[X[ MFOH QFPH RFPG YF[G ]F[G IZG[ IZK[ TZR[ TYS[ UYW[",
+ "G]MFQPN[ NFRPO[ OFSPP[ \\GSP KFRF YF_F K[S[ LFNG PFOH QFNG ZF\\G ^F\\G OZL[ OYM[ PYQ[ OZR[",
+ "G]ZFH[ [FI[ \\FJ[ \\FNFLL H[V[XU OFLL PFMI RFNG R[VZ T[WX U[XU",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "H\\JFR[ KFRX LFSX JFZFR[ LGYG LHYH",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "I]NPNOOOOQMQMONNPMTMVNWOXQXXYZZ[ VOWQWXXZ TMUNVPVXWZZ[[[ VRUSPTMULWLXMZP[S[UZVX NUMWMXNZ USQTOUNWNXOZP[",
+ "G\\LFL[MZOZ MGMY IFNFNZ NPONQMSMVNXPYSYUXXVZS[Q[OZNX WPXRXVWX SMUNVOWRWVVYUZS[ JFLG KFLH",
+ "H[WQWPVPVRXRXPVNTMQMNNLPKSKULXNZQ[S[VZXX MPLRLVMX QMONNOMRMVNYOZQ[",
+ "H]VFV[[[ WGWZ SFXFX[ VPUNSMQMNNLPKSKULXNZQ[S[UZVX MPLRLVMX QMONNOMRMVNYOZQ[ TFVG UFVH XYY[ XZZ[",
+ "H[MSXSXQWOVNSMQMNNLPKSKULXNZQ[S[VZXX WRWQVO MPLRLVMX VSVPUNSM QMONNOMRMVNYOZQ[",
+ "KYWHWGVGVIXIXGWFTFRGQHPKP[ RHQKQZ TFSGRIR[ MMVM M[U[ PZN[ PYO[ RYS[ RZT[",
+ "I\\XNYOZNYMXMVNUO QMONNOMQMSNUOVQWSWUVVUWSWQVOUNSMQM OONQNSOU UUVSVQUO QMPNOPOTPVQW SWTVUTUPTNSM NUMVLXLYM[N\\Q]U]X^Y_ N[Q\\U\\X] LYMZP[U[X\\Y^Y_XaUbObLaK_K^L\\O[ ObMaL_L^M\\O[",
+ "G^LFL[ MGMZ IFNFN[ NQOOPNRMUMWNXOYRY[ WOXRXZ UMVNWQW[ I[Q[ T[\\[ JFLG KFLH LZJ[ LYK[ NYO[ NZP[ WZU[ WYV[ YYZ[ YZ[[",
+ "LXQFQHSHSFQF RFRH QGSG QMQ[ RNRZ NMSMS[ N[V[ OMQN PMQO QZO[ QYP[ SYT[ SZU[",
+ "KXRFRHTHTFRF SFSH RGTG RMR^QaPb SNS]R` OMTMT]S`RaPbMbLaL_N_NaMaM` PMRN QMRO",
+ "G]LFL[ MGMZ IFNFN[ WNNW RSY[ RTX[ QTW[ TM[M I[Q[ T[[[ JFLG KFLH UMWN ZMWN LZJ[ LYK[ NYO[ NZP[ WYU[ VYZ[",
+ "LXQFQ[ RGRZ NFSFS[ N[V[ OFQG PFQH QZO[ QYP[ SYT[ SZU[",
+ "AcFMF[ GNGZ CMHMH[ HQIOJNLMOMQNROSRS[ QORRRZ OMPNQQQ[ SQTOUNWMZM\\N]O^R^[ \\O]R]Z ZM[N\\Q\\[ C[K[ N[V[ Y[a[ DMFN EMFO FZD[ FYE[ HYI[ HZJ[ QZO[ QYP[ SYT[ SZU[ \\ZZ[ \\Y[[ ^Y_[ ^Z`[",
+ "G^LML[ MNMZ IMNMN[ NQOOPNRMUMWNXOYRY[ WOXRXZ UMVNWQW[ I[Q[ T[\\[ JMLN KMLO LZJ[ LYK[ NYO[ NZP[ WZU[ WYV[ YYZ[ YZ[[",
+ "H\\QMNNLPKSKULXNZQ[S[VZXXYUYSXPVNSMQM MPLRLVMX WXXVXRWP QMONNOMRMVNYOZQ[ S[UZVYWVWRVOUNSM",
+ "G\\LMLb MNMa IMNMNb NPONQMSMVNXPYSYUXXVZS[Q[OZNX WPXRXVWX SMUNVOWRWVVYUZS[ IbQb JMLN KMLO LaJb L`Kb N`Ob NaPb",
+ "H\\VNVb WOWa UNWNXMXb VPUNSMQMNNLPKSKULXNZQ[S[UZVX MPLRLVMX QMONNOMRMVNYOZQ[ Sb[b VaTb V`Ub X`Yb XaZb",
+ "IZNMN[ ONOZ KMPMP[ WOWNVNVPXPXNWMUMSNQPPS K[S[ LMNN MMNO NZL[ NYM[ PYQ[ PZR[",
+ "J[WOXMXQWOVNTMPMNNMOMQNSPTUUWVXY NNMQ NRPSUTWU XVWZ MONQPRUSWTXVXYWZU[Q[OZNYMWM[NY",
+ "KZPHPVQYRZT[V[XZYX QHQWRY PHRFRWSZT[ MMVM",
+ "G^LMLVMYNZP[S[UZVYWW MNMWNY IMNMNWOZP[ WMW[\\[ XNXZ TMYMY[ JMLN KMLO YYZ[ YZ[[",
+ "I[LMR[ MMRY NMSY XNSYR[ JMQM TMZM KMNO PMNN VMXN YMXN",
+ "F^JMN[ KMNX LMOX RMOXN[ RMV[ SMVX RMTMWX ZNWXV[ GMOM WM]M HMKN NMLN XMZN \\MZN",
+ "H\\LMV[ MMW[ NMX[ WNMZ JMQM TMZM J[P[ S[Z[ KMMN PMNN UMWN YMWN MZK[ MZO[ VZT[ WZY[",
+ "H[LMR[ MMRY NMSY XNSYP_NaLbJbIaI_K_KaJaJ` JMQM TMZM KMNO PMNN VMXN YMXN",
+ "I[VML[ WMM[ XMN[ XMLMLQ L[X[XW MMLQ NMLP OMLO QMLN S[XZ U[XY V[XX W[XW",
+ "G^[MZQYTWXUZR[P[MZKXJUJSKPMNPMRMUNVOWQYXZZ[[\\[ ZMYQXTWVUYTZR[ LXKVKRLP P[NZMYLVLRMONNPM RMTNUOVQXXYZ[[",
+ "G\\QFNGMHLJKNKb NHMJLNLa QFOGNIMNMb QFSFVGWHXJXLWNVOSP PPTPWQXRYTYWXYWZT[Q[OZNYMW VHWJWLVN WRXTXWWY SFUGVIVMUOSP TPVQWSWXVZT[ KbMb",
+ "F\\HRINKMMMONPOQRRYSb IOKNMNOOPP HRIPKOMOOPPQQTRYRa XMWPVRTUSWR[Qb YMWQ ZMYOWRTVSXR[ XMZM QbSb",
+ "H\\SMQMNNLPKSKULXNZQ[S[VZXXYUYSXPVNSMPLNKMJMHNGPFSFWH MPLSLUMX WXXUXSWP QMONNOMRMVNYOZQ[ S[UZVYWVWRVOUNOKNJNIOHQGTGWH",
+ "I[SMUNVOWOVNSMQMMNLOLQMRQS SSQSMTKVKXMZP[S[VZXXWXVZ NNMOMQNR MULVLXMY QMONNONQORQS QSNTMVMXNZP[",
+ "I[QHRGRFQFPGPIQJTKXKYKYJXJUKSLPNNPMRLULWMYNZP[S\\U]V_VaUbSbRaR`S`Sa POOPNRMUMWNYOZ UKRMQNOQNTNWOYQ[S\\",
+ "G]JMKNLPL[ KMLNMPMZ HPINJMLMMNNPN[ UMVNWQWb WOXRXa NQOOPNRMUMWNXOYRYb L[N[ WbYb",
+ "F]IMJNKPKTLWMYNZQ[S[VZWYXWYRYOXJVGTFRFPGOIOKPMSOVP[Q JMKNLPLTMWNY VYWWXRXOWJVHTG GPHNIMKMLNMPMTNXOZQ[ S[UZVXWSWNVJUHSGQGOI",
+ "KZNMONPPPXQZS[U[WZXX OMPNQPQXRZ LPMNNMPMQNRPRXSZT[",
+ "G]JMKNLPL[ KMLNMPMZ HPINJMLMMNNPN[ SOUNWNXOXPZPZNXMVMTNQQOTNW XNYOYP PSQSWYYYZX TWWZYZ RTUZV[X[YZZX L[N[",
+ "H\\JGKFMFOGQIXXYZZ[ OHPIWXXY MFNGOIVXXZZ[[[ RMJZJ[K[RM",
+ "G]KMKb LNLa MMMb VMVXWZX[Z[[Z\\X WNWXXZY[ XMXXYZZ[ MXNZP[R[TZUYVW KMMM VMXM KbMb",
+ "G]JMKNLPMTN[ KMLNMPNTOZ HPINJMLMMNNPOTPZ VVWTXQXMYMZNYQXSVVTXQZN[ XRYOYM",
+ "JZPGSFRFPGOHOIPJSKVLWKVJSKPLNMMOMQNRPSSTVUWTVSSTOUMVLXLZM[O\\S]U^V_VaTbRbOaPaRb OMNONQOR NVMXMZN[ VKSKQLPMOOOQQSST VTSTPUOVNXNZP\\S]",
+ "H\\QMNNLPKSKULXNZQ[S[VZXXYUYSXPVNSMQM MPLRLVMX WXXVXRWP QMONNOMRMVNYOZQ[ S[UZVYWVWRVOUNSM",
+ "G]IQJOKNMM[M KOMNZN IQJPLO[O OONZM[LZMWOO UOVZW[XZWWUO [M[O OOMZ UOWZ",
+ "G\\QMNNLPKTKb MPLTLa QMONNOMSMb MWNYOZQ[S[VZXXYUYSXPVNSMQM WXXVXRWP S[UZVYWVWRVOUNSM KbMb",
+ "G]PMMNKPJSJUKXMZP[R[UZWXXUXSWPUNRM LPKRKVLX VXWVWRVP PMNNMOLRLVMYNZP[ R[TZUYVVVRUOTNRM RMZO[N[MPM RMZN",
+ "H\\JQKOLNNMZM LONNYN JQKPMOZO ROQZR[SZRO ZMZO RORZ",
+ "G\\JMKNLPLUMXOZQ[S[UZWXXVYRYNXMWMXPXSWWUZ KMLNMPMUNX WMXNXO HPINJMLMMNNPNVOYQ[",
+ "G]RQQNPMNMLNKOJRJUKXMZP[T[WZYXZUZRYOXNVMTMSNRQ LOKRKULX XXYUYRXO NMMNLQLVMYNZP[ T[VZWYXVXQWNVM RQQb RQRa RQSb QbSb",
+ "H\\LMMNNPT_VaXbZb[a NOOPU_V` INJMLMNNPPV_WaXb VSXPYMZMYOVSN\\K`JbKbL_N\\",
+ "F]HNINJPJUKXMZP[T[VZXXYVZRZNYMXMYPYSXWVZ JNKPKULX XMYNYO GPHNIMJMKNLPLVMYNZP[ QFSb RGRa SFQb QFSF QbSb",
+ "F^NMLNJPISIWJYKZM[O[QZRYSWSTRSQTQWRYSZU[W[YZZY[W[SZPXNVM KPJSJWKY RTRX YYZWZSYP NMLOKRKWLZM[ W[XZYWYRXOVM",
+ "G]WMUTUXVZW[Y[[Y\\W XMVTVZ WMYMWTVX UTUQTNRMPMMNKQJTJVKYLZN[P[RZSYTWUT NNLQKTKWLY PMNOMQLTLWMZN[",
+ "I\\PFNMMSMWNYOZQ[S[VZXWYTYRXOWNUMSMQNPOOQNT QFOMNQNWOZ VYWWXTXQWO MFRFPMNT S[UYVWWTWQVNUM NFQG OFPH",
+ "I[WQWPVPVRXRXPWNUMRMONMQLTLVMYNZP[R[UZWW OONQMTMWNY RMPOOQNTNWOZP[",
+ "G]YFVQUUUXVZW[Y[[Y\\W ZFWQVUVZ VF[FWTVX UTUQTNRMPMMNKQJTJVKYLZN[P[RZSYTWUT MOLQKTKWLY PMNOMQLTLWMZN[ WFZG XFYH",
+ "I[MVQUTTWRXPWNUMRMONMQLTLVMYNZP[R[UZWX OONQMTMWNY RMPOOQNTNWOZP[",
+ "JZZHZGYGYI[I[GZFXFVGTISKRNQRO[N^M`Kb TJSMRRP[O^ XFVHUJTMSRQZP]O_MaKbIbHaH_J_JaIaI` NMYM",
+ "H]XMT[S^QaOb YMU[S_ XMZMV[T_RaObLbJaI`I^K^K`J`J_ VTVQUNSMQMNNLQKTKVLYMZO[Q[SZTYUWVT NOMQLTLWMY QMOONQMTMWNZO[",
+ "G]OFI[K[ PFJ[ LFQFK[ MTOPQNSMUMWNXPXSVX WNWRVVVZ WPUUUXVZW[Y[[Y\\W MFPG NFOH",
+ "KXTFTHVHVFTF UFUH TGVG LQMOOMQMRNSPSSQX RNRRQVQZ RPPUPXQZR[T[VYWW",
+ "KXUFUHWHWFUF VFVH UGWG MQNOPMRMSNTPTSRZQ]P_NaLbJbIaI_K_KaJaJ` SNSSQZP]O_ SPRTP[O^N`Lb",
+ "G]OFI[K[ PFJ[ LFQFK[ YOYNXNXPZPZNYMWMUNQROS MSOSQTRUTYUZWZ QUSYTZ OSPTRZS[U[WZYW MFPG NFOH",
+ "LXTFQQPUPXQZR[T[VYWW UFRQQUQZ QFVFRTQX RFUG SFTH",
+ "@cAQBODMFMGNHPHSF[ GNGSE[ GPFTD[F[ HSJPLNNMPMRNSPSSQ[ RNRSP[ RPQTO[Q[ SSUPWNYM[M]N^P^S\\X ]N]R\\V\\Z ]P[U[X\\Z][_[aYbW",
+ "F^GQHOJMLMMNNPNSL[ MNMSK[ MPLTJ[L[ NSPPRNTMVMXNYPYSWX XNXRWVWZ XPVUVXWZX[Z[\\Y]W",
+ "H\\QMNNLQKTKVLYMZP[S[VZXWYTYRXOWNTMQM NOMQLTLWMY VYWWXTXQWO QMOONQMTMWNZP[ S[UYVWWTWQVNTM",
+ "G]HQIOKMMMNNOPOSNWKb NNNSMWJb NPMTIb OTPQQORNTMVMXNYOZRZTYWWZT[R[PZOWOT XOYQYTXWWY VMWNXQXTWWVYT[ FbNb JaGb J`Hb K`Lb JaMb",
+ "G\\WMQb XMRb WMYMSb UTUQTNRMPMMNKQJTJVKYLZN[P[RZSYTWUT MOLQKTKWLY PMNOMQLTLWMZN[ NbVb RaOb R`Pb S`Tb RaUb",
+ "I[JQKOMMOMPNQPQTO[ PNPTN[ PPOTM[O[ YOYNXNXPZPZNYMWMUNSPQT",
+ "J[XPXOWOWQYQYOXNUMRMONNONQOSQTTUVVWX ONNQ ORQSTTVU WVVZ NOOQQRTSVTWVWXVZS[P[MZLYLWNWNYMYMX",
+ "KYTFQQPUPXQZR[T[VYWW UFRQQUQZ TFVFRTQX NMXM",
+ "F^GQHOJMLMMNNPNSLX MNMRLVLZ MPKUKXLZN[P[RZTXVU XMVUVXWZX[Z[\\Y]W YMWUWZ XMZMXTWX",
+ "H\\IQJOLMNMONPPPSNX ONORNVNZ OPMUMXNZP[R[TZVXXUYQYMXMXNYP",
+ "CaDQEOGMIMJNKPKSIX JNJRIVIZ JPHUHXIZK[M[OZQXRU TMRURXSZU[W[YZ[X]U^Q^M]M]N^P UMSUSZ TMVMTTSX",
+ "G]JQLNNMPMRNSPSR PMQNQRPVOXMZK[I[HZHXJXJZIZIY RORRQVQY ZOZNYNYP[P[NZMXMVNTPSRRVRZS[ PVPXQZS[U[WZYW",
+ "G]HQIOKMMMNNOPOSMX NNNRMVMZ NPLULXMZO[Q[SZUXWT YMU[T^RaPb ZMV[T_ YM[MW[U_SaPbMbKaJ`J^L^L`K`K_",
+ "H\\YMXOVQNWLYK[ XOOOMPLR VORNONNO VORMOMMOLR LYUYWXXV NYRZUZVY NYR[U[WYXV",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "H\\WQVOUNSMQMNNLPKSKULXNZQ[S[VZWYXWYSYNXJWHVGSFQFNGMHNHOGQF MPLRLVMX VYWWXSXNWJVH QMONNOMRMVNYOZQ[ S[UZVXWTWMVIUGSF",
+ "I[UMWNXOYOXNUMRMONMPLSLUMXOZR[U[XZYYXYWZU[ NPMSMUNX RMPNOONRNVOYPZR[ NTTUUTTSNT NTTT",
+ "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF NHMJLNLSMWNY VYWWXSXNWJVH QFOGNIMNMSNXOZQ[ S[UZVXWSWNVIUGSF LPXQ LQXP",
+ "G]PMMNKPJSJUKXMZP[T[WZYXZUZSYPWNTMPM LPKSKULX XXYUYSXP PMNNMOLRLVMYNZP[T[VZWYXVXRWOVNTM QFSb RGRa SFQb QFSF QbSb",
+ "H\\TMVNXPYPYOWNTMPMMNLOKQKSLUNWPXRYSZT\\T^S_Q_O^P^Q_ MOLQLSMUOW PMNNMPMSNURY YPXO",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "NV",
+ "JZ",
+ "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF NHMJLNLSMWNY VYWWXSXNWJVH QFOGNIMNMSNXOZQ[ S[UZVXWSWNVIUGSF",
+ "H\\QHQ[ RHRZ SFS[ SFPINJ M[W[ QZO[ QYP[ SYT[ SZU[",
+ "H\\LJLKMKMJLJ LIMINJNKMLLLKKKJLHMGPFTFWGXHYJYLXNUPPRNSLUKXK[ WHXJXLWN TFVGWJWLVNTPPR KYLXNXSYWYYX NXSZWZXY NXS[W[XZYXYV",
+ "H\\LJLKMKMJLJ LIMINJNKMLLLKKKJLHMGPFTFWGXIXLWNTO VGWIWLVN SFUGVIVLUNSO QOTOVPXRYTYWXYWZT[P[MZLYKWKVLUMUNVNWMXLX WRXTXWWY SOUPVQWTWWVZT[ LVLWMWMVLV",
+ "H\\SIS[ THTZ UFU[ UFJUZU P[X[ SZQ[ SYR[ UYV[ UZW[",
+ "H\\MFKPMNPMSMVNXPYSYUXXVZS[P[MZLYKWKVLUMUNVNWMXLX WPXRXVWX SMUNVOWRWVVYUZS[ LVLWMWMVLV MFWF MGUG MHQHUGWF",
+ "H\\VIVJWJWIVI WHVHUIUJVKWKXJXIWGUFRFOGMILKKOKULXNZQ[S[VZXXYUYTXQVOSNQNOONPMR NIMKLOLUMXNY WXXVXSWQ RFPGOHNJMNMUNXOZQ[ S[UZVYWVWSVPUOSN",
+ "H\\KFKL YFYIXLTQSSRWR[ SRRTQWQ[ XLSQQTPWP[R[ KJLHNFPFUIWIXHYF MHNGPGRH KJLINHPHUI",
+ "H\\PFMGLILLMNPOTOWNXLXIWGTFPF NGMIMLNN VNWLWIVG PFOGNINLONPO TOUNVLVIUGTF POMPLQKSKWLYMZP[T[WZXYYWYSXQWPTO MQLSLWMY WYXWXSWQ PONPMSMWNZP[ T[VZWWWSVPTO",
+ "H\\MWMXNXNWMW WOVQURSSQSNRLPKMKLLINGQFSFVGXIYLYRXVWXUZR[O[MZLXLWMVNVOWOXNYMY MPLNLKMI VHWIXLXRWVVX QSORNQMNMKNHOGQF SFUGVIWLWSVWUYTZR[",
+ "MXRXQYQZR[S[TZTYSXRX RYRZSZSYRY",
+ "MXTZS[R[QZQYRXSXTYT\\S^Q_ RYRZSZSYRY S[T\\ TZS^",
+ "MXRMQNQORPSPTOTNSMRM RNROSOSNRN RXQYQZR[S[TZTYSXRX RYRZSZSYRY",
+ "MXRMQNQORPSPTOTNSMRM RNROSOSNRN TZS[R[QZQYRXSXTYT\\S^Q_ RYRZSZSYRY S[T\\ TZS^",
+ "MXRFQGQIRQ RFRTST RFSFST SFTGTISQ RXQYQZR[S[TZTYSXRX RYRZSZSYRY",
+ "I\\MKMJNJNLLLLJMHNGPFTFWGXHYJYLXNWOSQ WHXIXMWN TFVGWIWMVOUP RQRTSTSQRQ RXQYQZR[S[TZTYSXRX RYRZSZSYRY",
+ "MXTFRGQIQLRMSMTLTKSJRJQK RKRLSLSKRK RGQK QIRJ",
+ "MXTHSIRIQHQGRFSFTGTJSLQM RGRHSHSGRG SITJ THSL",
+ "E_[O[NZNZP\\P\\N[MZMYNXPVUTXRZP[L[JZIXIUJSPORMSKSIRGPFNGMIMLNOPRTWWZY[[[\\Y\\X KZJXJUKSLR RMSI SKRG NGMK NNPQTVWYYZ N[LZKXKULSPO MINMQQUVXYZZ[Z\\Y",
+ "H\\PBP_ TBT_ XKXJWJWLYLYJXHWGTFPFMGKIKLLNOPURWSXUXXWZ LLMNOOUQWRXT MGLILKMMONUPXRYTYWXYWZT[P[MZLYKWKUMUMWLWLV",
+ "G^[BIbJb [B\\BJb",
+ "KYUBSDQGOKNPNTOYQ]S`Ub QHPKOOOUPYQ\\ SDRFQIPOPUQ[R^S`",
+ "KYOBQDSGUKVPVTUYS]Q`Ob SHTKUOUUTYS\\ QDRFSITOTUS[R^Q`",
+ "JZRFQGSQRR RFRR RFSGQQRR MINIVOWO MIWO MIMJWNWO WIVINOMO WIMO WIWJMNMO",
+ "F_JQ[Q[R JQJR[R",
+ "F_RIRZSZ RISISZ JQ[Q[R JQJR[R",
+ "F_JM[M[N JMJN[N JU[U[V JUJV[V",
+ "NWSFRGRM SGRM SFTGRM",
+ "I[NFMGMM NGMM NFOGMM WFVGVM WGVM WFXGVM",
+ "KYQFOGNINKOMQNSNUMVKVIUGSFQF QFNIOMSNVKUGQF SFOGNKQNUMVISF",
+ "F^ZIJRZ[ ZIZJLRZZZ[",
+ "F^JIZRJ[ JIJJXRJZJ[",
+ "G^OFObPb OFPFPb UFUbVb UFVFVb JP[P[Q JPJQ[Q JW[W[X JWJX[X",
+ "F^[FYGVHSHPGNFLFJGIIIKKMMMOLPJPHNF [FH[ [FI[ [FJ[ YTWTUUTWTYV[X[ZZ[X[VYT OGLFIIJLMMPJOG NFJGIK KMOLPH ZUWTTWUZX[[XZU YTUUTY V[ZZ[V H[J[",
+ "E`VNULSKQKOLNMMOMRNTOUQVSVUUVS OMNONROT QKPLOOORPUQV VKVSWUYVZV\\U]R]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYYXYWZ WLWSXU VKXKXSYUZV",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "NV",
+ "JZ",
+ "H]TFQGOIMLLOKSKVLYMZO[Q[TZVXXUYRZNZKYHXGVFTF QHOJNLMOLSLWMY TYVWWUXRYNYJXH TFRGPJOLNOMSMXNZO[ Q[SZUWVUWRXNXIWGVF",
+ "H]TJO[Q[ WFUJP[ WFQ[ WFTIQKOL TJRKOL",
+ "H]OKOJPJPLNLNJOHPGSFVFYGZIZKYMWOMUKWI[ XGYIYKXMVOSQ VFWGXIXKWMUOMU JYKXMXRYWYXX MXRZWZ MXR[U[WZXXXW",
+ "H]OKOJPJPLNLNJOHPGSFVFYGZIZKYMXNVOSP XGYIYKXMWN VFWGXIXKWMUOSP QPSPVQWRXTXWWYUZR[O[LZKYJWJULULWKWKV VRWTWWVY SPUQVSVWUYTZR[",
+ "H]WJR[T[ ZFXJS[ ZFT[ ZFJUZU",
+ "H]QFLP QF[F QGYG PHUHYG[F LPMOPNSNVOWPXRXUWXUZQ[N[LZKYJWJULULWKWKV VPWRWUVXTZ SNUOVQVUUXSZQ[",
+ "H]YJYIXIXKZKZIYGWFTFQGOIMLLOKSKVLYMZO[R[UZWXXVXSWQVPTOQOOPNQMS PINLMOLSLWMY VXWVWSVQ TFRGPJOLNOMSMXNZO[ R[TZUYVVVRUPTO",
+ "H]NFLL [FZIXLTQRTQWP[ RSPWO[ XLRRPUOWN[P[ MIPFRFWI OGRGWI MIOHRHWIYIZH[F",
+ "H]SFPGOHNJNMOOQPTPWOYNZLZIYGWFSF UFPG PHOJONPO OORP SPWO XNYLYIXG YGUF SFQHPJPNQP TPVOWNXLXHWF QPMQKSJUJXKZN[R[VZWYXWXTWRVQTP RPMQ NQLSKUKXLZ KZP[VZ VYWWWTVR VQSP QPOQMSLULXMZN[ R[TZUYVWVSUQTP",
+ "H]XNWPVQTRQROQNPMNMKNIPGSFVFXGYHZKZNYRXUVXTZQ[N[LZKXKVMVMXLXLW OPNNNKOI XHYJYNXRWUUX QRPQOOOKPHQGSF VFWGXIXNWRVUUWSZQ[",
+ "MXPXOYOZP[Q[RZRYQXPX PYPZQZQYPY",
+ "MXQ[P[OZOYPXQXRYR[Q]P^N_ PYPZQZQYPY Q[Q\\P^",
+ "MXSMRNROSPTPUOUNTMSM SNSOTOTNSN PXOYOZP[Q[RZRYQXPX PYPZQZQYPY",
+ "MXSMRNROSPTPUOUNTMSM SNSOTOTNSN Q[P[OZOYPXQXRYR[Q]P^N_ PYPZQZQYPY Q[Q\\P^",
+ "MXVFUFTGRT VGUGRT VGVHRT VFWGWHRT PXOYOZP[Q[RZRYQXPX PYPZQZQYPY",
+ "H]OKOJPJPLNLNJOHPGSFWFZG[I[KZMYNWOSPQQQSSTTT UFZG YGZIZKYMXNVO WFXGYIYKXMWNSPRQRSST PXOYOZP[Q[RZRYQXPX PYPZQZQYPY",
+ "MXWFUGTHSJSLTMUMVLVKUJTJ UGTITJ TKTLULUKTK",
+ "MXVIUITHTGUFVFWGWIVKULSM UGUHVHVGUG VIVJUL",
+ "E_\\O\\N[N[P]P]N\\M[MYNWPRXPZN[K[HZGXGVHTISKRPPROTMUKUITGRFPGOIOLPRQURWTZV[X[YYYX L[HZ IZHXHVITJSLR PPQSTYVZ K[JZIXIVJTKSMRRO OLPOQRSVUYWZXZYY",
+ "H]TBL_ YBQ_ ZKZJYJYL[L[JZHYGVFRFOGMIMLNNPPVSWUWXVZ NLONVRWT OGNINKOMUPWRXTXWWYVZS[O[LZKYJWJULULWKWKV",
+ "G^_BEbFb _B`BFb",
+ "JZZBXCUERHPKNOMSMXN\\O_Qb SHQKOONTN\\ ZBWDTGRJQLPOOSN\\ NTO]P`Qb",
+ "JZSBUEVHWLWQVUTYR\\O_LaJb VHVPUUSYQ\\ SBTDUGVP VHUQTUSXRZP]M`Jb",
+ "J[TFSGUQTR TFTR TFUGSQTR OIPIXOYO OIYO OIOJYNYO YIXIPOOO YIOO YIYJONOO",
+ "F_JQ[Q[R JQJR[R",
+ "F_RIRZSZ RISISZ JQ[Q[R JQJR[R",
+ "F_JM[M[N JMJN[N JU[U[V JUJV[V",
+ "MWUFTGRM UGRM UFVGRM",
+ "H\\PFOGMM PGMM PFQGMM ZFYGWM ZGWM ZF[GWM",
+ "KZSFQGPIPKQMSNUNWMXKXIWGUFSF SFPIQMUNXKWGSF UFQGPKSNWMXIUF",
+ "F^ZIJRZ[ ZIZJLRZZZ[",
+ "F^JIZRJ[ JIJJXRJZJ[",
+ "G^SFKbLb SFTFLb YFQbRb YFZFRb KP\\P\\Q KPKQ\\Q IWZWZX IWIXZX",
+ "E^^F\\GXHUHQGOFMFKGJIJKLMNMPLQJQHOF ^FE[ ^FF[ ^FG[ XTVTTUSWSYU[W[YZZXZVXT PGMFJIKLNMQJPG OFKGJK LMPLQH YUVTSWTZW[ZXYU XTTUSY U[YZZV E[G[",
+ "E`UQUNTLRKPKNLMMLPLSMUOVQVSUTTUQ OLNMMPMSNU RKPLOMNPNSOUPV VKUQUSVUXVZV\\U]R]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYYXYWZ WKVQVSWU VKXKWQWSXUZV",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ 0 };
diff --git a/cxcore/src/cxpersistence.cpp b/cxcore/src/cxpersistence.cpp
new file mode 100644
index 0000000..75efa94
--- /dev/null
+++ b/cxcore/src/cxpersistence.cpp
@@ -0,0 +1,5250 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+#include <ctype.h>
+
+/****************************************************************************************\
+* Common macros and type definitions *
+\****************************************************************************************/
+
+#define cv_isprint(c) ((signed char)(c) >= (signed char)' ')
+#define cv_isprint_or_tab(c) ((signed char)(c) >= (signed char)' ' || (c) == '\t')
+
+static char* icv_itoa( int _val, char* buffer, int /*radix*/ )
+{
+ const int radix = 10;
+ char* ptr=buffer + 23 /* enough even for 64-bit integers */;
+ unsigned val = abs(_val);
+
+ *ptr = '\0';
+ do
+ {
+ unsigned r = val / radix;
+ *--ptr = (char)(val - (r*radix) + '0');
+ val = r;
+ }
+ while( val != 0 );
+
+ if( _val < 0 )
+ *--ptr = '-';
+
+ return ptr;
+}
+
+
+typedef struct CvGenericHash
+{
+ CV_SET_FIELDS()
+ int tab_size;
+ void** table;
+}
+CvGenericHash;
+
+typedef CvGenericHash CvStringHash;
+
+typedef struct CvFileMapNode
+{
+ CvFileNode value;
+ const CvStringHashNode* key;
+ struct CvFileMapNode* next;
+}
+CvFileMapNode;
+
+typedef struct CvXMLStackRecord
+{
+ CvMemStoragePos pos;
+ CvString struct_tag;
+ int struct_indent;
+ int struct_flags;
+}
+CvXMLStackRecord;
+
+#define CV_XML_OPENING_TAG 1
+#define CV_XML_CLOSING_TAG 2
+#define CV_XML_EMPTY_TAG 3
+#define CV_XML_HEADER_TAG 4
+#define CV_XML_DIRECTIVE_TAG 5
+
+//typedef void (*CvParse)( struct CvFileStorage* fs );
+typedef void (*CvStartWriteStruct)( struct CvFileStorage* fs, const char* key,
+ int struct_flags, const char* type_name );
+typedef void (*CvEndWriteStruct)( struct CvFileStorage* fs );
+typedef void (*CvWriteInt)( struct CvFileStorage* fs, const char* key, int value );
+typedef void (*CvWriteReal)( struct CvFileStorage* fs, const char* key, double value );
+typedef void (*CvWriteString)( struct CvFileStorage* fs, const char* key,
+ const char* value, int quote );
+typedef void (*CvWriteComment)( struct CvFileStorage* fs, const char* comment, int eol_comment );
+typedef void (*CvStartNextStream)( struct CvFileStorage* fs );
+
+typedef struct CvFileStorage
+{
+ int flags;
+ int is_xml;
+ int write_mode;
+ int is_first;
+ CvMemStorage* memstorage;
+ CvMemStorage* dststorage;
+ CvMemStorage* strstorage;
+ CvStringHash* str_hash;
+ CvSeq* roots;
+ CvSeq* write_stack;
+ int struct_indent;
+ int struct_flags;
+ CvString struct_tag;
+ int space;
+ char* filename;
+ FILE* file;
+ char* buffer;
+ char* buffer_start;
+ char* buffer_end;
+ int wrap_margin;
+ int lineno;
+ int dummy_eof;
+ const char* errmsg;
+ char errmsgbuf[128];
+
+ CvStartWriteStruct start_write_struct;
+ CvEndWriteStruct end_write_struct;
+ CvWriteInt write_int;
+ CvWriteReal write_real;
+ CvWriteString write_string;
+ CvWriteComment write_comment;
+ CvStartNextStream start_next_stream;
+ //CvParse parse;
+}
+CvFileStorage;
+
+
+#define CV_YML_INDENT 3
+#define CV_XML_INDENT 2
+#define CV_YML_INDENT_FLOW 1
+#define CV_FS_MAX_LEN 4096
+
+#define CV_FILE_STORAGE ('Y' + ('A' << 8) + ('M' << 16) + ('L' << 24))
+#define CV_IS_FILE_STORAGE(fs) ((fs) != 0 && (fs)->flags == CV_FILE_STORAGE)
+
+#define CV_CHECK_FILE_STORAGE(fs) \
+{ \
+ if( !CV_IS_FILE_STORAGE(fs) ) \
+ CV_ERROR( (fs) ? CV_StsBadArg : CV_StsNullPtr, \
+ "Invalid pointer to file storage" ); \
+}
+
+#define CV_CHECK_OUTPUT_FILE_STORAGE(fs) \
+{ \
+ CV_CHECK_FILE_STORAGE(fs); \
+ if( !fs->write_mode ) \
+ CV_ERROR( CV_StsError, "The file storage is opened for reading" ); \
+}
+
+CV_IMPL const char*
+cvAttrValue( const CvAttrList* attr, const char* attr_name )
+{
+ while( attr && attr->attr )
+ {
+ int i;
+ for( i = 0; attr->attr[i*2] != 0; i++ )
+ {
+ if( strcmp( attr_name, attr->attr[i*2] ) == 0 )
+ return attr->attr[i*2+1];
+ }
+ attr = attr->next;
+ }
+
+ return 0;
+}
+
+
+static CvGenericHash*
+cvCreateMap( int flags, int header_size, int elem_size,
+ CvMemStorage* storage, int start_tab_size )
+{
+ CvGenericHash* map = 0;
+
+ CV_FUNCNAME( "cvCreateMap" );
+
+ __BEGIN__;
+
+ if( header_size < (int)sizeof(CvGenericHash) )
+ CV_ERROR( CV_StsBadSize, "Too small map header_size" );
+
+ if( start_tab_size <= 0 )
+ start_tab_size = 16;
+
+ CV_CALL( map = (CvGenericHash*)cvCreateSet( flags, header_size, elem_size, storage ));
+
+ map->tab_size = start_tab_size;
+ start_tab_size *= sizeof(map->table[0]);
+ CV_CALL( map->table = (void**)cvMemStorageAlloc( storage, start_tab_size ));
+ memset( map->table, 0, start_tab_size );
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ map = 0;
+
+ return map;
+}
+
+
+#define CV_PARSE_ERROR( errmsg ) \
+{ \
+ icvParseError( fs, cvFuncName, (errmsg), __FILE__, __LINE__ ); \
+ EXIT; \
+}
+
+
+static void
+icvParseError( CvFileStorage* fs, const char* func_name,
+ const char* err_msg, const char* source_file, int source_line )
+{
+ char buf[1<<10];
+ sprintf( buf, "%s(%d): %s", fs->filename, fs->lineno, err_msg );
+ cvError( CV_StsParseError, func_name, buf, source_file, source_line );
+}
+
+
+static void
+icvFSCreateCollection( CvFileStorage* fs, int tag, CvFileNode* collection )
+{
+ CV_FUNCNAME( "icvFSCreateCollection" );
+
+ __BEGIN__;
+
+ if( CV_NODE_IS_MAP(tag) )
+ {
+ if( collection->tag != CV_NODE_NONE )
+ {
+ assert( fs->is_xml != 0 );
+ CV_PARSE_ERROR( "Sequence element should not have name (use <_></_>)" );
+ }
+
+ CV_CALL( collection->data.map = cvCreateMap( 0, sizeof(CvFileNodeHash),
+ sizeof(CvFileMapNode), fs->memstorage, 16 ));
+ }
+ else
+ {
+ CvSeq* seq;
+ CV_CALL( seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvFileNode), fs->memstorage ));
+
+ // if <collection> contains some scalar element, add it to the newly created collection
+ if( CV_NODE_TYPE(collection->tag) != CV_NODE_NONE )
+ cvSeqPush( seq, collection );
+
+ collection->data.seq = seq;
+ }
+
+ collection->tag = tag;
+ cvSetSeqBlockSize( collection->data.seq, 8 );
+
+ __END__;
+}
+
+
+/*static void
+icvFSReleaseCollection( CvSeq* seq )
+{
+ if( seq )
+ {
+ int is_map = CV_IS_SET(seq);
+ CvSeqReader reader;
+ int i, total = seq->total;
+ cvStartReadSeq( seq, &reader, 0 );
+
+ for( i = 0; i < total; i++ )
+ {
+ CvFileNode* node = (CvFileNode*)reader.ptr;
+
+ if( (!is_map || CV_IS_SET_ELEM( node )) && CV_NODE_IS_COLLECTION(node->tag) )
+ {
+ if( CV_NODE_IS_USER(node->tag) && node->info && node->data.obj.decoded )
+ cvRelease( (void**)&node->data.obj.decoded );
+ if( !CV_NODE_SEQ_IS_SIMPLE( node->data.seq ))
+ icvFSReleaseCollection( node->data.seq );
+ }
+ CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
+ }
+ }
+}*/
+
+
+static char*
+icvFSDoResize( CvFileStorage* fs, char* ptr, int len )
+{
+ char* new_ptr = 0;
+ CV_FUNCNAME( "icvFSDoResize" );
+
+ __BEGIN__;
+
+ int written_len = (int)(ptr - fs->buffer_start);
+ int new_size = (int)((fs->buffer_end - fs->buffer_start)*3/2);
+ new_size = MAX( written_len + len, new_size );
+ CV_CALL( new_ptr = (char*)cvAlloc( new_size + 256 ));
+ fs->buffer = new_ptr + (fs->buffer - fs->buffer_start);
+ if( written_len > 0 )
+ memcpy( new_ptr, fs->buffer_start, written_len );
+ fs->buffer_start = new_ptr;
+ fs->buffer_end = fs->buffer_start + new_size;
+ new_ptr += written_len;
+
+ __END__;
+
+ return new_ptr;
+}
+
+
+inline char* icvFSResizeWriteBuffer( CvFileStorage* fs, char* ptr, int len )
+{
+ return ptr + len < fs->buffer_end ? ptr : icvFSDoResize( fs, ptr, len );
+}
+
+
+static char*
+icvFSFlush( CvFileStorage* fs )
+{
+ char* ptr = fs->buffer;
+ int indent;
+
+ if( ptr > fs->buffer_start + fs->space )
+ {
+ ptr[0] = '\n';
+ ptr[1] = '\0';
+ fputs( fs->buffer_start, fs->file );
+ fs->buffer = fs->buffer_start;
+ }
+
+ indent = fs->struct_indent;
+
+ if( fs->space != indent )
+ {
+ if( fs->space < indent )
+ memset( fs->buffer_start + fs->space, ' ', indent - fs->space );
+ fs->space = indent;
+ }
+
+ ptr = fs->buffer = fs->buffer_start + fs->space;
+
+ return ptr;
+}
+
+
+/* closes file storage and deallocates buffers */
+CV_IMPL void
+cvReleaseFileStorage( CvFileStorage** p_fs )
+{
+ CV_FUNCNAME("cvReleaseFileStorage" );
+
+ __BEGIN__;
+
+ if( !p_fs )
+ CV_ERROR( CV_StsNullPtr, "NULL double pointer to file storage" );
+
+ if( *p_fs )
+ {
+ CvFileStorage* fs = *p_fs;
+ *p_fs = 0;
+
+ if( fs->write_mode && fs->file )
+ {
+ if( fs->write_stack )
+ {
+ while( fs->write_stack->total > 0 )
+ cvEndWriteStruct(fs);
+ }
+ icvFSFlush(fs);
+ if( fs->is_xml )
+ fputs("</opencv_storage>\n", fs->file );
+ }
+
+ //icvFSReleaseCollection( fs->roots ); // delete all the user types recursively
+
+ if( fs->file )
+ {
+ fclose( fs->file );
+ fs->file = 0;
+ }
+
+ cvReleaseMemStorage( &fs->strstorage );
+
+ cvFree( &fs->buffer_start );
+ cvReleaseMemStorage( &fs->memstorage );
+
+ memset( fs, 0, sizeof(*fs) );
+ cvFree( &fs );
+ }
+
+ __END__;
+}
+
+
+#define CV_HASHVAL_SCALE 33
+
+CV_IMPL CvStringHashNode*
+cvGetHashedKey( CvFileStorage* fs, const char* str, int len, int create_missing )
+{
+ CvStringHashNode* node = 0;
+ CV_FUNCNAME( "cvGetHashedKey" );
+
+ __BEGIN__;
+
+ unsigned hashval = 0;
+ int i, tab_size;
+ CvStringHash* map = fs->str_hash;
+
+ if( !fs )
+ EXIT;
+
+ if( len < 0 )
+ {
+ for( i = 0; str[i] != '\0'; i++ )
+ hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i];
+ len = i;
+ }
+ else for( i = 0; i < len; i++ )
+ hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i];
+
+ hashval &= INT_MAX;
+ tab_size = map->tab_size;
+ if( (tab_size & (tab_size - 1)) == 0 )
+ i = (int)(hashval & (tab_size - 1));
+ else
+ i = (int)(hashval % tab_size);
+
+ for( node = (CvStringHashNode*)(map->table[i]); node != 0; node = node->next )
+ {
+ if( node->hashval == hashval &&
+ node->str.len == len &&
+ memcmp( node->str.ptr, str, len ) == 0 )
+ break;
+ }
+
+ if( !node && create_missing )
+ {
+ node = (CvStringHashNode*)cvSetNew( (CvSet*)map );
+ node->hashval = hashval;
+ CV_CALL( node->str = cvMemStorageAllocString( map->storage, str, len ));
+ node->next = (CvStringHashNode*)(map->table[i]);
+ map->table[i] = node;
+ }
+
+ __END__;
+
+ return node;
+}
+
+
+CV_IMPL CvFileNode*
+cvGetFileNode( CvFileStorage* fs, CvFileNode* _map_node,
+ const CvStringHashNode* key,
+ int create_missing )
+{
+ CvFileNode* value = 0;
+
+ CV_FUNCNAME( "cvGetFileNode" );
+
+ __BEGIN__;
+
+ int k = 0, attempts = 1;
+
+ if( !fs )
+ EXIT;
+
+ CV_CHECK_FILE_STORAGE(fs);
+
+ if( !key )
+ CV_ERROR( CV_StsNullPtr, "Null key element" );
+
+ if( _map_node )
+ {
+ if( !fs->roots )
+ EXIT;
+ attempts = fs->roots->total;
+ }
+
+ for( k = 0; k < attempts; k++ )
+ {
+ int i, tab_size;
+ CvFileNode* map_node = _map_node;
+ CvFileMapNode* another;
+ CvFileNodeHash* map;
+
+ if( !map_node )
+ map_node = (CvFileNode*)cvGetSeqElem( fs->roots, k );
+
+ if( !CV_NODE_IS_MAP(map_node->tag) )
+ {
+ if( (!CV_NODE_IS_SEQ(map_node->tag) || map_node->data.seq->total != 0) &&
+ CV_NODE_TYPE(map_node->tag) != CV_NODE_NONE )
+ CV_ERROR( CV_StsError, "The node is neither a map nor an empty collection" );
+ EXIT;
+ }
+
+ map = map_node->data.map;
+ tab_size = map->tab_size;
+
+ if( (tab_size & (tab_size - 1)) == 0 )
+ i = (int)(key->hashval & (tab_size - 1));
+ else
+ i = (int)(key->hashval % tab_size);
+
+ for( another = (CvFileMapNode*)(map->table[i]); another != 0; another = another->next )
+ if( another->key == key )
+ {
+ if( !create_missing )
+ {
+ value = &another->value;
+ EXIT;
+ }
+ CV_PARSE_ERROR( "Duplicated key" );
+ }
+
+ if( k == attempts - 1 && create_missing )
+ {
+ CvFileMapNode* node = (CvFileMapNode*)cvSetNew( (CvSet*)map );
+ node->key = key;
+
+ node->next = (CvFileMapNode*)(map->table[i]);
+ map->table[i] = node;
+ value = (CvFileNode*)node;
+ }
+ }
+
+ __END__;
+
+ return value;
+}
+
+
+CV_IMPL CvFileNode*
+cvGetFileNodeByName( const CvFileStorage* fs, const CvFileNode* _map_node, const char* str )
+{
+ CvFileNode* value = 0;
+ CV_FUNCNAME( "cvGetFileNodeByName" );
+
+ __BEGIN__;
+
+ int i, len, tab_size;
+ unsigned hashval = 0;
+ int k = 0, attempts = 1;
+
+ if( !fs )
+ EXIT;
+
+ CV_CHECK_FILE_STORAGE(fs);
+
+ if( !str )
+ CV_ERROR( CV_StsNullPtr, "Null element name" );
+
+ for( i = 0; str[i] != '\0'; i++ )
+ hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i];
+ hashval &= INT_MAX;
+ len = i;
+
+ if( !_map_node )
+ {
+ if( !fs->roots )
+ EXIT;
+ attempts = fs->roots->total;
+ }
+
+ for( k = 0; k < attempts; k++ )
+ {
+ CvFileNodeHash* map;
+ const CvFileNode* map_node = _map_node;
+ CvFileMapNode* another;
+
+ if( !map_node )
+ map_node = (CvFileNode*)cvGetSeqElem( fs->roots, k );
+
+ if( !CV_NODE_IS_MAP(map_node->tag) )
+ {
+ if( (!CV_NODE_IS_SEQ(map_node->tag) || map_node->data.seq->total != 0) &&
+ CV_NODE_TYPE(map_node->tag) != CV_NODE_NONE )
+ CV_ERROR( CV_StsError, "The node is neither a map nor an empty collection" );
+ EXIT;
+ }
+
+ map = map_node->data.map;
+ tab_size = map->tab_size;
+
+ if( (tab_size & (tab_size - 1)) == 0 )
+ i = (int)(hashval & (tab_size - 1));
+ else
+ i = (int)(hashval % tab_size);
+
+ for( another = (CvFileMapNode*)(map->table[i]); another != 0; another = another->next )
+ {
+ const CvStringHashNode* key = another->key;
+
+ if( key->hashval == hashval &&
+ key->str.len == len &&
+ memcmp( key->str.ptr, str, len ) == 0 )
+ {
+ value = &another->value;
+ EXIT;
+ }
+ }
+ }
+
+ __END__;
+
+ return value;
+}
+
+
+CV_IMPL CvFileNode*
+cvGetRootFileNode( const CvFileStorage* fs, int stream_index )
+{
+ CvFileNode* value = 0;
+ CV_FUNCNAME( "cvGetRootFileNode" );
+
+ __BEGIN__;
+
+ CV_CHECK_FILE_STORAGE(fs);
+
+ if( !fs->roots || (unsigned)stream_index >= (unsigned)fs->roots->total )
+ EXIT;
+
+ value = (CvFileNode*)cvGetSeqElem( fs->roots, stream_index );
+
+ __END__;
+
+ return value;
+}
+
+
+/* returns the sequence element by its index */
+/*CV_IMPL CvFileNode*
+cvGetFileNodeFromSeq( CvFileStorage* fs,
+ CvFileNode* seq_node, int index )
+{
+ CvFileNode* value = 0;
+
+ CV_FUNCNAME( "cvGetFileNodeFromSeq" );
+
+ __BEGIN__;
+
+ CvSeq* seq;
+
+ if( !seq_node )
+ seq = fs->roots;
+ else if( !CV_NODE_IS_SEQ(seq_node->tag) )
+ {
+ if( CV_NODE_IS_MAP(seq_node->tag) )
+ CV_ERROR( CV_StsError, "The node is map. Use cvGetFileNodeFromMap()." );
+ if( CV_NODE_TYPE(seq_node->tag) == CV_NODE_NONE )
+ CV_ERROR( CV_StsError, "The node is an empty object (None)." );
+ if( index != 0 && index != -1 )
+ CV_ERROR( CV_StsOutOfRange, "" );
+ value = seq_node;
+ EXIT;
+ }
+ else
+ seq = seq_node->data.seq;
+
+ if( !seq )
+ CV_ERROR( CV_StsNullPtr, "The file storage is empty" );
+
+ value = (CvFileNode*)cvGetSeqElem( seq, index, 0 );
+
+ __END__;
+
+ return value;
+}*/
+
+
+static char*
+icvDoubleToString( char* buf, double value )
+{
+ Cv64suf val;
+ unsigned ieee754_hi;
+
+ val.f = value;
+ ieee754_hi = (unsigned)(val.u >> 32);
+
+ if( (ieee754_hi & 0x7ff00000) != 0x7ff00000 )
+ {
+ int ivalue = cvRound(value);
+ if( ivalue == value )
+ sprintf( buf, "%d.", ivalue );
+ else
+ {
+ static const char* fmt[] = {"%.16e", "%.16f"};
+ double avalue = fabs(value);
+ char* ptr = buf;
+ sprintf( buf, fmt[0.01 <= avalue && avalue < 1000], value );
+ if( *ptr == '+' || *ptr == '-' )
+ ptr++;
+ for( ; isdigit(*ptr); ptr++ )
+ ;
+ if( *ptr == ',' )
+ *ptr = '.';
+ }
+ }
+ else
+ {
+ unsigned ieee754_lo = (unsigned)val.u;
+ if( (ieee754_hi & 0x7fffffff) + (ieee754_lo != 0) > 0x7ff00000 )
+ strcpy( buf, ".Nan" );
+ else
+ strcpy( buf, (int)ieee754_hi < 0 ? "-.Inf" : ".Inf" );
+ }
+
+ return buf;
+}
+
+
+static char*
+icvFloatToString( char* buf, float value )
+{
+ Cv32suf val;
+ unsigned ieee754;
+ val.f = value;
+ ieee754 = val.u;
+
+ if( (ieee754 & 0x7f800000) != 0x7f800000 )
+ {
+ int ivalue = cvRound(value);
+ if( ivalue == value )
+ sprintf( buf, "%d.", ivalue );
+ else
+ {
+ static const char* fmt[] = {"%.8e", "%.8f"};
+ double avalue = fabs((double)value);
+ char* ptr = buf;
+ sprintf( buf, fmt[0.01 <= avalue && avalue < 1000], value );
+ if( *ptr == '+' || *ptr == '-' )
+ ptr++;
+ for( ; isdigit(*ptr); ptr++ )
+ ;
+ if( *ptr == ',' )
+ *ptr = '.';
+ }
+ }
+ else
+ {
+ if( (ieee754 & 0x7fffffff) != 0x7f800000 )
+ strcpy( buf, ".Nan" );
+ else
+ strcpy( buf, (int)ieee754 < 0 ? "-.Inf" : ".Inf" );
+ }
+
+ return buf;
+}
+
+
+static void
+icvProcessSpecialDouble( CvFileStorage* fs, char* buf, double* value, char** endptr )
+{
+ CV_FUNCNAME( "icvProcessSpecialDouble" );
+
+ __BEGIN__;
+
+ char c = buf[0];
+ int inf_hi = 0x7ff00000;
+
+ if( c == '-' || c == '+' )
+ {
+ inf_hi = c == '-' ? 0xfff00000 : 0x7ff00000;
+ c = *++buf;
+ }
+
+ if( c != '.' )
+ CV_PARSE_ERROR( "Bad format of floating-point constant" );
+
+ if( toupper(buf[1]) == 'I' && toupper(buf[2]) == 'N' && toupper(buf[3]) == 'F' )
+ *(uint64*)value = ((uint64)inf_hi << 32);
+ else if( toupper(buf[1]) == 'N' && toupper(buf[2]) == 'A' && toupper(buf[3]) == 'N' )
+ *(uint64*)value = (uint64)-1;
+ else
+ CV_PARSE_ERROR( "Bad format of floating-point constant" );
+
+ *endptr = buf + 4;
+
+ __END__;
+}
+
+
+static double icv_strtod( CvFileStorage* fs, char* ptr, char** endptr )
+{
+ double fval = strtod( ptr, endptr );
+ if( **endptr == '.' )
+ {
+ char* dot_pos = *endptr;
+ *dot_pos = ',';
+ double fval2 = strtod( ptr, endptr );
+ *dot_pos = '.';
+ if( *endptr > dot_pos )
+ fval = fval2;
+ else
+ *endptr = dot_pos;
+ }
+
+ if( *endptr == ptr || isalpha(**endptr) )
+ icvProcessSpecialDouble( fs, ptr, &fval, endptr );
+
+ return fval;
+}
+
+
+/****************************************************************************************\
+* YAML Parser *
+\****************************************************************************************/
+
+static char*
+icvYMLSkipSpaces( CvFileStorage* fs, char* ptr, int min_indent, int max_comment_indent )
+{
+ CV_FUNCNAME( "icvYMLSkipSpaces" );
+
+ __BEGIN__;
+
+ for(;;)
+ {
+ while( *ptr == ' ' )
+ ptr++;
+ if( *ptr == '#' )
+ {
+ if( ptr - fs->buffer_start > max_comment_indent )
+ EXIT;
+ *ptr = '\0';
+ }
+ else if( cv_isprint(*ptr) )
+ {
+ if( ptr - fs->buffer_start < min_indent )
+ CV_PARSE_ERROR( "Incorrect indentation" );
+ break;
+ }
+ else if( *ptr == '\0' || *ptr == '\n' || *ptr == '\r' )
+ {
+ int max_size = (int)(fs->buffer_end - fs->buffer_start);
+ ptr = fgets( fs->buffer_start, max_size, fs->file );
+ if( !ptr )
+ {
+ // emulate end of stream
+ ptr = fs->buffer_start;
+ ptr[0] = ptr[1] = ptr[2] = '.';
+ ptr[3] = '\0';
+ fs->dummy_eof = 1;
+ break;
+ }
+ else
+ {
+ int l = (int)strlen(ptr);
+ if( ptr[l-1] != '\n' && ptr[l-1] != '\r' && !feof(fs->file) )
+ CV_PARSE_ERROR( "Too long string or a last string w/o newline" );
+ }
+
+ fs->lineno++;
+ }
+ else
+ CV_PARSE_ERROR( *ptr == '\t' ? "Tabs are prohibited in YAML!" : "Invalid character" );
+ }
+
+ __END__;
+
+ return ptr;
+}
+
+
+static char*
+icvYMLParseKey( CvFileStorage* fs, char* ptr,
+ CvFileNode* map_node, CvFileNode** value_placeholder )
+{
+ CV_FUNCNAME( "icvYMLParseKey" );
+
+ __BEGIN__;
+
+ char c;
+ char *endptr = ptr - 1, *saveptr;
+ CvStringHashNode* str_hash_node;
+
+ if( *ptr == '-' )
+ CV_PARSE_ERROR( "Key may not start with \'-\'" );
+
+ do c = *++endptr;
+ while( cv_isprint(c) && c != ':' );
+
+ if( c != ':' )
+ CV_PARSE_ERROR( "Missing \':\'" );
+
+ saveptr = endptr + 1;
+ do c = *--endptr;
+ while( c == ' ' );
+
+ ++endptr;
+ if( endptr == ptr )
+ CV_PARSE_ERROR( "An empty key" );
+
+ CV_CALL( str_hash_node = cvGetHashedKey( fs, ptr, (int)(endptr - ptr), 1 ));
+ CV_CALL( *value_placeholder = cvGetFileNode( fs, map_node, str_hash_node, 1 ));
+ ptr = saveptr;
+
+ __END__;
+
+ return ptr;
+}
+
+
+static char*
+icvYMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
+ int parent_flags, int min_indent )
+{
+ CV_FUNCNAME( "icvYMLParseValue" );
+
+ __BEGIN__;
+
+ char buf[CV_FS_MAX_LEN + 1024];
+ char* endptr = 0;
+ char c = ptr[0], d = ptr[1];
+ int is_parent_flow = CV_NODE_IS_FLOW(parent_flags);
+ int value_type = CV_NODE_NONE;
+ int len;
+
+ memset( node, 0, sizeof(*node) );
+
+ if( c == '!' ) // handle explicit type specification
+ {
+ if( d == '!' || d == '^' )
+ {
+ ptr++;
+ value_type |= CV_NODE_USER;
+ }
+
+ endptr = ptr++;
+ do d = *++endptr;
+ while( cv_isprint(d) && d != ' ' );
+ len = (int)(endptr - ptr);
+ if( len == 0 )
+ CV_PARSE_ERROR( "Empty type name" );
+ d = *endptr;
+ *endptr = '\0';
+
+ if( len == 3 && !CV_NODE_IS_USER(value_type) )
+ {
+ if( memcmp( ptr, "str", 3 ) == 0 )
+ value_type = CV_NODE_STRING;
+ else if( memcmp( ptr, "int", 3 ) == 0 )
+ value_type = CV_NODE_INT;
+ else if( memcmp( ptr, "seq", 3 ) == 0 )
+ value_type = CV_NODE_SEQ;
+ else if( memcmp( ptr, "map", 3 ) == 0 )
+ value_type = CV_NODE_MAP;
+ }
+ else if( len == 5 && !CV_NODE_IS_USER(value_type) )
+ {
+ if( memcmp( ptr, "float", 5 ) == 0 )
+ value_type = CV_NODE_REAL;
+ }
+ else if( CV_NODE_IS_USER(value_type) )
+ {
+ CV_CALL( node->info = cvFindType( ptr ));
+ if( !node->info )
+ node->tag &= ~CV_NODE_USER;
+ }
+
+ *endptr = d;
+ CV_CALL( ptr = icvYMLSkipSpaces( fs, endptr, min_indent, INT_MAX ));
+
+ c = *ptr;
+
+ if( !CV_NODE_IS_USER(value_type) )
+ {
+ if( value_type == CV_NODE_STRING && c != '\'' && c != '\"' )
+ goto force_string;
+ if( value_type == CV_NODE_INT )
+ goto force_int;
+ if( value_type == CV_NODE_REAL )
+ goto force_real;
+ }
+ }
+
+ if( isdigit(c) ||
+ ((c == '-' || c == '+') && (isdigit(d) || d == '.')) ||
+ (c == '.' && isalnum(d))) // a number
+ {
+ double fval;
+ int ival;
+ endptr = ptr + (c == '-' || c == '+');
+ while( isdigit(*endptr) )
+ endptr++;
+ if( *endptr == '.' || *endptr == 'e' )
+ {
+force_real:
+ fval = icv_strtod( fs, ptr, &endptr );
+ /*if( endptr == ptr || isalpha(*endptr) )
+ CV_CALL( icvProcessSpecialDouble( fs, endptr, &fval, &endptr ));*/
+
+ node->tag = CV_NODE_REAL;
+ node->data.f = fval;
+ }
+ else
+ {
+force_int:
+ ival = (int)strtol( ptr, &endptr, 0 );
+ node->tag = CV_NODE_INT;
+ node->data.i = ival;
+ }
+
+ if( !endptr || endptr == ptr )
+ CV_PARSE_ERROR( "Invalid numeric value (inconsistent explicit type specification?)" );
+
+ ptr = endptr;
+ }
+ else if( c == '\'' || c == '\"' ) // an explicit string
+ {
+ node->tag = CV_NODE_STRING;
+ if( c == '\'' )
+ for( len = 0; len < CV_FS_MAX_LEN; )
+ {
+ c = *++ptr;
+ if( isalnum(c) || (c != '\'' && cv_isprint(c)))
+ buf[len++] = c;
+ else if( c == '\'' )
+ {
+ c = *++ptr;
+ if( c != '\'' )
+ break;
+ buf[len++] = c;
+ }
+ else
+ CV_PARSE_ERROR( "Invalid character" );
+ }
+ else
+ for( len = 0; len < CV_FS_MAX_LEN; )
+ {
+ c = *++ptr;
+ if( isalnum(c) || (c != '\\' && c != '\"' && cv_isprint(c)))
+ buf[len++] = c;
+ else if( c == '\"' )
+ {
+ ++ptr;
+ break;
+ }
+ else if( c == '\\' )
+ {
+ d = *++ptr;
+ if( d == '\'' )
+ buf[len++] = d;
+ else if( d == '\"' || d == '\\' || d == '\'' )
+ buf[len++] = d;
+ else if( d == 'n' )
+ buf[len++] = '\n';
+ else if( d == 'r' )
+ buf[len++] = '\r';
+ else if( d == 't' )
+ buf[len++] = '\t';
+ else if( d == 'x' || (isdigit(d) && d < '8') )
+ {
+ int val, is_hex = d == 'x';
+ c = ptr[3];
+ ptr[3] = '\0';
+ val = strtol( ptr + is_hex, &endptr, is_hex ? 8 : 16 );
+ ptr[3] = c;
+ if( endptr == ptr + is_hex )
+ buf[len++] = 'x';
+ else
+ {
+ buf[len++] = (char)val;
+ ptr = endptr;
+ }
+ }
+ }
+ else
+ CV_PARSE_ERROR( "Invalid character" );
+ }
+
+ if( len >= CV_FS_MAX_LEN )
+ CV_PARSE_ERROR( "Too long string literal" );
+
+ CV_CALL( node->data.str = cvMemStorageAllocString( fs->memstorage, buf, len ));
+ }
+ else if( c == '[' || c == '{' ) // collection as a flow
+ {
+ int new_min_indent = min_indent + !is_parent_flow;
+ int struct_flags = CV_NODE_FLOW + (c == '{' ? CV_NODE_MAP : CV_NODE_SEQ);
+ int is_simple = 1;
+
+ CV_CALL( icvFSCreateCollection( fs, CV_NODE_TYPE(struct_flags) +
+ (node->info ? CV_NODE_USER : 0), node ));
+
+ d = c == '[' ? ']' : '}';
+
+ for( ++ptr ;;)
+ {
+ CvFileNode* elem = 0;
+
+ CV_CALL( ptr = icvYMLSkipSpaces( fs, ptr, new_min_indent, INT_MAX ));
+ if( *ptr == '}' || *ptr == ']' )
+ {
+ if( *ptr != d )
+ CV_PARSE_ERROR( "The wrong closing bracket" );
+ ptr++;
+ break;
+ }
+
+ if( node->data.seq->total != 0 )
+ {
+ if( *ptr != ',' )
+ CV_PARSE_ERROR( "Missing , between the elements" );
+ CV_CALL( ptr = icvYMLSkipSpaces( fs, ptr + 1, new_min_indent, INT_MAX ));
+ }
+
+ if( CV_NODE_IS_MAP(struct_flags) )
+ {
+ CV_CALL( ptr = icvYMLParseKey( fs, ptr, node, &elem ));
+ CV_CALL( ptr = icvYMLSkipSpaces( fs, ptr, new_min_indent, INT_MAX ));
+ }
+ else
+ {
+ if( *ptr == ']' )
+ break;
+ elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 );
+ }
+ CV_CALL( ptr = icvYMLParseValue( fs, ptr, elem, struct_flags, new_min_indent ));
+ if( CV_NODE_IS_MAP(struct_flags) )
+ elem->tag |= CV_NODE_NAMED;
+ is_simple &= !CV_NODE_IS_COLLECTION(elem->tag);
+ }
+ node->data.seq->flags |= is_simple ? CV_NODE_SEQ_SIMPLE : 0;
+ }
+ else
+ {
+ int indent, struct_flags, is_simple;
+
+ if( is_parent_flow || c != '-' )
+ {
+ // implicit (one-line) string or nested block-style collection
+ if( !is_parent_flow )
+ {
+ if( c == '?' )
+ CV_PARSE_ERROR( "Complex keys are not supported" );
+ if( c == '|' || c == '>' )
+ CV_PARSE_ERROR( "Multi-line text literals are not supported" );
+ }
+
+force_string:
+ endptr = ptr - 1;
+
+ do c = *++endptr;
+ while( cv_isprint(c) &&
+ (!is_parent_flow || (c != ',' && c != '}' && c != ']')) &&
+ (is_parent_flow || c != ':' || value_type == CV_NODE_STRING));
+
+ if( endptr == ptr )
+ CV_PARSE_ERROR( "Invalid character" );
+
+ if( is_parent_flow || c != ':' )
+ {
+ char* str_end = endptr;
+ node->tag = CV_NODE_STRING;
+ // strip spaces in the end of string
+ do c = *--str_end;
+ while( str_end > ptr && c == ' ' );
+ str_end++;
+ CV_CALL( node->data.str = cvMemStorageAllocString( fs->memstorage, ptr, (int)(str_end - ptr) ));
+ ptr = endptr;
+ EXIT;
+ }
+ struct_flags = CV_NODE_MAP;
+ }
+ else
+ struct_flags = CV_NODE_SEQ;
+
+ CV_CALL( icvFSCreateCollection( fs, struct_flags +
+ (node->info ? CV_NODE_USER : 0), node ));
+
+ indent = (int)(ptr - fs->buffer_start);
+ is_simple = 1;
+
+ for(;;)
+ {
+ CvFileNode* elem = 0;
+
+ if( CV_NODE_IS_MAP(struct_flags) )
+ {
+ CV_CALL( ptr = icvYMLParseKey( fs, ptr, node, &elem ));
+ }
+ else
+ {
+ c = *ptr++;
+ if( c != '-' )
+ CV_PARSE_ERROR( "Block sequence elements must be preceded with \'-\'" );
+
+ CV_CALL( elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 ));
+ }
+
+ CV_CALL( ptr = icvYMLSkipSpaces( fs, ptr, indent + 1, INT_MAX ));
+ CV_CALL( ptr = icvYMLParseValue( fs, ptr, elem, struct_flags, indent + 1 ));
+ if( CV_NODE_IS_MAP(struct_flags) )
+ elem->tag |= CV_NODE_NAMED;
+ is_simple &= !CV_NODE_IS_COLLECTION(elem->tag);
+
+ CV_CALL( ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX ));
+ if( ptr - fs->buffer_start != indent )
+ {
+ if( ptr - fs->buffer_start < indent )
+ break;
+ else
+ CV_PARSE_ERROR( "Incorrect indentation" );
+ }
+ if( memcmp( ptr, "...", 3 ) == 0 )
+ break;
+ }
+
+ node->data.seq->flags |= is_simple ? CV_NODE_SEQ_SIMPLE : 0;
+ }
+
+ __END__;
+
+ return ptr;
+}
+
+
+static void
+icvYMLParse( CvFileStorage* fs )
+{
+ CV_FUNCNAME( "icvYMLParse" );
+
+ __BEGIN__;
+
+ char* ptr = fs->buffer_start;
+ int is_first = 1;
+
+ for(;;)
+ {
+ // 0. skip leading comments and directives and ...
+ // 1. reach the first item
+ for(;;)
+ {
+ CV_CALL( ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX ));
+ if( !ptr )
+ EXIT;
+
+ if( *ptr == '%' )
+ {
+ if( memcmp( ptr, "%YAML:", 6 ) == 0 &&
+ memcmp( ptr, "%YAML:1.", 8 ) != 0 )
+ CV_PARSE_ERROR( "Unsupported YAML version (it must be 1.x)" );
+ *ptr = '\0';
+ }
+ else if( *ptr == '-' )
+ {
+ if( memcmp(ptr, "---", 3) == 0 )
+ {
+ ptr += 3;
+ break;
+ }
+ else if( is_first )
+ break;
+ }
+ else if( isalnum(*ptr) || *ptr=='_')
+ {
+ if( !is_first )
+ CV_PARSE_ERROR( "The YAML streams must start with '---', except the first one" );
+ break;
+ }
+ else
+ CV_PARSE_ERROR( "Invalid or unsupported syntax" );
+ }
+
+ CV_CALL( ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX ));
+ if( memcmp( ptr, "...", 3 ) != 0 )
+ {
+ // 2. parse the collection
+ CvFileNode* root_node = (CvFileNode*)cvSeqPush( fs->roots, 0 );
+
+ CV_CALL( ptr = icvYMLParseValue( fs, ptr, root_node, CV_NODE_NONE, 0 ));
+ if( !CV_NODE_IS_COLLECTION(root_node->tag) )
+ CV_PARSE_ERROR( "Only collections as YAML streams are supported by this parser" );
+
+ // 3. parse until the end of file or next collection
+ CV_CALL( ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX ));
+ if( !ptr )
+ EXIT;
+ }
+
+ if( fs->dummy_eof )
+ break;
+ ptr += 3;
+ is_first = 0;
+ }
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* YAML Emitter *
+\****************************************************************************************/
+
+static void
+icvYMLWrite( CvFileStorage* fs, const char* key, const char* data, const char* cvFuncName )
+{
+ //CV_FUNCNAME( "icvYMLWrite" );
+
+ __BEGIN__;
+
+ int i, keylen = 0;
+ int datalen = 0;
+ int struct_flags;
+ char* ptr;
+
+ struct_flags = fs->struct_flags;
+
+ if( key && key[0] == '\0' )
+ key = 0;
+
+ if( CV_NODE_IS_COLLECTION(struct_flags) )
+ {
+ if( (CV_NODE_IS_MAP(struct_flags) ^ (key != 0)) )
+ CV_ERROR( CV_StsBadArg, "An attempt to add element without a key to a map, "
+ "or add element with key to sequence" );
+ }
+ else
+ {
+ fs->is_first = 0;
+ struct_flags = CV_NODE_EMPTY | (key ? CV_NODE_MAP : CV_NODE_SEQ);
+ }
+
+ if( key )
+ {
+ keylen = (int)strlen(key);
+ if( keylen == 0 )
+ CV_ERROR( CV_StsBadArg, "The key is an empty" );
+
+ if( keylen > CV_FS_MAX_LEN )
+ CV_ERROR( CV_StsBadArg, "The key is too long" );
+ }
+
+ if( data )
+ datalen = (int)strlen(data);
+
+ if( CV_NODE_IS_FLOW(struct_flags) )
+ {
+ int new_offset;
+ ptr = fs->buffer;
+ if( !CV_NODE_IS_EMPTY(struct_flags) )
+ *ptr++ = ',';
+ new_offset = (int)(ptr - fs->buffer_start) + keylen + datalen;
+ if( new_offset > fs->wrap_margin && new_offset - fs->struct_indent > 10 )
+ {
+ fs->buffer = ptr;
+ ptr = icvFSFlush(fs);
+ }
+ else
+ *ptr++ = ' ';
+ }
+ else
+ {
+ ptr = icvFSFlush(fs);
+ if( !CV_NODE_IS_MAP(struct_flags) )
+ {
+ *ptr++ = '-';
+ if( data )
+ *ptr++ = ' ';
+ }
+ }
+
+ if( key )
+ {
+ if( !isalpha(key[0]) && key[0] != '_' )
+ CV_ERROR( CV_StsBadArg, "Key must start with a letter or _" );
+
+ ptr = icvFSResizeWriteBuffer( fs, ptr, keylen );
+
+ for( i = 0; i < keylen; i++ )
+ {
+ int c = key[i];
+
+ ptr[i] = (char)c;
+ if( !isalnum(c) && c != '-' && c != '_' && c != ' ' )
+ CV_ERROR( CV_StsBadArg, "Invalid character occurs in the key" );
+ }
+
+ ptr += keylen;
+ *ptr++ = ':';
+ if( !CV_NODE_IS_FLOW(struct_flags) && data )
+ *ptr++ = ' ';
+ }
+
+ if( data )
+ {
+ ptr = icvFSResizeWriteBuffer( fs, ptr, datalen );
+ memcpy( ptr, data, datalen );
+ ptr += datalen;
+ }
+
+ fs->buffer = ptr;
+ fs->struct_flags = struct_flags & ~CV_NODE_EMPTY;
+
+ __END__;
+}
+
+
+static void
+icvYMLStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags,
+ const char* type_name CV_DEFAULT(0))
+{
+ CV_FUNCNAME( "icvYMLStartWriteStruct" );
+
+ __BEGIN__;
+
+ int parent_flags;
+ char buf[CV_FS_MAX_LEN + 1024];
+ const char* data = 0;
+
+ struct_flags = (struct_flags & (CV_NODE_TYPE_MASK|CV_NODE_FLOW)) | CV_NODE_EMPTY;
+ if( !CV_NODE_IS_COLLECTION(struct_flags))
+ CV_ERROR( CV_StsBadArg,
+ "Some collection type - CV_NODE_SEQ or CV_NODE_MAP, must be specified" );
+
+ if( CV_NODE_IS_FLOW(struct_flags) )
+ {
+ char c = CV_NODE_IS_MAP(struct_flags) ? '{' : '[';
+ struct_flags |= CV_NODE_FLOW;
+
+ if( type_name )
+ sprintf( buf, "!!%s %c", type_name, c );
+ else
+ {
+ buf[0] = c;
+ buf[1] = '\0';
+ }
+ data = buf;
+ }
+ else if( type_name )
+ {
+ sprintf( buf, "!!%s", type_name );
+ data = buf;
+ }
+
+ CV_CALL( icvYMLWrite( fs, key, data, cvFuncName ));
+
+ parent_flags = fs->struct_flags;
+ cvSeqPush( fs->write_stack, &parent_flags );
+ fs->struct_flags = struct_flags;
+
+ if( !CV_NODE_IS_FLOW(parent_flags) )
+ fs->struct_indent += CV_YML_INDENT + CV_NODE_IS_FLOW(struct_flags);
+
+ __END__;
+}
+
+
+static void
+icvYMLEndWriteStruct( CvFileStorage* fs )
+{
+ CV_FUNCNAME( "icvYMLEndWriteStruct" );
+
+ __BEGIN__;
+
+ int parent_flags = 0, struct_flags;
+ char* ptr;
+
+ struct_flags = fs->struct_flags;
+ if( fs->write_stack->total == 0 )
+ CV_ERROR( CV_StsError, "EndWriteStruct w/o matching StartWriteStruct" );
+
+ cvSeqPop( fs->write_stack, &parent_flags );
+
+ if( CV_NODE_IS_FLOW(struct_flags) )
+ {
+ ptr = fs->buffer;
+ if( ptr > fs->buffer_start + fs->struct_indent && !CV_NODE_IS_EMPTY(struct_flags) )
+ *ptr++ = ' ';
+ *ptr++ = CV_NODE_IS_MAP(struct_flags) ? '}' : ']';
+ fs->buffer = ptr;
+ }
+ else if( CV_NODE_IS_EMPTY(struct_flags) )
+ {
+ ptr = icvFSFlush(fs);
+ memcpy( ptr, CV_NODE_IS_MAP(struct_flags) ? "{}" : "[]", 2 );
+ fs->buffer = ptr + 2;
+ }
+
+ if( !CV_NODE_IS_FLOW(parent_flags) )
+ fs->struct_indent -= CV_YML_INDENT + CV_NODE_IS_FLOW(struct_flags);
+ assert( fs->struct_indent >= 0 );
+
+ fs->struct_flags = parent_flags;
+
+ __END__;
+}
+
+
+static void
+icvYMLStartNextStream( CvFileStorage* fs )
+{
+ //CV_FUNCNAME( "icvYMLStartNextStream" );
+
+ __BEGIN__;
+
+ if( !fs->is_first )
+ {
+ while( fs->write_stack->total > 0 )
+ icvYMLEndWriteStruct(fs);
+
+ fs->struct_indent = 0;
+ icvFSFlush(fs);
+ fputs( "...\n", fs->file );
+ fputs( "---\n", fs->file );
+ fs->buffer = fs->buffer_start;
+ }
+
+ __END__;
+}
+
+
+static void
+icvYMLWriteInt( CvFileStorage* fs, const char* key, int value )
+{
+ CV_FUNCNAME( "icvYMLWriteInt" );
+
+ __BEGIN__;
+
+ char buf[128];
+ CV_CALL( icvYMLWrite( fs, key, icv_itoa( value, buf, 10 ), cvFuncName ));
+
+ __END__;
+}
+
+
+static void
+icvYMLWriteReal( CvFileStorage* fs, const char* key, double value )
+{
+ CV_FUNCNAME( "icvYMLWriteReal" );
+
+ __BEGIN__;
+
+ char buf[128];
+ CV_CALL( icvYMLWrite( fs, key, icvDoubleToString( buf, value ), cvFuncName ));
+
+ __END__;
+}
+
+
+static void
+icvYMLWriteString( CvFileStorage* fs, const char* key,
+ const char* str, int quote CV_DEFAULT(0))
+{
+ CV_FUNCNAME( "icvYMLWriteString" );
+
+ __BEGIN__;
+
+ char buf[CV_FS_MAX_LEN*4+16];
+ char* data = (char*)str;
+ int i, len;
+
+ if( !str )
+ CV_ERROR( CV_StsNullPtr, "Null string pointer" );
+
+ len = (int)strlen(str);
+ if( len > CV_FS_MAX_LEN )
+ CV_ERROR( CV_StsBadArg, "The written string is too long" );
+
+ if( quote || len == 0 || str[0] != str[len-1] || (str[0] != '\"' && str[0] != '\'') )
+ {
+ int need_quote = quote || len == 0;
+ data = buf;
+ *data++ = '\"';
+ for( i = 0; i < len; i++ )
+ {
+ char c = str[i];
+
+ if( !need_quote && !isalnum(c) && c != '_' && c != ' ' && c != '-' &&
+ c != '(' && c != ')' && c != '/' && c != '+' && c != ';' )
+ need_quote = 1;
+
+ if( !isalnum(c) && (!cv_isprint(c) || c == '\\' || c == '\'' || c == '\"') )
+ {
+ *data++ = '\\';
+ if( cv_isprint(c) )
+ *data++ = c;
+ else if( c == '\n' )
+ *data++ = 'n';
+ else if( c == '\r' )
+ *data++ = 'r';
+ else if( c == '\t' )
+ *data++ = 't';
+ else
+ {
+ sprintf( data, "x%02x", c );
+ data += 3;
+ }
+ }
+ else
+ *data++ = c;
+ }
+ if( !need_quote && (isdigit(str[0]) ||
+ str[0] == '+' || str[0] == '-' || str[0] == '.' ))
+ need_quote = 1;
+
+ if( need_quote )
+ *data++ = '\"';
+ *data++ = '\0';
+ data = buf + !need_quote;
+ }
+
+ CV_CALL( icvYMLWrite( fs, key, data, cvFuncName ));
+
+ __END__;
+}
+
+
+static void
+icvYMLWriteComment( CvFileStorage* fs, const char* comment, int eol_comment )
+{
+ CV_FUNCNAME( "icvYMLWriteComment" );
+
+ __BEGIN__;
+
+ int len; //, indent;
+ int multiline;
+ const char* eol;
+ char* ptr;
+
+ if( !comment )
+ CV_ERROR( CV_StsNullPtr, "Null comment" );
+
+ len = (int)strlen(comment);
+ eol = strchr(comment, '\n');
+ multiline = eol != 0;
+ ptr = fs->buffer;
+
+ if( !eol_comment || multiline ||
+ fs->buffer_end - ptr < len || ptr == fs->buffer_start )
+ ptr = icvFSFlush( fs );
+ else
+ *ptr++ = ' ';
+
+ while( comment )
+ {
+ *ptr++ = '#';
+ *ptr++ = ' ';
+ if( eol )
+ {
+ ptr = icvFSResizeWriteBuffer( fs, ptr, (int)(eol - comment) + 1 );
+ memcpy( ptr, comment, eol - comment + 1 );
+ fs->buffer = ptr + (eol - comment);
+ comment = eol + 1;
+ eol = strchr( comment, '\n' );
+ }
+ else
+ {
+ len = (int)strlen(comment);
+ ptr = icvFSResizeWriteBuffer( fs, ptr, len );
+ memcpy( ptr, comment, len );
+ fs->buffer = ptr + len;
+ comment = 0;
+ }
+ ptr = icvFSFlush( fs );
+ }
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* XML Parser *
+\****************************************************************************************/
+
+#define CV_XML_INSIDE_COMMENT 1
+#define CV_XML_INSIDE_TAG 2
+#define CV_XML_INSIDE_DIRECTIVE 3
+
+static char*
+icvXMLSkipSpaces( CvFileStorage* fs, char* ptr, int mode )
+{
+ CV_FUNCNAME( "icvXMLSkipSpaces" );
+
+ __BEGIN__;
+
+ int level = 0;
+
+ for(;;)
+ {
+ char c;
+ ptr--;
+
+ if( mode == CV_XML_INSIDE_COMMENT )
+ {
+ do c = *++ptr;
+ while( cv_isprint_or_tab(c) && (c != '-' || ptr[1] != '-' || ptr[2] != '>') );
+
+ if( c == '-' )
+ {
+ assert( ptr[1] == '-' && ptr[2] == '>' );
+ mode = 0;
+ ptr += 3;
+ }
+ }
+ else if( mode == CV_XML_INSIDE_DIRECTIVE )
+ {
+ // !!!NOTE!!! This is not quite correct, but should work in most cases
+ do
+ {
+ c = *++ptr;
+ level += c == '<';
+ level -= c == '>';
+ if( level < 0 )
+ EXIT;
+ } while( cv_isprint_or_tab(c) );
+ }
+ else
+ {
+ do c = *++ptr;
+ while( c == ' ' || c == '\t' );
+
+ if( c == '<' && ptr[1] == '!' && ptr[2] == '-' && ptr[3] == '-' )
+ {
+ if( mode != 0 )
+ CV_PARSE_ERROR( "Comments are not allowed here" );
+ mode = CV_XML_INSIDE_COMMENT;
+ ptr += 4;
+ }
+ else if( cv_isprint(c) )
+ break;
+ }
+
+ if( !cv_isprint(*ptr) )
+ {
+ int max_size = (int)(fs->buffer_end - fs->buffer_start);
+ if( *ptr != '\0' && *ptr != '\n' && *ptr != '\r' )
+ CV_PARSE_ERROR( "Invalid character in the stream" );
+ ptr = fgets( fs->buffer_start, max_size, fs->file );
+ if( !ptr )
+ {
+ ptr = fs->buffer_start;
+ *ptr = '\0';
+ fs->dummy_eof = 1;
+ break;
+ }
+ else
+ {
+ int l = (int)strlen(ptr);
+ if( ptr[l-1] != '\n' && ptr[l-1] != '\r' && !feof(fs->file) )
+ CV_PARSE_ERROR( "Too long string or a last string w/o newline" );
+ }
+ fs->lineno++;
+ }
+ }
+
+ __END__;
+
+ return ptr;
+}
+
+
+static char*
+icvXMLParseTag( CvFileStorage* fs, char* ptr, CvStringHashNode** _tag,
+ CvAttrList** _list, int* _tag_type );
+
+static char*
+icvXMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
+ int value_type CV_DEFAULT(CV_NODE_NONE))
+{
+ CV_FUNCNAME( "icvXMLParseValue" );
+
+ __BEGIN__;
+
+ CvFileNode *elem = node;
+ int have_space = 1, is_simple = 1;
+ int is_user_type = CV_NODE_IS_USER(value_type);
+ memset( node, 0, sizeof(*node) );
+
+ value_type = CV_NODE_TYPE(value_type);
+
+ for(;;)
+ {
+ char c = *ptr, d;
+ char* endptr;
+
+ if( isspace(c) || c == '\0' || (c == '<' && ptr[1] == '!' && ptr[2] == '-') )
+ {
+ CV_CALL( ptr = icvXMLSkipSpaces( fs, ptr, 0 ));
+ have_space = 1;
+ c = *ptr;
+ }
+
+ d = ptr[1];
+
+ if( c =='<' )
+ {
+ CvStringHashNode *key = 0, *key2 = 0;
+ CvAttrList* list = 0;
+ CvTypeInfo* info = 0;
+ int tag_type = 0;
+ int is_noname = 0;
+ const char* type_name = 0;
+ int elem_type = CV_NODE_NONE;
+
+ if( d == '/' )
+ break;
+
+ CV_CALL( ptr = icvXMLParseTag( fs, ptr, &key, &list, &tag_type ));
+
+ if( tag_type == CV_XML_DIRECTIVE_TAG )
+ CV_PARSE_ERROR( "Directive tags are not allowed here" );
+ if( tag_type == CV_XML_EMPTY_TAG )
+ CV_PARSE_ERROR( "Empty tags are not supported" );
+
+ assert( tag_type == CV_XML_OPENING_TAG );
+
+ type_name = list ? cvAttrValue( list, "type_id" ) : 0;
+ if( type_name )
+ {
+ if( strcmp( type_name, "str" ) == 0 )
+ elem_type = CV_NODE_STRING;
+ else if( strcmp( type_name, "map" ) == 0 )
+ elem_type = CV_NODE_MAP;
+ else if( strcmp( type_name, "seq" ) == 0 )
+ elem_type = CV_NODE_MAP;
+ else
+ {
+ CV_CALL( info = cvFindType( type_name ));
+ if( info )
+ elem_type = CV_NODE_USER;
+ }
+ }
+
+ is_noname = key->str.len == 1 && key->str.ptr[0] == '_';
+ if( !CV_NODE_IS_COLLECTION(node->tag) )
+ {
+ CV_CALL( icvFSCreateCollection( fs, is_noname ? CV_NODE_SEQ : CV_NODE_MAP, node ));
+ }
+ else if( is_noname ^ CV_NODE_IS_SEQ(node->tag) )
+ CV_PARSE_ERROR( is_noname ? "Map element should have a name" :
+ "Sequence element should not have name (use <_></_>)" );
+
+ if( is_noname )
+ elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 );
+ else
+ CV_CALL( elem = cvGetFileNode( fs, node, key, 1 ));
+
+ CV_CALL( ptr = icvXMLParseValue( fs, ptr, elem, elem_type));
+ if( !is_noname )
+ elem->tag |= CV_NODE_NAMED;
+ is_simple &= !CV_NODE_IS_COLLECTION(elem->tag);
+ elem->info = info;
+ CV_CALL( ptr = icvXMLParseTag( fs, ptr, &key2, &list, &tag_type ));
+ if( tag_type != CV_XML_CLOSING_TAG || key2 != key )
+ CV_PARSE_ERROR( "Mismatched closing tag" );
+ have_space = 1;
+ }
+ else
+ {
+ if( !have_space )
+ CV_PARSE_ERROR( "There should be space between literals" );
+
+ elem = node;
+ if( node->tag != CV_NODE_NONE )
+ {
+ if( !CV_NODE_IS_COLLECTION(node->tag) )
+ CV_CALL( icvFSCreateCollection( fs, CV_NODE_SEQ, node ));
+
+ elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 );
+ elem->info = 0;
+ }
+
+ if( value_type != CV_NODE_STRING &&
+ (isdigit(c) || ((c == '-' || c == '+') &&
+ (isdigit(d) || d == '.')) || (c == '.' && isalnum(d))) ) // a number
+ {
+ double fval;
+ int ival;
+ endptr = ptr + (c == '-' || c == '+');
+ while( isdigit(*endptr) )
+ endptr++;
+ if( *endptr == '.' || *endptr == 'e' )
+ {
+ fval = icv_strtod( fs, ptr, &endptr );
+ /*if( endptr == ptr || isalpha(*endptr) )
+ CV_CALL( icvProcessSpecialDouble( fs, ptr, &fval, &endptr ));*/
+ elem->tag = CV_NODE_REAL;
+ elem->data.f = fval;
+ }
+ else
+ {
+ ival = (int)strtol( ptr, &endptr, 0 );
+ elem->tag = CV_NODE_INT;
+ elem->data.i = ival;
+ }
+
+ if( endptr == ptr )
+ CV_PARSE_ERROR( "Invalid numeric value (inconsistent explicit type specification?)" );
+
+ ptr = endptr;
+ }
+ else
+ {
+ // string
+ char buf[CV_FS_MAX_LEN+16];
+ int i = 0, len, is_quoted = 0;
+ elem->tag = CV_NODE_STRING;
+ if( c == '\"' )
+ is_quoted = 1;
+ else
+ --ptr;
+
+ for( ;; )
+ {
+ c = *++ptr;
+ if( !isalnum(c) )
+ {
+ if( c == '\"' )
+ {
+ if( !is_quoted )
+ CV_PARSE_ERROR( "Literal \" is not allowed within a string. Use &quot;" );
+ ++ptr;
+ break;
+ }
+ else if( !cv_isprint(c) || c == '<' || (!is_quoted && isspace(c)))
+ {
+ if( is_quoted )
+ CV_PARSE_ERROR( "Closing \" is expected" );
+ break;
+ }
+ else if( c == '\'' || c == '>' )
+ {
+ CV_PARSE_ERROR( "Literal \' or > are not allowed. Use &apos; or &gt;" );
+ }
+ else if( c == '&' )
+ {
+ if( *ptr == '#' )
+ {
+ int val;
+ ptr++;
+ val = (int)strtol( ptr, &endptr, 0 );
+ if( (unsigned)val > (unsigned)255 ||
+ !endptr || *endptr != ';' )
+ CV_PARSE_ERROR( "Invalid numeric value in the string" );
+ c = (char)val;
+ }
+ else
+ {
+ endptr = ptr++;
+ do c = *++endptr;
+ while( isalnum(c) );
+ if( c != ';' )
+ CV_PARSE_ERROR( "Invalid character in the symbol entity name" );
+ len = (int)(endptr - ptr);
+ if( len == 2 && memcmp( ptr, "lt", len ) == 0 )
+ c = '<';
+ else if( len == 2 && memcmp( ptr, "gt", len ) == 0 )
+ c = '>';
+ else if( len == 3 && memcmp( ptr, "amp", len ) == 0 )
+ c = '&';
+ else if( len == 4 && memcmp( ptr, "apos", len ) == 0 )
+ c = '\'';
+ else if( len == 4 && memcmp( ptr, "quot", len ) == 0 )
+ c = '\"';
+ else
+ {
+ memcpy( buf + i, ptr-1, len + 2 );
+ i += len + 2;
+ }
+ }
+ ptr = endptr;
+ }
+ }
+ buf[i++] = c;
+ if( i >= CV_FS_MAX_LEN )
+ CV_PARSE_ERROR( "Too long string literal" );
+ }
+ CV_CALL( elem->data.str = cvMemStorageAllocString( fs->memstorage, buf, i ));
+ }
+
+ if( !CV_NODE_IS_COLLECTION(value_type) && value_type != CV_NODE_NONE )
+ break;
+ have_space = 0;
+ }
+ }
+
+ if( (CV_NODE_TYPE(node->tag) == CV_NODE_NONE ||
+ (CV_NODE_TYPE(node->tag) != value_type &&
+ !CV_NODE_IS_COLLECTION(node->tag))) &&
+ CV_NODE_IS_COLLECTION(value_type) )
+ {
+ CV_CALL( icvFSCreateCollection( fs, CV_NODE_IS_MAP(value_type) ?
+ CV_NODE_MAP : CV_NODE_SEQ, node ));
+ }
+
+ if( value_type != CV_NODE_NONE &&
+ value_type != CV_NODE_TYPE(node->tag) )
+ CV_PARSE_ERROR( "The actual type is different from the specified type" );
+
+ if( CV_NODE_IS_COLLECTION(node->tag) && is_simple )
+ node->data.seq->flags |= CV_NODE_SEQ_SIMPLE;
+
+ node->tag |= is_user_type ? CV_NODE_USER : 0;
+
+ __END__;
+
+ return ptr;
+}
+
+
+static char*
+icvXMLParseTag( CvFileStorage* fs, char* ptr, CvStringHashNode** _tag,
+ CvAttrList** _list, int* _tag_type )
+{
+ int tag_type = 0;
+ CvStringHashNode* tagname = 0;
+ CvAttrList *first = 0, *last = 0;
+ int count = 0, max_count = 4;
+ int attr_buf_size = (max_count*2 + 1)*sizeof(char*) + sizeof(CvAttrList);
+
+ CV_FUNCNAME( "icvXMLParseTag" );
+
+ __BEGIN__;
+
+ char* endptr;
+ char c;
+ int have_space;
+
+ if( *ptr != '<' )
+ CV_PARSE_ERROR( "Tag should start with \'<\'" );
+
+ ptr++;
+ if( isalnum(*ptr) || *ptr == '_' )
+ tag_type = CV_XML_OPENING_TAG;
+ else if( *ptr == '/' )
+ {
+ tag_type = CV_XML_CLOSING_TAG;
+ ptr++;
+ }
+ else if( *ptr == '?' )
+ {
+ tag_type = CV_XML_HEADER_TAG;
+ ptr++;
+ }
+ else if( *ptr == '!' )
+ {
+ tag_type = CV_XML_DIRECTIVE_TAG;
+ assert( ptr[1] != '-' || ptr[2] != '-' );
+ ptr++;
+ }
+ else
+ CV_PARSE_ERROR( "Unknown tag type" );
+
+ for(;;)
+ {
+ CvStringHashNode* attrname;
+
+ if( !isalpha(*ptr) && *ptr != '_' )
+ CV_PARSE_ERROR( "Name should start with a letter or underscore" );
+
+ endptr = ptr - 1;
+ do c = *++endptr;
+ while( isalnum(c) || c == '_' || c == '-' );
+
+ CV_CALL( attrname = cvGetHashedKey( fs, ptr, (int)(endptr - ptr), 1 ));
+ ptr = endptr;
+
+ if( !tagname )
+ tagname = attrname;
+ else
+ {
+ if( tag_type == CV_XML_CLOSING_TAG )
+ CV_PARSE_ERROR( "Closing tag should not contain any attributes" );
+
+ if( !last || count >= max_count )
+ {
+ CvAttrList* chunk;
+
+ CV_CALL( chunk = (CvAttrList*)cvMemStorageAlloc( fs->memstorage, attr_buf_size ));
+ memset( chunk, 0, attr_buf_size );
+ chunk->attr = (const char**)(chunk + 1);
+ count = 0;
+ if( !last )
+ first = last = chunk;
+ else
+ last = last->next = chunk;
+ }
+ last->attr[count*2] = attrname->str.ptr;
+ }
+
+ if( last )
+ {
+ CvFileNode stub;
+
+ if( *ptr != '=' )
+ {
+ CV_CALL( ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG ));
+ if( *ptr != '=' )
+ CV_PARSE_ERROR( "Attribute name should be followed by \'=\'" );
+ }
+
+ c = *++ptr;
+ if( c != '\"' && c != '\'' )
+ {
+ CV_CALL( ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG ));
+ if( *ptr != '\"' && *ptr != '\'' )
+ CV_PARSE_ERROR( "Attribute value should be put into single or double quotes" );
+ }
+
+ ptr = icvXMLParseValue( fs, ptr, &stub, CV_NODE_STRING );
+ assert( stub.tag == CV_NODE_STRING );
+ last->attr[count*2+1] = stub.data.str.ptr;
+ count++;
+ }
+
+ c = *ptr;
+ have_space = isspace(c) || c == '\0';
+
+ if( c != '>' )
+ {
+ CV_CALL( ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG ));
+ c = *ptr;
+ }
+
+ if( c == '>' )
+ {
+ if( tag_type == CV_XML_HEADER_TAG )
+ CV_PARSE_ERROR( "Invalid closing tag for <?xml ..." );
+ ptr++;
+ break;
+ }
+ else if( c == '?' && tag_type == CV_XML_HEADER_TAG )
+ {
+ if( ptr[1] != '>' )
+ CV_PARSE_ERROR( "Invalid closing tag for <?xml ..." );
+ ptr += 2;
+ break;
+ }
+ else if( c == '/' && ptr[1] == '>' && tag_type == CV_XML_OPENING_TAG )
+ {
+ tag_type = CV_XML_EMPTY_TAG;
+ ptr += 2;
+ break;
+ }
+
+ if( !have_space )
+ CV_PARSE_ERROR( "There should be space between attributes" );
+ }
+
+ __END__;
+
+ *_tag = tagname;
+ *_tag_type = tag_type;
+ *_list = first;
+
+ return ptr;
+}
+
+
+static void
+icvXMLParse( CvFileStorage* fs )
+{
+ CV_FUNCNAME( "icvXMLParse" );
+
+ __BEGIN__;
+
+ char* ptr = fs->buffer_start;
+ CvStringHashNode *key = 0, *key2 = 0;
+ CvAttrList* list = 0;
+ int tag_type = 0;
+
+ // CV_XML_INSIDE_TAG is used to prohibit leading comments
+ CV_CALL( ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG ));
+
+ if( memcmp( ptr, "<?xml", 5 ) != 0 )
+ CV_PARSE_ERROR( "Valid XML should start with \'<?xml ...?>\'" );
+
+ CV_CALL( ptr = icvXMLParseTag( fs, ptr, &key, &list, &tag_type ));
+
+ /*{
+ const char* version = cvAttrValue( list, "version" );
+ if( version && strncmp( version, "1.", 2 ) != 0 )
+ CV_ERROR( CV_StsParseError, "Unsupported version of XML" );
+ }*/
+ {
+ const char* encoding = cvAttrValue( list, "encoding" );
+ if( encoding && strcmp( encoding, "ASCII" ) != 0 )
+ CV_PARSE_ERROR( "Unsupported encoding" );
+ }
+
+ while( *ptr != '\0' )
+ {
+ CV_CALL( ptr = icvXMLSkipSpaces( fs, ptr, 0 ));
+
+ if( *ptr != '\0' )
+ {
+ CvFileNode* root_node;
+ CV_CALL( ptr = icvXMLParseTag( fs, ptr, &key, &list, &tag_type ));
+ if( tag_type != CV_XML_OPENING_TAG ||
+ strcmp(key->str.ptr,"opencv_storage") != 0 )
+ CV_PARSE_ERROR( "<opencv_storage> tag is missing" );
+
+ root_node = (CvFileNode*)cvSeqPush( fs->roots, 0 );
+ CV_CALL( ptr = icvXMLParseValue( fs, ptr, root_node, CV_NODE_NONE ));
+ CV_CALL( ptr = icvXMLParseTag( fs, ptr, &key2, &list, &tag_type ));
+ if( tag_type != CV_XML_CLOSING_TAG || key != key2 )
+ CV_PARSE_ERROR( "</opencv_storage> tag is missing" );
+ CV_CALL( ptr = icvXMLSkipSpaces( fs, ptr, 0 ));
+ }
+ }
+
+ assert( fs->dummy_eof != 0 );
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* XML Emitter *
+\****************************************************************************************/
+
+#define icvXMLFlush icvFSFlush
+
+static void
+icvXMLWriteTag( CvFileStorage* fs, const char* key, int tag_type, CvAttrList list )
+{
+ CV_FUNCNAME( "icvXMLWriteTag" );
+
+ __BEGIN__;
+
+ char* ptr = fs->buffer;
+ int i, len = 0;
+ int struct_flags = fs->struct_flags;
+
+ if( key && key[0] == '\0' )
+ key = 0;
+
+ if( tag_type == CV_XML_OPENING_TAG || tag_type == CV_XML_EMPTY_TAG )
+ {
+ if( CV_NODE_IS_COLLECTION(struct_flags) )
+ {
+ if( CV_NODE_IS_MAP(struct_flags) ^ (key != 0) )
+ CV_ERROR( CV_StsBadArg, "An attempt to add element without a key to a map, "
+ "or add element with key to sequence" );
+ }
+ else
+ {
+ struct_flags = CV_NODE_EMPTY + (key ? CV_NODE_MAP : CV_NODE_SEQ);
+ fs->is_first = 0;
+ }
+
+ if( !CV_NODE_IS_EMPTY(struct_flags) )
+ ptr = icvXMLFlush(fs);
+ }
+
+ if( !key )
+ key = "_";
+ else if( key[0] == '_' && key[1] == '\0' )
+ CV_ERROR( CV_StsBadArg, "A single _ is a reserved tag name" );
+
+ len = (int)strlen( key );
+ *ptr++ = '<';
+ if( tag_type == CV_XML_CLOSING_TAG )
+ {
+ if( list.attr )
+ CV_ERROR( CV_StsBadArg, "Closing tag should not include any attributes" );
+ *ptr++ = '/';
+ }
+
+ if( !isalpha(key[0]) && key[0] != '_' )
+ CV_ERROR( CV_StsBadArg, "Key should start with a letter or _" );
+
+ ptr = icvFSResizeWriteBuffer( fs, ptr, len );
+ for( i = 0; i < len; i++ )
+ {
+ char c = key[i];
+ if( !isalnum(c) && c != '_' && c != '-' )
+ CV_ERROR( CV_StsBadArg, "Invalid character in the key" );
+ ptr[i] = c;
+ }
+ ptr += len;
+
+ for(;;)
+ {
+ const char** attr = list.attr;
+
+ for( ; attr && attr[0] != 0; attr += 2 )
+ {
+ int len0 = (int)strlen(attr[0]);
+ int len1 = (int)strlen(attr[1]);
+
+ ptr = icvFSResizeWriteBuffer( fs, ptr, len0 + len1 + 4 );
+ *ptr++ = ' ';
+ memcpy( ptr, attr[0], len0 );
+ ptr += len0;
+ *ptr++ = '=';
+ *ptr++ = '\"';
+ memcpy( ptr, attr[1], len1 );
+ ptr += len1;
+ *ptr++ = '\"';
+ }
+ if( !list.next )
+ break;
+ list = *list.next;
+ }
+
+ if( tag_type == CV_XML_EMPTY_TAG )
+ *ptr++ = '/';
+ *ptr++ = '>';
+ fs->buffer = ptr;
+ fs->struct_flags = struct_flags & ~CV_NODE_EMPTY;
+
+ __END__;
+}
+
+
+static void
+icvXMLStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags,
+ const char* type_name CV_DEFAULT(0))
+{
+ CV_FUNCNAME( "icvXMLStartWriteStruct" );
+
+ __BEGIN__;
+
+ CvXMLStackRecord parent;
+ const char* attr[10];
+ int idx = 0;
+
+ struct_flags = (struct_flags & (CV_NODE_TYPE_MASK|CV_NODE_FLOW)) | CV_NODE_EMPTY;
+ if( !CV_NODE_IS_COLLECTION(struct_flags))
+ CV_ERROR( CV_StsBadArg,
+ "Some collection type: CV_NODE_SEQ or CV_NODE_MAP must be specified" );
+
+ if( type_name )
+ {
+ attr[idx++] = "type_id";
+ attr[idx++] = type_name;
+ }
+ attr[idx++] = 0;
+
+ CV_CALL( icvXMLWriteTag( fs, key, CV_XML_OPENING_TAG, cvAttrList(attr,0) ));
+
+ parent.struct_flags = fs->struct_flags & ~CV_NODE_EMPTY;
+ parent.struct_indent = fs->struct_indent;
+ parent.struct_tag = fs->struct_tag;
+ cvSaveMemStoragePos( fs->strstorage, &parent.pos );
+ cvSeqPush( fs->write_stack, &parent );
+
+ fs->struct_indent += CV_XML_INDENT;
+ if( !CV_NODE_IS_FLOW(struct_flags) )
+ icvXMLFlush( fs );
+
+ fs->struct_flags = struct_flags;
+ if( key )
+ {
+ CV_CALL( fs->struct_tag = cvMemStorageAllocString( fs->strstorage, (char*)key, -1 ));
+ }
+ else
+ {
+ fs->struct_tag.ptr = 0;
+ fs->struct_tag.len = 0;
+ }
+
+ __END__;
+}
+
+
+static void
+icvXMLEndWriteStruct( CvFileStorage* fs )
+{
+ CV_FUNCNAME( "icvXMLStartWriteStruct" );
+
+ __BEGIN__;
+
+ CvXMLStackRecord parent;
+
+ if( fs->write_stack->total == 0 )
+ CV_ERROR( CV_StsError, "An extra closing tag" );
+
+ CV_CALL( icvXMLWriteTag( fs, fs->struct_tag.ptr, CV_XML_CLOSING_TAG, cvAttrList(0,0) ));
+ cvSeqPop( fs->write_stack, &parent );
+
+ fs->struct_indent = parent.struct_indent;
+ fs->struct_flags = parent.struct_flags;
+ fs->struct_tag = parent.struct_tag;
+ cvRestoreMemStoragePos( fs->strstorage, &parent.pos );
+
+ __END__;
+}
+
+
+static void
+icvXMLStartNextStream( CvFileStorage* fs )
+{
+ //CV_FUNCNAME( "icvXMLStartNextStream" );
+
+ __BEGIN__;
+
+ if( !fs->is_first )
+ {
+ while( fs->write_stack->total > 0 )
+ icvXMLEndWriteStruct(fs);
+
+ fs->struct_indent = 0;
+ icvXMLFlush(fs);
+ /* XML does not allow multiple top-level elements,
+ so we just put a comment and continue
+ the current (and the only) "stream" */
+ fputs( "\n<!-- next stream -->\n", fs->file );
+ /*fputs( "</opencv_storage>\n", fs->file );
+ fputs( "<opencv_storage>\n", fs->file );*/
+ fs->buffer = fs->buffer_start;
+ }
+
+ __END__;
+}
+
+
+static void
+icvXMLWriteScalar( CvFileStorage* fs, const char* key, const char* data, int len )
+{
+ CV_FUNCNAME( "icvXMLWriteScalar" );
+
+ __BEGIN__;
+
+ if( CV_NODE_IS_MAP(fs->struct_flags) ||
+ (!CV_NODE_IS_COLLECTION(fs->struct_flags) && key) )
+ {
+ icvXMLWriteTag( fs, key, CV_XML_OPENING_TAG, cvAttrList(0,0) );
+ char* ptr = icvFSResizeWriteBuffer( fs, fs->buffer, len );
+ memcpy( ptr, data, len );
+ fs->buffer = ptr + len;
+ icvXMLWriteTag( fs, key, CV_XML_CLOSING_TAG, cvAttrList(0,0) );
+ }
+ else
+ {
+ char* ptr = fs->buffer;
+ int new_offset = (int)(ptr - fs->buffer_start) + len;
+
+ if( key )
+ CV_ERROR( CV_StsBadArg, "elements with keys can not be written to sequence" );
+
+ fs->struct_flags = CV_NODE_SEQ;
+
+ if( (new_offset > fs->wrap_margin && new_offset - fs->struct_indent > 10) ||
+ (ptr > fs->buffer_start && ptr[-1] == '>' && !CV_NODE_IS_EMPTY(fs->struct_flags)) )
+ {
+ ptr = icvXMLFlush(fs);
+ }
+ else if( ptr > fs->buffer_start + fs->struct_indent && ptr[-1] != '>' )
+ *ptr++ = ' ';
+
+ memcpy( ptr, data, len );
+ fs->buffer = ptr + len;
+ }
+
+ __END__;
+}
+
+
+static void
+icvXMLWriteInt( CvFileStorage* fs, const char* key, int value )
+{
+ //CV_FUNCNAME( "cvXMLWriteInt" );
+
+ __BEGIN__;
+
+ char buf[128], *ptr = icv_itoa( value, buf, 10 );
+ int len = (int)strlen(ptr);
+ icvXMLWriteScalar( fs, key, ptr, len );
+
+ __END__;
+}
+
+
+static void
+icvXMLWriteReal( CvFileStorage* fs, const char* key, double value )
+{
+ //CV_FUNCNAME( "cvXMLWriteReal" );
+
+ __BEGIN__;
+
+ char buf[128];
+ int len = (int)strlen( icvDoubleToString( buf, value ));
+ icvXMLWriteScalar( fs, key, buf, len );
+
+ __END__;
+}
+
+
+static void
+icvXMLWriteString( CvFileStorage* fs, const char* key, const char* str, int quote )
+{
+ CV_FUNCNAME( "cvXMLWriteString" );
+
+ __BEGIN__;
+
+ char buf[CV_FS_MAX_LEN*6+16];
+ char* data = (char*)str;
+ int i, len;
+
+ if( !str )
+ CV_ERROR( CV_StsNullPtr, "Null string pointer" );
+
+ len = (int)strlen(str);
+ if( len > CV_FS_MAX_LEN )
+ CV_ERROR( CV_StsBadArg, "The written string is too long" );
+
+ if( quote || len == 0 || str[0] != '\"' || str[0] != str[len-1] )
+ {
+ int need_quote = quote || len == 0;
+ data = buf;
+ *data++ = '\"';
+ for( i = 0; i < len; i++ )
+ {
+ char c = str[i];
+
+ if( !isalnum(c) && (!cv_isprint(c) || c == '<' || c == '>' ||
+ c == '&' || c == '\'' || c == '\"') )
+ {
+ *data++ = '&';
+ if( c == '<' )
+ {
+ memcpy(data, "lt", 2);
+ data += 2;
+ }
+ else if( c == '>' )
+ {
+ memcpy(data, "gt", 2);
+ data += 2;
+ }
+ else if( c == '&' )
+ {
+ memcpy(data, "amp", 3);
+ data += 3;
+ }
+ else if( c == '\'' )
+ {
+ memcpy(data, "apos", 4);
+ data += 4;
+ }
+ else if( c == '\"' )
+ {
+ memcpy( data, "quot", 4);
+ data += 4;
+ }
+ else
+ {
+ sprintf( data, "#x%02x", c );
+ data += 4;
+ }
+ *data++ = ';';
+ }
+ else
+ {
+ if( c == ' ' )
+ need_quote = 1;
+ *data++ = c;
+ }
+ }
+ if( !need_quote && (isdigit(str[0]) ||
+ str[0] == '+' || str[0] == '-' || str[0] == '.' ))
+ need_quote = 1;
+
+ if( need_quote )
+ *data++ = '\"';
+ len = (int)(data - buf) - !need_quote;
+ *data++ = '\0';
+ data = buf + !need_quote;
+ }
+
+ icvXMLWriteScalar( fs, key, data, len );
+
+ __END__;
+}
+
+
+static void
+icvXMLWriteComment( CvFileStorage* fs, const char* comment, int eol_comment )
+{
+ CV_FUNCNAME( "cvXMLWriteComment" );
+
+ __BEGIN__;
+
+ int len;
+ int multiline;
+ const char* eol;
+ char* ptr;
+
+ if( !comment )
+ CV_ERROR( CV_StsNullPtr, "Null comment" );
+
+ if( strstr(comment, "--") != 0 )
+ CV_ERROR( CV_StsBadArg, "Double hyphen \'--\' is not allowed in the comments" );
+
+ len = (int)strlen(comment);
+ eol = strchr(comment, '\n');
+ multiline = eol != 0;
+ ptr = fs->buffer;
+
+ if( multiline || !eol_comment || fs->buffer_end - ptr < len + 5 )
+ ptr = icvXMLFlush( fs );
+ else if( ptr > fs->buffer_start + fs->struct_indent )
+ *ptr++ = ' ';
+
+ if( !multiline )
+ {
+ ptr = icvFSResizeWriteBuffer( fs, ptr, len + 9 );
+ sprintf( ptr, "<!-- %s -->", comment );
+ len = (int)strlen(ptr);
+ }
+ else
+ {
+ strcpy( ptr, "<!--" );
+ len = 4;
+ }
+
+ fs->buffer = ptr + len;
+ ptr = icvXMLFlush(fs);
+
+ if( multiline )
+ {
+ while( comment )
+ {
+ if( eol )
+ {
+ ptr = icvFSResizeWriteBuffer( fs, ptr, (int)(eol - comment) + 1 );
+ memcpy( ptr, comment, eol - comment + 1 );
+ ptr += eol - comment;
+ comment = eol + 1;
+ eol = strchr( comment, '\n' );
+ }
+ else
+ {
+ len = (int)strlen(comment);
+ ptr = icvFSResizeWriteBuffer( fs, ptr, len );
+ memcpy( ptr, comment, len );
+ ptr += len;
+ comment = 0;
+ }
+ fs->buffer = ptr;
+ ptr = icvXMLFlush( fs );
+ }
+ sprintf( ptr, "-->" );
+ fs->buffer = ptr + 3;
+ icvXMLFlush( fs );
+ }
+
+ __END__;
+}
+
+
+/****************************************************************************************\
+* Common High-Level Functions *
+\****************************************************************************************/
+
+CV_IMPL CvFileStorage*
+cvOpenFileStorage( const char* filename, CvMemStorage* dststorage, int flags )
+{
+ CvFileStorage* fs = 0;
+ char* xml_buf = 0;
+
+ CV_FUNCNAME("cvOpenFileStorage" );
+
+ __BEGIN__;
+
+ int default_block_size = 1 << 18;
+ bool append = (flags & 3) == CV_STORAGE_APPEND;
+
+ if( !filename )
+ CV_ERROR( CV_StsNullPtr, "NULL filename" );
+
+ CV_CALL( fs = (CvFileStorage*)cvAlloc( sizeof(*fs) ));
+ memset( fs, 0, sizeof(*fs));
+
+ CV_CALL( fs->memstorage = cvCreateMemStorage( default_block_size ));
+ fs->dststorage = dststorage ? dststorage : fs->memstorage;
+
+ CV_CALL( fs->filename = (char*)cvMemStorageAlloc( fs->memstorage, strlen(filename)+1 ));
+ strcpy( fs->filename, filename );
+
+ fs->flags = CV_FILE_STORAGE;
+ fs->write_mode = (flags & 3) != 0;
+ fs->file = fopen( fs->filename, !fs->write_mode ? "rt" : !append ? "wt" : "a+t" );
+ if( !fs->file )
+ EXIT;
+
+ fs->roots = 0;
+ fs->struct_indent = 0;
+ fs->struct_flags = 0;
+ fs->wrap_margin = 71;
+
+ if( fs->write_mode )
+ {
+ // we use factor=6 for XML (the longest characters (' and ") are encoded with 6 bytes (&apos; and &quot;)
+ // and factor=4 for YAML ( as we use 4 bytes for non ASCII characters (e.g. \xAB))
+ int buf_size = CV_FS_MAX_LEN*(fs->is_xml ? 6 : 4) + 1024;
+
+ char* dot_pos = strrchr( fs->filename, '.' );
+ fs->is_xml = dot_pos && (strcmp( dot_pos, ".xml" ) == 0 ||
+ strcmp( dot_pos, ".XML" ) == 0 || strcmp( dot_pos, ".Xml" ) == 0);
+
+ if( append )
+ fseek( fs->file, 0, SEEK_END );
+
+ fs->write_stack = cvCreateSeq( 0, sizeof(CvSeq), fs->is_xml ?
+ sizeof(CvXMLStackRecord) : sizeof(int), fs->memstorage );
+ fs->is_first = 1;
+ fs->struct_indent = 0;
+ fs->struct_flags = CV_NODE_EMPTY;
+ CV_CALL( fs->buffer_start = fs->buffer = (char*)cvAlloc( buf_size + 1024 ));
+ fs->buffer_end = fs->buffer_start + buf_size;
+ if( fs->is_xml )
+ {
+ int file_size = (int)ftell( fs->file );
+ CV_CALL( fs->strstorage = cvCreateChildMemStorage( fs->memstorage ));
+ if( !append || file_size == 0 )
+ {
+ fputs( "<?xml version=\"1.0\"?>\n", fs->file );
+ fputs( "<opencv_storage>\n", fs->file );
+ }
+ else
+ {
+ int xml_buf_size = 1 << 10;
+ char substr[] = "</opencv_storage>";
+ int last_occurence = -1;
+ xml_buf_size = MIN(xml_buf_size, file_size);
+ fseek( fs->file, -xml_buf_size, SEEK_END );
+ CV_CALL(xml_buf = (char*)cvAlloc( xml_buf_size+2 ));
+ // find the last occurence of </opencv_storage>
+ for(;;)
+ {
+ int line_offset = ftell( fs->file );
+ char* ptr0 = fgets( xml_buf, xml_buf_size, fs->file ), *ptr;
+ if( !ptr0 )
+ break;
+ ptr = ptr0;
+ for(;;)
+ {
+ ptr = strstr( ptr, substr );
+ if( !ptr )
+ break;
+ last_occurence = line_offset + (int)(ptr - ptr0);
+ ptr += strlen(substr);
+ }
+ }
+ if( last_occurence < 0 )
+ CV_ERROR( CV_StsError, "Could not find </opencv_storage> in the end of file.\n" );
+ fclose( fs->file );
+ fs->file = fopen( fs->filename, "r+t" );
+ fseek( fs->file, last_occurence, SEEK_SET );
+ // replace the last "</opencv_storage>" with " <!-- resumed -->", which has the same length
+ fputs( " <!-- resumed -->", fs->file );
+ fseek( fs->file, 0, SEEK_END );
+ fputs( "\n", fs->file );
+ }
+ fs->start_write_struct = icvXMLStartWriteStruct;
+ fs->end_write_struct = icvXMLEndWriteStruct;
+ fs->write_int = icvXMLWriteInt;
+ fs->write_real = icvXMLWriteReal;
+ fs->write_string = icvXMLWriteString;
+ fs->write_comment = icvXMLWriteComment;
+ fs->start_next_stream = icvXMLStartNextStream;
+ }
+ else
+ {
+ if( !append )
+ fputs( "%YAML:1.0\n", fs->file );
+ else
+ fputs( "...\n---\n", fs->file );
+ fs->start_write_struct = icvYMLStartWriteStruct;
+ fs->end_write_struct = icvYMLEndWriteStruct;
+ fs->write_int = icvYMLWriteInt;
+ fs->write_real = icvYMLWriteReal;
+ fs->write_string = icvYMLWriteString;
+ fs->write_comment = icvYMLWriteComment;
+ fs->start_next_stream = icvYMLStartNextStream;
+ }
+ }
+ else
+ {
+ int buf_size;
+ const char* yaml_signature = "%YAML:";
+ char buf[16];
+ fgets( buf, sizeof(buf)-2, fs->file );
+ fs->is_xml = strncmp( buf, yaml_signature, strlen(yaml_signature) ) != 0;
+
+ fseek( fs->file, 0, SEEK_END );
+ buf_size = ftell( fs->file );
+ fseek( fs->file, 0, SEEK_SET );
+
+ buf_size = MIN( buf_size, (1 << 20) );
+ buf_size = MAX( buf_size, CV_FS_MAX_LEN*2 + 1024 );
+
+ CV_CALL( fs->str_hash = cvCreateMap( 0, sizeof(CvStringHash),
+ sizeof(CvStringHashNode), fs->memstorage, 256 ));
+
+ CV_CALL( fs->roots = cvCreateSeq( 0, sizeof(CvSeq),
+ sizeof(CvFileNode), fs->memstorage ));
+
+ CV_CALL( fs->buffer = fs->buffer_start = (char*)cvAlloc( buf_size + 256 ));
+ fs->buffer_end = fs->buffer_start + buf_size;
+ fs->buffer[0] = '\n';
+ fs->buffer[1] = '\0';
+
+ //mode = cvGetErrMode();
+ //cvSetErrMode( CV_ErrModeSilent );
+ if( fs->is_xml )
+ icvXMLParse( fs );
+ else
+ icvYMLParse( fs );
+ //cvSetErrMode( mode );
+
+ // release resources that we do not need anymore
+ cvFree( &fs->buffer_start );
+ fs->buffer = fs->buffer_end = 0;
+ }
+
+ __END__;
+
+ if( fs )
+ {
+ if( cvGetErrStatus() < 0 || !fs->file )
+ {
+ cvReleaseFileStorage( &fs );
+ }
+ else if( !fs->write_mode )
+ {
+ fclose( fs->file );
+ fs->file = 0;
+ }
+ }
+
+ cvFree( &xml_buf );
+
+ return fs;
+}
+
+
+CV_IMPL void
+cvStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags,
+ const char* type_name, CvAttrList /*attributes*/ )
+{
+ CV_FUNCNAME( "cvStartWriteStruct" );
+
+ __BEGIN__;
+
+ CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+ CV_CALL( fs->start_write_struct( fs, key, struct_flags, type_name ));
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvEndWriteStruct( CvFileStorage* fs )
+{
+ CV_FUNCNAME( "cvEndWriteStruct" );
+
+ __BEGIN__;
+
+ CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+ CV_CALL( fs->end_write_struct( fs ));
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvWriteInt( CvFileStorage* fs, const char* key, int value )
+{
+ CV_FUNCNAME( "cvWriteInt" );
+
+ __BEGIN__;
+
+ CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+ CV_CALL( fs->write_int( fs, key, value ));
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvWriteReal( CvFileStorage* fs, const char* key, double value )
+{
+ CV_FUNCNAME( "cvWriteReal" );
+
+ __BEGIN__;
+
+ CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+ CV_CALL( fs->write_real( fs, key, value ));
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvWriteString( CvFileStorage* fs, const char* key, const char* value, int quote )
+{
+ CV_FUNCNAME( "cvWriteString" );
+
+ __BEGIN__;
+
+ CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+ CV_CALL( fs->write_string( fs, key, value, quote ));
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvWriteComment( CvFileStorage* fs, const char* comment, int eol_comment )
+{
+ CV_FUNCNAME( "cvWriteComment" );
+
+ __BEGIN__;
+
+ CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+ CV_CALL( fs->write_comment( fs, comment, eol_comment ));
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvStartNextStream( CvFileStorage* fs )
+{
+ CV_FUNCNAME( "cvStartNextStream" );
+
+ __BEGIN__;
+
+ CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+ CV_CALL( fs->start_next_stream( fs ));
+
+ __END__;
+}
+
+
+static const char icvTypeSymbol[] = "ucwsifdr";
+#define CV_FS_MAX_FMT_PAIRS 128
+
+static char*
+icvEncodeFormat( int elem_type, char* dt )
+{
+ sprintf( dt, "%d%c", CV_MAT_CN(elem_type), icvTypeSymbol[CV_MAT_DEPTH(elem_type)] );
+ return dt + ( dt[2] == '\0' && dt[0] == '1' );
+}
+
+static int
+icvDecodeFormat( const char* dt, int* fmt_pairs, int max_len )
+{
+ int fmt_pair_count = 0;
+ CV_FUNCNAME( "icvDecodeFormat" );
+
+ __BEGIN__;
+
+ int i = 0, k = 0, len = dt ? (int)strlen(dt) : 0;
+
+ if( !dt || !len )
+ EXIT;
+
+ assert( fmt_pairs != 0 && max_len > 0 );
+ fmt_pairs[0] = 0;
+ max_len *= 2;
+
+ for( ; k < len; k++ )
+ {
+ char c = dt[k];
+
+ if( isdigit(c) )
+ {
+ int count = c - '0';
+ if( isdigit(dt[k+1]) )
+ {
+ char* endptr = 0;
+ count = (int)strtol( dt+k, &endptr, 10 );
+ k = (int)(endptr - dt) - 1;
+ }
+
+ if( count <= 0 )
+ CV_ERROR( CV_StsBadArg, "Invalid data type specification" );
+
+ fmt_pairs[i] = count;
+ }
+ else
+ {
+ const char* pos = strchr( icvTypeSymbol, c );
+ if( !pos )
+ CV_ERROR( CV_StsBadArg, "Invalid data type specification" );
+ if( fmt_pairs[i] == 0 )
+ fmt_pairs[i] = 1;
+ fmt_pairs[i+1] = (int)(pos - icvTypeSymbol);
+ if( i > 0 && fmt_pairs[i+1] == fmt_pairs[i-1] )
+ fmt_pairs[i-2] += fmt_pairs[i];
+ else
+ {
+ i += 2;
+ if( i >= max_len )
+ CV_ERROR( CV_StsBadArg, "Too long data type specification" );
+ }
+ fmt_pairs[i] = 0;
+ }
+ }
+
+ fmt_pair_count = i/2;
+
+ __END__;
+
+ return fmt_pair_count;
+}
+
+
+static int
+icvCalcElemSize( const char* dt, int initial_size )
+{
+ int size = 0;
+ CV_FUNCNAME( "icvCalcElemSize" );
+
+ __BEGIN__;
+
+ int fmt_pairs[CV_FS_MAX_FMT_PAIRS], i, fmt_pair_count;
+ int comp_size;
+
+ CV_CALL( fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ));
+ fmt_pair_count *= 2;
+ for( i = 0, size = initial_size; i < fmt_pair_count; i += 2 )
+ {
+ comp_size = CV_ELEM_SIZE(fmt_pairs[i+1]);
+ size = cvAlign( size, comp_size );
+ size += comp_size * fmt_pairs[i];
+ }
+ if( initial_size == 0 )
+ {
+ comp_size = CV_ELEM_SIZE(fmt_pairs[1]);
+ size = cvAlign( size, comp_size );
+ }
+
+ __END__;
+
+ return size;
+}
+
+
+static int
+icvDecodeSimpleFormat( const char* dt )
+{
+ int elem_type = -1;
+
+ CV_FUNCNAME( "icvDecodeSimpleFormat" );
+
+ __BEGIN__;
+
+ int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count;
+
+ CV_CALL( fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ));
+ if( fmt_pair_count != 1 || fmt_pairs[0] > 4 )
+ CV_ERROR( CV_StsError, "Too complex format for the matrix" );
+
+ elem_type = CV_MAKETYPE( fmt_pairs[1], fmt_pairs[0] );
+
+ __END__;
+
+ return elem_type;
+}
+
+
+CV_IMPL void
+cvWriteRawData( CvFileStorage* fs, const void* _data, int len, const char* dt )
+{
+ const char* data0 = (const char*)_data;
+
+ CV_FUNCNAME( "cvWriteRawData" );
+
+ __BEGIN__;
+
+ int offset = 0;
+ int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2], k, fmt_pair_count;
+ char buf[256] = "";
+
+ CV_CHECK_OUTPUT_FILE_STORAGE( fs );
+
+ if( !data0 )
+ CV_ERROR( CV_StsNullPtr, "Null data pointer" );
+
+ if( len < 0 )
+ CV_ERROR( CV_StsOutOfRange, "Negative number of elements" );
+
+ CV_CALL( fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ));
+
+ if( !len )
+ EXIT;
+
+ if( fmt_pair_count == 1 )
+ {
+ fmt_pairs[0] *= len;
+ len = 1;
+ }
+
+ for(;len--;)
+ {
+ for( k = 0; k < fmt_pair_count; k++ )
+ {
+ int i, count = fmt_pairs[k*2];
+ int elem_type = fmt_pairs[k*2+1];
+ int elem_size = CV_ELEM_SIZE(elem_type);
+ const char* data, *ptr;
+
+ offset = cvAlign( offset, elem_size );
+ data = data0 + offset;
+
+ for( i = 0; i < count; i++ )
+ {
+ switch( elem_type )
+ {
+ case CV_8U:
+ ptr = icv_itoa( *(uchar*)data, buf, 10 );
+ data++;
+ break;
+ case CV_8S:
+ ptr = icv_itoa( *(char*)data, buf, 10 );
+ data++;
+ break;
+ case CV_16U:
+ ptr = icv_itoa( *(ushort*)data, buf, 10 );
+ data += sizeof(ushort);
+ break;
+ case CV_16S:
+ ptr = icv_itoa( *(short*)data, buf, 10 );
+ data += sizeof(short);
+ break;
+ case CV_32S:
+ ptr = icv_itoa( *(int*)data, buf, 10 );
+ data += sizeof(int);
+ break;
+ case CV_32F:
+ ptr = icvFloatToString( buf, *(float*)data );
+ data += sizeof(float);
+ break;
+ case CV_64F:
+ ptr = icvDoubleToString( buf, *(double*)data );
+ data += sizeof(double);
+ break;
+ case CV_USRTYPE1: /* reference */
+ ptr = icv_itoa( (int)*(size_t*)data, buf, 10 );
+ data += sizeof(size_t);
+ break;
+ default:
+ assert(0);
+ EXIT;
+ }
+
+ if( fs->is_xml )
+ {
+ int buf_len = (int)strlen(ptr);
+ CV_CALL( icvXMLWriteScalar( fs, 0, ptr, buf_len ));
+ }
+ else
+ CV_CALL( icvYMLWrite( fs, 0, ptr, cvFuncName ));
+ }
+
+ offset = (int)(data - data0);
+ }
+ }
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvStartReadRawData( const CvFileStorage* fs, const CvFileNode* src, CvSeqReader* reader )
+{
+ CV_FUNCNAME( "cvStartReadRawData" );
+
+ __BEGIN__;
+
+ int node_type;
+ CV_CHECK_FILE_STORAGE( fs );
+
+ if( !src || !reader )
+ CV_ERROR( CV_StsNullPtr, "Null pointer to source file node or reader" );
+
+ node_type = CV_NODE_TYPE(src->tag);
+ if( node_type == CV_NODE_INT || node_type == CV_NODE_REAL )
+ {
+ // emulate reading from 1-element sequence
+ reader->ptr = (schar*)src;
+ reader->block_max = reader->ptr + sizeof(*src)*2;
+ reader->block_min = reader->ptr;
+ reader->seq = 0;
+ }
+ else if( node_type == CV_NODE_SEQ )
+ {
+ CV_CALL( cvStartReadSeq( src->data.seq, reader, 0 ));
+ }
+ else if( node_type == CV_NODE_NONE )
+ {
+ memset( reader, 0, sizeof(*reader) );
+ }
+ else
+ CV_ERROR( CV_StsBadArg, "The file node should be a numerical scalar or a sequence" );
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader,
+ int len, void* _data, const char* dt )
+{
+ char* data0 = (char*)_data;
+ CV_FUNCNAME( "cvReadRawDataSlice" );
+
+ __BEGIN__;
+
+ int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2], k = 0, fmt_pair_count;
+ int i = 0, offset = 0, count = 0;
+
+ CV_CHECK_FILE_STORAGE( fs );
+
+ if( !reader || !data0 )
+ CV_ERROR( CV_StsNullPtr, "Null pointer to reader or destination array" );
+
+ if( !reader->seq && len != 1 )
+ CV_ERROR( CV_StsBadSize, "The readed sequence is a scalar, thus len must be 1" );
+
+ CV_CALL( fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ));
+
+ for(;;)
+ {
+ for( k = 0; k < fmt_pair_count; k++ )
+ {
+ int elem_type = fmt_pairs[k*2+1];
+ int elem_size = CV_ELEM_SIZE(elem_type);
+ char* data;
+
+ count = fmt_pairs[k*2];
+ offset = cvAlign( offset, elem_size );
+ data = data0 + offset;
+
+ for( i = 0; i < count; i++ )
+ {
+ CvFileNode* node = (CvFileNode*)reader->ptr;
+ if( CV_NODE_IS_INT(node->tag) )
+ {
+ int ival = node->data.i;
+
+ switch( elem_type )
+ {
+ case CV_8U:
+ *(uchar*)data = CV_CAST_8U(ival);
+ data++;
+ break;
+ case CV_8S:
+ *(char*)data = CV_CAST_8S(ival);
+ break;
+ case CV_16U:
+ *(ushort*)data = CV_CAST_16U(ival);
+ data += sizeof(ushort);
+ break;
+ case CV_16S:
+ *(short*)data = CV_CAST_16S(ival);
+ data += sizeof(short);
+ break;
+ case CV_32S:
+ *(int*)data = ival;
+ data += sizeof(int);
+ break;
+ case CV_32F:
+ *(float*)data = (float)ival;
+ data += sizeof(float);
+ break;
+ case CV_64F:
+ *(double*)data = (double)ival;
+ data += sizeof(double);
+ break;
+ case CV_USRTYPE1: /* reference */
+ *(size_t*)data = ival;
+ data += sizeof(size_t);
+ break;
+ default:
+ assert(0);
+ EXIT;
+ }
+ }
+ else if( CV_NODE_IS_REAL(node->tag) )
+ {
+ double fval = node->data.f;
+ int ival;
+
+ switch( elem_type )
+ {
+ case CV_8U:
+ ival = cvRound(fval);
+ *(uchar*)data = CV_CAST_8U(ival);
+ data++;
+ break;
+ case CV_8S:
+ ival = cvRound(fval);
+ *(char*)data = CV_CAST_8S(ival);
+ break;
+ case CV_16U:
+ ival = cvRound(fval);
+ *(ushort*)data = CV_CAST_16U(ival);
+ data += sizeof(ushort);
+ break;
+ case CV_16S:
+ ival = cvRound(fval);
+ *(short*)data = CV_CAST_16S(ival);
+ data += sizeof(short);
+ break;
+ case CV_32S:
+ ival = cvRound(fval);
+ *(int*)data = ival;
+ data += sizeof(int);
+ break;
+ case CV_32F:
+ *(float*)data = (float)fval;
+ data += sizeof(float);
+ break;
+ case CV_64F:
+ *(double*)data = fval;
+ data += sizeof(double);
+ break;
+ case CV_USRTYPE1: /* reference */
+ ival = cvRound(fval);
+ *(size_t*)data = ival;
+ data += sizeof(size_t);
+ break;
+ default:
+ assert(0);
+ EXIT;
+ }
+ }
+ else
+ CV_ERROR( CV_StsError,
+ "The sequence element is not a numerical scalar" );
+
+ CV_NEXT_SEQ_ELEM( sizeof(CvFileNode), *reader );
+ if( !--len )
+ goto end_loop;
+ }
+
+ offset = (int)(data - data0);
+ }
+ }
+
+end_loop:
+ if( i != count - 1 || k != fmt_pair_count - 1 )
+ CV_ERROR( CV_StsBadSize,
+ "The sequence slice does not fit an integer number of records" );
+
+ if( !reader->seq )
+ reader->ptr -= sizeof(CvFileNode);
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvReadRawData( const CvFileStorage* fs, const CvFileNode* src,
+ void* data, const char* dt )
+{
+ CV_FUNCNAME( "cvReadRawData" );
+
+ __BEGIN__;
+
+ CvSeqReader reader;
+
+ if( !src || !data )
+ CV_ERROR( CV_StsNullPtr, "Null pointers to source file node or destination array" );
+
+ CV_CALL( cvStartReadRawData( fs, src, &reader ));
+ cvReadRawDataSlice( fs, &reader, CV_NODE_IS_SEQ(src->tag) ?
+ src->data.seq->total : 1, data, dt );
+
+ __END__;
+}
+
+
+static void
+icvWriteFileNode( CvFileStorage* fs, const char* name, const CvFileNode* node );
+
+static void
+icvWriteCollection( CvFileStorage* fs, const CvFileNode* node )
+{
+ int i, total = node->data.seq->total;
+ int elem_size = node->data.seq->elem_size;
+ int is_map = CV_NODE_IS_MAP(node->tag);
+ CvSeqReader reader;
+
+ cvStartReadSeq( node->data.seq, &reader, 0 );
+
+ for( i = 0; i < total; i++ )
+ {
+ CvFileMapNode* elem = (CvFileMapNode*)reader.ptr;
+ if( !is_map || CV_IS_SET_ELEM(elem) )
+ {
+ const char* name = is_map ? elem->key->str.ptr : 0;
+ icvWriteFileNode( fs, name, &elem->value );
+ }
+ CV_NEXT_SEQ_ELEM( elem_size, reader );
+ }
+}
+
+static void
+icvWriteFileNode( CvFileStorage* fs, const char* name, const CvFileNode* node )
+{
+ CV_FUNCNAME( "icvWriteFileNode" );
+
+ __BEGIN__;
+
+ switch( CV_NODE_TYPE(node->tag) )
+ {
+ case CV_NODE_INT:
+ fs->write_int( fs, name, node->data.i );
+ break;
+ case CV_NODE_REAL:
+ fs->write_real( fs, name, node->data.f );
+ break;
+ case CV_NODE_STR:
+ fs->write_string( fs, name, node->data.str.ptr, 0 );
+ break;
+ case CV_NODE_SEQ:
+ case CV_NODE_MAP:
+ fs->start_write_struct( fs, name, CV_NODE_TYPE(node->tag) +
+ (CV_NODE_SEQ_IS_SIMPLE(node->data.seq) ? CV_NODE_FLOW : 0),
+ node->info ? node->info->type_name : 0 );
+ icvWriteCollection( fs, node );
+ fs->end_write_struct( fs );
+ break;
+ case CV_NODE_NONE:
+ fs->start_write_struct( fs, name, CV_NODE_SEQ, 0 );
+ fs->end_write_struct( fs );
+ break;
+ default:
+ CV_ERROR( CV_StsBadFlag, "Unknown type of file node" );
+ }
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvWriteFileNode( CvFileStorage* fs, const char* new_node_name,
+ const CvFileNode* node, int embed )
+{
+ CvFileStorage* dst = 0;
+
+ CV_FUNCNAME( "cvWriteFileNode" );
+
+ __BEGIN__;
+
+ CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+
+ if( !node )
+ EXIT;
+
+ if( CV_NODE_IS_COLLECTION(node->tag) && embed )
+ {
+ CV_CALL( icvWriteCollection( fs, node ));
+ }
+ else
+ {
+ CV_CALL( icvWriteFileNode( fs, new_node_name, node ));
+ }
+ /*
+ int i, stream_count;
+ stream_count = fs->roots->total;
+ for( i = 0; i < stream_count; i++ )
+ {
+ CvFileNode* node = (CvFileNode*)cvGetSeqElem( fs->roots, i, 0 );
+ icvDumpCollection( dst, node );
+ if( i < stream_count - 1 )
+ dst->start_next_stream( dst );
+ }*/
+
+ __END__;
+
+ cvReleaseFileStorage( &dst );
+}
+
+
+CV_IMPL const char*
+cvGetFileNodeName( const CvFileNode* file_node )
+{
+ return file_node && CV_NODE_HAS_NAME(file_node->tag) ?
+ ((CvFileMapNode*)file_node)->key->str.ptr : 0;
+}
+
+/****************************************************************************************\
+* Reading/Writing etc. for standard types *
+\****************************************************************************************/
+
+/*#define CV_TYPE_NAME_MAT "opencv-matrix"
+#define CV_TYPE_NAME_MATND "opencv-nd-matrix"
+#define CV_TYPE_NAME_SPARSE_MAT "opencv-sparse-matrix"
+#define CV_TYPE_NAME_IMAGE "opencv-image"
+#define CV_TYPE_NAME_SEQ "opencv-sequence"
+#define CV_TYPE_NAME_SEQ_TREE "opencv-sequence-tree"
+#define CV_TYPE_NAME_GRAPH "opencv-graph"*/
+
+/******************************* CvMat ******************************/
+
+static int
+icvIsMat( const void* ptr )
+{
+ return CV_IS_MAT_HDR(ptr);
+}
+
+static void
+icvWriteMat( CvFileStorage* fs, const char* name,
+ const void* struct_ptr, CvAttrList /*attr*/ )
+{
+ CV_FUNCNAME( "icvWriteMat" );
+
+ __BEGIN__;
+
+ const CvMat* mat = (const CvMat*)struct_ptr;
+ char dt[16];
+ CvSize size;
+ int y;
+
+ assert( CV_IS_MAT(mat) );
+
+ CV_CALL( cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_MAT ));
+ cvWriteInt( fs, "rows", mat->rows );
+ cvWriteInt( fs, "cols", mat->cols );
+ cvWriteString( fs, "dt", icvEncodeFormat( CV_MAT_TYPE(mat->type), dt ), 0 );
+ cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
+
+ size = cvGetSize(mat);
+ if( CV_IS_MAT_CONT(mat->type) )
+ {
+ size.width *= size.height;
+ size.height = 1;
+ }
+
+ for( y = 0; y < size.height; y++ )
+ cvWriteRawData( fs, mat->data.ptr + y*mat->step, size.width, dt );
+ cvEndWriteStruct( fs );
+ cvEndWriteStruct( fs );
+
+ __END__;
+}
+
+
+static int
+icvFileNodeSeqLen( CvFileNode* node )
+{
+ return CV_NODE_IS_COLLECTION(node->tag) ? node->data.seq->total :
+ CV_NODE_TYPE(node->tag) != CV_NODE_NONE;
+}
+
+
+static void*
+icvReadMat( CvFileStorage* fs, CvFileNode* node )
+{
+ void* ptr = 0;
+ CV_FUNCNAME( "icvReadMat" );
+
+ __BEGIN__;
+
+ CvMat* mat;
+ const char* dt;
+ CvFileNode* data;
+ int rows, cols, elem_type;
+
+ CV_CALL( rows = cvReadIntByName( fs, node, "rows", 0 ));
+ cols = cvReadIntByName( fs, node, "cols", 0 );
+ dt = cvReadStringByName( fs, node, "dt", 0 );
+
+ if( rows == 0 || cols == 0 || dt == 0 )
+ CV_ERROR( CV_StsError, "Some of essential matrix attributes are absent" );
+
+ CV_CALL( elem_type = icvDecodeSimpleFormat( dt ));
+
+ data = cvGetFileNodeByName( fs, node, "data" );
+ if( !data )
+ CV_ERROR( CV_StsError, "The matrix data is not found in file storage" );
+
+ if( icvFileNodeSeqLen( data ) != rows*cols*CV_MAT_CN(elem_type) )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The matrix size does not match to the number of stored elements" );
+
+ CV_CALL( mat = cvCreateMat( rows, cols, elem_type ));
+ CV_CALL( cvReadRawData( fs, data, mat->data.ptr, dt ));
+
+ ptr = mat;
+
+ __END__;
+
+ return ptr;
+}
+
+
+/******************************* CvMatND ******************************/
+
+static int
+icvIsMatND( const void* ptr )
+{
+ return CV_IS_MATND(ptr);
+}
+
+
+static void
+icvWriteMatND( CvFileStorage* fs, const char* name,
+ const void* struct_ptr, CvAttrList /*attr*/ )
+{
+ CV_FUNCNAME( "icvWriteMatND" );
+
+ __BEGIN__;
+
+ void* mat = (void*)struct_ptr;
+ CvMatND stub;
+ CvNArrayIterator iterator;
+ int dims, sizes[CV_MAX_DIM];
+ char dt[16];
+
+ assert( CV_IS_MATND(mat) );
+
+ CV_CALL( cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_MATND ));
+ dims = cvGetDims( mat, sizes );
+ cvStartWriteStruct( fs, "sizes", CV_NODE_SEQ + CV_NODE_FLOW );
+ cvWriteRawData( fs, sizes, dims, "i" );
+ cvEndWriteStruct( fs );
+ cvWriteString( fs, "dt", icvEncodeFormat( cvGetElemType(mat), dt ), 0 );
+ cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
+
+ CV_CALL( cvInitNArrayIterator( 1, &mat, 0, &stub, &iterator ));
+
+ do
+ cvWriteRawData( fs, iterator.ptr[0], iterator.size.width, dt );
+ while( cvNextNArraySlice( &iterator ));
+ cvEndWriteStruct( fs );
+ cvEndWriteStruct( fs );
+
+ __END__;
+}
+
+
+static void*
+icvReadMatND( CvFileStorage* fs, CvFileNode* node )
+{
+ void* ptr = 0;
+ CV_FUNCNAME( "icvReadMatND" );
+
+ __BEGIN__;
+
+ CvMatND* mat;
+ const char* dt;
+ CvFileNode* data;
+ CvFileNode* sizes_node;
+ int sizes[CV_MAX_DIM], dims, elem_type;
+ int i, total_size;
+
+ CV_CALL( sizes_node = cvGetFileNodeByName( fs, node, "sizes" ));
+ dt = cvReadStringByName( fs, node, "dt", 0 );
+
+ if( !sizes_node || !dt )
+ CV_ERROR( CV_StsError, "Some of essential matrix attributes are absent" );
+
+ dims = CV_NODE_IS_SEQ(sizes_node->tag) ? sizes_node->data.seq->total :
+ CV_NODE_IS_INT(sizes_node->tag) ? 1 : -1;
+
+ if( dims <= 0 || dims > CV_MAX_DIM )
+ CV_ERROR( CV_StsParseError, "Could not determine the matrix dimensionality" );
+
+ CV_CALL( cvReadRawData( fs, sizes_node, sizes, "i" ));
+ CV_CALL( elem_type = icvDecodeSimpleFormat( dt ));
+
+ data = cvGetFileNodeByName( fs, node, "data" );
+ if( !data )
+ CV_ERROR( CV_StsError, "The matrix data is not found in file storage" );
+
+ for( total_size = CV_MAT_CN(elem_type), i = 0; i < dims; i++ )
+ total_size *= sizes[i];
+
+ if( icvFileNodeSeqLen( data ) != total_size )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The matrix size does not match to the number of stored elements" );
+
+ CV_CALL( mat = cvCreateMatND( dims, sizes, elem_type ));
+ CV_CALL( cvReadRawData( fs, data, mat->data.ptr, dt ));
+
+ ptr = mat;
+
+ __END__;
+
+ return ptr;
+}
+
+
+/******************************* CvSparseMat ******************************/
+
+static int
+icvIsSparseMat( const void* ptr )
+{
+ return CV_IS_SPARSE_MAT(ptr);
+}
+
+
+static int
+icvSortIdxCmpFunc( const void* _a, const void* _b, void* userdata )
+{
+ int i, dims = *(int*)userdata;
+ const int* a = *(const int**)_a;
+ const int* b = *(const int**)_b;
+
+ for( i = 0; i < dims; i++ )
+ {
+ int delta = a[i] - b[i];
+ if( delta )
+ return delta;
+ }
+
+ return 0;
+}
+
+
+static void
+icvWriteSparseMat( CvFileStorage* fs, const char* name,
+ const void* struct_ptr, CvAttrList /*attr*/ )
+{
+ CvMemStorage* memstorage = 0;
+
+ CV_FUNCNAME( "icvWriteSparseMat" );
+
+ __BEGIN__;
+
+ const CvSparseMat* mat = (const CvSparseMat*)struct_ptr;
+ CvSparseMatIterator iterator;
+ CvSparseNode* node;
+ CvSeq* elements;
+ CvSeqReader reader;
+ int i, dims;
+ int *prev_idx = 0;
+ char dt[16];
+
+ assert( CV_IS_SPARSE_MAT(mat) );
+
+ CV_CALL( memstorage = cvCreateMemStorage());
+
+ CV_CALL( cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SPARSE_MAT ));
+ dims = cvGetDims( mat, 0 );
+
+ cvStartWriteStruct( fs, "sizes", CV_NODE_SEQ + CV_NODE_FLOW );
+ cvWriteRawData( fs, mat->size, dims, "i" );
+ cvEndWriteStruct( fs );
+ cvWriteString( fs, "dt", icvEncodeFormat( CV_MAT_TYPE(mat->type), dt ), 0 );
+ cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
+
+ elements = cvCreateSeq( CV_SEQ_ELTYPE_PTR, sizeof(CvSeq), sizeof(int*), memstorage );
+
+ node = cvInitSparseMatIterator( mat, &iterator );
+ while( node )
+ {
+ int* idx = CV_NODE_IDX( mat, node );
+ cvSeqPush( elements, &idx );
+ node = cvGetNextSparseNode( &iterator );
+ }
+
+ cvSeqSort( elements, icvSortIdxCmpFunc, &dims );
+ cvStartReadSeq( elements, &reader, 0 );
+
+ for( i = 0; i < elements->total; i++ )
+ {
+ int* idx;
+ void* val;
+ int k = 0;
+
+ CV_READ_SEQ_ELEM( idx, reader );
+ if( i > 0 )
+ {
+ for( ; idx[k] == prev_idx[k]; k++ )
+ assert( k < dims );
+ if( k < dims - 1 )
+ fs->write_int( fs, 0, k - dims + 1 );
+ }
+ for( ; k < dims; k++ )
+ fs->write_int( fs, 0, idx[k] );
+ prev_idx = idx;
+
+ node = (CvSparseNode*)((uchar*)idx - mat->idxoffset );
+ val = CV_NODE_VAL( mat, node );
+
+ cvWriteRawData( fs, val, 1, dt );
+ }
+
+ cvEndWriteStruct( fs );
+ cvEndWriteStruct( fs );
+
+ __END__;
+
+ cvReleaseMemStorage( &memstorage );
+}
+
+
+static void*
+icvReadSparseMat( CvFileStorage* fs, CvFileNode* node )
+{
+ void* ptr = 0;
+ CV_FUNCNAME( "icvReadSparseMat" );
+
+ __BEGIN__;
+
+ CvSparseMat* mat;
+ const char* dt;
+ CvFileNode* data;
+ CvFileNode* sizes_node;
+ CvSeqReader reader;
+ CvSeq* elements;
+ int* idx;
+ int* sizes = 0, dims, elem_type, cn;
+ int i;
+
+ CV_CALL( sizes_node = cvGetFileNodeByName( fs, node, "sizes" ));
+ dt = cvReadStringByName( fs, node, "dt", 0 );
+
+ if( !sizes_node || !dt )
+ CV_ERROR( CV_StsError, "Some of essential matrix attributes are absent" );
+
+ dims = CV_NODE_IS_SEQ(sizes_node->tag) ? sizes_node->data.seq->total :
+ CV_NODE_IS_INT(sizes_node->tag) ? 1 : -1;
+
+ if( dims <= 0 || dims > CV_MAX_DIM_HEAP )
+ CV_ERROR( CV_StsParseError, "Could not determine sparse matrix dimensionality" );
+
+ sizes = (int*)alloca( dims*sizeof(sizes[0]));
+ CV_CALL( cvReadRawData( fs, sizes_node, sizes, "i" ));
+ CV_CALL( elem_type = icvDecodeSimpleFormat( dt ));
+
+ data = cvGetFileNodeByName( fs, node, "data" );
+ if( !data || !CV_NODE_IS_SEQ(data->tag) )
+ CV_ERROR( CV_StsError, "The matrix data is not found in file storage" );
+
+ CV_CALL( mat = cvCreateSparseMat( dims, sizes, elem_type ));
+
+ cn = CV_MAT_CN(elem_type);
+ idx = (int*)alloca( dims*sizeof(idx[0]) );
+ elements = data->data.seq;
+ cvStartReadRawData( fs, data, &reader );
+
+ for( i = 0; i < elements->total; )
+ {
+ CvFileNode* elem = (CvFileNode*)reader.ptr;
+ uchar* val;
+ int k;
+ if( !CV_NODE_IS_INT(elem->tag ))
+ CV_ERROR( CV_StsParseError, "Sparse matrix data is corrupted" );
+ k = elem->data.i;
+ if( i > 0 && k >= 0 )
+ idx[dims-1] = k;
+ else
+ {
+ if( i > 0 )
+ k = dims + k - 1;
+ else
+ idx[0] = k, k = 1;
+ for( ; k < dims; k++ )
+ {
+ CV_NEXT_SEQ_ELEM( elements->elem_size, reader );
+ i++;
+ elem = (CvFileNode*)reader.ptr;
+ if( !CV_NODE_IS_INT(elem->tag ) || elem->data.i < 0 )
+ CV_ERROR( CV_StsParseError, "Sparse matrix data is corrupted" );
+ idx[k] = elem->data.i;
+ }
+ }
+ CV_NEXT_SEQ_ELEM( elements->elem_size, reader );
+ i++;
+ CV_CALL( val = cvPtrND( mat, idx, 0, 1, 0 ));
+ CV_CALL( cvReadRawDataSlice( fs, &reader, cn, val, dt ));
+ i += cn;
+ }
+
+ ptr = mat;
+
+ __END__;
+
+ return ptr;
+}
+
+
+/******************************* IplImage ******************************/
+
+static int
+icvIsImage( const void* ptr )
+{
+ return CV_IS_IMAGE_HDR(ptr);
+}
+
+static void
+icvWriteImage( CvFileStorage* fs, const char* name,
+ const void* struct_ptr, CvAttrList /*attr*/ )
+{
+ CV_FUNCNAME( "icvWriteImage" );
+
+ __BEGIN__;
+
+ const IplImage* image = (const IplImage*)struct_ptr;
+ char dt_buf[16], *dt;
+ CvSize size;
+ int y, depth;
+
+ assert( CV_IS_IMAGE(image) );
+
+ if( image->dataOrder == IPL_DATA_ORDER_PLANE )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Images with planar data layout are not supported" );
+
+ CV_CALL( cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_IMAGE ));
+ cvWriteInt( fs, "width", image->width );
+ cvWriteInt( fs, "height", image->height );
+ cvWriteString( fs, "origin", image->origin == IPL_ORIGIN_TL
+ ? "top-left" : "bottom-left", 0 );
+ cvWriteString( fs, "layout", image->dataOrder == IPL_DATA_ORDER_PLANE
+ ? "planar" : "interleaved", 0 );
+ if( image->roi )
+ {
+ cvStartWriteStruct( fs, "roi", CV_NODE_MAP + CV_NODE_FLOW );
+ cvWriteInt( fs, "x", image->roi->xOffset );
+ cvWriteInt( fs, "y", image->roi->yOffset );
+ cvWriteInt( fs, "width", image->roi->width );
+ cvWriteInt( fs, "height", image->roi->height );
+ cvWriteInt( fs, "coi", image->roi->coi );
+ cvEndWriteStruct( fs );
+ }
+
+ depth = icvIplToCvDepth(image->depth);
+ sprintf( dt_buf, "%d%c", image->nChannels, icvTypeSymbol[depth] );
+ dt = dt_buf + (dt_buf[2] == '\0' && dt_buf[0] == '1');
+ cvWriteString( fs, "dt", dt, 0 );
+
+ size = cvSize(image->width, image->height);
+ if( size.width*image->nChannels*CV_ELEM_SIZE(depth) == image->widthStep )
+ {
+ size.width *= size.height;
+ size.height = 1;
+ }
+
+ cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
+ for( y = 0; y < size.height; y++ )
+ cvWriteRawData( fs, image->imageData + y*image->widthStep, size.width, dt );
+ cvEndWriteStruct( fs );
+ cvEndWriteStruct( fs );
+
+ __END__;
+}
+
+
+static void*
+icvReadImage( CvFileStorage* fs, CvFileNode* node )
+{
+ void* ptr = 0;
+ CV_FUNCNAME( "icvReadImage" );
+
+ __BEGIN__;
+
+ IplImage* image;
+ const char* dt;
+ CvFileNode* data;
+ CvFileNode* roi_node;
+ CvSeqReader reader;
+ CvRect roi;
+ int y, width, height, elem_type, coi, depth;
+ const char* origin, *data_order;
+
+ CV_CALL( width = cvReadIntByName( fs, node, "width", 0 ));
+ height = cvReadIntByName( fs, node, "height", 0 );
+ dt = cvReadStringByName( fs, node, "dt", 0 );
+ origin = cvReadStringByName( fs, node, "origin", 0 );
+
+ if( width == 0 || height == 0 || dt == 0 || origin == 0 )
+ CV_ERROR( CV_StsError, "Some of essential image attributes are absent" );
+
+ CV_CALL( elem_type = icvDecodeSimpleFormat( dt ));
+ data_order = cvReadStringByName( fs, node, "layout", "interleaved" );
+ if( strcmp( data_order, "interleaved" ) != 0 )
+ CV_ERROR( CV_StsError, "Only interleaved images can be read" );
+
+ data = cvGetFileNodeByName( fs, node, "data" );
+ if( !data )
+ CV_ERROR( CV_StsError, "The image data is not found in file storage" );
+
+ if( icvFileNodeSeqLen( data ) != width*height*CV_MAT_CN(elem_type) )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The matrix size does not match to the number of stored elements" );
+
+ depth = cvCvToIplDepth(elem_type);
+ CV_CALL( image = cvCreateImage( cvSize(width,height), depth, CV_MAT_CN(elem_type) ));
+
+ roi_node = cvGetFileNodeByName( fs, node, "roi" );
+ if( roi_node )
+ {
+ roi.x = cvReadIntByName( fs, roi_node, "x", 0 );
+ roi.y = cvReadIntByName( fs, roi_node, "y", 0 );
+ roi.width = cvReadIntByName( fs, roi_node, "width", 0 );
+ roi.height = cvReadIntByName( fs, roi_node, "height", 0 );
+ coi = cvReadIntByName( fs, roi_node, "coi", 0 );
+
+ cvSetImageROI( image, roi );
+ cvSetImageCOI( image, coi );
+ }
+
+ if( width*CV_ELEM_SIZE(elem_type) == image->widthStep )
+ {
+ width *= height;
+ height = 1;
+ }
+
+ width *= CV_MAT_CN(elem_type);
+ cvStartReadRawData( fs, data, &reader );
+ for( y = 0; y < height; y++ )
+ {
+ CV_CALL( cvReadRawDataSlice( fs, &reader, width,
+ image->imageData + y*image->widthStep, dt ));
+ }
+
+ ptr = image;
+
+ __END__;
+
+ return ptr;
+}
+
+
+/******************************* CvSeq ******************************/
+
+static int
+icvIsSeq( const void* ptr )
+{
+ return CV_IS_SEQ(ptr);
+}
+
+
+static void
+icvReleaseSeq( void** ptr )
+{
+ CV_FUNCNAME( "icvReleaseSeq" );
+
+ __BEGIN__;
+
+ if( !ptr )
+ CV_ERROR( CV_StsNullPtr, "NULL double pointer" );
+
+ *ptr = 0; // it's impossible now to release seq, so just clear the pointer
+
+ __END__;
+}
+
+
+static void*
+icvCloneSeq( const void* ptr )
+{
+ return cvSeqSlice( (CvSeq*)ptr, CV_WHOLE_SEQ,
+ 0 /* use the same storage as for the original sequence */, 1 );
+}
+
+
+static void
+icvWriteHeaderData( CvFileStorage* fs, const CvSeq* seq,
+ CvAttrList* attr, int initial_header_size )
+{
+ CV_FUNCNAME( "icvWriteHeaderData" );
+
+ __BEGIN__;
+
+ char header_dt_buf[128];
+ const char* header_dt = cvAttrValue( attr, "header_dt" );
+
+ if( header_dt )
+ {
+ int dt_header_size;
+ CV_CALL( dt_header_size = icvCalcElemSize( header_dt, initial_header_size ));
+ if( dt_header_size > seq->header_size )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The size of header calculated from \"header_dt\" is greater than header_size" );
+ }
+ else if( seq->header_size > initial_header_size )
+ {
+ if( CV_IS_SEQ(seq) && CV_IS_SEQ_POINT_SET(seq) &&
+ seq->header_size == sizeof(CvPoint2DSeq) &&
+ seq->elem_size == sizeof(int)*2 )
+ {
+ CvPoint2DSeq* point_seq = (CvPoint2DSeq*)seq;
+
+ cvStartWriteStruct( fs, "rect", CV_NODE_MAP + CV_NODE_FLOW );
+ cvWriteInt( fs, "x", point_seq->rect.x );
+ cvWriteInt( fs, "y", point_seq->rect.y );
+ cvWriteInt( fs, "width", point_seq->rect.width );
+ cvWriteInt( fs, "height", point_seq->rect.height );
+ cvEndWriteStruct( fs );
+ cvWriteInt( fs, "color", point_seq->color );
+ }
+ else if( CV_IS_SEQ(seq) && CV_IS_SEQ_CHAIN(seq) &&
+ CV_MAT_TYPE(seq->flags) == CV_8UC1 )
+ {
+ CvChain* chain = (CvChain*)seq;
+
+ cvStartWriteStruct( fs, "origin", CV_NODE_MAP + CV_NODE_FLOW );
+ cvWriteInt( fs, "x", chain->origin.x );
+ cvWriteInt( fs, "y", chain->origin.y );
+ cvEndWriteStruct( fs );
+ }
+ else
+ {
+ unsigned extra_size = seq->header_size - initial_header_size;
+ // a heuristic to provide nice defaults for sequences of int's & float's
+ if( extra_size % sizeof(int) == 0 )
+ sprintf( header_dt_buf, "%ui", (unsigned)(extra_size/sizeof(int)) );
+ else
+ sprintf( header_dt_buf, "%uu", extra_size );
+ header_dt = header_dt_buf;
+ }
+ }
+
+ if( header_dt )
+ {
+ cvWriteString( fs, "header_dt", header_dt, 0 );
+ cvStartWriteStruct( fs, "header_user_data", CV_NODE_SEQ + CV_NODE_FLOW );
+ cvWriteRawData( fs, (uchar*)seq + sizeof(CvSeq), 1, header_dt );
+ cvEndWriteStruct( fs );
+ }
+
+ __END__;
+}
+
+
+static char*
+icvGetFormat( const CvSeq* seq, const char* dt_key, CvAttrList* attr,
+ int initial_elem_size, char* dt_buf )
+{
+ char* dt = 0;
+
+ CV_FUNCNAME( "icvWriteFormat" );
+
+ __BEGIN__;
+
+ dt = (char*)cvAttrValue( attr, dt_key );
+
+ if( dt )
+ {
+ int dt_elem_size;
+ CV_CALL( dt_elem_size = icvCalcElemSize( dt, initial_elem_size ));
+ if( dt_elem_size != seq->elem_size )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The size of element calculated from \"dt\" and "
+ "the elem_size do not match" );
+ }
+ else if( CV_MAT_TYPE(seq->flags) != 0 || seq->elem_size == 1 )
+ {
+ int align = CV_MAT_DEPTH(seq->flags) == CV_64F ? sizeof(double) : sizeof(size_t);
+ int full_elem_size = cvAlign(CV_ELEM_SIZE(seq->flags) + initial_elem_size, align);
+ if( seq->elem_size != full_elem_size )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Size of sequence element (elem_size) is inconsistent with seq->flags" );
+ dt = icvEncodeFormat( CV_MAT_TYPE(seq->flags), dt_buf );
+ }
+ else if( seq->elem_size > initial_elem_size )
+ {
+ unsigned extra_elem_size = seq->elem_size - initial_elem_size;
+ // a heuristic to provide nice defaults for sequences of int's & float's
+ if( extra_elem_size % sizeof(int) == 0 )
+ sprintf( dt_buf, "%ui", (unsigned)(extra_elem_size/sizeof(int)) );
+ else
+ sprintf( dt_buf, "%uu", extra_elem_size );
+ dt = dt_buf;
+ }
+
+ __END__;
+
+ return dt;
+}
+
+
+static void
+icvWriteSeq( CvFileStorage* fs, const char* name,
+ const void* struct_ptr,
+ CvAttrList attr, int level )
+{
+ CV_FUNCNAME( "icvWriteSeq" );
+
+ __BEGIN__;
+
+ const CvSeq* seq = (CvSeq*)struct_ptr;
+ CvSeqBlock* block;
+ char buf[128];
+ char dt_buf[128], *dt;
+
+ assert( CV_IS_SEQ( seq ));
+ CV_CALL( cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SEQ ));
+
+ if( level >= 0 )
+ cvWriteInt( fs, "level", level );
+
+ sprintf( buf, "%08x", seq->flags );
+ cvWriteString( fs, "flags", buf, 1 );
+ cvWriteInt( fs, "count", seq->total );
+ CV_CALL( dt = icvGetFormat( seq, "dt", &attr, 0, dt_buf ));
+ cvWriteString( fs, "dt", dt, 0 );
+
+ CV_CALL( icvWriteHeaderData( fs, seq, &attr, sizeof(CvSeq) ));
+ cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
+
+ for( block = seq->first; block; block = block->next )
+ {
+ cvWriteRawData( fs, block->data, block->count, dt );
+ if( block == seq->first->prev )
+ break;
+ }
+ cvEndWriteStruct( fs );
+ cvEndWriteStruct( fs );
+
+ __END__;
+}
+
+
+static void
+icvWriteSeqTree( CvFileStorage* fs, const char* name,
+ const void* struct_ptr, CvAttrList attr )
+{
+ CV_FUNCNAME( "icvWriteSeqTree" );
+
+ __BEGIN__;
+
+ const CvSeq* seq = (CvSeq*)struct_ptr;
+ const char* recursive_value = cvAttrValue( &attr, "recursive" );
+ int is_recursive = recursive_value &&
+ strcmp(recursive_value,"0") != 0 &&
+ strcmp(recursive_value,"false") != 0 &&
+ strcmp(recursive_value,"False") != 0 &&
+ strcmp(recursive_value,"FALSE") != 0;
+
+ assert( CV_IS_SEQ( seq ));
+
+ if( !is_recursive )
+ {
+ CV_CALL( icvWriteSeq( fs, name, seq, attr, -1 ));
+ }
+ else
+ {
+ CvTreeNodeIterator tree_iterator;
+
+ CV_CALL( cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SEQ_TREE ));
+ CV_CALL( cvStartWriteStruct( fs, "sequences", CV_NODE_SEQ ));
+ cvInitTreeNodeIterator( &tree_iterator, seq, INT_MAX );
+
+ for(;;)
+ {
+ if( !tree_iterator.node )
+ break;
+ CV_CALL( icvWriteSeq( fs, 0, tree_iterator.node, attr, tree_iterator.level ));
+ cvNextTreeNode( &tree_iterator );
+ }
+
+ cvEndWriteStruct( fs );
+ cvEndWriteStruct( fs );
+ }
+
+ __END__;
+}
+
+
+static void*
+icvReadSeq( CvFileStorage* fs, CvFileNode* node )
+{
+ void* ptr = 0;
+ CV_FUNCNAME( "icvReadSeq" );
+
+ __BEGIN__;
+
+ CvSeq* seq;
+ CvSeqBlock* block;
+ CvFileNode *data, *header_node, *rect_node, *origin_node;
+ CvSeqReader reader;
+ int total, flags;
+ int elem_size, header_size = sizeof(CvSeq);
+ int fmt_pairs[CV_FS_MAX_FMT_PAIRS], i, fmt_pair_count;
+ int items_per_elem = 0;
+ const char* flags_str;
+ const char* header_dt;
+ const char* dt;
+ char* endptr = 0;
+
+ CV_CALL( flags_str = cvReadStringByName( fs, node, "flags", 0 ));
+ total = cvReadIntByName( fs, node, "count", -1 );
+ dt = cvReadStringByName( fs, node, "dt", 0 );
+
+ if( !flags_str || total == -1 || !dt )
+ CV_ERROR( CV_StsError, "Some of essential sequence attributes are absent" );
+
+ flags = (int)strtol( flags_str, &endptr, 16 );
+ if( endptr == flags_str || (flags & CV_MAGIC_MASK) != CV_SEQ_MAGIC_VAL )
+ CV_ERROR( CV_StsError, "The sequence flags are invalid" );
+
+ header_dt = cvReadStringByName( fs, node, "header_dt", 0 );
+ header_node = cvGetFileNodeByName( fs, node, "header_user_data" );
+
+ if( (header_dt != 0) ^ (header_node != 0) )
+ CV_ERROR( CV_StsError,
+ "One of \"header_dt\" and \"header_user_data\" is there, while the other is not" );
+
+ rect_node = cvGetFileNodeByName( fs, node, "rect" );
+ origin_node = cvGetFileNodeByName( fs, node, "origin" );
+
+ if( (header_node != 0) + (rect_node != 0) + (origin_node != 0) > 1 )
+ CV_ERROR( CV_StsError, "Only one of \"header_user_data\", \"rect\" and \"origin\" tags may occur" );
+
+ if( header_dt )
+ {
+ CV_CALL( header_size = icvCalcElemSize( header_dt, header_size ));
+ }
+ else if( rect_node )
+ header_size = sizeof(CvPoint2DSeq);
+ else if( origin_node )
+ header_size = sizeof(CvChain);
+
+ CV_CALL( elem_size = icvCalcElemSize( dt, 0 ));
+ CV_CALL( seq = cvCreateSeq( flags, header_size, elem_size, fs->dststorage ));
+
+ if( header_node )
+ {
+ CV_CALL( cvReadRawData( fs, header_node, (char*)seq + sizeof(CvSeq), header_dt ));
+ }
+ else if( rect_node )
+ {
+ CvPoint2DSeq* point_seq = (CvPoint2DSeq*)seq;
+ point_seq->rect.x = cvReadIntByName( fs, rect_node, "x", 0 );
+ point_seq->rect.y = cvReadIntByName( fs, rect_node, "y", 0 );
+ point_seq->rect.width = cvReadIntByName( fs, rect_node, "width", 0 );
+ point_seq->rect.height = cvReadIntByName( fs, rect_node, "height", 0 );
+ point_seq->color = cvReadIntByName( fs, node, "color", 0 );
+ }
+ else if( origin_node )
+ {
+ CvChain* chain = (CvChain*)seq;
+ chain->origin.x = cvReadIntByName( fs, origin_node, "x", 0 );
+ chain->origin.y = cvReadIntByName( fs, origin_node, "y", 0 );
+ }
+
+ cvSeqPushMulti( seq, 0, total, 0 );
+ CV_CALL( fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ));
+ fmt_pair_count *= 2;
+ for( i = 0; i < fmt_pair_count; i += 2 )
+ items_per_elem += fmt_pairs[i];
+
+ data = cvGetFileNodeByName( fs, node, "data" );
+ if( !data )
+ CV_ERROR( CV_StsError, "The image data is not found in file storage" );
+
+ if( icvFileNodeSeqLen( data ) != total*items_per_elem )
+ CV_ERROR( CV_StsError, "The number of stored elements does not match to \"count\"" );
+
+ cvStartReadRawData( fs, data, &reader );
+ for( block = seq->first; block; block = block->next )
+ {
+ int delta = block->count*items_per_elem;
+ cvReadRawDataSlice( fs, &reader, delta, block->data, dt );
+ if( block == seq->first->prev )
+ break;
+ }
+
+ ptr = seq;
+
+ __END__;
+
+ return ptr;
+}
+
+
+static void*
+icvReadSeqTree( CvFileStorage* fs, CvFileNode* node )
+{
+ void* ptr = 0;
+ CV_FUNCNAME( "icvReadSeqTree" );
+
+ __BEGIN__;
+
+ CvFileNode *sequences_node = cvGetFileNodeByName( fs, node, "sequences" );
+ CvSeq* sequences;
+ CvSeq* root = 0;
+ CvSeq* parent = 0;
+ CvSeq* prev_seq = 0;
+ CvSeqReader reader;
+ int i, total;
+ int prev_level = 0;
+
+ if( !sequences_node || !CV_NODE_IS_SEQ(sequences_node->tag) )
+ CV_ERROR( CV_StsParseError,
+ "opencv-sequence-tree instance should contain a field \"sequences\" that should be a sequence" );
+
+ sequences = sequences_node->data.seq;
+ total = sequences->total;
+
+ cvStartReadSeq( sequences, &reader, 0 );
+ for( i = 0; i < total; i++ )
+ {
+ CvFileNode* elem = (CvFileNode*)reader.ptr;
+ CvSeq* seq;
+ int level;
+ CV_CALL( seq = (CvSeq*)cvRead( fs, elem ));
+ CV_CALL( level = cvReadIntByName( fs, elem, "level", -1 ));
+ if( level < 0 )
+ CV_ERROR( CV_StsParseError, "All the sequence tree nodes should contain \"level\" field" );
+ if( !root )
+ root = seq;
+ if( level > prev_level )
+ {
+ assert( level == prev_level + 1 );
+ parent = prev_seq;
+ prev_seq = 0;
+ if( parent )
+ parent->v_next = seq;
+ }
+ else if( level < prev_level )
+ {
+ for( ; prev_level > level; prev_level-- )
+ prev_seq = prev_seq->v_prev;
+ parent = prev_seq->v_prev;
+ }
+ seq->h_prev = prev_seq;
+ if( prev_seq )
+ prev_seq->h_next = seq;
+ seq->v_prev = parent;
+ prev_seq = seq;
+ prev_level = level;
+ CV_NEXT_SEQ_ELEM( sequences->elem_size, reader );
+ }
+
+ ptr = root;
+
+ __END__;
+
+ return ptr;
+}
+
+/******************************* CvGraph ******************************/
+
+static int
+icvIsGraph( const void* ptr )
+{
+ return CV_IS_GRAPH(ptr);
+}
+
+
+static void
+icvReleaseGraph( void** ptr )
+{
+ CV_FUNCNAME( "icvReleaseGraph" );
+
+ __BEGIN__;
+
+ if( !ptr )
+ CV_ERROR( CV_StsNullPtr, "NULL double pointer" );
+
+ *ptr = 0; // it's impossible now to release graph, so just clear the pointer
+
+ __END__;
+}
+
+
+static void*
+icvCloneGraph( const void* ptr )
+{
+ return cvCloneGraph( (const CvGraph*)ptr, 0 );
+}
+
+
+static void
+icvWriteGraph( CvFileStorage* fs, const char* name,
+ const void* struct_ptr, CvAttrList attr )
+{
+ int* flag_buf = 0;
+ char* write_buf = 0;
+ CV_FUNCNAME( "icvWriteGraph" );
+
+ __BEGIN__;
+
+ const CvGraph* graph = (const CvGraph*)struct_ptr;
+ CvSeqReader reader;
+ char buf[128];
+ int i, k, vtx_count, edge_count;
+ char vtx_dt_buf[128], *vtx_dt;
+ char edge_dt_buf[128], *edge_dt;
+ int write_buf_size;
+
+ assert( CV_IS_GRAPH(graph) );
+ vtx_count = cvGraphGetVtxCount( graph );
+ edge_count = cvGraphGetEdgeCount( graph );
+ CV_CALL( flag_buf = (int*)cvAlloc( vtx_count*sizeof(flag_buf[0])));
+
+ // count vertices
+ cvStartReadSeq( (CvSeq*)graph, &reader );
+ for( i = 0, k = 0; i < graph->total; i++ )
+ {
+ if( CV_IS_SET_ELEM( reader.ptr ))
+ {
+ CvGraphVtx* vtx = (CvGraphVtx*)reader.ptr;
+ flag_buf[k] = vtx->flags;
+ vtx->flags = k++;
+ }
+ CV_NEXT_SEQ_ELEM( graph->elem_size, reader );
+ }
+
+ // write header
+ CV_CALL( cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_GRAPH ));
+
+ sprintf( buf, "%08x", graph->flags );
+ cvWriteString( fs, "flags", buf, 1 );
+
+ cvWriteInt( fs, "vertex_count", vtx_count );
+ CV_CALL( vtx_dt = icvGetFormat( (CvSeq*)graph, "vertex_dt",
+ &attr, sizeof(CvGraphVtx), vtx_dt_buf ));
+ if( vtx_dt )
+ cvWriteString( fs, "vertex_dt", vtx_dt, 0 );
+
+ cvWriteInt( fs, "edge_count", edge_count );
+ CV_CALL( edge_dt = icvGetFormat( (CvSeq*)graph->edges, "edge_dt",
+ &attr, sizeof(CvGraphEdge), buf ));
+ sprintf( edge_dt_buf, "2if%s", edge_dt ? edge_dt : "" );
+ edge_dt = edge_dt_buf;
+ cvWriteString( fs, "edge_dt", edge_dt, 0 );
+
+ CV_CALL( icvWriteHeaderData( fs, (CvSeq*)graph, &attr, sizeof(CvGraph) ));
+
+ write_buf_size = MAX( 3*graph->elem_size, 1 << 16 );
+ write_buf_size = MAX( 3*graph->edges->elem_size, write_buf_size );
+ CV_CALL( write_buf = (char*)cvAlloc( write_buf_size ));
+
+ // as vertices and edges are written in similar way,
+ // do it as a parametrized 2-iteration loop
+ for( k = 0; k < 2; k++ )
+ {
+ const char* dt = k == 0 ? vtx_dt : edge_dt;
+ if( dt )
+ {
+ CvSet* data = k == 0 ? (CvSet*)graph : graph->edges;
+ int elem_size = data->elem_size;
+ int write_elem_size = icvCalcElemSize( dt, 0 );
+ char* src_ptr = write_buf;
+ int write_max = write_buf_size / write_elem_size, write_count = 0;
+
+ // alignment of user part of the edge data following 2if
+ int edge_user_align = sizeof(float);
+
+ if( k == 1 )
+ {
+ int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count;
+ fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
+ if( fmt_pair_count > 2 || CV_ELEM_SIZE(fmt_pairs[2*2+1]) >= (int)sizeof(double))
+ edge_user_align = sizeof(double);
+ }
+
+ cvStartWriteStruct( fs, k == 0 ? "vertices" : "edges",
+ CV_NODE_SEQ + CV_NODE_FLOW );
+ cvStartReadSeq( (CvSeq*)data, &reader );
+ for( i = 0; i < data->total; i++ )
+ {
+ if( CV_IS_SET_ELEM( reader.ptr ))
+ {
+ if( k == 0 ) // vertices
+ memcpy( src_ptr, reader.ptr + sizeof(CvGraphVtx), write_elem_size );
+ else
+ {
+ CvGraphEdge* edge = (CvGraphEdge*)reader.ptr;
+ src_ptr = (char*)cvAlignPtr( src_ptr, sizeof(int) );
+ ((int*)src_ptr)[0] = edge->vtx[0]->flags;
+ ((int*)src_ptr)[1] = edge->vtx[1]->flags;
+ *(float*)(src_ptr + sizeof(int)*2) = edge->weight;
+ if( elem_size > (int)sizeof(CvGraphEdge) )
+ {
+ char* src_ptr2 = (char*)cvAlignPtr( src_ptr + 2*sizeof(int)
+ + sizeof(float), edge_user_align );
+ memcpy( src_ptr2, edge + 1, elem_size - sizeof(CvGraphEdge) );
+ }
+ }
+ src_ptr += write_elem_size;
+ if( ++write_count >= write_max )
+ {
+ cvWriteRawData( fs, write_buf, write_count, dt );
+ write_count = 0;
+ src_ptr = write_buf;
+ }
+ }
+ CV_NEXT_SEQ_ELEM( data->elem_size, reader );
+ }
+
+ if( write_count > 0 )
+ cvWriteRawData( fs, write_buf, write_count, dt );
+ cvEndWriteStruct( fs );
+ }
+ }
+
+ cvEndWriteStruct( fs );
+
+ // final stage. restore the graph flags
+ cvStartReadSeq( (CvSeq*)graph, &reader );
+ vtx_count = 0;
+ for( i = 0; i < graph->total; i++ )
+ {
+ if( CV_IS_SET_ELEM( reader.ptr ))
+ ((CvGraphVtx*)reader.ptr)->flags = flag_buf[vtx_count++];
+ CV_NEXT_SEQ_ELEM( graph->elem_size, reader );
+ }
+
+ __END__;
+
+ cvFree( &write_buf );
+ cvFree( &flag_buf );
+}
+
+
+static void*
+icvReadGraph( CvFileStorage* fs, CvFileNode* node )
+{
+ void* ptr = 0;
+ char* read_buf = 0;
+ CvGraphVtx** vtx_buf = 0;
+ CV_FUNCNAME( "icvReadGraph" );
+
+ __BEGIN__;
+
+ CvGraph* graph;
+ CvFileNode *header_node, *vtx_node, *edge_node;
+ int flags, vtx_count, edge_count;
+ int vtx_size = sizeof(CvGraphVtx), edge_size, header_size = sizeof(CvGraph);
+ int src_vtx_size = 0, src_edge_size;
+ int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count;
+ int vtx_items_per_elem = 0, edge_items_per_elem = 0;
+ int edge_user_align = sizeof(float);
+ int read_buf_size;
+ int i, k;
+ const char* flags_str;
+ const char* header_dt;
+ const char* vtx_dt;
+ const char* edge_dt;
+ char* endptr = 0;
+
+ CV_CALL( flags_str = cvReadStringByName( fs, node, "flags", 0 ));
+ vtx_dt = cvReadStringByName( fs, node, "vertex_dt", 0 );
+ edge_dt = cvReadStringByName( fs, node, "edge_dt", 0 );
+ vtx_count = cvReadIntByName( fs, node, "vertex_count", -1 );
+ edge_count = cvReadIntByName( fs, node, "edge_count", -1 );
+
+ if( !flags_str || vtx_count == -1 || edge_count == -1 || !edge_dt )
+ CV_ERROR( CV_StsError, "Some of essential sequence attributes are absent" );
+
+ flags = (int)strtol( flags_str, &endptr, 16 );
+ if( endptr == flags_str ||
+ (flags & (CV_SEQ_KIND_MASK|CV_MAGIC_MASK)) != (CV_GRAPH|CV_SET_MAGIC_VAL))
+ CV_ERROR( CV_StsError, "Invalid graph signature" );
+
+ header_dt = cvReadStringByName( fs, node, "header_dt", 0 );
+ header_node = cvGetFileNodeByName( fs, node, "header_user_data" );
+
+ if( (header_dt != 0) ^ (header_node != 0) )
+ CV_ERROR( CV_StsError,
+ "One of \"header_dt\" and \"header_user_data\" is there, while the other is not" );
+
+ if( header_dt )
+ CV_CALL( header_size = icvCalcElemSize( header_dt, header_size ));
+
+ if( vtx_dt > 0 )
+ {
+ CV_CALL( src_vtx_size = icvCalcElemSize( vtx_dt, 0 ));
+ CV_CALL( vtx_size = icvCalcElemSize( vtx_dt, vtx_size ));
+ CV_CALL( fmt_pair_count = icvDecodeFormat( edge_dt,
+ fmt_pairs, CV_FS_MAX_FMT_PAIRS ));
+ fmt_pair_count *= 2;
+ for( i = 0; i < fmt_pair_count; i += 2 )
+ vtx_items_per_elem += fmt_pairs[i];
+ }
+
+ {
+ char dst_edge_dt_buf[128];
+ const char* dst_edge_dt = 0;
+
+ CV_CALL( fmt_pair_count = icvDecodeFormat( edge_dt,
+ fmt_pairs, CV_FS_MAX_FMT_PAIRS ));
+ if( fmt_pair_count < 2 ||
+ fmt_pairs[0] != 2 || fmt_pairs[1] != CV_32S ||
+ fmt_pairs[2] < 1 || fmt_pairs[3] != CV_32F )
+ CV_ERROR( CV_StsBadArg,
+ "Graph edges should start with 2 integers and a float" );
+
+ // alignment of user part of the edge data following 2if
+ if( fmt_pair_count > 2 && CV_ELEM_SIZE(fmt_pairs[5]) >= (int)sizeof(double))
+ edge_user_align = sizeof(double);
+
+ fmt_pair_count *= 2;
+ for( i = 0; i < fmt_pair_count; i += 2 )
+ edge_items_per_elem += fmt_pairs[i];
+
+ if( edge_dt[2] == 'f' || (edge_dt[2] == '1' && edge_dt[3] == 'f') )
+ dst_edge_dt = edge_dt + 3 + isdigit(edge_dt[2]);
+ else
+ {
+ int val = (int)strtol( edge_dt + 2, &endptr, 10 );
+ sprintf( dst_edge_dt_buf, "%df%s", val-1, endptr );
+ dst_edge_dt = dst_edge_dt_buf;
+ }
+
+ CV_CALL( edge_size = icvCalcElemSize( dst_edge_dt, sizeof(CvGraphEdge) ));
+ CV_CALL( src_edge_size = icvCalcElemSize( edge_dt, 0 ));
+ }
+
+ CV_CALL( graph = cvCreateGraph( flags, header_size, vtx_size, edge_size, fs->dststorage ));
+
+ if( header_node )
+ CV_CALL( cvReadRawData( fs, header_node, (char*)graph + sizeof(CvGraph), header_dt ));
+
+ read_buf_size = MAX( src_vtx_size*3, 1 << 16 );
+ read_buf_size = MAX( src_edge_size*3, read_buf_size );
+ CV_CALL( read_buf = (char*)cvAlloc( read_buf_size ));
+ CV_CALL( vtx_buf = (CvGraphVtx**)cvAlloc( vtx_count * sizeof(vtx_buf[0]) ));
+
+ vtx_node = cvGetFileNodeByName( fs, node, "vertices" );
+ edge_node = cvGetFileNodeByName( fs, node, "edges" );
+ if( !edge_node )
+ CV_ERROR( CV_StsBadArg, "No edges data" );
+ if( vtx_dt && !vtx_node )
+ CV_ERROR( CV_StsBadArg, "No vertices data" );
+
+ // as vertices and edges are read in similar way,
+ // do it as a parametrized 2-iteration loop
+ for( k = 0; k < 2; k++ )
+ {
+ const char* dt = k == 0 ? vtx_dt : edge_dt;
+ int elem_size = k == 0 ? vtx_size : edge_size;
+ int src_elem_size = k == 0 ? src_vtx_size : src_edge_size;
+ int items_per_elem = k == 0 ? vtx_items_per_elem : edge_items_per_elem;
+ int elem_count = k == 0 ? vtx_count : edge_count;
+ char* dst_ptr = read_buf;
+ int read_max = read_buf_size /MAX(src_elem_size, 1), read_count = 0;
+ CvSeqReader reader;
+ cvStartReadRawData( fs, k == 0 ? vtx_node : edge_node, &reader );
+
+ for( i = 0; i < elem_count; i++ )
+ {
+ if( read_count == 0 && dt )
+ {
+ int count = MIN( elem_count - i, read_max )*items_per_elem;
+ cvReadRawDataSlice( fs, &reader, count, read_buf, dt );
+ read_count = count;
+ dst_ptr = read_buf;
+ }
+
+ if( k == 0 )
+ {
+ CvGraphVtx* vtx;
+ cvGraphAddVtx( graph, 0, &vtx );
+ vtx_buf[i] = vtx;
+ if( dt )
+ memcpy( vtx + 1, dst_ptr, src_elem_size );
+ }
+ else
+ {
+ CvGraphEdge* edge = 0;
+ int vtx1 = ((int*)dst_ptr)[0];
+ int vtx2 = ((int*)dst_ptr)[1];
+ int result;
+
+ if( (unsigned)vtx1 >= (unsigned)vtx_count ||
+ (unsigned)vtx2 >= (unsigned)vtx_count )
+ CV_ERROR( CV_StsOutOfRange,
+ "Some of stored vertex indices are out of range" );
+
+ CV_CALL( result = cvGraphAddEdgeByPtr( graph,
+ vtx_buf[vtx1], vtx_buf[vtx2], 0, &edge ));
+
+ if( result == 0 )
+ CV_ERROR( CV_StsBadArg, "Duplicated edge has occured" );
+
+ edge->weight = *(float*)(dst_ptr + sizeof(int)*2);
+ if( elem_size > (int)sizeof(CvGraphEdge) )
+ {
+ char* dst_ptr2 = (char*)cvAlignPtr( dst_ptr + sizeof(int)*2 +
+ sizeof(float), edge_user_align );
+ memcpy( edge + 1, dst_ptr2, elem_size - sizeof(CvGraphEdge) );
+ }
+ }
+
+ dst_ptr += src_elem_size;
+ read_count--;
+ }
+ }
+
+ ptr = graph;
+
+ __END__;
+
+ cvFree( &read_buf );
+ cvFree( &vtx_buf );
+
+ return ptr;
+}
+
+/****************************************************************************************\
+* RTTI Functions *
+\****************************************************************************************/
+
+CvTypeInfo *CvType::first = 0, *CvType::last = 0;
+
+CvType::CvType( const char* type_name,
+ CvIsInstanceFunc is_instance, CvReleaseFunc release,
+ CvReadFunc read, CvWriteFunc write, CvCloneFunc clone )
+{
+ CvTypeInfo _info;
+ _info.flags = 0;
+ _info.header_size = sizeof(_info);
+ _info.type_name = type_name;
+ _info.prev = _info.next = 0;
+ _info.is_instance = is_instance;
+ _info.release = release;
+ _info.clone = clone;
+ _info.read = read;
+ _info.write = write;
+
+ cvRegisterType( &_info );
+ info = first;
+}
+
+
+CvType::~CvType()
+{
+ cvUnregisterType( info->type_name );
+}
+
+
+CvType seq_type( CV_TYPE_NAME_SEQ, icvIsSeq, icvReleaseSeq, icvReadSeq,
+ icvWriteSeqTree /* this is the entry point for
+ writing a single sequence too */, icvCloneSeq );
+
+CvType seq_tree_type( CV_TYPE_NAME_SEQ_TREE, icvIsSeq, icvReleaseSeq,
+ icvReadSeqTree, icvWriteSeqTree, icvCloneSeq );
+
+CvType seq_graph_type( CV_TYPE_NAME_GRAPH, icvIsGraph, icvReleaseGraph,
+ icvReadGraph, icvWriteGraph, icvCloneGraph );
+
+CvType sparse_mat_type( CV_TYPE_NAME_SPARSE_MAT, icvIsSparseMat,
+ (CvReleaseFunc)cvReleaseSparseMat, icvReadSparseMat,
+ icvWriteSparseMat, (CvCloneFunc)cvCloneSparseMat );
+
+CvType image_type( CV_TYPE_NAME_IMAGE, icvIsImage, (CvReleaseFunc)cvReleaseImage,
+ icvReadImage, icvWriteImage, (CvCloneFunc)cvCloneImage );
+
+CvType mat_type( CV_TYPE_NAME_MAT, icvIsMat, (CvReleaseFunc)cvReleaseMat,
+ icvReadMat, icvWriteMat, (CvCloneFunc)cvCloneMat );
+
+CvType matnd_type( CV_TYPE_NAME_MATND, icvIsMatND, (CvReleaseFunc)cvReleaseMatND,
+ icvReadMatND, icvWriteMatND, (CvCloneFunc)cvCloneMatND );
+
+CV_IMPL void
+cvRegisterType( const CvTypeInfo* _info )
+{
+ CV_FUNCNAME("cvRegisterType" );
+
+ __BEGIN__;
+
+ CvTypeInfo* info = 0;
+ int i, len;
+ char c;
+
+ //if( !CvType::first )
+ // icvCreateStandardTypes();
+
+ if( !_info || _info->header_size != sizeof(CvTypeInfo) )
+ CV_ERROR( CV_StsBadSize, "Invalid type info" );
+
+ if( !_info->is_instance || !_info->release ||
+ !_info->read || !_info->write )
+ CV_ERROR( CV_StsNullPtr,
+ "Some of required function pointers "
+ "(is_instance, release, read or write) are NULL");
+
+ c = _info->type_name[0];
+ if( !isalpha(c) && c != '_' )
+ CV_ERROR( CV_StsBadArg, "Type name should start with a letter or _" );
+
+ len = (int)strlen(_info->type_name);
+
+ for( i = 0; i < len; i++ )
+ {
+ c = _info->type_name[i];
+ if( !isalnum(c) && c != '-' && c != '_' )
+ CV_ERROR( CV_StsBadArg,
+ "Type name should contain only letters, digits, - and _" );
+ }
+
+ CV_CALL( info = (CvTypeInfo*)cvAlloc( sizeof(*info) + len + 1 ));
+
+ *info = *_info;
+ info->type_name = (char*)(info + 1);
+ memcpy( (char*)info->type_name, _info->type_name, len + 1 );
+
+ info->flags = 0;
+ info->next = CvType::first;
+ info->prev = 0;
+ if( CvType::first )
+ CvType::first->prev = info;
+ else
+ CvType::last = info;
+ CvType::first = info;
+
+ __END__;
+}
+
+
+CV_IMPL void
+cvUnregisterType( const char* type_name )
+{
+ CV_FUNCNAME("cvUnregisterType" );
+
+ __BEGIN__;
+
+ CvTypeInfo* info;
+
+ CV_CALL( info = cvFindType( type_name ));
+ if( info )
+ {
+ if( info->prev )
+ info->prev->next = info->next;
+ else
+ CvType::first = info->next;
+
+ if( info->next )
+ info->next->prev = info->prev;
+ else
+ CvType::last = info->prev;
+
+ if( !CvType::first || !CvType::last )
+ CvType::first = CvType::last = 0;
+
+ cvFree( &info );
+ }
+
+ __END__;
+}
+
+
+CV_IMPL CvTypeInfo*
+cvFirstType( void )
+{
+ return CvType::first;
+}
+
+
+CV_IMPL CvTypeInfo*
+cvFindType( const char* type_name )
+{
+ CvTypeInfo* info = 0;
+
+ for( info = CvType::first; info != 0; info = info->next )
+ if( strcmp( info->type_name, type_name ) == 0 )
+ break;
+
+ return info;
+}
+
+
+CV_IMPL CvTypeInfo*
+cvTypeOf( const void* struct_ptr )
+{
+ CvTypeInfo* info = 0;
+
+ for( info = CvType::first; info != 0; info = info->next )
+ if( info->is_instance( struct_ptr ))
+ break;
+
+ return info;
+}
+
+
+/* universal functions */
+CV_IMPL void
+cvRelease( void** struct_ptr )
+{
+ CV_FUNCNAME("cvRelease" );
+
+ __BEGIN__;
+
+ CvTypeInfo* info;
+
+ if( !struct_ptr )
+ CV_ERROR( CV_StsNullPtr, "NULL double pointer" );
+
+ if( *struct_ptr )
+ {
+ CV_CALL( info = cvTypeOf( *struct_ptr ));
+ if( !info )
+ CV_ERROR( CV_StsError, "Unknown object type" );
+ if( !info->release )
+ CV_ERROR( CV_StsError, "release function pointer is NULL" );
+
+ CV_CALL( info->release( struct_ptr ));
+ *struct_ptr = 0;
+ }
+
+ __END__;
+}
+
+
+void* cvClone( const void* struct_ptr )
+{
+ void* struct_copy = 0;
+
+ CV_FUNCNAME("cvClone" );
+
+ __BEGIN__;
+
+ CvTypeInfo* info;
+
+ if( !struct_ptr )
+ CV_ERROR( CV_StsNullPtr, "NULL structure pointer" );
+
+ CV_CALL( info = cvTypeOf( struct_ptr ));
+ if( !info )
+ CV_ERROR( CV_StsError, "Unknown object type" );
+ if( !info->clone )
+ CV_ERROR( CV_StsError, "clone function pointer is NULL" );
+
+ CV_CALL( struct_copy = info->clone( struct_ptr ));
+
+ __END__;
+
+ return struct_copy;
+}
+
+
+/* reads matrix, image, sequence, graph etc. */
+CV_IMPL void*
+cvRead( CvFileStorage* fs, CvFileNode* node, CvAttrList* list )
+{
+ void* obj = 0;
+
+ CV_FUNCNAME( "cvRead" );
+
+ __BEGIN__;
+
+ CV_CHECK_FILE_STORAGE( fs );
+
+ if( !node )
+ EXIT;
+
+ if( !CV_NODE_IS_USER(node->tag) || !node->info )
+ CV_ERROR( CV_StsError, "The node does not represent a user object (unknown type?)" );
+
+ CV_CALL( obj = node->info->read( fs, node ));
+
+ __END__;
+
+ if( list )
+ *list = cvAttrList(0,0);
+
+ return obj;
+}
+
+
+/* writes matrix, image, sequence, graph etc. */
+CV_IMPL void
+cvWrite( CvFileStorage* fs, const char* name,
+ const void* ptr, CvAttrList attributes )
+{
+ CV_FUNCNAME( "cvWrite" );
+
+ __BEGIN__;
+
+ CvTypeInfo* info;
+
+ CV_CHECK_OUTPUT_FILE_STORAGE( fs );
+
+ if( !ptr )
+ CV_ERROR( CV_StsNullPtr, "Null pointer to the written object" );
+
+ CV_CALL( info = cvTypeOf( ptr ));
+ if( !info )
+ CV_ERROR( CV_StsBadArg, "Unknown object" );
+
+ if( !info->write )
+ CV_ERROR( CV_StsBadArg, "The object does not have write function" );
+
+ CV_CALL( info->write( fs, name, ptr, attributes ));
+
+ __END__;
+}
+
+
+/* simple API for reading/writing data */
+CV_IMPL void
+cvSave( const char* filename, const void* struct_ptr,
+ const char* _name, const char* comment, CvAttrList attributes )
+{
+ CvFileStorage* fs = 0;
+
+ CV_FUNCNAME( "cvSave" );
+
+ __BEGIN__;
+
+ char name_buf[CV_FS_MAX_LEN + 256];
+ char* name = (char*)_name;
+
+ if( !struct_ptr )
+ CV_ERROR( CV_StsNullPtr, "NULL object pointer" );
+
+ CV_CALL( fs = cvOpenFileStorage( filename, 0, CV_STORAGE_WRITE ));
+ if( !fs )
+ CV_ERROR( CV_StsError, "Could not open the file storage. Check the path and permissions" );
+
+ if( !name )
+ {
+ static const char* stubname = "unnamed";
+ const char* ptr2 = filename + strlen( filename );
+ const char* ptr = ptr2 - 1;
+
+ while( ptr >= filename && *ptr != '\\' && *ptr != '/' && *ptr != ':' )
+ {
+ if( *ptr == '.' && !*ptr2 )
+ ptr2 = ptr;
+ ptr--;
+ }
+ ptr++;
+ if( ptr == ptr2 )
+ CV_ERROR( CV_StsBadArg, "Invalid filename" );
+
+ name=name_buf;
+
+ // name must start with letter or '_'
+ if( !isalpha(*ptr) && *ptr!= '_' ){
+ *name++ = '_';
+ }
+
+ while( ptr < ptr2 )
+ {
+ char c = *ptr++;
+ if( !isalnum(c) && c != '-' && c != '_' )
+ c = '_';
+ *name++ = c;
+ }
+ *name = '\0';
+ name = name_buf;
+ if( strcmp( name, "_" ) == 0 )
+ strcpy( name, stubname );
+ }
+
+ if( comment )
+ CV_CALL( cvWriteComment( fs, comment, 0 ));
+ CV_CALL( cvWrite( fs, name, struct_ptr, attributes ));
+
+ __END__;
+
+ cvReleaseFileStorage( &fs );
+}
+
+
+CV_IMPL void*
+cvLoad( const char* filename, CvMemStorage* memstorage,
+ const char* name, const char** _real_name )
+{
+ void* ptr = 0;
+ const char* real_name = 0;
+ CvFileStorage* fs = 0;
+
+ CV_FUNCNAME( "cvLoad" );
+
+ __BEGIN__;
+
+ CvFileNode* node = 0;
+ CV_CALL( fs = cvOpenFileStorage( filename, memstorage, CV_STORAGE_READ ));
+
+ if( !fs )
+ EXIT;
+
+ if( name )
+ {
+ CV_CALL( node = cvGetFileNodeByName( fs, 0, name ));
+ }
+ else
+ {
+ int i, k;
+ for( k = 0; k < fs->roots->total; k++ )
+ {
+ CvSeq* seq;
+ CvSeqReader reader;
+
+ node = (CvFileNode*)cvGetSeqElem( fs->roots, k );
+ if( !CV_NODE_IS_MAP( node->tag ))
+ EXIT;
+ seq = node->data.seq;
+ node = 0;
+
+ cvStartReadSeq( seq, &reader, 0 );
+
+ // find the first element in the map
+ for( i = 0; i < seq->total; i++ )
+ {
+ if( CV_IS_SET_ELEM( reader.ptr ))
+ {
+ node = (CvFileNode*)reader.ptr;
+ goto stop_search;
+ }
+ CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
+ }
+ }
+
+stop_search:
+ ;
+ }
+
+ if( !node )
+ CV_ERROR( CV_StsObjectNotFound, "Could not find the/an object in file storage" );
+
+ real_name = cvGetFileNodeName( node );
+ CV_CALL( ptr = cvRead( fs, node, 0 ));
+
+ // sanity check
+ if( !memstorage && (CV_IS_SEQ( ptr ) || CV_IS_SET( ptr )) )
+ CV_ERROR( CV_StsNullPtr,
+ "NULL memory storage is passed - the loaded dynamic structure can not be stored" );
+
+ __END__;
+
+ cvReleaseFileStorage( &fs );
+ if( cvGetErrStatus() < 0 )
+ {
+ cvRelease( (void**)&ptr );
+ real_name = 0;
+ }
+
+ if( _real_name )
+ *_real_name = real_name;
+
+ return ptr;
+}
+
+/* End of file. */
diff --git a/cxcore/src/cxprecomp.cpp b/cxcore/src/cxprecomp.cpp
new file mode 100644
index 0000000..2a7b2e2
--- /dev/null
+++ b/cxcore/src/cxprecomp.cpp
@@ -0,0 +1,44 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+
+/* End of file. */
diff --git a/cxcore/src/cxrand.cpp b/cxcore/src/cxrand.cpp
new file mode 100644
index 0000000..842bdd3
--- /dev/null
+++ b/cxcore/src/cxrand.cpp
@@ -0,0 +1,600 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/* ////////////////////////////////////////////////////////////////////
+//
+// Filling CvMat/IplImage instances with random numbers
+//
+// */
+
+#include "_cxcore.h"
+
+
+///////////////////////////// Functions Declaration //////////////////////////////////////
+
+/*
+ Multiply-with-carry generator is used here:
+ temp = ( A*X(n) + carry )
+ X(n+1) = temp mod (2^32)
+ carry = temp / (2^32)
+*/
+#define ICV_RNG_NEXT(x) ((uint64)(unsigned)(x)*1554115554 + ((x) >> 32))
+#define ICV_CVT_FLT(x) (((unsigned)(x) >> 9)|CV_1F)
+#define ICV_1D CV_BIG_INT(0x3FF0000000000000)
+#define ICV_CVT_DBL(x) (((uint64)(unsigned)(x) << 20)|((x) >> 44)|ICV_1D)
+
+/***************************************************************************************\
+* Pseudo-Random Number Generators (PRNGs) *
+\***************************************************************************************/
+
+#define ICV_IMPL_RAND_BITS( flavor, arrtype, cast_macro ) \
+static CvStatus CV_STDCALL \
+icvRandBits_##flavor##_C1R( arrtype* arr, int step, CvSize size, \
+ uint64* state, const int* param ) \
+{ \
+ uint64 temp = *state; \
+ int small_flag = (param[12]|param[13]|param[14]|param[15]) <= 255; \
+ step /= sizeof(arr[0]); \
+ \
+ for( ; size.height--; arr += step ) \
+ { \
+ int i, k = 3; \
+ const int* p = param; \
+ \
+ if( !small_flag ) \
+ { \
+ for( i = 0; i <= size.width - 4; i += 4 ) \
+ { \
+ unsigned t0, t1; \
+ \
+ temp = ICV_RNG_NEXT(temp); \
+ t0 = ((unsigned)temp & p[i + 12]) + p[i]; \
+ temp = ICV_RNG_NEXT(temp); \
+ t1 = ((unsigned)temp & p[i + 13]) + p[i+1]; \
+ arr[i] = cast_macro((int)t0); \
+ arr[i+1] = cast_macro((int)t1); \
+ \
+ temp = ICV_RNG_NEXT(temp); \
+ t0 = ((unsigned)temp & p[i + 14]) + p[i+2]; \
+ temp = ICV_RNG_NEXT(temp); \
+ t1 = ((unsigned)temp & p[i + 15]) + p[i+3]; \
+ arr[i+2] = cast_macro((int)t0); \
+ arr[i+3] = cast_macro((int)t1); \
+ \
+ if( !--k ) \
+ { \
+ k = 3; \
+ p -= 12; \
+ } \
+ } \
+ } \
+ else \
+ { \
+ for( i = 0; i <= size.width - 4; i += 4 ) \
+ { \
+ unsigned t0, t1, t; \
+ \
+ temp = ICV_RNG_NEXT(temp); \
+ t = (unsigned)temp; \
+ t0 = (t & p[i + 12]) + p[i]; \
+ t1 = ((t >> 8) & p[i + 13]) + p[i+1]; \
+ arr[i] = cast_macro((int)t0); \
+ arr[i+1] = cast_macro((int)t1); \
+ \
+ t0 = ((t >> 16) & p[i + 14]) + p[i + 2]; \
+ t1 = ((t >> 24) & p[i + 15]) + p[i + 3]; \
+ arr[i+2] = cast_macro((int)t0); \
+ arr[i+3] = cast_macro((int)t1); \
+ \
+ if( !--k ) \
+ { \
+ k = 3; \
+ p -= 12; \
+ } \
+ } \
+ } \
+ \
+ for( ; i < size.width; i++ ) \
+ { \
+ unsigned t0; \
+ temp = ICV_RNG_NEXT(temp); \
+ \
+ t0 = ((unsigned)temp & p[i + 12]) + p[i]; \
+ arr[i] = cast_macro((int)t0); \
+ } \
+ } \
+ \
+ *state = temp; \
+ return CV_OK; \
+}
+
+
+#define ICV_IMPL_RAND( flavor, arrtype, worktype, cast_macro1, cast_macro2 )\
+static CvStatus CV_STDCALL \
+icvRand_##flavor##_C1R( arrtype* arr, int step, CvSize size, \
+ uint64* state, const double* param ) \
+{ \
+ uint64 temp = *state; \
+ step /= sizeof(arr[0]); \
+ \
+ for( ; size.height--; arr += step ) \
+ { \
+ int i, k = 3; \
+ const double* p = param; \
+ \
+ for( i = 0; i <= size.width - 4; i += 4 ) \
+ { \
+ worktype f0, f1; \
+ Cv32suf t0, t1; \
+ \
+ temp = ICV_RNG_NEXT(temp); \
+ t0.u = ICV_CVT_FLT(temp); \
+ temp = ICV_RNG_NEXT(temp); \
+ t1.u = ICV_CVT_FLT(temp); \
+ f0 = cast_macro1( t0.f * p[i + 12] + p[i] ); \
+ f1 = cast_macro1( t1.f * p[i + 13] + p[i + 1] ); \
+ arr[i] = cast_macro2(f0); \
+ arr[i+1] = cast_macro2(f1); \
+ \
+ temp = ICV_RNG_NEXT(temp); \
+ t0.u = ICV_CVT_FLT(temp); \
+ temp = ICV_RNG_NEXT(temp); \
+ t1.u = ICV_CVT_FLT(temp); \
+ f0 = cast_macro1( t0.f * p[i + 14] + p[i + 2] ); \
+ f1 = cast_macro1( t1.f * p[i + 15] + p[i + 3] ); \
+ arr[i+2] = cast_macro2(f0); \
+ arr[i+3] = cast_macro2(f1); \
+ \
+ if( !--k ) \
+ { \
+ k = 3; \
+ p -= 12; \
+ } \
+ } \
+ \
+ for( ; i < size.width; i++ ) \
+ { \
+ worktype f0; \
+ Cv32suf t0; \
+ \
+ temp = ICV_RNG_NEXT(temp); \
+ t0.u = ICV_CVT_FLT(temp); \
+ f0 = cast_macro1( t0.f * p[i + 12] + p[i] ); \
+ arr[i] = cast_macro2(f0); \
+ } \
+ } \
+ \
+ *state = temp; \
+ return CV_OK; \
+}
+
+
+static CvStatus CV_STDCALL
+icvRand_64f_C1R( double* arr, int step, CvSize size,
+ uint64* state, const double* param )
+{
+ uint64 temp = *state;
+ step /= sizeof(arr[0]);
+
+ for( ; size.height--; arr += step )
+ {
+ int i, k = 3;
+ const double* p = param;
+
+ for( i = 0; i <= size.width - 4; i += 4 )
+ {
+ double f0, f1;
+ Cv64suf t0, t1;
+
+ temp = ICV_RNG_NEXT(temp);
+ t0.u = ICV_CVT_DBL(temp);
+ temp = ICV_RNG_NEXT(temp);
+ t1.u = ICV_CVT_DBL(temp);
+ f0 = t0.f * p[i + 12] + p[i];
+ f1 = t1.f * p[i + 13] + p[i + 1];
+ arr[i] = f0;
+ arr[i+1] = f1;
+
+ temp = ICV_RNG_NEXT(temp);
+ t0.u = ICV_CVT_DBL(temp);
+ temp = ICV_RNG_NEXT(temp);
+ t1.u = ICV_CVT_DBL(temp);
+ f0 = t0.f * p[i + 14] + p[i + 2];
+ f1 = t1.f * p[i + 15] + p[i + 3];
+ arr[i+2] = f0;
+ arr[i+3] = f1;
+
+ if( !--k )
+ {
+ k = 3;
+ p -= 12;
+ }
+ }
+
+ for( ; i < size.width; i++ )
+ {
+ double f0;
+ Cv64suf t0;
+
+ temp = ICV_RNG_NEXT(temp);
+ t0.u = ICV_CVT_DBL(temp);
+ f0 = t0.f * p[i + 12] + p[i];
+ arr[i] = f0;
+ }
+ }
+
+ *state = temp;
+ return CV_OK;
+}
+
+
+/***************************************************************************************\
+ The code below implements algorithm from the paper:
+
+ G. Marsaglia and W.W. Tsang,
+ The Monty Python method for generating random variables,
+ ACM Transactions on Mathematical Software, Vol. 24, No. 3,
+ Pages 341-350, September, 1998.
+\***************************************************************************************/
+
+static CvStatus CV_STDCALL
+icvRandn_0_1_32f_C1R( float* arr, int len, uint64* state )
+{
+ uint64 temp = *state;
+ int i;
+ temp = ICV_RNG_NEXT(temp);
+
+ for( i = 0; i < len; i++ )
+ {
+ double x, y, v, ax, bx;
+
+ for(;;)
+ {
+ x = ((int)temp)*1.167239e-9;
+ temp = ICV_RNG_NEXT(temp);
+ ax = fabs(x);
+ v = 2.8658 - ax*(2.0213 - 0.3605*ax);
+ y = ((unsigned)temp)*2.328306e-10;
+ temp = ICV_RNG_NEXT(temp);
+
+ if( y < v || ax < 1.17741 )
+ break;
+
+ bx = x;
+ x = bx > 0 ? 0.8857913*(2.506628 - ax) : -0.8857913*(2.506628 - ax);
+
+ if( y > v + 0.0506 )
+ break;
+
+ if( log(y) < .6931472 - .5*bx*bx )
+ {
+ x = bx;
+ break;
+ }
+
+ if( log(1.8857913 - y) < .5718733-.5*x*x )
+ break;
+
+ do
+ {
+ v = ((int)temp)*4.656613e-10;
+ x = -log(fabs(v))*.3989423;
+ temp = ICV_RNG_NEXT(temp);
+ y = -log(((unsigned)temp)*2.328306e-10);
+ temp = ICV_RNG_NEXT(temp);
+ }
+ while( y+y < x*x );
+
+ x = v > 0 ? 2.506628 + x : -2.506628 - x;
+ break;
+ }
+
+ arr[i] = (float)x;
+ }
+ *state = temp;
+ return CV_OK;
+}
+
+
+#define RAND_BUF_SIZE 96
+
+
+#define ICV_IMPL_RANDN( flavor, arrtype, worktype, cast_macro1, cast_macro2 ) \
+static CvStatus CV_STDCALL \
+icvRandn_##flavor##_C1R( arrtype* arr, int step, CvSize size, \
+ uint64* state, const double* param ) \
+{ \
+ float buffer[RAND_BUF_SIZE]; \
+ step /= sizeof(arr[0]); \
+ \
+ for( ; size.height--; arr += step ) \
+ { \
+ int i, j, len = RAND_BUF_SIZE; \
+ \
+ for( i = 0; i < size.width; i += RAND_BUF_SIZE ) \
+ { \
+ int k = 3; \
+ const double* p = param; \
+ \
+ if( i + len > size.width ) \
+ len = size.width - i; \
+ \
+ icvRandn_0_1_32f_C1R( buffer, len, state ); \
+ \
+ for( j = 0; j <= len - 4; j += 4 ) \
+ { \
+ worktype f0, f1; \
+ \
+ f0 = cast_macro1( buffer[j]*p[j+12] + p[j] ); \
+ f1 = cast_macro1( buffer[j+1]*p[j+13] + p[j+1] ); \
+ arr[i+j] = cast_macro2(f0); \
+ arr[i+j+1] = cast_macro2(f1); \
+ \
+ f0 = cast_macro1( buffer[j+2]*p[j+14] + p[j+2] ); \
+ f1 = cast_macro1( buffer[j+3]*p[j+15] + p[j+3] ); \
+ arr[i+j+2] = cast_macro2(f0); \
+ arr[i+j+3] = cast_macro2(f1); \
+ \
+ if( --k == 0 ) \
+ { \
+ k = 3; \
+ p -= 12; \
+ } \
+ } \
+ \
+ for( ; j < len; j++ ) \
+ { \
+ worktype f0 = cast_macro1( buffer[j]*p[j+12] + p[j] ); \
+ arr[i+j] = cast_macro2(f0); \
+ } \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_IMPL_RAND_BITS( 8u, uchar, CV_CAST_8U )
+ICV_IMPL_RAND_BITS( 16u, ushort, CV_CAST_16U )
+ICV_IMPL_RAND_BITS( 16s, short, CV_CAST_16S )
+ICV_IMPL_RAND_BITS( 32s, int, CV_CAST_32S )
+
+ICV_IMPL_RAND( 8u, uchar, int, cvFloor, CV_CAST_8U )
+ICV_IMPL_RAND( 16u, ushort, int, cvFloor, CV_CAST_16U )
+ICV_IMPL_RAND( 16s, short, int, cvFloor, CV_CAST_16S )
+ICV_IMPL_RAND( 32s, int, int, cvFloor, CV_CAST_32S )
+ICV_IMPL_RAND( 32f, float, float, CV_CAST_32F, CV_NOP )
+
+ICV_IMPL_RANDN( 8u, uchar, int, cvRound, CV_CAST_8U )
+ICV_IMPL_RANDN( 16u, ushort, int, cvRound, CV_CAST_16U )
+ICV_IMPL_RANDN( 16s, short, int, cvRound, CV_CAST_16S )
+ICV_IMPL_RANDN( 32s, int, int, cvRound, CV_CAST_32S )
+ICV_IMPL_RANDN( 32f, float, float, CV_CAST_32F, CV_NOP )
+ICV_IMPL_RANDN( 64f, double, double, CV_CAST_64F, CV_NOP )
+
+static void icvInitRandTable( CvFuncTable* fastrng_tab,
+ CvFuncTable* rng_tab,
+ CvFuncTable* normal_tab )
+{
+ fastrng_tab->fn_2d[CV_8U] = (void*)icvRandBits_8u_C1R;
+ fastrng_tab->fn_2d[CV_8S] = 0;
+ fastrng_tab->fn_2d[CV_16U] = (void*)icvRandBits_16u_C1R;
+ fastrng_tab->fn_2d[CV_16S] = (void*)icvRandBits_16s_C1R;
+ fastrng_tab->fn_2d[CV_32S] = (void*)icvRandBits_32s_C1R;
+
+ rng_tab->fn_2d[CV_8U] = (void*)icvRand_8u_C1R;
+ rng_tab->fn_2d[CV_8S] = 0;
+ rng_tab->fn_2d[CV_16U] = (void*)icvRand_16u_C1R;
+ rng_tab->fn_2d[CV_16S] = (void*)icvRand_16s_C1R;
+ rng_tab->fn_2d[CV_32S] = (void*)icvRand_32s_C1R;
+ rng_tab->fn_2d[CV_32F] = (void*)icvRand_32f_C1R;
+ rng_tab->fn_2d[CV_64F] = (void*)icvRand_64f_C1R;
+
+ normal_tab->fn_2d[CV_8U] = (void*)icvRandn_8u_C1R;
+ normal_tab->fn_2d[CV_8S] = 0;
+ normal_tab->fn_2d[CV_16U] = (void*)icvRandn_16u_C1R;
+ normal_tab->fn_2d[CV_16S] = (void*)icvRandn_16s_C1R;
+ normal_tab->fn_2d[CV_32S] = (void*)icvRandn_32s_C1R;
+ normal_tab->fn_2d[CV_32F] = (void*)icvRandn_32f_C1R;
+ normal_tab->fn_2d[CV_64F] = (void*)icvRandn_64f_C1R;
+}
+
+
+CV_IMPL void
+cvRandArr( CvRNG* rng, CvArr* arr, int disttype, CvScalar param1, CvScalar param2 )
+{
+ static CvFuncTable rng_tab[2], fastrng_tab;
+ static int inittab = 0;
+
+ CV_FUNCNAME( "cvRandArr" );
+
+ __BEGIN__;
+
+ int is_nd = 0;
+ CvMat stub, *mat = (CvMat*)arr;
+ int type, depth, channels;
+ double dparam[2][12];
+ int iparam[2][12];
+ void* param = dparam;
+ int i, fast_int_mode = 0;
+ int mat_step = 0;
+ CvSize size;
+ CvFunc2D_1A2P func = 0;
+ CvMatND stub_nd;
+ CvNArrayIterator iterator_state, *iterator = 0;
+
+ if( !inittab )
+ {
+ icvInitRandTable( &fastrng_tab, &rng_tab[CV_RAND_UNI],
+ &rng_tab[CV_RAND_NORMAL] );
+ inittab = 1;
+ }
+
+ if( !rng )
+ CV_ERROR( CV_StsNullPtr, "Null pointer to RNG state" );
+
+ if( CV_IS_MATND(mat) )
+ {
+ iterator = &iterator_state;
+ CV_CALL( cvInitNArrayIterator( 1, &arr, 0, &stub_nd, iterator ));
+ type = CV_MAT_TYPE(iterator->hdr[0]->type);
+ size = iterator->size;
+ is_nd = 1;
+ }
+ else
+ {
+ if( !CV_IS_MAT(mat))
+ {
+ int coi = 0;
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+
+ if( coi != 0 )
+ CV_ERROR( CV_BadCOI, "COI is not supported" );
+ }
+
+ type = CV_MAT_TYPE( mat->type );
+ size = cvGetMatSize( mat );
+ mat_step = mat->step;
+
+ if( mat->height > 1 && CV_IS_MAT_CONT( mat->type ))
+ {
+ size.width *= size.height;
+ mat_step = CV_STUB_STEP;
+ size.height = 1;
+ }
+ }
+
+ depth = CV_MAT_DEPTH( type );
+ channels = CV_MAT_CN( type );
+ size.width *= channels;
+
+ if( disttype == CV_RAND_UNI )
+ {
+ if( depth <= CV_32S )
+ {
+ for( i = 0, fast_int_mode = 1; i < channels; i++ )
+ {
+ int t0 = iparam[0][i] = cvCeil( param1.val[i] );
+ int t1 = iparam[1][i] = cvFloor( param2.val[i] ) - t0;
+ double diff = param1.val[i] - param2.val[i];
+
+ fast_int_mode &= INT_MIN <= diff && diff <= INT_MAX && (t1 & (t1 - 1)) == 0;
+ }
+ }
+
+ if( fast_int_mode )
+ {
+ for( i = 0; i < channels; i++ )
+ iparam[1][i]--;
+
+ for( ; i < 12; i++ )
+ {
+ int t0 = iparam[0][i - channels];
+ int t1 = iparam[1][i - channels];
+
+ iparam[0][i] = t0;
+ iparam[1][i] = t1;
+ }
+
+ CV_GET_FUNC_PTR( func, (CvFunc2D_1A2P)(fastrng_tab.fn_2d[depth]));
+ param = iparam;
+ }
+ else
+ {
+ for( i = 0; i < channels; i++ )
+ {
+ double t0 = param1.val[i];
+ double t1 = param2.val[i];
+
+ dparam[0][i] = t0 - (t1 - t0);
+ dparam[1][i] = t1 - t0;
+ }
+
+ CV_GET_FUNC_PTR( func, (CvFunc2D_1A2P)(rng_tab[0].fn_2d[depth]));
+ }
+ }
+ else if( disttype == CV_RAND_NORMAL )
+ {
+ for( i = 0; i < channels; i++ )
+ {
+ double t0 = param1.val[i];
+ double t1 = param2.val[i];
+
+ dparam[0][i] = t0;
+ dparam[1][i] = t1;
+ }
+
+ CV_GET_FUNC_PTR( func, (CvFunc2D_1A2P)(rng_tab[1].fn_2d[depth]));
+ }
+ else
+ {
+ CV_ERROR( CV_StsBadArg, "Unknown distribution type" );
+ }
+
+ if( !fast_int_mode )
+ {
+ for( i = channels; i < 12; i++ )
+ {
+ double t0 = dparam[0][i - channels];
+ double t1 = dparam[1][i - channels];
+
+ dparam[0][i] = t0;
+ dparam[1][i] = t1;
+ }
+ }
+
+ if( !is_nd )
+ {
+ IPPI_CALL( func( mat->data.ptr, mat_step, size, rng, param ));
+ }
+ else
+ {
+ do
+ {
+ IPPI_CALL( func( iterator->ptr[0], CV_STUB_STEP, size, rng, param ));
+ }
+ while( cvNextNArraySlice( iterator ));
+ }
+
+ __END__;
+}
+
+/* End of file. */
diff --git a/cxcore/src/cxsumpixels.cpp b/cxcore/src/cxsumpixels.cpp
new file mode 100644
index 0000000..a44517a
--- /dev/null
+++ b/cxcore/src/cxsumpixels.cpp
@@ -0,0 +1,1015 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+
+/****************************************************************************************\
+* Find sum of pixels in the ROI *
+\****************************************************************************************/
+
+#define ICV_SUM_COI_CASE( __op__, len, cn ) \
+ for( ; x <= (len) - 4*(cn); x += 4*(cn) ) \
+ s0 += __op__(src[x]) + __op__(src[x+(cn)]) + \
+ __op__(src[x+(cn)*2]) + __op__(src[x+(cn)*3]);\
+ \
+ for( ; x < (len); x += (cn) ) \
+ s0 += __op__(src[x]);
+
+
+#define ICV_SUM_CASE_C1( __op__, len ) \
+ ICV_SUM_COI_CASE( __op__, len, 1 )
+
+
+#define ICV_SUM_CASE_C2( __op__, len ) \
+ for( ; x <= (len) - 8; x += 8 ) \
+ { \
+ s0 += __op__(src[x]) + __op__(src[x+2]) + \
+ __op__(src[x+4]) + __op__(src[x+6]); \
+ s1 += __op__(src[x+1]) + __op__(src[x+3]) + \
+ __op__(src[x+5]) + __op__(src[x+7]); \
+ } \
+ \
+ for( ; x < (len); x += 2 ) \
+ { \
+ s0 += __op__(src[x]); \
+ s1 += __op__(src[x+1]); \
+ }
+
+
+
+#define ICV_SUM_CASE_C3( __op__, len ) \
+ for( ; x <= (len) - 12; x += 12 ) \
+ { \
+ s0 += __op__(src[x]) + __op__(src[x+3]) + \
+ __op__(src[x+6]) + __op__(src[x+9]); \
+ s1 += __op__(src[x+1]) + __op__(src[x+4]) + \
+ __op__(src[x+7]) + __op__(src[x+10]); \
+ s2 += __op__(src[x+2]) + __op__(src[x+5]) + \
+ __op__(src[x+8]) + __op__(src[x+11]); \
+ } \
+ \
+ for( ; x < (len); x += 3 ) \
+ { \
+ s0 += __op__(src[x]); \
+ s1 += __op__(src[x+1]); \
+ s2 += __op__(src[x+2]); \
+ }
+
+
+#define ICV_SUM_CASE_C4( __op__, len ) \
+ for( ; x <= (len) - 16; x += 16 ) \
+ { \
+ s0 += __op__(src[x]) + __op__(src[x+4]) + \
+ __op__(src[x+8]) + __op__(src[x+12]); \
+ s1 += __op__(src[x+1]) + __op__(src[x+5]) + \
+ __op__(src[x+9]) + __op__(src[x+13]); \
+ s2 += __op__(src[x+2]) + __op__(src[x+6]) + \
+ __op__(src[x+10]) + __op__(src[x+14]); \
+ s3 += __op__(src[x+3]) + __op__(src[x+7]) + \
+ __op__(src[x+11]) + __op__(src[x+15]); \
+ } \
+ \
+ for( ; x < (len); x += 4 ) \
+ { \
+ s0 += __op__(src[x]); \
+ s1 += __op__(src[x+1]); \
+ s2 += __op__(src[x+2]); \
+ s3 += __op__(src[x+3]); \
+ }
+
+
+////////////////////////////////////// entry macros //////////////////////////////////////
+
+#define ICV_SUM_ENTRY_COMMON() \
+ step /= sizeof(src[0])
+
+#define ICV_SUM_ENTRY_C1( sumtype ) \
+ sumtype s0 = 0; \
+ ICV_SUM_ENTRY_COMMON()
+
+#define ICV_SUM_ENTRY_C2( sumtype ) \
+ sumtype s0 = 0, s1 = 0; \
+ ICV_SUM_ENTRY_COMMON()
+
+#define ICV_SUM_ENTRY_C3( sumtype ) \
+ sumtype s0 = 0, s1 = 0, s2 = 0; \
+ ICV_SUM_ENTRY_COMMON()
+
+#define ICV_SUM_ENTRY_C4( sumtype ) \
+ sumtype s0 = 0, s1 = 0, s2 = 0, s3 = 0; \
+ ICV_SUM_ENTRY_COMMON()
+
+
+#define ICV_SUM_ENTRY_BLOCK_COMMON( block_size ) \
+ int remaining = block_size; \
+ ICV_SUM_ENTRY_COMMON()
+
+#define ICV_SUM_ENTRY_BLOCK_C1( sumtype, worktype, block_size ) \
+ sumtype sum0 = 0; \
+ worktype s0 = 0; \
+ ICV_SUM_ENTRY_BLOCK_COMMON( block_size )
+
+#define ICV_SUM_ENTRY_BLOCK_C2( sumtype, worktype, block_size ) \
+ sumtype sum0 = 0, sum1 = 0; \
+ worktype s0 = 0, s1 = 0; \
+ ICV_SUM_ENTRY_BLOCK_COMMON( block_size )
+
+#define ICV_SUM_ENTRY_BLOCK_C3( sumtype, worktype, block_size ) \
+ sumtype sum0 = 0, sum1 = 0, sum2 = 0; \
+ worktype s0 = 0, s1 = 0, s2 = 0; \
+ ICV_SUM_ENTRY_BLOCK_COMMON( block_size )
+
+#define ICV_SUM_ENTRY_BLOCK_C4( sumtype, worktype, block_size ) \
+ sumtype sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0; \
+ worktype s0 = 0, s1 = 0, s2 = 0, s3 = 0; \
+ ICV_SUM_ENTRY_BLOCK_COMMON( block_size )
+
+
+/////////////////////////////////////// exit macros //////////////////////////////////////
+
+#define ICV_SUM_EXIT_C1( tmp, sumtype ) \
+ sum[0] = (sumtype)tmp##0
+
+#define ICV_SUM_EXIT_C2( tmp, sumtype ) \
+ sum[0] = (sumtype)tmp##0; \
+ sum[1] = (sumtype)tmp##1;
+
+#define ICV_SUM_EXIT_C3( tmp, sumtype ) \
+ sum[0] = (sumtype)tmp##0; \
+ sum[1] = (sumtype)tmp##1; \
+ sum[2] = (sumtype)tmp##2;
+
+#define ICV_SUM_EXIT_C4( tmp, sumtype ) \
+ sum[0] = (sumtype)tmp##0; \
+ sum[1] = (sumtype)tmp##1; \
+ sum[2] = (sumtype)tmp##2; \
+ sum[3] = (sumtype)tmp##3;
+
+#define ICV_SUM_EXIT_BLOCK_C1( sumtype ) \
+ sum0 += s0; \
+ ICV_SUM_EXIT_C1( sum, sumtype )
+
+#define ICV_SUM_EXIT_BLOCK_C2( sumtype ) \
+ sum0 += s0; sum1 += s1; \
+ ICV_SUM_EXIT_C2( sum, sumtype )
+
+#define ICV_SUM_EXIT_BLOCK_C3( sumtype ) \
+ sum0 += s0; sum1 += s1; \
+ sum2 += s2; \
+ ICV_SUM_EXIT_C3( sum, sumtype )
+
+#define ICV_SUM_EXIT_BLOCK_C4( sumtype ) \
+ sum0 += s0; sum1 += s1; \
+ sum2 += s2; sum3 += s3; \
+ ICV_SUM_EXIT_C4( sum, sumtype )
+
+////////////////////////////////////// update macros /////////////////////////////////////
+
+#define ICV_SUM_UPDATE_COMMON( block_size ) \
+ remaining = block_size
+
+#define ICV_SUM_UPDATE_C1( block_size ) \
+ ICV_SUM_UPDATE_COMMON( block_size ); \
+ sum0 += s0; \
+ s0 = 0
+
+#define ICV_SUM_UPDATE_C2( block_size ) \
+ ICV_SUM_UPDATE_COMMON( block_size ); \
+ sum0 += s0; sum1 += s1; \
+ s0 = s1 = 0
+
+#define ICV_SUM_UPDATE_C3( block_size ) \
+ ICV_SUM_UPDATE_COMMON( block_size ); \
+ sum0 += s0; sum1 += s1; sum2 += s2; \
+ s0 = s1 = s2 = 0
+
+#define ICV_SUM_UPDATE_C4( block_size ) \
+ ICV_SUM_UPDATE_COMMON( block_size ); \
+ sum0 += s0; sum1 += s1; \
+ sum2 += s2; sum3 += s3; \
+ s0 = s1 = s2 = s3 = 0
+
+
+#define ICV_DEF_SUM_NOHINT_BLOCK_FUNC_2D( name, flavor, cn, \
+ __op__, arrtype, sumtype_final, sumtype, worktype, block_size )\
+IPCVAPI_IMPL(CvStatus, icv##name##_##flavor##_C##cn##R,( \
+ const arrtype* src, int step, CvSize size, \
+ sumtype_final* sum ), (src, step, size, sum) ) \
+{ \
+ ICV_SUM_ENTRY_BLOCK_C##cn(sumtype,worktype,(block_size)*(cn)); \
+ size.width *= cn; \
+ \
+ for( ; size.height--; src += step ) \
+ { \
+ int x = 0; \
+ while( x < size.width ) \
+ { \
+ int limit = MIN( remaining, size.width - x ); \
+ remaining -= limit; \
+ limit += x; \
+ ICV_SUM_CASE_C##cn( __op__, limit ); \
+ if( remaining == 0 ) \
+ { \
+ ICV_SUM_UPDATE_C##cn( (block_size)*(cn) ); \
+ } \
+ } \
+ } \
+ \
+ ICV_SUM_EXIT_BLOCK_C##cn( sumtype_final ); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_SUM_NOHINT_FUNC_2D( name, flavor, cn, \
+ __op__, arrtype, sumtype_final, sumtype, worktype, block_size )\
+IPCVAPI_IMPL(CvStatus, icv##name##_##flavor##_C##cn##R,( \
+ const arrtype* src, int step, CvSize size, \
+ sumtype_final* sum ), (src, step, size, sum) ) \
+{ \
+ ICV_SUM_ENTRY_C##cn( sumtype ); \
+ size.width *= cn; \
+ \
+ for( ; size.height--; src += step ) \
+ { \
+ int x = 0; \
+ ICV_SUM_CASE_C##cn( __op__, size.width ); \
+ } \
+ \
+ ICV_SUM_EXIT_C##cn( s, sumtype_final ); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_SUM_HINT_FUNC_2D( name, flavor, cn, \
+ __op__, arrtype, sumtype_final, sumtype, worktype, block_size )\
+IPCVAPI_IMPL(CvStatus, icv##name##_##flavor##_C##cn##R,( \
+ const arrtype* src, int step, CvSize size, \
+ sumtype_final* sum, CvHintAlgorithm /*hint*/ ), \
+ (src, step, size, sum, cvAlgHintAccurate) ) \
+{ \
+ ICV_SUM_ENTRY_C##cn( sumtype ); \
+ size.width *= cn; \
+ \
+ for( ; size.height--; src += step ) \
+ { \
+ int x = 0; \
+ ICV_SUM_CASE_C##cn( __op__, size.width ); \
+ } \
+ \
+ ICV_SUM_EXIT_C##cn( s, sumtype_final ); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_SUM_NOHINT_BLOCK_FUNC_2D_COI( name, flavor, \
+ __op__, arrtype, sumtype_final, sumtype, worktype, block_size )\
+static CvStatus CV_STDCALL icv##name##_##flavor##_CnCR( \
+ const arrtype* src, int step, CvSize size, int cn, \
+ int coi, sumtype_final* sum ) \
+{ \
+ ICV_SUM_ENTRY_BLOCK_C1(sumtype,worktype,(block_size)*(cn)); \
+ size.width *= cn; \
+ src += coi - 1; \
+ \
+ for( ; size.height--; src += step ) \
+ { \
+ int x = 0; \
+ while( x < size.width ) \
+ { \
+ int limit = MIN( remaining, size.width - x ); \
+ remaining -= limit; \
+ limit += x; \
+ ICV_SUM_COI_CASE( __op__, limit, cn ); \
+ if( remaining == 0 ) \
+ { \
+ ICV_SUM_UPDATE_C1( (block_size)*(cn) ); \
+ } \
+ } \
+ } \
+ \
+ ICV_SUM_EXIT_BLOCK_C1( sumtype_final ); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_SUM_NOHINT_FUNC_2D_COI( name, flavor, \
+ __op__, arrtype, sumtype_final, sumtype, worktype, block_size )\
+static CvStatus CV_STDCALL icv##name##_##flavor##_CnCR( \
+ const arrtype* src, int step, CvSize size, int cn, \
+ int coi, sumtype_final* sum ) \
+{ \
+ ICV_SUM_ENTRY_C1( sumtype ); \
+ size.width *= cn; \
+ src += coi - 1; \
+ \
+ for( ; size.height--; src += step ) \
+ { \
+ int x = 0; \
+ ICV_SUM_COI_CASE( __op__, size.width, cn ); \
+ } \
+ \
+ ICV_SUM_EXIT_C1( s, sumtype_final ); \
+ return CV_OK; \
+}
+
+
+#define ICV_DEF_SUM_ALL( name, flavor, __op__, arrtype, sumtype_final, sumtype, \
+ worktype, hintp_type, nohint_type, block_size ) \
+ ICV_DEF_SUM_##hintp_type##_FUNC_2D( name, flavor, 1, __op__, arrtype, \
+ sumtype_final, sumtype, worktype, block_size ) \
+ ICV_DEF_SUM_##hintp_type##_FUNC_2D( name, flavor, 2, __op__, arrtype, \
+ sumtype_final, sumtype, worktype, block_size ) \
+ ICV_DEF_SUM_##hintp_type##_FUNC_2D( name, flavor, 3, __op__, arrtype, \
+ sumtype_final, sumtype, worktype, block_size ) \
+ ICV_DEF_SUM_##hintp_type##_FUNC_2D( name, flavor, 4, __op__, arrtype, \
+ sumtype_final, sumtype, worktype, block_size ) \
+ ICV_DEF_SUM_##nohint_type##_FUNC_2D_COI( name, flavor, __op__, arrtype, \
+ sumtype_final, sumtype, worktype, block_size )
+
+ICV_DEF_SUM_ALL( Sum, 8u, CV_NOP, uchar, double, int64, unsigned,
+ NOHINT_BLOCK, NOHINT_BLOCK, 1 << 24 )
+ICV_DEF_SUM_ALL( Sum, 16u, CV_NOP, ushort, double, int64, unsigned,
+ NOHINT_BLOCK, NOHINT_BLOCK, 1 << 16 )
+ICV_DEF_SUM_ALL( Sum, 16s, CV_NOP, short, double, int64, int,
+ NOHINT_BLOCK, NOHINT_BLOCK, 1 << 16 )
+ICV_DEF_SUM_ALL( Sum, 32s, CV_NOP, int, double, double, double, NOHINT, NOHINT, 0 )
+ICV_DEF_SUM_ALL( Sum, 32f, CV_NOP, float, double, double, double, HINT, NOHINT, 0 )
+ICV_DEF_SUM_ALL( Sum, 64f, CV_NOP, double, double, double, double, NOHINT, NOHINT, 0 )
+
+#define icvSum_8s_C1R 0
+#define icvSum_8s_C2R 0
+#define icvSum_8s_C3R 0
+#define icvSum_8s_C4R 0
+#define icvSum_8s_CnCR 0
+
+CV_DEF_INIT_BIG_FUNC_TAB_2D( Sum, R )
+CV_DEF_INIT_FUNC_TAB_2D( Sum, CnCR )
+
+CV_IMPL CvScalar
+cvSum( const CvArr* arr )
+{
+ static CvBigFuncTable sum_tab;
+ static CvFuncTable sumcoi_tab;
+ static int inittab = 0;
+
+ CvScalar sum = {{0,0,0,0}};
+
+ CV_FUNCNAME("cvSum");
+
+ __BEGIN__;
+
+ int type, coi = 0;
+ int mat_step;
+ CvSize size;
+ CvMat stub, *mat = (CvMat*)arr;
+
+ if( !inittab )
+ {
+ icvInitSumRTable( &sum_tab );
+ icvInitSumCnCRTable( &sumcoi_tab );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(mat) )
+ {
+ if( CV_IS_MATND(mat) )
+ {
+ void* matnd = (void*)mat;
+ CvMatND nstub;
+ CvNArrayIterator iterator;
+ int pass_hint;
+
+ CV_CALL( cvInitNArrayIterator( 1, &matnd, 0, &nstub, &iterator ));
+
+ type = CV_MAT_TYPE(iterator.hdr[0]->type);
+ if( CV_MAT_CN(type) > 4 )
+ CV_ERROR( CV_StsOutOfRange, "The input array must have at most 4 channels" );
+
+ pass_hint = CV_MAT_DEPTH(type) == CV_32F;
+
+ if( !pass_hint )
+ {
+ CvFunc2D_1A1P func = (CvFunc2D_1A1P)(sum_tab.fn_2d[type]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ do
+ {
+ CvScalar temp = {{0,0,0,0}};
+ IPPI_CALL( func( iterator.ptr[0], CV_STUB_STEP,
+ iterator.size, temp.val ));
+ sum.val[0] += temp.val[0];
+ sum.val[1] += temp.val[1];
+ sum.val[2] += temp.val[2];
+ sum.val[3] += temp.val[3];
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ else
+ {
+ CvFunc2D_1A1P1I func = (CvFunc2D_1A1P1I)(sum_tab.fn_2d[type]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ do
+ {
+ CvScalar temp = {{0,0,0,0}};
+ IPPI_CALL( func( iterator.ptr[0], CV_STUB_STEP,
+ iterator.size, temp.val, cvAlgHintAccurate ));
+ sum.val[0] += temp.val[0];
+ sum.val[1] += temp.val[1];
+ sum.val[2] += temp.val[2];
+ sum.val[3] += temp.val[3];
+ }
+ while( cvNextNArraySlice( &iterator ));
+ }
+ EXIT;
+ }
+ else
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+ }
+
+ type = CV_MAT_TYPE(mat->type);
+ size = cvGetMatSize( mat );
+
+ mat_step = mat->step;
+
+ if( CV_IS_MAT_CONT( mat->type ))
+ {
+ size.width *= size.height;
+
+ if( size.width <= CV_MAX_INLINE_MAT_OP_SIZE )
+ {
+ if( type == CV_32FC1 )
+ {
+ float* data = mat->data.fl;
+
+ do
+ {
+ sum.val[0] += data[size.width - 1];
+ }
+ while( --size.width );
+
+ EXIT;
+ }
+
+ if( type == CV_64FC1 )
+ {
+ double* data = mat->data.db;
+
+ do
+ {
+ sum.val[0] += data[size.width - 1];
+ }
+ while( --size.width );
+
+ EXIT;
+ }
+ }
+ size.height = 1;
+ mat_step = CV_STUB_STEP;
+ }
+
+ if( CV_MAT_CN(type) == 1 || coi == 0 )
+ {
+ int pass_hint = CV_MAT_DEPTH(type) == CV_32F;
+
+ if( CV_MAT_CN(type) > 4 )
+ CV_ERROR( CV_StsOutOfRange, "The input array must have at most 4 channels" );
+
+ if( !pass_hint )
+ {
+ CvFunc2D_1A1P func = (CvFunc2D_1A1P)(sum_tab.fn_2d[type]);
+
+ if( !func )
+ CV_ERROR( CV_StsBadArg, cvUnsupportedFormat );
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, size, sum.val ));
+ }
+ else
+ {
+ CvFunc2D_1A1P1I func = (CvFunc2D_1A1P1I)(sum_tab.fn_2d[type]);
+
+ if( !func )
+ CV_ERROR( CV_StsBadArg, cvUnsupportedFormat );
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, size, sum.val, cvAlgHintAccurate ));
+ }
+ }
+ else
+ {
+ CvFunc2DnC_1A1P func = (CvFunc2DnC_1A1P)(sumcoi_tab.fn_2d[CV_MAT_DEPTH(type)]);
+
+ if( !func )
+ CV_ERROR( CV_StsBadArg, cvUnsupportedFormat );
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, size,
+ CV_MAT_CN(type), coi, sum.val ));
+ }
+
+ __END__;
+
+ return sum;
+}
+
+
+#define ICV_DEF_NONZERO_ALL( flavor, __op__, arrtype ) \
+ ICV_DEF_SUM_NOHINT_FUNC_2D( CountNonZero, flavor, 1, __op__, \
+ arrtype, int, int, int, 0 ) \
+ ICV_DEF_SUM_NOHINT_FUNC_2D_COI( CountNonZero, flavor, __op__, \
+ arrtype, int, int, int, 0 )
+
+#undef CV_NONZERO_DBL
+#define CV_NONZERO_DBL(x) (((x) & CV_BIG_INT(0x7fffffffffffffff)) != 0)
+
+ICV_DEF_NONZERO_ALL( 8u, CV_NONZERO, uchar )
+ICV_DEF_NONZERO_ALL( 16s, CV_NONZERO, ushort )
+ICV_DEF_NONZERO_ALL( 32s, CV_NONZERO, int )
+ICV_DEF_NONZERO_ALL( 32f, CV_NONZERO_FLT, int )
+ICV_DEF_NONZERO_ALL( 64f, CV_NONZERO_DBL, int64 )
+
+#define icvCountNonZero_8s_C1R icvCountNonZero_8u_C1R
+#define icvCountNonZero_8s_CnCR icvCountNonZero_8u_CnCR
+#define icvCountNonZero_16u_C1R icvCountNonZero_16s_C1R
+#define icvCountNonZero_16u_CnCR icvCountNonZero_16s_CnCR
+
+CV_DEF_INIT_FUNC_TAB_2D( CountNonZero, C1R )
+CV_DEF_INIT_FUNC_TAB_2D( CountNonZero, CnCR )
+
+CV_IMPL int
+cvCountNonZero( const CvArr* arr )
+{
+ static CvFuncTable nz_tab;
+ static CvFuncTable nzcoi_tab;
+ static int inittab = 0;
+
+ int count = 0;
+
+ CV_FUNCNAME("cvCountNonZero");
+
+ __BEGIN__;
+
+ int type, coi = 0;
+ int mat_step;
+ CvSize size;
+ CvMat stub, *mat = (CvMat*)arr;
+
+ if( !inittab )
+ {
+ icvInitCountNonZeroC1RTable( &nz_tab );
+ icvInitCountNonZeroCnCRTable( &nzcoi_tab );
+ inittab = 1;
+ }
+
+ if( !CV_IS_MAT(mat) )
+ {
+ if( CV_IS_MATND(mat) )
+ {
+ void* matnd = (void*)arr;
+ CvMatND nstub;
+ CvNArrayIterator iterator;
+ CvFunc2D_1A1P func;
+
+ CV_CALL( cvInitNArrayIterator( 1, &matnd, 0, &nstub, &iterator ));
+
+ type = CV_MAT_TYPE(iterator.hdr[0]->type);
+
+ if( CV_MAT_CN(type) != 1 )
+ CV_ERROR( CV_BadNumChannels,
+ "Only single-channel array are supported here" );
+
+ func = (CvFunc2D_1A1P)(nz_tab.fn_2d[CV_MAT_DEPTH(type)]);
+ if( !func )
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+
+ do
+ {
+ int temp;
+ IPPI_CALL( func( iterator.ptr[0], CV_STUB_STEP,
+ iterator.size, &temp ));
+ count += temp;
+ }
+ while( cvNextNArraySlice( &iterator ));
+ EXIT;
+ }
+ else
+ CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
+ }
+
+ type = CV_MAT_TYPE(mat->type);
+ size = cvGetMatSize( mat );
+
+ mat_step = mat->step;
+
+ if( CV_IS_MAT_CONT( mat->type ))
+ {
+ size.width *= size.height;
+ size.height = 1;
+ mat_step = CV_STUB_STEP;
+ }
+
+ if( CV_MAT_CN(type) == 1 || coi == 0 )
+ {
+ CvFunc2D_1A1P func = (CvFunc2D_1A1P)(nz_tab.fn_2d[CV_MAT_DEPTH(type)]);
+
+ if( CV_MAT_CN(type) != 1 )
+ CV_ERROR( CV_BadNumChannels,
+ "The function can handle only a single channel at a time (use COI)");
+
+ if( !func )
+ CV_ERROR( CV_StsBadArg, cvUnsupportedFormat );
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, size, &count ));
+ }
+ else
+ {
+ CvFunc2DnC_1A1P func = (CvFunc2DnC_1A1P)(nzcoi_tab.fn_2d[CV_MAT_DEPTH(type)]);
+
+ if( !func )
+ CV_ERROR( CV_StsBadArg, cvUnsupportedFormat );
+
+ IPPI_CALL( func( mat->data.ptr, mat_step, size, CV_MAT_CN(type), coi, &count ));
+ }
+
+ __END__;
+
+ return count;
+}
+
+
+/****************************************************************************************\
+* Reduce Matrix to Vector *
+\****************************************************************************************/
+
+#define ICV_ACC_ROWS_FUNC( name, flavor, arrtype, acctype, \
+ __op__, load_macro ) \
+static CvStatus CV_STDCALL \
+icv##name##Rows_##flavor##_C1R( const arrtype* src, int srcstep,\
+ acctype* dst, CvSize size ) \
+{ \
+ int i, width = size.width; \
+ srcstep /= sizeof(src[0]); \
+ \
+ for( i = 0; i < width; i++ ) \
+ dst[i] = load_macro(src[i]); \
+ \
+ for( ; --size.height; ) \
+ { \
+ src += srcstep; \
+ for( i = 0; i <= width - 4; i += 4 ) \
+ { \
+ acctype s0 = load_macro(src[i]); \
+ acctype s1 = load_macro(src[i+1]); \
+ acctype a0 = dst[i], a1 = dst[i+1]; \
+ a0 = (acctype)__op__(a0,s0); a1 = (acctype)__op__(a1,s1); \
+ dst[i] = a0; dst[i+1] = a1; \
+ \
+ s0 = load_macro(src[i+2]); \
+ s1 = load_macro(src[i+3]); \
+ a0 = dst[i+2]; a1 = dst[i+3]; \
+ a0 = (acctype)__op__(a0,s0); a1 = (acctype)__op__(a1,s1); \
+ dst[i+2] = a0; dst[i+3] = a1; \
+ } \
+ \
+ for( ; i < width; i++ ) \
+ { \
+ acctype s0 = load_macro(src[i]), a0 = dst[i]; \
+ a0 = (acctype)__op__(a0,s0); \
+ dst[i] = a0; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_ACC_COLS_FUNC_C1( name, flavor, arrtype, worktype, acctype, __op__ )\
+static CvStatus CV_STDCALL \
+icv##name##Cols_##flavor##_C1R( const arrtype* src, int srcstep, \
+ acctype* dst, int dststep, CvSize size )\
+{ \
+ int i, width = size.width; \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ if( width == 1 ) \
+ dst[0] = (acctype)src[0]; \
+ else \
+ { \
+ worktype a0 = src[0], a1 = src[1]; \
+ for( i = 2; i <= width - 4; i += 4 ) \
+ { \
+ worktype s0 = src[i], s1 = src[i+1]; \
+ a0 = __op__(a0, s0); \
+ a1 = __op__(a1, s1); \
+ s0 = src[i+2]; s1 = src[i+3]; \
+ a0 = __op__(a0, s0); \
+ a1 = __op__(a1, s1); \
+ } \
+ \
+ for( ; i < width; i++ ) \
+ { \
+ worktype s0 = src[i]; \
+ a0 = __op__(a0, s0); \
+ } \
+ a0 = __op__(a0, a1); \
+ dst[0] = (acctype)a0; \
+ } \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_ACC_COLS_FUNC_C3( name, flavor, arrtype, worktype, acctype, __op__ ) \
+static CvStatus CV_STDCALL \
+icv##name##Cols_##flavor##_C3R( const arrtype* src, int srcstep, \
+ acctype* dst, int dststep, CvSize size )\
+{ \
+ int i, width = size.width*3; \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ worktype a0 = src[0], a1 = src[1], a2 = src[2]; \
+ for( i = 3; i < width; i += 3 ) \
+ { \
+ worktype s0 = src[i], s1 = src[i+1], s2 = src[i+2]; \
+ a0 = __op__(a0, s0); \
+ a1 = __op__(a1, s1); \
+ a2 = __op__(a2, s2); \
+ } \
+ \
+ dst[0] = (acctype)a0; \
+ dst[1] = (acctype)a1; \
+ dst[2] = (acctype)a2; \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+#define ICV_ACC_COLS_FUNC_C4( name, flavor, arrtype, worktype, acctype, __op__ ) \
+static CvStatus CV_STDCALL \
+icv##name##Cols_##flavor##_C4R( const arrtype* src, int srcstep, \
+ acctype* dst, int dststep, CvSize size )\
+{ \
+ int i, width = size.width*4; \
+ srcstep /= sizeof(src[0]); \
+ dststep /= sizeof(dst[0]); \
+ \
+ for( ; size.height--; src += srcstep, dst += dststep ) \
+ { \
+ worktype a0 = src[0], a1 = src[1], a2 = src[2], a3 = src[3]; \
+ for( i = 4; i < width; i += 4 ) \
+ { \
+ worktype s0 = src[i], s1 = src[i+1]; \
+ a0 = __op__(a0, s0); \
+ a1 = __op__(a1, s1); \
+ s0 = src[i+2]; s1 = src[i+3]; \
+ a2 = __op__(a2, s0); \
+ a3 = __op__(a3, s1); \
+ } \
+ \
+ dst[0] = (acctype)a0; \
+ dst[1] = (acctype)a1; \
+ dst[2] = (acctype)a2; \
+ dst[3] = (acctype)a3; \
+ } \
+ \
+ return CV_OK; \
+}
+
+
+ICV_ACC_ROWS_FUNC( Sum, 8u32s, uchar, int, CV_ADD, CV_NOP )
+ICV_ACC_ROWS_FUNC( Sum, 8u32f, uchar, float, CV_ADD, CV_8TO32F )
+ICV_ACC_ROWS_FUNC( Sum, 16u32f, ushort, float, CV_ADD, CV_NOP )
+ICV_ACC_ROWS_FUNC( Sum, 16u64f, ushort, double, CV_ADD, CV_NOP )
+ICV_ACC_ROWS_FUNC( Sum, 16s32f, short, float, CV_ADD, CV_NOP )
+ICV_ACC_ROWS_FUNC( Sum, 16s64f, short, double, CV_ADD, CV_NOP )
+ICV_ACC_ROWS_FUNC( Sum, 32f, float, float, CV_ADD, CV_NOP )
+ICV_ACC_ROWS_FUNC( Sum, 32f64f, float, double, CV_ADD, CV_NOP )
+ICV_ACC_ROWS_FUNC( Sum, 64f, double, double, CV_ADD, CV_NOP )
+
+ICV_ACC_ROWS_FUNC( Max, 8u, uchar, uchar, CV_MAX_8U, CV_NOP )
+ICV_ACC_ROWS_FUNC( Max, 32f, float, float, MAX, CV_NOP )
+ICV_ACC_ROWS_FUNC( Max, 64f, double, double, MAX, CV_NOP )
+
+ICV_ACC_ROWS_FUNC( Min, 8u, uchar, uchar, CV_MIN_8U, CV_NOP )
+ICV_ACC_ROWS_FUNC( Min, 32f, float, float, MIN, CV_NOP )
+ICV_ACC_ROWS_FUNC( Min, 64f, double, double, MIN, CV_NOP )
+
+ICV_ACC_COLS_FUNC_C1( Sum, 8u32s, uchar, int, int, CV_ADD )
+ICV_ACC_COLS_FUNC_C1( Sum, 8u32f, uchar, int, float, CV_ADD )
+ICV_ACC_COLS_FUNC_C1( Sum, 16u32f, ushort, float, float, CV_ADD )
+ICV_ACC_COLS_FUNC_C1( Sum, 16u64f, ushort, double, double, CV_ADD )
+ICV_ACC_COLS_FUNC_C1( Sum, 16s32f, short, float, float, CV_ADD )
+ICV_ACC_COLS_FUNC_C1( Sum, 16s64f, short, double, double, CV_ADD )
+
+ICV_ACC_COLS_FUNC_C1( Sum, 32f, float, float, float, CV_ADD )
+ICV_ACC_COLS_FUNC_C1( Sum, 32f64f, float, double, double, CV_ADD )
+ICV_ACC_COLS_FUNC_C1( Sum, 64f, double, double, double, CV_ADD )
+ICV_ACC_COLS_FUNC_C3( Sum, 8u32s, uchar, int, int, CV_ADD )
+ICV_ACC_COLS_FUNC_C3( Sum, 8u32f, uchar, int, float, CV_ADD )
+ICV_ACC_COLS_FUNC_C3( Sum, 32f, float, float, float, CV_ADD )
+ICV_ACC_COLS_FUNC_C3( Sum, 64f, double, double, double, CV_ADD )
+ICV_ACC_COLS_FUNC_C4( Sum, 8u32s, uchar, int, int, CV_ADD )
+ICV_ACC_COLS_FUNC_C4( Sum, 8u32f, uchar, int, float, CV_ADD )
+ICV_ACC_COLS_FUNC_C4( Sum, 32f, float, float, float, CV_ADD )
+ICV_ACC_COLS_FUNC_C4( Sum, 64f, double, double, double, CV_ADD )
+
+ICV_ACC_COLS_FUNC_C1( Max, 8u, uchar, int, uchar, CV_MAX_8U )
+ICV_ACC_COLS_FUNC_C1( Max, 32f, float, float, float, MAX )
+ICV_ACC_COLS_FUNC_C1( Max, 64f, double, double, double, MAX )
+
+ICV_ACC_COLS_FUNC_C1( Min, 8u, uchar, int, uchar, CV_MIN_8U )
+ICV_ACC_COLS_FUNC_C1( Min, 32f, float, float, float, MIN )
+ICV_ACC_COLS_FUNC_C1( Min, 64f, double, double, double, MIN )
+
+typedef CvStatus (CV_STDCALL * CvReduceToRowFunc)
+ ( const void* src, int srcstep, void* dst, CvSize size );
+
+typedef CvStatus (CV_STDCALL * CvReduceToColFunc)
+ ( const void* src, int srcstep, void* dst, int dststep, CvSize size );
+
+
+CV_IMPL void
+cvReduce( const CvArr* srcarr, CvArr* dstarr, int dim, int op )
+{
+ CvMat* temp = 0;
+
+ CV_FUNCNAME( "cvReduce" );
+
+ __BEGIN__;
+
+ CvMat sstub, *src = (CvMat*)srcarr;
+ CvMat dstub, *dst = (CvMat*)dstarr, *dst0;
+ int sdepth, ddepth, cn, op0 = op;
+ CvSize size;
+
+ if( !CV_IS_MAT(src) )
+ CV_CALL( src = cvGetMat( src, &sstub ));
+
+ if( !CV_IS_MAT(dst) )
+ CV_CALL( dst = cvGetMat( dst, &dstub ));
+
+ if( !CV_ARE_CNS_EQ(src, dst) )
+ CV_ERROR( CV_StsUnmatchedFormats, "Input and output arrays must have the same number of channels" );
+
+ sdepth = CV_MAT_DEPTH(src->type);
+ ddepth = CV_MAT_DEPTH(dst->type);
+ cn = CV_MAT_CN(src->type);
+ dst0 = dst;
+
+ size = cvGetMatSize(src);
+
+ if( dim < 0 )
+ dim = src->rows > dst->rows ? 0 : src->cols > dst->cols ? 1 : dst->cols == 1;
+
+ if( dim > 1 )
+ CV_ERROR( CV_StsOutOfRange, "The reduced dimensionality index is out of range" );
+
+ if( (dim == 0 && (dst->cols != src->cols || dst->rows != 1)) ||
+ (dim == 1 && (dst->rows != src->rows || dst->cols != 1)) )
+ CV_ERROR( CV_StsBadSize, "The output array size is incorrect" );
+
+ if( op == CV_REDUCE_AVG )
+ {
+ int ttype = sdepth == CV_8U ? CV_MAKETYPE(CV_32S,cn) : dst->type;
+ if( ttype != dst->type )
+ CV_CALL( dst = temp = cvCreateMat( dst->rows, dst->cols, ttype ));
+ op = CV_REDUCE_SUM;
+ ddepth = CV_MAT_DEPTH(ttype);
+ }
+
+ if( op != CV_REDUCE_SUM && op != CV_REDUCE_MAX && op != CV_REDUCE_MIN )
+ CV_ERROR( CV_StsBadArg, "Unknown reduce operation index, must be one of CV_REDUCE_*" );
+
+ if( dim == 0 )
+ {
+ CvReduceToRowFunc rfunc =
+ op == CV_REDUCE_SUM ?
+ (sdepth == CV_8U && ddepth == CV_32S ? (CvReduceToRowFunc)icvSumRows_8u32s_C1R :
+ sdepth == CV_8U && ddepth == CV_32F ? (CvReduceToRowFunc)icvSumRows_8u32f_C1R :
+ sdepth == CV_16U && ddepth == CV_32F ? (CvReduceToRowFunc)icvSumRows_16u32f_C1R :
+ sdepth == CV_16U && ddepth == CV_64F ? (CvReduceToRowFunc)icvSumRows_16u64f_C1R :
+ sdepth == CV_16S && ddepth == CV_32F ? (CvReduceToRowFunc)icvSumRows_16s32f_C1R :
+ sdepth == CV_16S && ddepth == CV_64F ? (CvReduceToRowFunc)icvSumRows_16s64f_C1R :
+ sdepth == CV_32F && ddepth == CV_32F ? (CvReduceToRowFunc)icvSumRows_32f_C1R :
+ sdepth == CV_32F && ddepth == CV_64F ? (CvReduceToRowFunc)icvSumRows_32f64f_C1R :
+ sdepth == CV_64F && ddepth == CV_64F ? (CvReduceToRowFunc)icvSumRows_64f_C1R : 0) :
+ op == CV_REDUCE_MAX ?
+ (sdepth == CV_8U && ddepth == CV_8U ? (CvReduceToRowFunc)icvMaxRows_8u_C1R :
+ sdepth == CV_32F && ddepth == CV_32F ? (CvReduceToRowFunc)icvMaxRows_32f_C1R :
+ sdepth == CV_64F && ddepth == CV_64F ? (CvReduceToRowFunc)icvMaxRows_64f_C1R : 0) :
+
+ (sdepth == CV_8U && ddepth == CV_8U ? (CvReduceToRowFunc)icvMinRows_8u_C1R :
+ sdepth == CV_32F && ddepth == CV_32F ? (CvReduceToRowFunc)icvMinRows_32f_C1R :
+ sdepth == CV_64F && ddepth == CV_64F ? (CvReduceToRowFunc)icvMinRows_64f_C1R : 0);
+
+ if( !rfunc )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Unsupported combination of input and output array formats" );
+
+ size.width *= cn;
+ IPPI_CALL( rfunc( src->data.ptr, src->step ? src->step : CV_STUB_STEP,
+ dst->data.ptr, size ));
+ }
+ else
+ {
+ CvReduceToColFunc cfunc =
+ op == CV_REDUCE_SUM ?
+ (sdepth == CV_8U && ddepth == CV_32S ?
+ (CvReduceToColFunc)(cn == 1 ? icvSumCols_8u32s_C1R :
+ cn == 3 ? icvSumCols_8u32s_C3R :
+ cn == 4 ? icvSumCols_8u32s_C4R : 0) :
+ sdepth == CV_8U && ddepth == CV_32F ?
+ (CvReduceToColFunc)(cn == 1 ? icvSumCols_8u32f_C1R :
+ cn == 3 ? icvSumCols_8u32f_C3R :
+ cn == 4 ? icvSumCols_8u32f_C4R : 0) :
+ sdepth == CV_16U && ddepth == CV_32F ?
+ (CvReduceToColFunc)(cn == 1 ? icvSumCols_16u32f_C1R : 0) :
+ sdepth == CV_16U && ddepth == CV_64F ?
+ (CvReduceToColFunc)(cn == 1 ? icvSumCols_16u64f_C1R : 0) :
+ sdepth == CV_16S && ddepth == CV_32F ?
+ (CvReduceToColFunc)(cn == 1 ? icvSumCols_16s32f_C1R : 0) :
+ sdepth == CV_16S && ddepth == CV_64F ?
+ (CvReduceToColFunc)(cn == 1 ? icvSumCols_16s64f_C1R : 0) :
+ sdepth == CV_32F && ddepth == CV_32F ?
+ (CvReduceToColFunc)(cn == 1 ? icvSumCols_32f_C1R :
+ cn == 3 ? icvSumCols_32f_C3R :
+ cn == 4 ? icvSumCols_32f_C4R : 0) :
+ sdepth == CV_32F && ddepth == CV_64F ?
+ (CvReduceToColFunc)(cn == 1 ? icvSumCols_32f64f_C1R : 0) :
+ sdepth == CV_64F && ddepth == CV_64F ?
+ (CvReduceToColFunc)(cn == 1 ? icvSumCols_64f_C1R :
+ cn == 3 ? icvSumCols_64f_C3R :
+ cn == 4 ? icvSumCols_64f_C4R : 0) : 0) :
+ op == CV_REDUCE_MAX && cn == 1 ?
+ (sdepth == CV_8U && ddepth == CV_8U ? (CvReduceToColFunc)icvMaxCols_8u_C1R :
+ sdepth == CV_32F && ddepth == CV_32F ? (CvReduceToColFunc)icvMaxCols_32f_C1R :
+ sdepth == CV_64F && ddepth == CV_64F ? (CvReduceToColFunc)icvMaxCols_64f_C1R : 0) :
+ op == CV_REDUCE_MIN && cn == 1 ?
+ (sdepth == CV_8U && ddepth == CV_8U ? (CvReduceToColFunc)icvMinCols_8u_C1R :
+ sdepth == CV_32F && ddepth == CV_32F ? (CvReduceToColFunc)icvMinCols_32f_C1R :
+ sdepth == CV_64F && ddepth == CV_64F ? (CvReduceToColFunc)icvMinCols_64f_C1R : 0) : 0;
+
+ if( !cfunc )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Unsupported combination of input and output array formats" );
+
+ IPPI_CALL( cfunc( src->data.ptr, src->step ? src->step : CV_STUB_STEP,
+ dst->data.ptr, dst->step ? dst->step : CV_STUB_STEP, size ));
+ }
+
+ if( op0 == CV_REDUCE_AVG )
+ cvScale( dst, dst0, 1./(dim == 0 ? src->rows : src->cols) );
+
+ __END__;
+
+ if( temp )
+ cvReleaseMat( &temp );
+}
+
+/* End of file. */
diff --git a/cxcore/src/cxsvd.cpp b/cxcore/src/cxsvd.cpp
new file mode 100644
index 0000000..ab81752
--- /dev/null
+++ b/cxcore/src/cxsvd.cpp
@@ -0,0 +1,1622 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+#include <float.h>
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define icvGivens_64f( n, x, y, c, s ) \
+{ \
+ int _i; \
+ double* _x = (x); \
+ double* _y = (y); \
+ \
+ for( _i = 0; _i < n; _i++ ) \
+ { \
+ double t0 = _x[_i]; \
+ double t1 = _y[_i]; \
+ _x[_i] = t0*c + t1*s; \
+ _y[_i] = -t0*s + t1*c; \
+ } \
+}
+
+
+/* y[0:m,0:n] += diag(a[0:1,0:m]) * x[0:m,0:n] */
+static void
+icvMatrAXPY_64f( int m, int n, const double* x, int dx,
+ const double* a, double* y, int dy )
+{
+ int i, j;
+
+ for( i = 0; i < m; i++, x += dx, y += dy )
+ {
+ double s = a[i];
+
+ for( j = 0; j <= n - 4; j += 4 )
+ {
+ double t0 = y[j] + s*x[j];
+ double t1 = y[j+1] + s*x[j+1];
+ y[j] = t0;
+ y[j+1] = t1;
+ t0 = y[j+2] + s*x[j+2];
+ t1 = y[j+3] + s*x[j+3];
+ y[j+2] = t0;
+ y[j+3] = t1;
+ }
+
+ for( ; j < n; j++ ) y[j] += s*x[j];
+ }
+}
+
+
+/* y[1:m,-1] = h*y[1:m,0:n]*x[0:1,0:n]'*x[-1] (this is used for U&V reconstruction)
+ y[1:m,0:n] += h*y[1:m,0:n]*x[0:1,0:n]'*x[0:1,0:n] */
+static void
+icvMatrAXPY3_64f( int m, int n, const double* x, int l, double* y, double h )
+{
+ int i, j;
+
+ for( i = 1; i < m; i++ )
+ {
+ double s = 0;
+
+ y += l;
+
+ for( j = 0; j <= n - 4; j += 4 )
+ s += x[j]*y[j] + x[j+1]*y[j+1] + x[j+2]*y[j+2] + x[j+3]*y[j+3];
+
+ for( ; j < n; j++ ) s += x[j]*y[j];
+
+ s *= h;
+ y[-1] = s*x[-1];
+
+ for( j = 0; j <= n - 4; j += 4 )
+ {
+ double t0 = y[j] + s*x[j];
+ double t1 = y[j+1] + s*x[j+1];
+ y[j] = t0;
+ y[j+1] = t1;
+ t0 = y[j+2] + s*x[j+2];
+ t1 = y[j+3] + s*x[j+3];
+ y[j+2] = t0;
+ y[j+3] = t1;
+ }
+
+ for( ; j < n; j++ ) y[j] += s*x[j];
+ }
+}
+
+
+#define icvGivens_32f( n, x, y, c, s ) \
+{ \
+ int _i; \
+ float* _x = (x); \
+ float* _y = (y); \
+ \
+ for( _i = 0; _i < n; _i++ ) \
+ { \
+ double t0 = _x[_i]; \
+ double t1 = _y[_i]; \
+ _x[_i] = (float)(t0*c + t1*s); \
+ _y[_i] = (float)(-t0*s + t1*c);\
+ } \
+}
+
+static void
+icvMatrAXPY_32f( int m, int n, const float* x, int dx,
+ const float* a, float* y, int dy )
+{
+ int i, j;
+
+ for( i = 0; i < m; i++, x += dx, y += dy )
+ {
+ double s = a[i];
+
+ for( j = 0; j <= n - 4; j += 4 )
+ {
+ double t0 = y[j] + s*x[j];
+ double t1 = y[j+1] + s*x[j+1];
+ y[j] = (float)t0;
+ y[j+1] = (float)t1;
+ t0 = y[j+2] + s*x[j+2];
+ t1 = y[j+3] + s*x[j+3];
+ y[j+2] = (float)t0;
+ y[j+3] = (float)t1;
+ }
+
+ for( ; j < n; j++ )
+ y[j] = (float)(y[j] + s*x[j]);
+ }
+}
+
+
+static void
+icvMatrAXPY3_32f( int m, int n, const float* x, int l, float* y, double h )
+{
+ int i, j;
+
+ for( i = 1; i < m; i++ )
+ {
+ double s = 0;
+ y += l;
+
+ for( j = 0; j <= n - 4; j += 4 )
+ s += x[j]*y[j] + x[j+1]*y[j+1] + x[j+2]*y[j+2] + x[j+3]*y[j+3];
+
+ for( ; j < n; j++ ) s += x[j]*y[j];
+
+ s *= h;
+ y[-1] = (float)(s*x[-1]);
+
+ for( j = 0; j <= n - 4; j += 4 )
+ {
+ double t0 = y[j] + s*x[j];
+ double t1 = y[j+1] + s*x[j+1];
+ y[j] = (float)t0;
+ y[j+1] = (float)t1;
+ t0 = y[j+2] + s*x[j+2];
+ t1 = y[j+3] + s*x[j+3];
+ y[j+2] = (float)t0;
+ y[j+3] = (float)t1;
+ }
+
+ for( ; j < n; j++ ) y[j] = (float)(y[j] + s*x[j]);
+ }
+}
+
+/* accurate hypotenuse calculation */
+static double
+pythag( double a, double b )
+{
+ a = fabs( a );
+ b = fabs( b );
+ if( a > b )
+ {
+ b /= a;
+ a *= sqrt( 1. + b * b );
+ }
+ else if( b != 0 )
+ {
+ a /= b;
+ a = b * sqrt( 1. + a * a );
+ }
+
+ return a;
+}
+
+/****************************************************************************************/
+/****************************************************************************************/
+
+#define MAX_ITERS 30
+
+static void
+icvSVD_64f( double* a, int lda, int m, int n,
+ double* w,
+ double* uT, int lduT, int nu,
+ double* vT, int ldvT,
+ double* buffer )
+{
+ double* e;
+ double* temp;
+ double *w1, *e1;
+ double *hv;
+ double ku0 = 0, kv0 = 0;
+ double anorm = 0;
+ double *a1, *u0 = uT, *v0 = vT;
+ double scale, h;
+ int i, j, k, l;
+ int nm, m1, n1;
+ int nv = n;
+ int iters = 0;
+ double* hv0 = (double*)cvStackAlloc( (m+2)*sizeof(hv0[0])) + 1;
+
+ e = buffer;
+ w1 = w;
+ e1 = e + 1;
+ nm = n;
+
+ temp = buffer + nm;
+
+ memset( w, 0, nm * sizeof( w[0] ));
+ memset( e, 0, nm * sizeof( e[0] ));
+
+ m1 = m;
+ n1 = n;
+
+ /* transform a to bi-diagonal form */
+ for( ;; )
+ {
+ int update_u;
+ int update_v;
+
+ if( m1 == 0 )
+ break;
+
+ scale = h = 0;
+ update_u = uT && m1 > m - nu;
+ hv = update_u ? uT : hv0;
+
+ for( j = 0, a1 = a; j < m1; j++, a1 += lda )
+ {
+ double t = a1[0];
+ scale += fabs( hv[j] = t );
+ }
+
+ if( scale != 0 )
+ {
+ double f = 1./scale, g, s = 0;
+
+ for( j = 0; j < m1; j++ )
+ {
+ double t = (hv[j] *= f);
+ s += t * t;
+ }
+
+ g = sqrt( s );
+ f = hv[0];
+ if( f >= 0 )
+ g = -g;
+ hv[0] = f - g;
+ h = 1. / (f * g - s);
+
+ memset( temp, 0, n1 * sizeof( temp[0] ));
+
+ /* calc temp[0:n-i] = a[i:m,i:n]'*hv[0:m-i] */
+ icvMatrAXPY_64f( m1, n1 - 1, a + 1, lda, hv, temp + 1, 0 );
+ for( k = 1; k < n1; k++ ) temp[k] *= h;
+
+ /* modify a: a[i:m,i:n] = a[i:m,i:n] + hv[0:m-i]*temp[0:n-i]' */
+ icvMatrAXPY_64f( m1, n1 - 1, temp + 1, 0, hv, a + 1, lda );
+ *w1 = g*scale;
+ }
+ w1++;
+
+ /* store -2/(hv'*hv) */
+ if( update_u )
+ {
+ if( m1 == m )
+ ku0 = h;
+ else
+ hv[-1] = h;
+ }
+
+ a++;
+ n1--;
+ if( vT )
+ vT += ldvT + 1;
+
+ if( n1 == 0 )
+ break;
+
+ scale = h = 0;
+ update_v = vT && n1 > n - nv;
+
+ hv = update_v ? vT : hv0;
+
+ for( j = 0; j < n1; j++ )
+ {
+ double t = a[j];
+ scale += fabs( hv[j] = t );
+ }
+
+ if( scale != 0 )
+ {
+ double f = 1./scale, g, s = 0;
+
+ for( j = 0; j < n1; j++ )
+ {
+ double t = (hv[j] *= f);
+ s += t * t;
+ }
+
+ g = sqrt( s );
+ f = hv[0];
+ if( f >= 0 )
+ g = -g;
+ hv[0] = f - g;
+ h = 1. / (f * g - s);
+ hv[-1] = 0.;
+
+ /* update a[i:m:i+1:n] = a[i:m,i+1:n] + (a[i:m,i+1:n]*hv[0:m-i])*... */
+ icvMatrAXPY3_64f( m1, n1, hv, lda, a, h );
+
+ *e1 = g*scale;
+ }
+ e1++;
+
+ /* store -2/(hv'*hv) */
+ if( update_v )
+ {
+ if( n1 == n )
+ kv0 = h;
+ else
+ hv[-1] = h;
+ }
+
+ a += lda;
+ m1--;
+ if( uT )
+ uT += lduT + 1;
+ }
+
+ m1 -= m1 != 0;
+ n1 -= n1 != 0;
+
+ /* accumulate left transformations */
+ if( uT )
+ {
+ m1 = m - m1;
+ uT = u0 + m1 * lduT;
+ for( i = m1; i < nu; i++, uT += lduT )
+ {
+ memset( uT + m1, 0, (m - m1) * sizeof( uT[0] ));
+ uT[i] = 1.;
+ }
+
+ for( i = m1 - 1; i >= 0; i-- )
+ {
+ double s;
+ int lh = nu - i;
+
+ l = m - i;
+
+ hv = u0 + (lduT + 1) * i;
+ h = i == 0 ? ku0 : hv[-1];
+
+ assert( h <= 0 );
+
+ if( h != 0 )
+ {
+ uT = hv;
+ icvMatrAXPY3_64f( lh, l-1, hv+1, lduT, uT+1, h );
+
+ s = hv[0] * h;
+ for( k = 0; k < l; k++ ) hv[k] *= s;
+ hv[0] += 1;
+ }
+ else
+ {
+ for( j = 1; j < l; j++ )
+ hv[j] = 0;
+ for( j = 1; j < lh; j++ )
+ hv[j * lduT] = 0;
+ hv[0] = 1;
+ }
+ }
+ uT = u0;
+ }
+
+ /* accumulate right transformations */
+ if( vT )
+ {
+ n1 = n - n1;
+ vT = v0 + n1 * ldvT;
+ for( i = n1; i < nv; i++, vT += ldvT )
+ {
+ memset( vT + n1, 0, (n - n1) * sizeof( vT[0] ));
+ vT[i] = 1.;
+ }
+
+ for( i = n1 - 1; i >= 0; i-- )
+ {
+ double s;
+ int lh = nv - i;
+
+ l = n - i;
+ hv = v0 + (ldvT + 1) * i;
+ h = i == 0 ? kv0 : hv[-1];
+
+ assert( h <= 0 );
+
+ if( h != 0 )
+ {
+ vT = hv;
+ icvMatrAXPY3_64f( lh, l-1, hv+1, ldvT, vT+1, h );
+
+ s = hv[0] * h;
+ for( k = 0; k < l; k++ ) hv[k] *= s;
+ hv[0] += 1;
+ }
+ else
+ {
+ for( j = 1; j < l; j++ )
+ hv[j] = 0;
+ for( j = 1; j < lh; j++ )
+ hv[j * ldvT] = 0;
+ hv[0] = 1;
+ }
+ }
+ vT = v0;
+ }
+
+ for( i = 0; i < nm; i++ )
+ {
+ double tnorm = fabs( w[i] );
+ tnorm += fabs( e[i] );
+
+ if( anorm < tnorm )
+ anorm = tnorm;
+ }
+
+ anorm *= DBL_EPSILON;
+
+ /* diagonalization of the bidiagonal form */
+ for( k = nm - 1; k >= 0; k-- )
+ {
+ double z = 0;
+ iters = 0;
+
+ for( ;; ) /* do iterations */
+ {
+ double c, s, f, g, x, y;
+ int flag = 0;
+
+ /* test for splitting */
+ for( l = k; l >= 0; l-- )
+ {
+ if( fabs(e[l]) <= anorm )
+ {
+ flag = 1;
+ break;
+ }
+ assert( l > 0 );
+ if( fabs(w[l - 1]) <= anorm )
+ break;
+ }
+
+ if( !flag )
+ {
+ c = 0;
+ s = 1;
+
+ for( i = l; i <= k; i++ )
+ {
+ f = s * e[i];
+
+ e[i] *= c;
+
+ if( anorm + fabs( f ) == anorm )
+ break;
+
+ g = w[i];
+ h = pythag( f, g );
+ w[i] = h;
+ c = g / h;
+ s = -f / h;
+
+ if( uT )
+ icvGivens_64f( m, uT + lduT * (l - 1), uT + lduT * i, c, s );
+ }
+ }
+
+ z = w[k];
+ if( l == k || iters++ == MAX_ITERS )
+ break;
+
+ /* shift from bottom 2x2 minor */
+ x = w[l];
+ y = w[k - 1];
+ g = e[k - 1];
+ h = e[k];
+ f = 0.5 * (((g + z) / h) * ((g - z) / y) + y / h - h / y);
+ g = pythag( f, 1 );
+ if( f < 0 )
+ g = -g;
+ f = x - (z / x) * z + (h / x) * (y / (f + g) - h);
+ /* next QR transformation */
+ c = s = 1;
+
+ for( i = l + 1; i <= k; i++ )
+ {
+ g = e[i];
+ y = w[i];
+ h = s * g;
+ g *= c;
+ z = pythag( f, h );
+ e[i - 1] = z;
+ c = f / z;
+ s = h / z;
+ f = x * c + g * s;
+ g = -x * s + g * c;
+ h = y * s;
+ y *= c;
+
+ if( vT )
+ icvGivens_64f( n, vT + ldvT * (i - 1), vT + ldvT * i, c, s );
+
+ z = pythag( f, h );
+ w[i - 1] = z;
+
+ /* rotation can be arbitrary if z == 0 */
+ if( z != 0 )
+ {
+ c = f / z;
+ s = h / z;
+ }
+ f = c * g + s * y;
+ x = -s * g + c * y;
+
+ if( uT )
+ icvGivens_64f( m, uT + lduT * (i - 1), uT + lduT * i, c, s );
+ }
+
+ e[l] = 0;
+ e[k] = f;
+ w[k] = x;
+ } /* end of iteration loop */
+
+ if( iters > MAX_ITERS )
+ break;
+
+ if( z < 0 )
+ {
+ w[k] = -z;
+ if( vT )
+ {
+ for( j = 0; j < n; j++ )
+ vT[j + k * ldvT] = -vT[j + k * ldvT];
+ }
+ }
+ } /* end of diagonalization loop */
+
+ /* sort singular values and corresponding values */
+ for( i = 0; i < nm; i++ )
+ {
+ k = i;
+ for( j = i + 1; j < nm; j++ )
+ if( w[k] < w[j] )
+ k = j;
+
+ if( k != i )
+ {
+ double t;
+ CV_SWAP( w[i], w[k], t );
+
+ if( vT )
+ for( j = 0; j < n; j++ )
+ CV_SWAP( vT[j + ldvT*k], vT[j + ldvT*i], t );
+
+ if( uT )
+ for( j = 0; j < m; j++ )
+ CV_SWAP( uT[j + lduT*k], uT[j + lduT*i], t );
+ }
+ }
+}
+
+
+static void
+icvSVD_32f( float* a, int lda, int m, int n,
+ float* w,
+ float* uT, int lduT, int nu,
+ float* vT, int ldvT,
+ float* buffer )
+{
+ float* e;
+ float* temp;
+ float *w1, *e1;
+ float *hv;
+ double ku0 = 0, kv0 = 0;
+ double anorm = 0;
+ float *a1, *u0 = uT, *v0 = vT;
+ double scale, h;
+ int i, j, k, l;
+ int nm, m1, n1;
+ int nv = n;
+ int iters = 0;
+ float* hv0 = (float*)cvStackAlloc( (m+2)*sizeof(hv0[0])) + 1;
+
+ e = buffer;
+
+ w1 = w;
+ e1 = e + 1;
+ nm = n;
+
+ temp = buffer + nm;
+
+ memset( w, 0, nm * sizeof( w[0] ));
+ memset( e, 0, nm * sizeof( e[0] ));
+
+ m1 = m;
+ n1 = n;
+
+ /* transform a to bi-diagonal form */
+ for( ;; )
+ {
+ int update_u;
+ int update_v;
+
+ if( m1 == 0 )
+ break;
+
+ scale = h = 0;
+
+ update_u = uT && m1 > m - nu;
+ hv = update_u ? uT : hv0;
+
+ for( j = 0, a1 = a; j < m1; j++, a1 += lda )
+ {
+ double t = a1[0];
+ scale += fabs( hv[j] = (float)t );
+ }
+
+ if( scale != 0 )
+ {
+ double f = 1./scale, g, s = 0;
+
+ for( j = 0; j < m1; j++ )
+ {
+ double t = (hv[j] = (float)(hv[j]*f));
+ s += t * t;
+ }
+
+ g = sqrt( s );
+ f = hv[0];
+ if( f >= 0 )
+ g = -g;
+ hv[0] = (float)(f - g);
+ h = 1. / (f * g - s);
+
+ memset( temp, 0, n1 * sizeof( temp[0] ));
+
+ /* calc temp[0:n-i] = a[i:m,i:n]'*hv[0:m-i] */
+ icvMatrAXPY_32f( m1, n1 - 1, a + 1, lda, hv, temp + 1, 0 );
+
+ for( k = 1; k < n1; k++ ) temp[k] = (float)(temp[k]*h);
+
+ /* modify a: a[i:m,i:n] = a[i:m,i:n] + hv[0:m-i]*temp[0:n-i]' */
+ icvMatrAXPY_32f( m1, n1 - 1, temp + 1, 0, hv, a + 1, lda );
+ *w1 = (float)(g*scale);
+ }
+ w1++;
+
+ /* store -2/(hv'*hv) */
+ if( update_u )
+ {
+ if( m1 == m )
+ ku0 = h;
+ else
+ hv[-1] = (float)h;
+ }
+
+ a++;
+ n1--;
+ if( vT )
+ vT += ldvT + 1;
+
+ if( n1 == 0 )
+ break;
+
+ scale = h = 0;
+ update_v = vT && n1 > n - nv;
+ hv = update_v ? vT : hv0;
+
+ for( j = 0; j < n1; j++ )
+ {
+ double t = a[j];
+ scale += fabs( hv[j] = (float)t );
+ }
+
+ if( scale != 0 )
+ {
+ double f = 1./scale, g, s = 0;
+
+ for( j = 0; j < n1; j++ )
+ {
+ double t = (hv[j] = (float)(hv[j]*f));
+ s += t * t;
+ }
+
+ g = sqrt( s );
+ f = hv[0];
+ if( f >= 0 )
+ g = -g;
+ hv[0] = (float)(f - g);
+ h = 1. / (f * g - s);
+ hv[-1] = 0.f;
+
+ /* update a[i:m:i+1:n] = a[i:m,i+1:n] + (a[i:m,i+1:n]*hv[0:m-i])*... */
+ icvMatrAXPY3_32f( m1, n1, hv, lda, a, h );
+
+ *e1 = (float)(g*scale);
+ }
+ e1++;
+
+ /* store -2/(hv'*hv) */
+ if( update_v )
+ {
+ if( n1 == n )
+ kv0 = h;
+ else
+ hv[-1] = (float)h;
+ }
+
+ a += lda;
+ m1--;
+ if( uT )
+ uT += lduT + 1;
+ }
+
+ m1 -= m1 != 0;
+ n1 -= n1 != 0;
+
+ /* accumulate left transformations */
+ if( uT )
+ {
+ m1 = m - m1;
+ uT = u0 + m1 * lduT;
+ for( i = m1; i < nu; i++, uT += lduT )
+ {
+ memset( uT + m1, 0, (m - m1) * sizeof( uT[0] ));
+ uT[i] = 1.;
+ }
+
+ for( i = m1 - 1; i >= 0; i-- )
+ {
+ double s;
+ int lh = nu - i;
+
+ l = m - i;
+
+ hv = u0 + (lduT + 1) * i;
+ h = i == 0 ? ku0 : hv[-1];
+
+ assert( h <= 0 );
+
+ if( h != 0 )
+ {
+ uT = hv;
+ icvMatrAXPY3_32f( lh, l-1, hv+1, lduT, uT+1, h );
+
+ s = hv[0] * h;
+ for( k = 0; k < l; k++ ) hv[k] = (float)(hv[k]*s);
+ hv[0] += 1;
+ }
+ else
+ {
+ for( j = 1; j < l; j++ )
+ hv[j] = 0;
+ for( j = 1; j < lh; j++ )
+ hv[j * lduT] = 0;
+ hv[0] = 1;
+ }
+ }
+ uT = u0;
+ }
+
+ /* accumulate right transformations */
+ if( vT )
+ {
+ n1 = n - n1;
+ vT = v0 + n1 * ldvT;
+ for( i = n1; i < nv; i++, vT += ldvT )
+ {
+ memset( vT + n1, 0, (n - n1) * sizeof( vT[0] ));
+ vT[i] = 1.;
+ }
+
+ for( i = n1 - 1; i >= 0; i-- )
+ {
+ double s;
+ int lh = nv - i;
+
+ l = n - i;
+ hv = v0 + (ldvT + 1) * i;
+ h = i == 0 ? kv0 : hv[-1];
+
+ assert( h <= 0 );
+
+ if( h != 0 )
+ {
+ vT = hv;
+ icvMatrAXPY3_32f( lh, l-1, hv+1, ldvT, vT+1, h );
+
+ s = hv[0] * h;
+ for( k = 0; k < l; k++ ) hv[k] = (float)(hv[k]*s);
+ hv[0] += 1;
+ }
+ else
+ {
+ for( j = 1; j < l; j++ )
+ hv[j] = 0;
+ for( j = 1; j < lh; j++ )
+ hv[j * ldvT] = 0;
+ hv[0] = 1;
+ }
+ }
+ vT = v0;
+ }
+
+ for( i = 0; i < nm; i++ )
+ {
+ double tnorm = fabs( w[i] );
+ tnorm += fabs( e[i] );
+
+ if( anorm < tnorm )
+ anorm = tnorm;
+ }
+
+ anorm *= FLT_EPSILON;
+
+ /* diagonalization of the bidiagonal form */
+ for( k = nm - 1; k >= 0; k-- )
+ {
+ double z = 0;
+ iters = 0;
+
+ for( ;; ) /* do iterations */
+ {
+ double c, s, f, g, x, y;
+ int flag = 0;
+
+ /* test for splitting */
+ for( l = k; l >= 0; l-- )
+ {
+ if( fabs( e[l] ) <= anorm )
+ {
+ flag = 1;
+ break;
+ }
+ assert( l > 0 );
+ if( fabs( w[l - 1] ) <= anorm )
+ break;
+ }
+
+ if( !flag )
+ {
+ c = 0;
+ s = 1;
+
+ for( i = l; i <= k; i++ )
+ {
+ f = s * e[i];
+ e[i] = (float)(e[i]*c);
+
+ if( anorm + fabs( f ) == anorm )
+ break;
+
+ g = w[i];
+ h = pythag( f, g );
+ w[i] = (float)h;
+ c = g / h;
+ s = -f / h;
+
+ if( uT )
+ icvGivens_32f( m, uT + lduT * (l - 1), uT + lduT * i, c, s );
+ }
+ }
+
+ z = w[k];
+ if( l == k || iters++ == MAX_ITERS )
+ break;
+
+ /* shift from bottom 2x2 minor */
+ x = w[l];
+ y = w[k - 1];
+ g = e[k - 1];
+ h = e[k];
+ f = 0.5 * (((g + z) / h) * ((g - z) / y) + y / h - h / y);
+ g = pythag( f, 1 );
+ if( f < 0 )
+ g = -g;
+ f = x - (z / x) * z + (h / x) * (y / (f + g) - h);
+ /* next QR transformation */
+ c = s = 1;
+
+ for( i = l + 1; i <= k; i++ )
+ {
+ g = e[i];
+ y = w[i];
+ h = s * g;
+ g *= c;
+ z = pythag( f, h );
+ e[i - 1] = (float)z;
+ c = f / z;
+ s = h / z;
+ f = x * c + g * s;
+ g = -x * s + g * c;
+ h = y * s;
+ y *= c;
+
+ if( vT )
+ icvGivens_32f( n, vT + ldvT * (i - 1), vT + ldvT * i, c, s );
+
+ z = pythag( f, h );
+ w[i - 1] = (float)z;
+
+ /* rotation can be arbitrary if z == 0 */
+ if( z != 0 )
+ {
+ c = f / z;
+ s = h / z;
+ }
+ f = c * g + s * y;
+ x = -s * g + c * y;
+
+ if( uT )
+ icvGivens_32f( m, uT + lduT * (i - 1), uT + lduT * i, c, s );
+ }
+
+ e[l] = 0;
+ e[k] = (float)f;
+ w[k] = (float)x;
+ } /* end of iteration loop */
+
+ if( iters > MAX_ITERS )
+ break;
+
+ if( z < 0 )
+ {
+ w[k] = (float)(-z);
+ if( vT )
+ {
+ for( j = 0; j < n; j++ )
+ vT[j + k * ldvT] = -vT[j + k * ldvT];
+ }
+ }
+ } /* end of diagonalization loop */
+
+ /* sort singular values and corresponding vectors */
+ for( i = 0; i < nm; i++ )
+ {
+ k = i;
+ for( j = i + 1; j < nm; j++ )
+ if( w[k] < w[j] )
+ k = j;
+
+ if( k != i )
+ {
+ float t;
+ CV_SWAP( w[i], w[k], t );
+
+ if( vT )
+ for( j = 0; j < n; j++ )
+ CV_SWAP( vT[j + ldvT*k], vT[j + ldvT*i], t );
+
+ if( uT )
+ for( j = 0; j < m; j++ )
+ CV_SWAP( uT[j + lduT*k], uT[j + lduT*i], t );
+ }
+ }
+}
+
+
+static void
+icvSVBkSb_64f( int m, int n, const double* w,
+ const double* uT, int lduT,
+ const double* vT, int ldvT,
+ const double* b, int ldb, int nb,
+ double* x, int ldx, double* buffer )
+{
+ double threshold = 0;
+ int i, j, nm = MIN( m, n );
+
+ if( !b )
+ nb = m;
+
+ for( i = 0; i < n; i++ )
+ memset( x + i*ldx, 0, nb*sizeof(x[0]));
+
+ for( i = 0; i < nm; i++ )
+ threshold += w[i];
+ threshold *= 2*DBL_EPSILON;
+
+ /* vT * inv(w) * uT * b */
+ for( i = 0; i < nm; i++, uT += lduT, vT += ldvT )
+ {
+ double wi = w[i];
+
+ if( wi > threshold )
+ {
+ wi = 1./wi;
+
+ if( nb == 1 )
+ {
+ double s = 0;
+ if( b )
+ {
+ if( ldb == 1 )
+ {
+ for( j = 0; j <= m - 4; j += 4 )
+ s += uT[j]*b[j] + uT[j+1]*b[j+1] + uT[j+2]*b[j+2] + uT[j+3]*b[j+3];
+ for( ; j < m; j++ )
+ s += uT[j]*b[j];
+ }
+ else
+ {
+ for( j = 0; j < m; j++ )
+ s += uT[j]*b[j*ldb];
+ }
+ }
+ else
+ s = uT[0];
+ s *= wi;
+ if( ldx == 1 )
+ {
+ for( j = 0; j <= n - 4; j += 4 )
+ {
+ double t0 = x[j] + s*vT[j];
+ double t1 = x[j+1] + s*vT[j+1];
+ x[j] = t0;
+ x[j+1] = t1;
+ t0 = x[j+2] + s*vT[j+2];
+ t1 = x[j+3] + s*vT[j+3];
+ x[j+2] = t0;
+ x[j+3] = t1;
+ }
+
+ for( ; j < n; j++ )
+ x[j] += s*vT[j];
+ }
+ else
+ {
+ for( j = 0; j < n; j++ )
+ x[j*ldx] += s*vT[j];
+ }
+ }
+ else
+ {
+ if( b )
+ {
+ memset( buffer, 0, nb*sizeof(buffer[0]));
+ icvMatrAXPY_64f( m, nb, b, ldb, uT, buffer, 0 );
+ for( j = 0; j < nb; j++ )
+ buffer[j] *= wi;
+ }
+ else
+ {
+ for( j = 0; j < nb; j++ )
+ buffer[j] = uT[j]*wi;
+ }
+ icvMatrAXPY_64f( n, nb, buffer, 0, vT, x, ldx );
+ }
+ }
+ }
+}
+
+
+static void
+icvSVBkSb_32f( int m, int n, const float* w,
+ const float* uT, int lduT,
+ const float* vT, int ldvT,
+ const float* b, int ldb, int nb,
+ float* x, int ldx, float* buffer )
+{
+ float threshold = 0.f;
+ int i, j, nm = MIN( m, n );
+
+ if( !b )
+ nb = m;
+
+ for( i = 0; i < n; i++ )
+ memset( x + i*ldx, 0, nb*sizeof(x[0]));
+
+ for( i = 0; i < nm; i++ )
+ threshold += w[i];
+ threshold *= 2*FLT_EPSILON;
+
+ /* vT * inv(w) * uT * b */
+ for( i = 0; i < nm; i++, uT += lduT, vT += ldvT )
+ {
+ double wi = w[i];
+
+ if( wi > threshold )
+ {
+ wi = 1./wi;
+
+ if( nb == 1 )
+ {
+ double s = 0;
+ if( b )
+ {
+ if( ldb == 1 )
+ {
+ for( j = 0; j <= m - 4; j += 4 )
+ s += uT[j]*b[j] + uT[j+1]*b[j+1] + uT[j+2]*b[j+2] + uT[j+3]*b[j+3];
+ for( ; j < m; j++ )
+ s += uT[j]*b[j];
+ }
+ else
+ {
+ for( j = 0; j < m; j++ )
+ s += uT[j]*b[j*ldb];
+ }
+ }
+ else
+ s = uT[0];
+ s *= wi;
+
+ if( ldx == 1 )
+ {
+ for( j = 0; j <= n - 4; j += 4 )
+ {
+ double t0 = x[j] + s*vT[j];
+ double t1 = x[j+1] + s*vT[j+1];
+ x[j] = (float)t0;
+ x[j+1] = (float)t1;
+ t0 = x[j+2] + s*vT[j+2];
+ t1 = x[j+3] + s*vT[j+3];
+ x[j+2] = (float)t0;
+ x[j+3] = (float)t1;
+ }
+
+ for( ; j < n; j++ )
+ x[j] = (float)(x[j] + s*vT[j]);
+ }
+ else
+ {
+ for( j = 0; j < n; j++ )
+ x[j*ldx] = (float)(x[j*ldx] + s*vT[j]);
+ }
+ }
+ else
+ {
+ if( b )
+ {
+ memset( buffer, 0, nb*sizeof(buffer[0]));
+ icvMatrAXPY_32f( m, nb, b, ldb, uT, buffer, 0 );
+ for( j = 0; j < nb; j++ )
+ buffer[j] = (float)(buffer[j]*wi);
+ }
+ else
+ {
+ for( j = 0; j < nb; j++ )
+ buffer[j] = (float)(uT[j]*wi);
+ }
+ icvMatrAXPY_32f( n, nb, buffer, 0, vT, x, ldx );
+ }
+ }
+ }
+}
+
+
+CV_IMPL void
+cvSVD( CvArr* aarr, CvArr* warr, CvArr* uarr, CvArr* varr, int flags )
+{
+ uchar* buffer = 0;
+ int local_alloc = 0;
+
+ CV_FUNCNAME( "cvSVD" );
+
+ __BEGIN__;
+
+ CvMat astub, *a = (CvMat*)aarr;
+ CvMat wstub, *w = (CvMat*)warr;
+ CvMat ustub, *u;
+ CvMat vstub, *v;
+ CvMat tmat;
+ uchar* tw = 0;
+ int type;
+ int a_buf_offset = 0, u_buf_offset = 0, buf_size, pix_size;
+ int temp_u = 0, /* temporary storage for U is needed */
+ t_svd; /* special case: a->rows < a->cols */
+ int m, n;
+ int w_rows, w_cols;
+ int u_rows = 0, u_cols = 0;
+ int w_is_mat = 0;
+
+ if( !CV_IS_MAT( a ))
+ CV_CALL( a = cvGetMat( a, &astub ));
+
+ if( !CV_IS_MAT( w ))
+ CV_CALL( w = cvGetMat( w, &wstub ));
+
+ if( !CV_ARE_TYPES_EQ( a, w ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( a->rows >= a->cols )
+ {
+ m = a->rows;
+ n = a->cols;
+ w_rows = w->rows;
+ w_cols = w->cols;
+ t_svd = 0;
+ }
+ else
+ {
+ CvArr* t;
+ CV_SWAP( uarr, varr, t );
+
+ flags = (flags & CV_SVD_U_T ? CV_SVD_V_T : 0)|
+ (flags & CV_SVD_V_T ? CV_SVD_U_T : 0);
+ m = a->cols;
+ n = a->rows;
+ w_rows = w->cols;
+ w_cols = w->rows;
+ t_svd = 1;
+ }
+
+ u = (CvMat*)uarr;
+ v = (CvMat*)varr;
+
+ w_is_mat = w_cols > 1 && w_rows > 1;
+
+ if( !w_is_mat && CV_IS_MAT_CONT(w->type) && w_cols + w_rows - 1 == n )
+ tw = w->data.ptr;
+
+ if( u )
+ {
+ if( !CV_IS_MAT( u ))
+ CV_CALL( u = cvGetMat( u, &ustub ));
+
+ if( !(flags & CV_SVD_U_T) )
+ {
+ u_rows = u->rows;
+ u_cols = u->cols;
+ }
+ else
+ {
+ u_rows = u->cols;
+ u_cols = u->rows;
+ }
+
+ if( !CV_ARE_TYPES_EQ( a, u ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( u_rows != m || (u_cols != m && u_cols != n))
+ CV_ERROR( CV_StsUnmatchedSizes, !t_svd ? "U matrix has unappropriate size" :
+ "V matrix has unappropriate size" );
+
+ temp_u = (u_rows != u_cols && !(flags & CV_SVD_U_T)) || u->data.ptr==a->data.ptr;
+
+ if( w_is_mat && u_cols != w_rows )
+ CV_ERROR( CV_StsUnmatchedSizes, !t_svd ? "U and W have incompatible sizes" :
+ "V and W have incompatible sizes" );
+ }
+ else
+ {
+ u = &ustub;
+ u->data.ptr = 0;
+ u->step = 0;
+ }
+
+ if( v )
+ {
+ int v_rows, v_cols;
+
+ if( !CV_IS_MAT( v ))
+ CV_CALL( v = cvGetMat( v, &vstub ));
+
+ if( !(flags & CV_SVD_V_T) )
+ {
+ v_rows = v->rows;
+ v_cols = v->cols;
+ }
+ else
+ {
+ v_rows = v->cols;
+ v_cols = v->rows;
+ }
+
+ if( !CV_ARE_TYPES_EQ( a, v ))
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
+
+ if( v_rows != n || v_cols != n )
+ CV_ERROR( CV_StsUnmatchedSizes, t_svd ? "U matrix has unappropriate size" :
+ "V matrix has unappropriate size" );
+
+ if( w_is_mat && w_cols != v_cols )
+ CV_ERROR( CV_StsUnmatchedSizes, t_svd ? "U and W have incompatible sizes" :
+ "V and W have incompatible sizes" );
+ }
+ else
+ {
+ v = &vstub;
+ v->data.ptr = 0;
+ v->step = 0;
+ }
+
+ type = CV_MAT_TYPE( a->type );
+ pix_size = CV_ELEM_SIZE(type);
+ buf_size = n*2 + m;
+
+ if( !(flags & CV_SVD_MODIFY_A) )
+ {
+ a_buf_offset = buf_size;
+ buf_size += a->rows*a->cols;
+ }
+
+ if( temp_u )
+ {
+ u_buf_offset = buf_size;
+ buf_size += u->rows*u->cols;
+ }
+
+ buf_size *= pix_size;
+
+ if( buf_size <= CV_MAX_LOCAL_SIZE )
+ {
+ buffer = (uchar*)cvStackAlloc( buf_size );
+ local_alloc = 1;
+ }
+ else
+ {
+ CV_CALL( buffer = (uchar*)cvAlloc( buf_size ));
+ }
+
+ if( !(flags & CV_SVD_MODIFY_A) )
+ {
+ cvInitMatHeader( &tmat, m, n, type,
+ buffer + a_buf_offset*pix_size );
+ if( !t_svd )
+ cvCopy( a, &tmat );
+ else
+ cvT( a, &tmat );
+ a = &tmat;
+ }
+
+ if( temp_u )
+ {
+ cvInitMatHeader( &ustub, u_cols, u_rows, type, buffer + u_buf_offset*pix_size );
+ u = &ustub;
+ }
+
+ if( !tw )
+ tw = buffer + (n + m)*pix_size;
+
+ if( type == CV_32FC1 )
+ {
+ icvSVD_32f( a->data.fl, a->step/sizeof(float), a->rows, a->cols,
+ (float*)tw, u->data.fl, u->step/sizeof(float), u_cols,
+ v->data.fl, v->step/sizeof(float), (float*)buffer );
+ }
+ else if( type == CV_64FC1 )
+ {
+ icvSVD_64f( a->data.db, a->step/sizeof(double), a->rows, a->cols,
+ (double*)tw, u->data.db, u->step/sizeof(double), u_cols,
+ v->data.db, v->step/sizeof(double), (double*)buffer );
+ }
+ else
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+ }
+
+ if( tw != w->data.ptr )
+ {
+ int shift = w->cols != 1;
+ cvSetZero( w );
+ if( type == CV_32FC1 )
+ for( int i = 0; i < n; i++ )
+ ((float*)(w->data.ptr + i*w->step))[i*shift] = ((float*)tw)[i];
+ else
+ for( int i = 0; i < n; i++ )
+ ((double*)(w->data.ptr + i*w->step))[i*shift] = ((double*)tw)[i];
+ }
+
+ if( uarr )
+ {
+ if( !(flags & CV_SVD_U_T))
+ cvT( u, uarr );
+ else if( temp_u )
+ cvCopy( u, uarr );
+ /*CV_CHECK_NANS( uarr );*/
+ }
+
+ if( varr )
+ {
+ if( !(flags & CV_SVD_V_T))
+ cvT( v, varr );
+ /*CV_CHECK_NANS( varr );*/
+ }
+
+ CV_CHECK_NANS( w );
+
+ __END__;
+
+ if( buffer && !local_alloc )
+ cvFree( &buffer );
+}
+
+
+CV_IMPL void
+cvSVBkSb( const CvArr* warr, const CvArr* uarr,
+ const CvArr* varr, const CvArr* barr,
+ CvArr* xarr, int flags )
+{
+ uchar* buffer = 0;
+ int local_alloc = 0;
+
+ CV_FUNCNAME( "cvSVBkSb" );
+
+ __BEGIN__;
+
+ CvMat wstub, *w = (CvMat*)warr;
+ CvMat bstub, *b = (CvMat*)barr;
+ CvMat xstub, *x = (CvMat*)xarr;
+ CvMat ustub, ustub2, *u = (CvMat*)uarr;
+ CvMat vstub, vstub2, *v = (CvMat*)varr;
+ uchar* tw = 0;
+ int type;
+ int temp_u = 0, temp_v = 0;
+ int u_buf_offset = 0, v_buf_offset = 0, w_buf_offset = 0, t_buf_offset = 0;
+ int buf_size = 0, pix_size;
+ int m, n, nm;
+ int u_rows, u_cols;
+ int v_rows, v_cols;
+
+ if( !CV_IS_MAT( w ))
+ CV_CALL( w = cvGetMat( w, &wstub ));
+
+ if( !CV_IS_MAT( u ))
+ CV_CALL( u = cvGetMat( u, &ustub ));
+
+ if( !CV_IS_MAT( v ))
+ CV_CALL( v = cvGetMat( v, &vstub ));
+
+ if( !CV_IS_MAT( x ))
+ CV_CALL( x = cvGetMat( x, &xstub ));
+
+ if( !CV_ARE_TYPES_EQ( w, u ) || !CV_ARE_TYPES_EQ( w, v ) || !CV_ARE_TYPES_EQ( w, x ))
+ CV_ERROR( CV_StsUnmatchedFormats, "All matrices must have the same type" );
+
+ type = CV_MAT_TYPE( w->type );
+ pix_size = CV_ELEM_SIZE(type);
+
+ if( !(flags & CV_SVD_U_T) )
+ {
+ temp_u = 1;
+ u_buf_offset = buf_size;
+ buf_size += u->cols*u->rows*pix_size;
+ u_rows = u->rows;
+ u_cols = u->cols;
+ }
+ else
+ {
+ u_rows = u->cols;
+ u_cols = u->rows;
+ }
+
+ if( !(flags & CV_SVD_V_T) )
+ {
+ temp_v = 1;
+ v_buf_offset = buf_size;
+ buf_size += v->cols*v->rows*pix_size;
+ v_rows = v->rows;
+ v_cols = v->cols;
+ }
+ else
+ {
+ v_rows = v->cols;
+ v_cols = v->rows;
+ }
+
+ m = u_rows;
+ n = v_rows;
+ nm = MIN(n,m);
+
+ if( (u_rows != u_cols && v_rows != v_cols) || x->rows != v_rows )
+ CV_ERROR( CV_StsBadSize, "V or U matrix must be square" );
+
+ if( (w->rows == 1 || w->cols == 1) && w->rows + w->cols - 1 == nm )
+ {
+ if( CV_IS_MAT_CONT(w->type) )
+ tw = w->data.ptr;
+ else
+ {
+ w_buf_offset = buf_size;
+ buf_size += nm*pix_size;
+ }
+ }
+ else
+ {
+ if( w->cols != v_cols || w->rows != u_cols )
+ CV_ERROR( CV_StsBadSize, "W must be 1d array of MIN(m,n) elements or "
+ "matrix which size matches to U and V" );
+ w_buf_offset = buf_size;
+ buf_size += nm*pix_size;
+ }
+
+ if( b )
+ {
+ if( !CV_IS_MAT( b ))
+ CV_CALL( b = cvGetMat( b, &bstub ));
+ if( !CV_ARE_TYPES_EQ( w, b ))
+ CV_ERROR( CV_StsUnmatchedFormats, "All matrices must have the same type" );
+ if( b->cols != x->cols || b->rows != m )
+ CV_ERROR( CV_StsUnmatchedSizes, "b matrix must have (m x x->cols) size" );
+ }
+ else
+ {
+ b = &bstub;
+ memset( b, 0, sizeof(*b));
+ }
+
+ t_buf_offset = buf_size;
+ buf_size += (MAX(m,n) + b->cols)*pix_size;
+
+ if( buf_size <= CV_MAX_LOCAL_SIZE )
+ {
+ buffer = (uchar*)cvStackAlloc( buf_size );
+ local_alloc = 1;
+ }
+ else
+ CV_CALL( buffer = (uchar*)cvAlloc( buf_size ));
+
+ if( temp_u )
+ {
+ cvInitMatHeader( &ustub2, u_cols, u_rows, type, buffer + u_buf_offset );
+ cvT( u, &ustub2 );
+ u = &ustub2;
+ }
+
+ if( temp_v )
+ {
+ cvInitMatHeader( &vstub2, v_cols, v_rows, type, buffer + v_buf_offset );
+ cvT( v, &vstub2 );
+ v = &vstub2;
+ }
+
+ if( !tw )
+ {
+ int i, shift = w->cols > 1 ? pix_size : 0;
+ tw = buffer + w_buf_offset;
+ for( i = 0; i < nm; i++ )
+ memcpy( tw + i*pix_size, w->data.ptr + i*(w->step + shift), pix_size );
+ }
+
+ if( type == CV_32FC1 )
+ {
+ icvSVBkSb_32f( m, n, (float*)tw, u->data.fl, u->step/sizeof(float),
+ v->data.fl, v->step/sizeof(float),
+ b->data.fl, b->step/sizeof(float), b->cols,
+ x->data.fl, x->step/sizeof(float),
+ (float*)(buffer + t_buf_offset) );
+ }
+ else if( type == CV_64FC1 )
+ {
+ icvSVBkSb_64f( m, n, (double*)tw, u->data.db, u->step/sizeof(double),
+ v->data.db, v->step/sizeof(double),
+ b->data.db, b->step/sizeof(double), b->cols,
+ x->data.db, x->step/sizeof(double),
+ (double*)(buffer + t_buf_offset) );
+ }
+ else
+ {
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
+ }
+
+ __END__;
+
+ if( buffer && !local_alloc )
+ cvFree( &buffer );
+}
+
+/* End of file. */
diff --git a/cxcore/src/cxswitcher.cpp b/cxcore/src/cxswitcher.cpp
new file mode 100644
index 0000000..3d98f29
--- /dev/null
+++ b/cxcore/src/cxswitcher.cpp
@@ -0,0 +1,816 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+
+/****************************************************************************************/
+/* Dynamic detection and loading of IPP modules */
+/****************************************************************************************/
+
+#include "_cxcore.h"
+
+#if defined _MSC_VER && _MSC_VER >= 1200
+#pragma warning( disable: 4115 ) /* type definition in () */
+#endif
+
+#if defined _MSC_VER && defined WIN64 && !defined EM64T
+#pragma optimize( "", off )
+#endif
+
+#if defined WIN32 || defined WIN64
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#include <sys/time.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#define CV_PROC_GENERIC 0
+#define CV_PROC_SHIFT 10
+#define CV_PROC_ARCH_MASK ((1 << CV_PROC_SHIFT) - 1)
+#define CV_PROC_IA32_GENERIC 1
+#define CV_PROC_IA32_WITH_MMX (CV_PROC_IA32_GENERIC|(2 << CV_PROC_SHIFT))
+#define CV_PROC_IA32_WITH_SSE (CV_PROC_IA32_GENERIC|(3 << CV_PROC_SHIFT))
+#define CV_PROC_IA32_WITH_SSE2 (CV_PROC_IA32_GENERIC|(4 << CV_PROC_SHIFT))
+#define CV_PROC_IA64 2
+#define CV_PROC_EM64T 3
+#define CV_GET_PROC_ARCH(model) ((model) & CV_PROC_ARCH_MASK)
+
+typedef struct CvProcessorInfo
+{
+ int model;
+ int count;
+ double frequency; // clocks per microsecond
+}
+CvProcessorInfo;
+
+#undef MASM_INLINE_ASSEMBLY
+
+#if defined WIN32 && !defined WIN64
+
+#if defined _MSC_VER
+#define MASM_INLINE_ASSEMBLY 1
+#elif defined __BORLANDC__
+
+#if __BORLANDC__ >= 0x560
+#define MASM_INLINE_ASSEMBLY 1
+#endif
+
+#endif
+
+#endif
+
+/*
+ determine processor type
+*/
+static void
+icvInitProcessorInfo( CvProcessorInfo* cpu_info )
+{
+ memset( cpu_info, 0, sizeof(*cpu_info) );
+ cpu_info->model = CV_PROC_GENERIC;
+
+#if defined WIN32 || defined WIN64
+
+#ifndef PROCESSOR_ARCHITECTURE_AMD64
+#define PROCESSOR_ARCHITECTURE_AMD64 9
+#endif
+
+#ifndef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
+#define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10
+#endif
+
+ SYSTEM_INFO sys;
+ LARGE_INTEGER freq;
+
+ GetSystemInfo( &sys );
+
+ if( sys.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL &&
+ sys.dwProcessorType == PROCESSOR_INTEL_PENTIUM && sys.wProcessorLevel >= 6 )
+ {
+ int version = 0, features = 0, family = 0;
+ int id = 0;
+ HKEY key = 0;
+
+ cpu_info->count = (int)sys.dwNumberOfProcessors;
+ unsigned long val = 0, sz = sizeof(val);
+
+ if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\SYSTEM\\CentralProcessor\\0\\",
+ 0, KEY_QUERY_VALUE, &key ) >= 0 )
+ {
+ if( RegQueryValueEx( key, "~MHz", 0, 0, (uchar*)&val, &sz ) >= 0 )
+ cpu_info->frequency = (double)val;
+ RegCloseKey( key );
+ }
+
+#ifdef MASM_INLINE_ASSEMBLY
+ __asm
+ {
+ /* use CPUID to determine the features supported */
+ pushfd
+ mov eax, 1
+ push ebx
+ push esi
+ push edi
+#ifdef __BORLANDC__
+ db 0fh
+ db 0a2h
+#else
+ _emit 0x0f
+ _emit 0xa2
+#endif
+ pop edi
+ pop esi
+ pop ebx
+ mov version, eax
+ mov features, edx
+ popfd
+ }
+#elif defined WIN32 && __GNUC__ > 2
+ asm volatile
+ (
+ "movl $1,%%eax\n\t"
+ ".byte 0x0f; .byte 0xa2\n\t"
+ "movl %%eax, %0\n\t"
+ "movl %%edx, %1\n\t"
+ : "=r"(version), "=r" (features)
+ :
+ : "%ebx", "%esi", "%edi"
+ );
+#else
+ {
+ static const char cpuid_code[] =
+ "\x53\x56\x57\xb8\x01\x00\x00\x00\x0f\xa2\x5f\x5e\x5b\xc3";
+ typedef int64 (CV_CDECL * func_ptr)(void);
+ func_ptr cpuid = (func_ptr)(void*)cpuid_code;
+ int64 cpuid_val = cpuid();
+ version = (int)cpuid_val;
+ features = (int)(cpuid_val >> 32);
+ }
+#endif
+
+ #define ICV_CPUID_M6 ((1<<15)|(1<<23)) /* cmov + MMX */
+ #define ICV_CPUID_A6 ((1<<25)|ICV_CPUID_M6) /* <all above> + SSE */
+ #define ICV_CPUID_W7 ((1<<26)|ICV_CPUID_A6) /* <all above> + SSE2 */
+
+ family = (version >> 8) & 15;
+ if( family >= 6 && (features & ICV_CPUID_M6) != 0 ) /* Pentium II or higher */
+ id = features & ICV_CPUID_W7;
+
+ cpu_info->model = id == ICV_CPUID_W7 ? CV_PROC_IA32_WITH_SSE2 :
+ id == ICV_CPUID_A6 ? CV_PROC_IA32_WITH_SSE :
+ id == ICV_CPUID_M6 ? CV_PROC_IA32_WITH_MMX :
+ CV_PROC_IA32_GENERIC;
+ }
+ else
+ {
+#if defined EM64T
+ if( sys.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 )
+ cpu_info->model = CV_PROC_EM64T;
+#elif defined WIN64
+ if( sys.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 )
+ cpu_info->model = CV_PROC_IA64;
+#endif
+ if( QueryPerformanceFrequency( &freq ) )
+ cpu_info->frequency = (double)freq.QuadPart;
+ }
+#else
+ cpu_info->frequency = 1;
+
+#ifdef __x86_64__
+ cpu_info->model = CV_PROC_EM64T;
+#elif defined __ia64__
+ cpu_info->model = CV_PROC_IA64;
+#elif !defined __i386__
+ cpu_info->model = CV_PROC_GENERIC;
+#else
+ cpu_info->model = CV_PROC_IA32_GENERIC;
+
+ // reading /proc/cpuinfo file (proc file system must be supported)
+ FILE *file = fopen( "/proc/cpuinfo", "r" );
+
+ if( file )
+ {
+ char buffer[1024];
+ int max_size = sizeof(buffer)-1;
+
+ for(;;)
+ {
+ const char* ptr = fgets( buffer, max_size, file );
+ if( !ptr )
+ break;
+ if( strncmp( buffer, "flags", 5 ) == 0 )
+ {
+ if( strstr( buffer, "mmx" ) && strstr( buffer, "cmov" ))
+ {
+ cpu_info->model = CV_PROC_IA32_WITH_MMX;
+ if( strstr( buffer, "xmm" ) || strstr( buffer, "sse" ))
+ {
+ cpu_info->model = CV_PROC_IA32_WITH_SSE;
+ if( strstr( buffer, "emm" ))
+ cpu_info->model = CV_PROC_IA32_WITH_SSE2;
+ }
+ }
+ }
+ else if( strncmp( buffer, "cpu MHz", 7 ) == 0 )
+ {
+ char* pos = strchr( buffer, ':' );
+ if( pos )
+ cpu_info->frequency = strtod( pos + 1, &pos );
+ }
+ }
+
+ fclose( file );
+ if( CV_GET_PROC_ARCH(cpu_info->model) != CV_PROC_IA32_GENERIC )
+ cpu_info->frequency = 1;
+ else
+ assert( cpu_info->frequency > 1 );
+ }
+#endif
+#endif
+}
+
+
+CV_INLINE const CvProcessorInfo*
+icvGetProcessorInfo()
+{
+ static CvProcessorInfo cpu_info;
+ static int init_cpu_info = 0;
+ if( !init_cpu_info )
+ {
+ icvInitProcessorInfo( &cpu_info );
+ init_cpu_info = 1;
+ }
+ return &cpu_info;
+}
+
+
+/****************************************************************************************/
+/* Make functions descriptions */
+/****************************************************************************************/
+
+#undef IPCVAPI_EX
+#define IPCVAPI_EX(type,func_name,names,modules,arg) \
+ { (void**)&func_name##_p, (void*)(size_t)-1, names, modules, 0 },
+
+#undef IPCVAPI_C_EX
+#define IPCVAPI_C_EX(type,func_name,names,modules,arg) \
+ { (void**)&func_name##_p, (void*)(size_t)-1, names, modules, 0 },
+
+static CvPluginFuncInfo cxcore_ipp_tab[] =
+{
+#undef _CXCORE_IPP_H_
+#include "_cxipp.h"
+#undef _CXCORE_IPP_H_
+ {0, 0, 0, 0, 0}
+};
+
+
+/*
+ determine processor type, load appropriate dll and
+ initialize all function pointers
+*/
+#if defined WIN32 || defined WIN64
+#define DLL_PREFIX ""
+#define DLL_SUFFIX ".dll"
+#else
+#define DLL_PREFIX "lib"
+#define DLL_SUFFIX ".so"
+#define LoadLibrary(name) dlopen(name, RTLD_LAZY)
+#define FreeLibrary(name) dlclose(name)
+#define GetProcAddress dlsym
+typedef void* HMODULE;
+#endif
+
+#if 0 /*def _DEBUG*/
+#define DLL_DEBUG_FLAG "d"
+#else
+#define DLL_DEBUG_FLAG ""
+#endif
+
+#define VERBOSE_LOADING 0
+
+#if VERBOSE_LOADING
+#define ICV_PRINTF(args) printf args; fflush(stdout)
+#else
+#define ICV_PRINTF(args)
+#endif
+
+typedef struct CvPluginInfo
+{
+ const char* basename;
+ HMODULE handle;
+ char name[100];
+}
+CvPluginInfo;
+
+static CvPluginInfo plugins[CV_PLUGIN_MAX];
+static CvModuleInfo cxcore_info = { 0, "cxcore", CV_VERSION, cxcore_ipp_tab };
+
+CvModuleInfo *CvModule::first = 0, *CvModule::last = 0;
+
+CvModule::CvModule( CvModuleInfo* _info )
+{
+ cvRegisterModule( _info );
+ info = last;
+}
+
+CvModule::~CvModule()
+{
+ if( info )
+ {
+ CvModuleInfo* p = first;
+ for( ; p != 0 && p->next != info; p = p->next )
+ ;
+ if( p )
+ p->next = info->next;
+ if( first == info )
+ first = info->next;
+ if( last == info )
+ last = p;
+ cvFree( &info );
+ info = 0;
+ }
+}
+
+static int
+icvUpdatePluginFuncTab( CvPluginFuncInfo* func_tab )
+{
+ int i, loaded_functions = 0;
+
+ // 1. reset pointers
+ for( i = 0; func_tab[i].func_addr != 0; i++ )
+ {
+ if( func_tab[i].default_func_addr == (void*)(size_t)-1 )
+ func_tab[i].default_func_addr = *func_tab[i].func_addr;
+ else
+ *func_tab[i].func_addr = func_tab[i].default_func_addr;
+ func_tab[i].loaded_from = 0;
+ }
+
+ // ippopencv substitutes all the other IPP modules
+ if( plugins[CV_PLUGIN_OPTCV].handle != 0 )
+ {
+ for( i = 2; i < CV_PLUGIN_MKL; i++ )
+ {
+ assert( plugins[i].handle == 0 );
+ plugins[i].handle = plugins[CV_PLUGIN_OPTCV].handle;
+ }
+ }
+
+ // 2. try to find corresponding functions in ipp* and reassign pointers to them
+ for( i = 0; func_tab[i].func_addr != 0; i++ )
+ {
+ #if defined _MSC_VER && _MSC_VER >= 1200
+ #pragma warning( disable: 4054 4055 ) /* converting pointers to code<->data */
+ #endif
+ char name[100];
+ int j = 0, idx = 0;
+
+ assert( func_tab[i].loaded_from == 0 );
+
+ if( func_tab[i].search_modules )
+ {
+ uchar* addr = 0;
+ const char* name_ptr = func_tab[i].func_names;
+
+ for( ; j < 10 && name_ptr; j++ )
+ {
+ const char* name_start = name_ptr;
+ const char* name_end;
+ while( !isalpha(name_start[0]) && name_start[0] != '\0' )
+ name_start++;
+ if( !name_start[0] )
+ name_start = 0;
+ name_end = name_start ? strchr( name_start, ',' ) : 0;
+ idx = (func_tab[i].search_modules / (1<<j*4)) % CV_PLUGIN_MAX;
+
+ if( plugins[idx].handle != 0 && name_start )
+ {
+ if( name_end != 0 )
+ {
+ strncpy( name, name_start, name_end - name_start );
+ name[name_end - name_start] = '\0';
+ }
+ else
+ strcpy( name, name_start );
+
+ addr = (uchar*)GetProcAddress( plugins[idx].handle, name );
+ if( addr )
+ break;
+ }
+ name_ptr = name_end;
+ }
+
+ if( addr )
+ {
+ /*#ifdef WIN32
+ while( *addr == 0xE9 )
+ addr += 5 + *((int*)(addr + 1));
+ #endif*/
+ *func_tab[i].func_addr = addr;
+ func_tab[i].loaded_from = idx; // store index of the module
+ // that contain the loaded function
+ loaded_functions++;
+ ICV_PRINTF(("%s: \t%s\n", name, plugins[idx].name ));
+ }
+
+ #if defined _MSC_VER && _MSC_VER >= 1200
+ #pragma warning( default: 4054 4055 )
+ #endif
+ }
+ }
+
+#if VERBOSE_LOADING
+ {
+ int not_loaded = 0;
+ ICV_PRINTF(("\nTotal loaded: %d\n\n", loaded_functions ));
+ printf( "***************************************************\nNot loaded ...\n\n" );
+ for( i = 0; func_tab[i].func_addr != 0; i++ )
+ if( !func_tab[i].loaded_from )
+ {
+ ICV_PRINTF(( "%s\n", func_tab[i].func_names ));
+ not_loaded++;
+ }
+
+ ICV_PRINTF(("\nTotal: %d\n", not_loaded ));
+ }
+#endif
+
+ if( plugins[CV_PLUGIN_OPTCV].handle != 0 )
+ {
+ for( i = 2; i < CV_PLUGIN_MKL; i++ )
+ plugins[i].handle = 0;
+ }
+
+ return loaded_functions;
+}
+
+
+CV_IMPL int
+cvRegisterModule( const CvModuleInfo* module )
+{
+ CvModuleInfo* module_copy = 0;
+
+ CV_FUNCNAME( "cvRegisterModule" );
+
+ __BEGIN__;
+
+ size_t name_len, version_len;
+
+ CV_ASSERT( module != 0 && module->name != 0 && module->version != 0 );
+
+ name_len = strlen(module->name);
+ version_len = strlen(module->version);
+
+ CV_CALL( module_copy = (CvModuleInfo*)cvAlloc( sizeof(*module_copy) +
+ name_len + 1 + version_len + 1 ));
+
+ *module_copy = *module;
+ module_copy->name = (char*)(module_copy + 1);
+ module_copy->version = (char*)(module_copy + 1) + name_len + 1;
+
+ memcpy( (void*)module_copy->name, module->name, name_len + 1 );
+ memcpy( (void*)module_copy->version, module->version, version_len + 1 );
+ module_copy->next = 0;
+
+ if( CvModule::first == 0 )
+ CvModule::first = module_copy;
+ else
+ CvModule::last->next = module_copy;
+ CvModule::last = module_copy;
+
+ if( CvModule::first == CvModule::last )
+ {
+ CV_CALL( cvUseOptimized(1));
+ }
+ else
+ {
+ CV_CALL( icvUpdatePluginFuncTab( module_copy->func_tab ));
+ }
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 && module_copy )
+ cvFree( &module_copy );
+
+ return module_copy ? 0 : -1;
+}
+
+
+CV_IMPL int
+cvUseOptimized( int load_flag )
+{
+ int i, loaded_modules = 0, loaded_functions = 0;
+ CvModuleInfo* module;
+ const CvProcessorInfo* cpu_info = icvGetProcessorInfo();
+ int arch = CV_GET_PROC_ARCH(cpu_info->model);
+
+ // TODO: implement some more elegant way
+ // to find the latest and the greatest IPP/MKL libraries
+ static const char* opencv_sfx[] = { "100", "099", "097", 0 };
+ static const char* ipp_sfx_ia32[] = { "-6.1", "-6.0", "-5.3", "-5.2", "-5.1", "", 0 };
+ static const char* ipp_sfx_ia64[] = { "64-6.1", "64-6.0", "64-5.3", "64-5.2", "64-5.1", "64", 0 };
+ static const char* ipp_sfx_em64t[] = { "em64t-6.1", "em64t-6.0", "em64t-5.3", "em64t-5.2", "em64t-5.1", "em64t", 0 };
+ static const char* mkl_sfx_ia32[] = { "p4", "p3", "def", 0 };
+ static const char* mkl_sfx_ia64[] = { "i2p", "itp", 0 };
+ static const char* mkl_sfx_em64t[] = { "def", 0 };
+ const char** ipp_suffix = arch == CV_PROC_IA64 ? ipp_sfx_ia64 :
+ arch == CV_PROC_EM64T ? ipp_sfx_em64t : ipp_sfx_ia32;
+ const char** mkl_suffix = arch == CV_PROC_IA64 ? mkl_sfx_ia64 :
+ arch == CV_PROC_EM64T ? mkl_sfx_em64t : mkl_sfx_ia32;
+
+ for( i = 0; i < CV_PLUGIN_MAX; i++ )
+ plugins[i].basename = 0;
+ plugins[CV_PLUGIN_NONE].basename = 0;
+ plugins[CV_PLUGIN_NONE].name[0] = '\0';
+ plugins[CV_PLUGIN_OPTCV].basename = "ippopencv";
+ plugins[CV_PLUGIN_IPPCV].basename = "ippcv";
+ plugins[CV_PLUGIN_IPPI].basename = "ippi";
+ plugins[CV_PLUGIN_IPPS].basename = "ipps";
+ plugins[CV_PLUGIN_IPPVM].basename = "ippvm";
+ plugins[CV_PLUGIN_IPPCC].basename = "ippcc";
+ plugins[CV_PLUGIN_MKL].basename = "mkl_";
+
+ // try to load optimized dlls
+ for( i = 1; i < CV_PLUGIN_MAX; i++ )
+ {
+ // unload previously loaded optimized modules
+ if( plugins[i].handle )
+ {
+ FreeLibrary( plugins[i].handle );
+ plugins[i].handle = 0;
+ }
+
+ // do not load regular IPP modules if the custom merged IPP module is already found.
+ if( i < CV_PLUGIN_MKL && load_flag && plugins[CV_PLUGIN_OPTCV].handle != 0 )
+ continue;
+
+ if( load_flag && plugins[i].basename &&
+ (arch == CV_PROC_IA32_GENERIC || arch == CV_PROC_IA64 || arch == CV_PROC_EM64T) )
+ {
+ const char** suffix = i == CV_PLUGIN_OPTCV ? opencv_sfx :
+ i < CV_PLUGIN_MKL ? ipp_suffix : mkl_suffix;
+ if( suffix == mkl_sfx_ia32 )
+ {
+ if( !(cpu_info->model & CV_PROC_IA32_WITH_SSE2) )
+ suffix++;
+ if( !(cpu_info->model & CV_PROC_IA32_WITH_SSE) )
+ suffix++;
+ }
+
+ for( ; *suffix != 0; suffix++ )
+ {
+ sprintf( plugins[i].name, DLL_PREFIX "%s%s" DLL_DEBUG_FLAG DLL_SUFFIX,
+ plugins[i].basename, *suffix );
+
+ ICV_PRINTF(("loading %s...\n", plugins[i].name ));
+ plugins[i].handle = LoadLibrary( plugins[i].name );
+ if( plugins[i].handle != 0 )
+ {
+ ICV_PRINTF(("%s loaded\n", plugins[i].name ));
+ loaded_modules++;
+ break;
+ }
+ #ifndef WIN32
+ // temporary workaround for MacOSX
+ sprintf( plugins[i].name, DLL_PREFIX "%s%s" DLL_DEBUG_FLAG ".dylib",
+ plugins[i].basename, *suffix );
+
+ ICV_PRINTF(("loading %s...\n", plugins[i].name ));
+ plugins[i].handle = LoadLibrary( plugins[i].name );
+ if( plugins[i].handle != 0 )
+ {
+ ICV_PRINTF(("%s loaded\n", plugins[i].name ));
+ loaded_modules++;
+ break;
+ }
+ #endif
+ }
+ }
+ }
+
+ for( module = CvModule::first; module != 0; module = module->next )
+ loaded_functions += icvUpdatePluginFuncTab( module->func_tab );
+
+ return loaded_functions;
+}
+
+CvModule cxcore_module( &cxcore_info );
+
+CV_IMPL void
+cvGetModuleInfo( const char* name, const char **version, const char **plugin_list )
+{
+ static char joint_verinfo[1024] = "";
+ static char plugin_list_buf[1024] = "";
+
+ CV_FUNCNAME( "cvGetLibraryInfo" );
+
+ if( version )
+ *version = 0;
+
+ if( plugin_list )
+ *plugin_list = 0;
+
+ __BEGIN__;
+
+ CvModuleInfo* module;
+
+ if( version )
+ {
+ if( name )
+ {
+ size_t i, name_len = strlen(name);
+
+ for( module = CvModule::first; module != 0; module = module->next )
+ {
+ if( strlen(module->name) == name_len )
+ {
+ for( i = 0; i < name_len; i++ )
+ {
+ int c0 = toupper(module->name[i]), c1 = toupper(name[i]);
+ if( c0 != c1 )
+ break;
+ }
+ if( i == name_len )
+ break;
+ }
+ }
+ if( !module )
+ CV_ERROR( CV_StsObjectNotFound, "The module is not found" );
+
+ *version = module->version;
+ }
+ else
+ {
+ char* ptr = joint_verinfo;
+
+ for( module = CvModule::first; module != 0; module = module->next )
+ {
+ sprintf( ptr, "%s: %s%s", module->name, module->version, module->next ? ", " : "" );
+ ptr += strlen(ptr);
+ }
+
+ *version = joint_verinfo;
+ }
+ }
+
+ if( plugin_list )
+ {
+ char* ptr = plugin_list_buf;
+ int i;
+
+ for( i = 0; i < CV_PLUGIN_MAX; i++ )
+ if( plugins[i].handle != 0 )
+ {
+ sprintf( ptr, "%s, ", plugins[i].name );
+ ptr += strlen(ptr);
+ }
+
+ if( ptr > plugin_list_buf )
+ {
+ ptr[-2] = '\0';
+ *plugin_list = plugin_list_buf;
+ }
+ else
+ *plugin_list = "";
+ }
+
+ __END__;
+}
+
+
+typedef int64 (CV_CDECL * rdtsc_func)(void);
+
+/* helper functions for RNG initialization and accurate time measurement */
+CV_IMPL int64 cvGetTickCount( void )
+{
+ const CvProcessorInfo* cpu_info = icvGetProcessorInfo();
+
+ if( cpu_info->frequency > 1 &&
+ CV_GET_PROC_ARCH(cpu_info->model) == CV_PROC_IA32_GENERIC )
+ {
+#ifdef MASM_INLINE_ASSEMBLY
+ #ifdef __BORLANDC__
+ __asm db 0fh
+ __asm db 31h
+ #else
+ __asm _emit 0x0f;
+ __asm _emit 0x31;
+ #endif
+#elif (defined __GNUC__ || defined CV_ICC) && defined __i386__
+ int64 t;
+ asm volatile (".byte 0xf; .byte 0x31" /* "rdtsc" */ : "=A" (t));
+ return t;
+#else
+ static const char code[] = "\x0f\x31\xc3";
+ rdtsc_func func = (rdtsc_func)(void*)code;
+ return func();
+#endif
+ }
+ else
+ {
+#if defined WIN32 || defined WIN64
+ LARGE_INTEGER counter;
+ QueryPerformanceCounter( &counter );
+ return (int64)counter.QuadPart;
+#else
+ struct timeval tv;
+ struct timezone tz;
+ gettimeofday( &tv, &tz );
+ return (int64)tv.tv_sec*1000000 + tv.tv_usec;
+#endif
+ }
+}
+
+CV_IMPL double cvGetTickFrequency()
+{
+ return icvGetProcessorInfo()->frequency;
+}
+
+
+static int icvNumThreads = 0;
+static int icvNumProcs = 0;
+
+CV_IMPL int cvGetNumThreads(void)
+{
+ if( !icvNumProcs )
+ cvSetNumThreads(0);
+ return icvNumThreads;
+}
+
+CV_IMPL void cvSetNumThreads( int threads )
+{
+ if( !icvNumProcs )
+ {
+#ifdef _OPENMP
+ icvNumProcs = omp_get_num_procs();
+ icvNumProcs = MIN( icvNumProcs, CV_MAX_THREADS );
+#else
+ icvNumProcs = 1;
+#endif
+ }
+
+#ifdef _OPENMP
+ if( threads <= 0 )
+ threads = icvNumProcs;
+ //else
+ // threads = MIN( threads, icvNumProcs );
+
+ icvNumThreads = threads;
+#else
+ icvNumThreads = 1;
+#endif
+}
+
+
+CV_IMPL int cvGetThreadNum(void)
+{
+#ifdef _OPENMP
+ return omp_get_thread_num();
+#else
+ return 0;
+#endif
+}
+
+
+/* End of file. */
diff --git a/cxcore/src/cxtables.cpp b/cxcore/src/cxtables.cpp
new file mode 100644
index 0000000..7d54465
--- /dev/null
+++ b/cxcore/src/cxtables.cpp
@@ -0,0 +1,210 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/* ////////////////////////////////////////////////////////////////////
+//
+// CvMat helper tables
+//
+// */
+
+#include "_cxcore.h"
+
+const signed char icvDepthToType[] =
+{
+ -1, -1, CV_8U, CV_8S, CV_16U, CV_16S, -1, -1,
+ CV_32F, CV_32S, -1, -1, -1, -1, -1, -1, CV_64F, -1
+};
+
+const float icv8x32fTab[] =
+{
+ -128.f, -127.f, -126.f, -125.f, -124.f, -123.f, -122.f, -121.f,
+ -120.f, -119.f, -118.f, -117.f, -116.f, -115.f, -114.f, -113.f,
+ -112.f, -111.f, -110.f, -109.f, -108.f, -107.f, -106.f, -105.f,
+ -104.f, -103.f, -102.f, -101.f, -100.f, -99.f, -98.f, -97.f,
+ -96.f, -95.f, -94.f, -93.f, -92.f, -91.f, -90.f, -89.f,
+ -88.f, -87.f, -86.f, -85.f, -84.f, -83.f, -82.f, -81.f,
+ -80.f, -79.f, -78.f, -77.f, -76.f, -75.f, -74.f, -73.f,
+ -72.f, -71.f, -70.f, -69.f, -68.f, -67.f, -66.f, -65.f,
+ -64.f, -63.f, -62.f, -61.f, -60.f, -59.f, -58.f, -57.f,
+ -56.f, -55.f, -54.f, -53.f, -52.f, -51.f, -50.f, -49.f,
+ -48.f, -47.f, -46.f, -45.f, -44.f, -43.f, -42.f, -41.f,
+ -40.f, -39.f, -38.f, -37.f, -36.f, -35.f, -34.f, -33.f,
+ -32.f, -31.f, -30.f, -29.f, -28.f, -27.f, -26.f, -25.f,
+ -24.f, -23.f, -22.f, -21.f, -20.f, -19.f, -18.f, -17.f,
+ -16.f, -15.f, -14.f, -13.f, -12.f, -11.f, -10.f, -9.f,
+ -8.f, -7.f, -6.f, -5.f, -4.f, -3.f, -2.f, -1.f,
+ 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f,
+ 8.f, 9.f, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f,
+ 16.f, 17.f, 18.f, 19.f, 20.f, 21.f, 22.f, 23.f,
+ 24.f, 25.f, 26.f, 27.f, 28.f, 29.f, 30.f, 31.f,
+ 32.f, 33.f, 34.f, 35.f, 36.f, 37.f, 38.f, 39.f,
+ 40.f, 41.f, 42.f, 43.f, 44.f, 45.f, 46.f, 47.f,
+ 48.f, 49.f, 50.f, 51.f, 52.f, 53.f, 54.f, 55.f,
+ 56.f, 57.f, 58.f, 59.f, 60.f, 61.f, 62.f, 63.f,
+ 64.f, 65.f, 66.f, 67.f, 68.f, 69.f, 70.f, 71.f,
+ 72.f, 73.f, 74.f, 75.f, 76.f, 77.f, 78.f, 79.f,
+ 80.f, 81.f, 82.f, 83.f, 84.f, 85.f, 86.f, 87.f,
+ 88.f, 89.f, 90.f, 91.f, 92.f, 93.f, 94.f, 95.f,
+ 96.f, 97.f, 98.f, 99.f, 100.f, 101.f, 102.f, 103.f,
+ 104.f, 105.f, 106.f, 107.f, 108.f, 109.f, 110.f, 111.f,
+ 112.f, 113.f, 114.f, 115.f, 116.f, 117.f, 118.f, 119.f,
+ 120.f, 121.f, 122.f, 123.f, 124.f, 125.f, 126.f, 127.f,
+ 128.f, 129.f, 130.f, 131.f, 132.f, 133.f, 134.f, 135.f,
+ 136.f, 137.f, 138.f, 139.f, 140.f, 141.f, 142.f, 143.f,
+ 144.f, 145.f, 146.f, 147.f, 148.f, 149.f, 150.f, 151.f,
+ 152.f, 153.f, 154.f, 155.f, 156.f, 157.f, 158.f, 159.f,
+ 160.f, 161.f, 162.f, 163.f, 164.f, 165.f, 166.f, 167.f,
+ 168.f, 169.f, 170.f, 171.f, 172.f, 173.f, 174.f, 175.f,
+ 176.f, 177.f, 178.f, 179.f, 180.f, 181.f, 182.f, 183.f,
+ 184.f, 185.f, 186.f, 187.f, 188.f, 189.f, 190.f, 191.f,
+ 192.f, 193.f, 194.f, 195.f, 196.f, 197.f, 198.f, 199.f,
+ 200.f, 201.f, 202.f, 203.f, 204.f, 205.f, 206.f, 207.f,
+ 208.f, 209.f, 210.f, 211.f, 212.f, 213.f, 214.f, 215.f,
+ 216.f, 217.f, 218.f, 219.f, 220.f, 221.f, 222.f, 223.f,
+ 224.f, 225.f, 226.f, 227.f, 228.f, 229.f, 230.f, 231.f,
+ 232.f, 233.f, 234.f, 235.f, 236.f, 237.f, 238.f, 239.f,
+ 240.f, 241.f, 242.f, 243.f, 244.f, 245.f, 246.f, 247.f,
+ 248.f, 249.f, 250.f, 251.f, 252.f, 253.f, 254.f, 255.f
+};
+
+/* [-255..255].^2 */
+const ushort icv8x16uSqrTab[] =
+{
+ 65025, 64516, 64009, 63504, 63001, 62500, 62001, 61504, 61009, 60516, 60025, 59536,
+ 59049, 58564, 58081, 57600, 57121, 56644, 56169, 55696, 55225, 54756, 54289, 53824,
+ 53361, 52900, 52441, 51984, 51529, 51076, 50625, 50176, 49729, 49284, 48841, 48400,
+ 47961, 47524, 47089, 46656, 46225, 45796, 45369, 44944, 44521, 44100, 43681, 43264,
+ 42849, 42436, 42025, 41616, 41209, 40804, 40401, 40000, 39601, 39204, 38809, 38416,
+ 38025, 37636, 37249, 36864, 36481, 36100, 35721, 35344, 34969, 34596, 34225, 33856,
+ 33489, 33124, 32761, 32400, 32041, 31684, 31329, 30976, 30625, 30276, 29929, 29584,
+ 29241, 28900, 28561, 28224, 27889, 27556, 27225, 26896, 26569, 26244, 25921, 25600,
+ 25281, 24964, 24649, 24336, 24025, 23716, 23409, 23104, 22801, 22500, 22201, 21904,
+ 21609, 21316, 21025, 20736, 20449, 20164, 19881, 19600, 19321, 19044, 18769, 18496,
+ 18225, 17956, 17689, 17424, 17161, 16900, 16641, 16384, 16129, 15876, 15625, 15376,
+ 15129, 14884, 14641, 14400, 14161, 13924, 13689, 13456, 13225, 12996, 12769, 12544,
+ 12321, 12100, 11881, 11664, 11449, 11236, 11025, 10816, 10609, 10404, 10201, 10000,
+ 9801, 9604, 9409, 9216, 9025, 8836, 8649, 8464, 8281, 8100, 7921, 7744,
+ 7569, 7396, 7225, 7056, 6889, 6724, 6561, 6400, 6241, 6084, 5929, 5776,
+ 5625, 5476, 5329, 5184, 5041, 4900, 4761, 4624, 4489, 4356, 4225, 4096,
+ 3969, 3844, 3721, 3600, 3481, 3364, 3249, 3136, 3025, 2916, 2809, 2704,
+ 2601, 2500, 2401, 2304, 2209, 2116, 2025, 1936, 1849, 1764, 1681, 1600,
+ 1521, 1444, 1369, 1296, 1225, 1156, 1089, 1024, 961, 900, 841, 784,
+ 729, 676, 625, 576, 529, 484, 441, 400, 361, 324, 289, 256,
+ 225, 196, 169, 144, 121, 100, 81, 64, 49, 36, 25, 16,
+ 9, 4, 1, 0, 1, 4, 9, 16, 25, 36, 49, 64,
+ 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400,
+ 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, 1024,
+ 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936,
+ 2025, 2116, 2209, 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136,
+ 3249, 3364, 3481, 3600, 3721, 3844, 3969, 4096, 4225, 4356, 4489, 4624,
+ 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, 6400,
+ 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464,
+ 8649, 8836, 9025, 9216, 9409, 9604, 9801, 10000, 10201, 10404, 10609, 10816,
+ 11025, 11236, 11449, 11664, 11881, 12100, 12321, 12544, 12769, 12996, 13225, 13456,
+ 13689, 13924, 14161, 14400, 14641, 14884, 15129, 15376, 15625, 15876, 16129, 16384,
+ 16641, 16900, 17161, 17424, 17689, 17956, 18225, 18496, 18769, 19044, 19321, 19600,
+ 19881, 20164, 20449, 20736, 21025, 21316, 21609, 21904, 22201, 22500, 22801, 23104,
+ 23409, 23716, 24025, 24336, 24649, 24964, 25281, 25600, 25921, 26244, 26569, 26896,
+ 27225, 27556, 27889, 28224, 28561, 28900, 29241, 29584, 29929, 30276, 30625, 30976,
+ 31329, 31684, 32041, 32400, 32761, 33124, 33489, 33856, 34225, 34596, 34969, 35344,
+ 35721, 36100, 36481, 36864, 37249, 37636, 38025, 38416, 38809, 39204, 39601, 40000,
+ 40401, 40804, 41209, 41616, 42025, 42436, 42849, 43264, 43681, 44100, 44521, 44944,
+ 45369, 45796, 46225, 46656, 47089, 47524, 47961, 48400, 48841, 49284, 49729, 50176,
+ 50625, 51076, 51529, 51984, 52441, 52900, 53361, 53824, 54289, 54756, 55225, 55696,
+ 56169, 56644, 57121, 57600, 58081, 58564, 59049, 59536, 60025, 60516, 61009, 61504,
+ 62001, 62500, 63001, 63504, 64009, 64516, 65025
+};
+
+const uchar icvSaturate8u[] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+ 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255
+};
+
+
+/* End of file. */
diff --git a/cxcore/src/cxutils.cpp b/cxcore/src/cxutils.cpp
new file mode 100644
index 0000000..fa4d166
--- /dev/null
+++ b/cxcore/src/cxutils.cpp
@@ -0,0 +1,1206 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_cxcore.h"
+
+CV_IMPL void
+cvKMeans2( const CvArr* samples_arr, int cluster_count,
+ CvArr* labels_arr, CvTermCriteria termcrit )
+{
+ CvMat* centers = 0;
+ CvMat* old_centers = 0;
+ CvMat* counters = 0;
+
+ CV_FUNCNAME( "cvKMeans2" );
+
+ __BEGIN__;
+
+ CvMat samples_stub, labels_stub;
+ CvMat* samples = (CvMat*)samples_arr;
+ CvMat* labels = (CvMat*)labels_arr;
+ CvMat* temp = 0;
+ CvRNG rng = CvRNG(-1);
+ int i, j, k, sample_count, dims;
+ int ids_delta, iter;
+ double max_dist;
+
+ if( !CV_IS_MAT( samples ))
+ CV_CALL( samples = cvGetMat( samples, &samples_stub ));
+
+ if( !CV_IS_MAT( labels ))
+ CV_CALL( labels = cvGetMat( labels, &labels_stub ));
+
+ if( cluster_count < 1 )
+ CV_ERROR( CV_StsOutOfRange, "Number of clusters should be positive" );
+
+ if( CV_MAT_DEPTH(samples->type) != CV_32F || CV_MAT_TYPE(labels->type) != CV_32SC1 )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "samples should be floating-point matrix, cluster_idx - integer vector" );
+
+ if( (labels->rows != 1 && (labels->cols != 1 || !CV_IS_MAT_CONT(labels->type))) ||
+ labels->rows + labels->cols - 1 != samples->rows )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "cluster_idx should be 1D vector of the same number of elements as samples' number of rows" );
+
+ CV_CALL( termcrit = cvCheckTermCriteria( termcrit, 1e-6, 100 ));
+
+ termcrit.epsilon *= termcrit.epsilon;
+ sample_count = samples->rows;
+
+ if( cluster_count > sample_count )
+ cluster_count = sample_count;
+
+ dims = samples->cols*CV_MAT_CN(samples->type);
+ ids_delta = labels->step ? labels->step/(int)sizeof(int) : 1;
+
+ CV_CALL( centers = cvCreateMat( cluster_count, dims, CV_64FC1 ));
+ CV_CALL( old_centers = cvCreateMat( cluster_count, dims, CV_64FC1 ));
+ CV_CALL( counters = cvCreateMat( 1, cluster_count, CV_32SC1 ));
+
+ // init centers
+ for( i = 0; i < sample_count; i++ )
+ labels->data.i[i] = cvRandInt(&rng) % cluster_count;
+
+ counters->cols = cluster_count; // cut down counters
+ max_dist = termcrit.epsilon*2;
+
+ for( iter = 0; iter < termcrit.max_iter; iter++ )
+ {
+ // computer centers
+ cvZero( centers );
+ cvZero( counters );
+
+ for( i = 0; i < sample_count; i++ )
+ {
+ float* s = (float*)(samples->data.ptr + i*samples->step);
+ k = labels->data.i[i*ids_delta];
+ double* c = (double*)(centers->data.ptr + k*centers->step);
+ for( j = 0; j <= dims - 4; j += 4 )
+ {
+ double t0 = c[j] + s[j];
+ double t1 = c[j+1] + s[j+1];
+
+ c[j] = t0;
+ c[j+1] = t1;
+
+ t0 = c[j+2] + s[j+2];
+ t1 = c[j+3] + s[j+3];
+
+ c[j+2] = t0;
+ c[j+3] = t1;
+ }
+ for( ; j < dims; j++ )
+ c[j] += s[j];
+ counters->data.i[k]++;
+ }
+
+ if( iter > 0 )
+ max_dist = 0;
+
+ for( k = 0; k < cluster_count; k++ )
+ {
+ double* c = (double*)(centers->data.ptr + k*centers->step);
+ if( counters->data.i[k] != 0 )
+ {
+ double scale = 1./counters->data.i[k];
+ for( j = 0; j < dims; j++ )
+ c[j] *= scale;
+ }
+ else
+ {
+ i = cvRandInt( &rng ) % sample_count;
+ float* s = (float*)(samples->data.ptr + i*samples->step);
+ for( j = 0; j < dims; j++ )
+ c[j] = s[j];
+ }
+
+ if( iter > 0 )
+ {
+ double dist = 0;
+ double* c_o = (double*)(old_centers->data.ptr + k*old_centers->step);
+ for( j = 0; j < dims; j++ )
+ {
+ double t = c[j] - c_o[j];
+ dist += t*t;
+ }
+ if( max_dist < dist )
+ max_dist = dist;
+ }
+ }
+
+ // assign labels
+ for( i = 0; i < sample_count; i++ )
+ {
+ float* s = (float*)(samples->data.ptr + i*samples->step);
+ int k_best = 0;
+ double min_dist = DBL_MAX;
+
+ for( k = 0; k < cluster_count; k++ )
+ {
+ double* c = (double*)(centers->data.ptr + k*centers->step);
+ double dist = 0;
+
+ j = 0;
+ for( ; j <= dims - 4; j += 4 )
+ {
+ double t0 = c[j] - s[j];
+ double t1 = c[j+1] - s[j+1];
+ dist += t0*t0 + t1*t1;
+ t0 = c[j+2] - s[j+2];
+ t1 = c[j+3] - s[j+3];
+ dist += t0*t0 + t1*t1;
+ }
+
+ for( ; j < dims; j++ )
+ {
+ double t = c[j] - s[j];
+ dist += t*t;
+ }
+
+ if( min_dist > dist )
+ {
+ min_dist = dist;
+ k_best = k;
+ }
+ }
+
+ labels->data.i[i*ids_delta] = k_best;
+ }
+
+ if( max_dist < termcrit.epsilon )
+ break;
+
+ CV_SWAP( centers, old_centers, temp );
+ }
+
+ cvZero( counters );
+ for( i = 0; i < sample_count; i++ )
+ counters->data.i[labels->data.i[i]]++;
+
+ // ensure that we do not have empty clusters
+ for( k = 0; k < cluster_count; k++ )
+ if( counters->data.i[k] == 0 )
+ for(;;)
+ {
+ i = cvRandInt(&rng) % sample_count;
+ j = labels->data.i[i];
+ if( counters->data.i[j] > 1 )
+ {
+ labels->data.i[i] = k;
+ counters->data.i[j]--;
+ counters->data.i[k]++;
+ break;
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &centers );
+ cvReleaseMat( &old_centers );
+ cvReleaseMat( &counters );
+}
+
+
+/*
+ Finds real roots of cubic, quadratic or linear equation.
+ The original code has been taken from Ken Turkowski web page
+ (http://www.worldserver.com/turk/opensource/) and adopted for OpenCV.
+ Here is the copyright notice.
+
+ -----------------------------------------------------------------------
+ Copyright (C) 1978-1999 Ken Turkowski. <turk@computer.org>
+
+ All rights reserved.
+
+ Warranty Information
+ Even though I have reviewed this software, I make no warranty
+ or representation, either express or implied, with respect to this
+ software, its quality, accuracy, merchantability, or fitness for a
+ particular purpose. As a result, this software is provided "as is,"
+ and you, its user, are assuming the entire risk as to its quality
+ and accuracy.
+
+ This code may be used and freely distributed as long as it includes
+ this copyright notice and the above warranty information.
+ -----------------------------------------------------------------------
+*/
+CV_IMPL int
+cvSolveCubic( const CvMat* coeffs, CvMat* roots )
+{
+ int n = 0;
+
+ CV_FUNCNAME( "cvSolveCubic" );
+
+ __BEGIN__;
+
+ double a0 = 1., a1, a2, a3;
+ double x0 = 0., x1 = 0., x2 = 0.;
+ int step = 1, coeff_count;
+
+ if( !CV_IS_MAT(coeffs) )
+ CV_ERROR( !coeffs ? CV_StsNullPtr : CV_StsBadArg, "Input parameter is not a valid matrix" );
+
+ if( !CV_IS_MAT(roots) )
+ CV_ERROR( !roots ? CV_StsNullPtr : CV_StsBadArg, "Output parameter is not a valid matrix" );
+
+ if( (CV_MAT_TYPE(coeffs->type) != CV_32FC1 && CV_MAT_TYPE(coeffs->type) != CV_64FC1) ||
+ (CV_MAT_TYPE(roots->type) != CV_32FC1 && CV_MAT_TYPE(roots->type) != CV_64FC1) )
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "Both matrices should be floating-point (single or double precision)" );
+
+ coeff_count = coeffs->rows + coeffs->cols - 1;
+
+ if( (coeffs->rows != 1 && coeffs->cols != 1) || (coeff_count != 3 && coeff_count != 4) )
+ CV_ERROR( CV_StsBadSize,
+ "The matrix of coefficients must be 1-dimensional vector of 3 or 4 elements" );
+
+ if( (roots->rows != 1 && roots->cols != 1) ||
+ roots->rows + roots->cols - 1 != 3 )
+ CV_ERROR( CV_StsBadSize,
+ "The matrix of roots must be 1-dimensional vector of 3 elements" );
+
+ if( CV_MAT_TYPE(coeffs->type) == CV_32FC1 )
+ {
+ const float* c = coeffs->data.fl;
+ if( coeffs->rows > 1 )
+ step = coeffs->step/sizeof(c[0]);
+ if( coeff_count == 4 )
+ a0 = c[0], c += step;
+ a1 = c[0];
+ a2 = c[step];
+ a3 = c[step*2];
+ }
+ else
+ {
+ const double* c = coeffs->data.db;
+ if( coeffs->rows > 1 )
+ step = coeffs->step/sizeof(c[0]);
+ if( coeff_count == 4 )
+ a0 = c[0], c += step;
+ a1 = c[0];
+ a2 = c[step];
+ a3 = c[step*2];
+ }
+
+ if( a0 == 0 )
+ {
+ if( a1 == 0 )
+ {
+ if( a2 == 0 )
+ n = a3 == 0 ? -1 : 0;
+ else
+ {
+ // linear equation
+ x0 = a3/a2;
+ n = 1;
+ }
+ }
+ else
+ {
+ // quadratic equation
+ double d = a2*a2 - 4*a1*a3;
+ if( d >= 0 )
+ {
+ d = sqrt(d);
+ double q = (-a2 + (a2 < 0 ? -d : d)) * 0.5;
+ x0 = q / a1;
+ x1 = a3 / q;
+ n = d > 0 ? 2 : 1;
+ }
+ }
+ }
+ else
+ {
+ a0 = 1./a0;
+ a1 *= a0;
+ a2 *= a0;
+ a3 *= a0;
+
+ double Q = (a1 * a1 - 3 * a2) * (1./9);
+ double R = (2 * a1 * a1 * a1 - 9 * a1 * a2 + 27 * a3) * (1./54);
+ double Qcubed = Q * Q * Q;
+ double d = Qcubed - R * R;
+
+ if( d >= 0 )
+ {
+ double theta = acos(R / sqrt(Qcubed));
+ double sqrtQ = sqrt(Q);
+ double t0 = -2 * sqrtQ;
+ double t1 = theta * (1./3);
+ double t2 = a1 * (1./3);
+ x0 = t0 * cos(t1) - t2;
+ x1 = t0 * cos(t1 + (2.*CV_PI/3)) - t2;
+ x2 = t0 * cos(t1 + (4.*CV_PI/3)) - t2;
+ n = 3;
+ }
+ else
+ {
+ double e;
+ d = sqrt(-d);
+ e = pow(d + fabs(R), 0.333333333333);
+ if( R > 0 )
+ e = -e;
+ x0 = (e + Q / e) - a1 * (1./3);
+ n = 1;
+ }
+ }
+
+ step = 1;
+
+ if( CV_MAT_TYPE(roots->type) == CV_32FC1 )
+ {
+ float* r = roots->data.fl;
+ if( roots->rows > 1 )
+ step = roots->step/sizeof(r[0]);
+ r[0] = (float)x0;
+ r[step] = (float)x1;
+ r[step*2] = (float)x2;
+ }
+ else
+ {
+ double* r = roots->data.db;
+ if( roots->rows > 1 )
+ step = roots->step/sizeof(r[0]);
+ r[0] = x0;
+ r[step] = x1;
+ r[step*2] = x2;
+ }
+
+ __END__;
+
+ return n;
+}
+
+
+/*
+ Finds real and complex roots of polynomials of any degree with real
+ coefficients. The original code has been taken from Ken Turkowski's web
+ page (http://www.worldserver.com/turk/opensource/) and adopted for OpenCV.
+ Here is the copyright notice.
+
+ -----------------------------------------------------------------------
+ Copyright (C) 1981-1999 Ken Turkowski. <turk@computer.org>
+
+ All rights reserved.
+
+ Warranty Information
+ Even though I have reviewed this software, I make no warranty
+ or representation, either express or implied, with respect to this
+ software, its quality, accuracy, merchantability, or fitness for a
+ particular purpose. As a result, this software is provided "as is,"
+ and you, its user, are assuming the entire risk as to its quality
+ and accuracy.
+
+ This code may be used and freely distributed as long as it includes
+ this copyright notice and the above warranty information.
+*/
+
+
+/*******************************************************************************
+ * FindPolynomialRoots
+ *
+ * The Bairstow and Newton correction formulae are used for a simultaneous
+ * linear and quadratic iterated synthetic division. The coefficients of
+ * a polynomial of degree n are given as a[i] (i=0,i,..., n) where a[0] is
+ * the constant term. The coefficients are scaled by dividing them by
+ * their geometric mean. The Bairstow or Newton iteration method will
+ * nearly always converge to the number of figures carried, fig, either to
+ * root values or to their reciprocals. If the simultaneous Newton and
+ * Bairstow iteration fails to converge on root values or their
+ * reciprocals in maxiter iterations, the convergence requirement will be
+ * successively reduced by one decimal figure. This program anticipates
+ * and protects against loss of significance in the quadratic synthetic
+ * division. (Refer to "On Programming the Numerical Solution of
+ * Polynomial Equations," by K. W. Ellenberger, Commun. ACM 3 (Dec. 1960),
+ * 644-647.) The real and imaginary part of each root is stated as u[i]
+ * and v[i], respectively.
+ *
+ * ACM algorithm #30 - Numerical Solution of the Polynomial Equation
+ * K. W. Ellenberger
+ * Missle Division, North American Aviation, Downey, California
+ * Converted to C, modified, optimized, and structured by
+ * Ken Turkowski
+ * CADLINC, Inc., Palo Alto, California
+ *******************************************************************************/
+
+#define MAXN 16
+
+static void icvFindPolynomialRoots(const double *a, double *u, int n, int maxiter, int fig)
+{
+ int i;
+ int j;
+ double h[MAXN + 3], b[MAXN + 3], c[MAXN + 3], d[MAXN + 3], e[MAXN + 3];
+ // [-2 : n]
+ double K, ps, qs, pt, qt, s, rev, r = 0;
+ int t;
+ double p = 0, q = 0, qq;
+
+ // Zero elements with negative indices
+ b[2 + -1] = b[2 + -2] =
+ c[2 + -1] = c[2 + -2] =
+ d[2 + -1] = d[2 + -2] =
+ e[2 + -1] = e[2 + -2] =
+ h[2 + -1] = h[2 + -2] = 0.0;
+
+ // Copy polynomial coefficients to working storage
+ for (j = n; j >= 0; j--)
+ h[2 + j] = *a++; // Note reversal of coefficients
+
+ t = 1;
+ K = pow(10.0, (double)(fig)); // Relative accuracy
+
+ for (; h[2 + n] == 0.0; n--) { // Look for zero high-order coeff.
+ *u++ = 0.0;
+ *u++ = 0.0;
+ }
+
+ INIT:
+ if (n == 0)
+ return;
+
+ ps = qs = pt = qt = s = 0.0;
+ rev = 1.0;
+ K = pow(10.0, (double)(fig));
+
+ if (n == 1) {
+ r = -h[2 + 1] / h[2 + 0];
+ goto LINEAR;
+ }
+
+ for (j = n; j >= 0; j--) // Find geometric mean of coeff's
+ if (h[2 + j] != 0.0)
+ s += log(fabs(h[2 + j]));
+ s = exp(s / (n + 1));
+
+ for (j = n; j >= 0; j--) // Normalize coeff's by mean
+ h[2 + j] /= s;
+
+ if (fabs(h[2 + 1] / h[2 + 0]) < fabs(h[2 + n - 1] / h[2 + n])) {
+ REVERSE:
+ t = -t;
+ for (j = (n - 1) / 2; j >= 0; j--) {
+ s = h[2 + j];
+ h[2 + j] = h[2 + n - j];
+ h[2 + n - j] = s;
+ }
+ }
+ if (qs != 0.0) {
+ p = ps;
+ q = qs;
+ } else {
+ if (h[2 + n - 2] == 0.0) {
+ q = 1.0;
+ p = -2.0;
+ } else {
+ q = h[2 + n] / h[2 + n - 2];
+ p = (h[2 + n - 1] - q * h[2 + n - 3]) / h[2 + n - 2];
+ }
+ if (n == 2)
+ goto QADRTIC;
+ r = 0.0;
+ }
+ ITERATE:
+ for (i = maxiter; i > 0; i--) {
+
+ for (j = 0; j <= n; j++) { // BAIRSTOW
+ b[2 + j] = h[2 + j] - p * b[2 + j - 1] - q * b[2 + j - 2];
+ c[2 + j] = b[2 + j] - p * c[2 + j - 1] - q * c[2 + j - 2];
+ }
+ if ((h[2 + n - 1] != 0.0) && (b[2 + n - 1] != 0.0)) {
+ if (fabs(h[2 + n - 1] / b[2 + n - 1]) >= K) {
+ b[2 + n] = h[2 + n] - q * b[2 + n - 2];
+ }
+ if (b[2 + n] == 0.0)
+ goto QADRTIC;
+ if (K < fabs(h[2 + n] / b[2 + n]))
+ goto QADRTIC;
+ }
+
+ for (j = 0; j <= n; j++) { // NEWTON
+ d[2 + j] = h[2 + j] + r * d[2 + j - 1]; // Calculate polynomial at r
+ e[2 + j] = d[2 + j] + r * e[2 + j - 1]; // Calculate derivative at r
+ }
+ if (d[2 + n] == 0.0)
+ goto LINEAR;
+ if (K < fabs(h[2 + n] / d[2 + n]))
+ goto LINEAR;
+
+ c[2 + n - 1] = -p * c[2 + n - 2] - q * c[2 + n - 3];
+ s = c[2 + n - 2] * c[2 + n - 2] - c[2 + n - 1] * c[2 + n - 3];
+ if (s == 0.0) {
+ p -= 2.0;
+ q *= (q + 1.0);
+ } else {
+ p += (b[2 + n - 1] * c[2 + n - 2] - b[2 + n] * c[2 + n - 3]) / s;
+ q += (-b[2 + n - 1] * c[2 + n - 1] + b[2 + n] * c[2 + n - 2]) / s;
+ }
+ if (e[2 + n - 1] == 0.0)
+ r -= 1.0; // Minimum step
+ else
+ r -= d[2 + n] / e[2 + n - 1]; // Newton's iteration
+ }
+ ps = pt;
+ qs = qt;
+ pt = p;
+ qt = q;
+ if (rev < 0.0)
+ K /= 10.0;
+ rev = -rev;
+ goto REVERSE;
+
+ LINEAR:
+ if (t < 0)
+ r = 1.0 / r;
+ n--;
+ *u++ = r;
+ *u++ = 0.0;
+
+ for (j = n; j >= 0; j--) { // Polynomial deflation by lin-nomial
+ if ((d[2 + j] != 0.0) && (fabs(h[2 + j] / d[2 + j]) < K))
+ h[2 + j] = d[2 + j];
+ else
+ h[2 + j] = 0.0;
+ }
+
+ if (n == 0)
+ return;
+ goto ITERATE;
+
+ QADRTIC:
+ if (t < 0) {
+ p /= q;
+ q = 1.0 / q;
+ }
+ n -= 2;
+
+ if (0.0 < (q - (p * p / 4.0))) { // Two complex roots
+ s = sqrt(q - (p * p / 4.0));
+ *u++ = -p / 2.0;
+ *u++ = s;
+ *u++ = -p / 2.0;
+ *u++ = -s;
+ } else { // Two real roots
+ s = sqrt(((p * p / 4.0)) - q);
+ if (p < 0.0)
+ *u++ = qq = -p / 2.0 + s;
+ else
+ *u++ = qq = -p / 2.0 - s;
+ *u++ = 0.0;
+ *u++ = q / qq;
+ *u++ = 0.0;
+ }
+
+ for (j = n; j >= 0; j--) { // Polynomial deflation by quadratic
+ if ((b[2 + j] != 0.0) && (fabs(h[2 + j] / b[2 + j]) < K))
+ h[2 + j] = b[2 + j];
+ else
+ h[2 + j] = 0.0;
+ }
+ goto INIT;
+}
+
+#undef MAXN
+
+void cvSolvePoly(const CvMat* a, CvMat *r, int maxiter, int fig)
+{
+ __BEGIN__;
+
+ int m, n;
+ double *ad = 0, *rd = 0;
+
+ CV_FUNCNAME("cvSolvePoly");
+
+ if (CV_MAT_TYPE(a->type) != CV_32FC1 &&
+ CV_MAT_TYPE(a->type) != CV_64FC1)
+ CV_ERROR(CV_StsUnsupportedFormat, "coeffs must be either CV_32FC1 or CV_64FC1");
+ if (CV_MAT_TYPE(r->type) != CV_32FC2 &&
+ CV_MAT_TYPE(r->type) != CV_64FC2)
+ CV_ERROR(CV_StsUnsupportedFormat, "roots must be either CV_32FC2 or CV_64FC2");
+ m = a->rows * a->cols;
+ n = r->rows * r->cols;
+
+ if (m - 1 != n)
+ CV_ERROR(CV_StsUnmatchedFormats, "must have n + 1 coefficients");
+
+ if( CV_MAT_TYPE(a->type) == CV_32F || !CV_IS_MAT_CONT(a->type))
+ {
+ ad = (double*)cvStackAlloc(m*sizeof(ad[0]));
+ CvMat _a = cvMat( a->rows, a->cols, CV_64F, ad );
+ cvConvert( a, &_a );
+ }
+ else
+ ad = a->data.db;
+
+ if( CV_MAT_TYPE(r->type) == CV_32F || !CV_IS_MAT_CONT(r->type))
+ rd = (double*)cvStackAlloc(n*sizeof(ad[0]));
+ else
+ rd = r->data.db;
+
+ icvFindPolynomialRoots( ad, rd, n, maxiter, fig);
+ if( rd != r->data.db )
+ {
+ CvMat _r = cvMat( r->rows, r->cols, CV_64F, rd );
+ cvConvert( &_r, r );
+ }
+
+ __END__;
+}
+
+
+CV_IMPL void cvNormalize( const CvArr* src, CvArr* dst,
+ double a, double b, int norm_type, const CvArr* mask )
+{
+ CvMat* tmp = 0;
+
+ CV_FUNCNAME( "cvNormalize" );
+
+ __BEGIN__;
+
+ double scale, shift;
+
+ if( norm_type == CV_MINMAX )
+ {
+ double smin = 0, smax = 0;
+ double dmin = MIN( a, b ), dmax = MAX( a, b );
+ cvMinMaxLoc( src, &smin, &smax, 0, 0, mask );
+ scale = (dmax - dmin)*(smax - smin > DBL_EPSILON ? 1./(smax - smin) : 0);
+ shift = dmin - smin*scale;
+ }
+ else if( norm_type == CV_L2 || norm_type == CV_L1 || norm_type == CV_C )
+ {
+ CvMat *s = (CvMat*)src, *d = (CvMat*)dst;
+
+ if( CV_IS_MAT(s) && CV_IS_MAT(d) && CV_IS_MAT_CONT(s->type & d->type) &&
+ CV_ARE_TYPES_EQ(s,d) && CV_ARE_SIZES_EQ(s,d) && !mask &&
+ s->cols*s->rows <= CV_MAX_INLINE_MAT_OP_SIZE*CV_MAX_INLINE_MAT_OP_SIZE )
+ {
+ int i, len = s->cols*s->rows;
+ double norm = 0, v;
+
+ if( CV_MAT_TYPE(s->type) == CV_32FC1 )
+ {
+ const float* sptr = s->data.fl;
+ float* dptr = d->data.fl;
+
+ if( norm_type == CV_L2 )
+ {
+ for( i = 0; i < len; i++ )
+ {
+ v = sptr[i];
+ norm += v*v;
+ }
+ norm = sqrt(norm);
+ }
+ else if( norm_type == CV_L1 )
+ for( i = 0; i < len; i++ )
+ {
+ v = fabs((double)sptr[i]);
+ norm += v;
+ }
+ else
+ for( i = 0; i < len; i++ )
+ {
+ v = fabs((double)sptr[i]);
+ norm = MAX(norm,v);
+ }
+
+ norm = norm > DBL_EPSILON ? 1./norm : 0.;
+ for( i = 0; i < len; i++ )
+ dptr[i] = (float)(sptr[i]*norm);
+ EXIT;
+ }
+
+ if( CV_MAT_TYPE(s->type) == CV_64FC1 )
+ {
+ const double* sptr = s->data.db;
+ double* dptr = d->data.db;
+
+ if( norm_type == CV_L2 )
+ {
+ for( i = 0; i < len; i++ )
+ {
+ v = sptr[i];
+ norm += v*v;
+ }
+ norm = sqrt(norm);
+ }
+ else if( norm_type == CV_L1 )
+ for( i = 0; i < len; i++ )
+ {
+ v = fabs(sptr[i]);
+ norm += v;
+ }
+ else
+ for( i = 0; i < len; i++ )
+ {
+ v = fabs(sptr[i]);
+ norm = MAX(norm,v);
+ }
+
+ norm = norm > DBL_EPSILON ? 1./norm : 0.;
+ for( i = 0; i < len; i++ )
+ dptr[i] = sptr[i]*norm;
+ EXIT;
+ }
+ }
+
+ scale = cvNorm( src, 0, norm_type, mask );
+ scale = scale > DBL_EPSILON ? 1./scale : 0.;
+ shift = 0;
+ }
+ else
+ CV_ERROR( CV_StsBadArg, "Unknown/unsupported norm type" );
+
+ if( !mask )
+ cvConvertScale( src, dst, scale, shift );
+ else
+ {
+ CvMat stub, *dmat;
+ CV_CALL( dmat = cvGetMat(dst, &stub));
+ CV_CALL( tmp = cvCreateMat(dmat->rows, dmat->cols, dmat->type) );
+ cvConvertScale( src, tmp, scale, shift );
+ cvCopy( tmp, dst, mask );
+ }
+
+ __END__;
+
+ if( tmp )
+ cvReleaseMat( &tmp );
+}
+
+
+CV_IMPL void cvRandShuffle( CvArr* arr, CvRNG* rng, double iter_factor )
+{
+ CV_FUNCNAME( "cvRandShuffle" );
+
+ __BEGIN__;
+
+ const int sizeof_int = (int)sizeof(int);
+ CvMat stub, *mat = (CvMat*)arr;
+ int i, j, k, iters, delta = 0;
+ int cont_flag, arr_size, elem_size, cols, step;
+ const int pair_buf_sz = 100;
+ int* pair_buf = (int*)cvStackAlloc( pair_buf_sz*sizeof(pair_buf[0])*2 );
+ CvMat _pair_buf = cvMat( 1, pair_buf_sz*2, CV_32S, pair_buf );
+ CvRNG _rng = cvRNG(-1);
+ uchar* data = 0;
+ int* idata = 0;
+
+ if( !CV_IS_MAT(mat) )
+ CV_CALL( mat = cvGetMat( mat, &stub ));
+
+ if( !rng )
+ rng = &_rng;
+
+ cols = mat->cols;
+ step = mat->step;
+ arr_size = cols*mat->rows;
+ iters = cvRound(iter_factor*arr_size)*2;
+ cont_flag = CV_IS_MAT_CONT(mat->type);
+ elem_size = CV_ELEM_SIZE(mat->type);
+ if( elem_size % sizeof_int == 0 && (cont_flag || step % sizeof_int == 0) )
+ {
+ idata = mat->data.i;
+ step /= sizeof_int;
+ elem_size /= sizeof_int;
+ }
+ else
+ data = mat->data.ptr;
+
+ for( i = 0; i < iters; i += delta )
+ {
+ delta = MIN( iters - i, pair_buf_sz*2 );
+ _pair_buf.cols = delta;
+ cvRandArr( rng, &_pair_buf, CV_RAND_UNI, cvRealScalar(0), cvRealScalar(arr_size) );
+
+ if( cont_flag )
+ {
+ if( idata )
+ for( j = 0; j < delta; j += 2 )
+ {
+ int* p = idata + pair_buf[j]*elem_size, *q = idata + pair_buf[j+1]*elem_size, t;
+ for( k = 0; k < elem_size; k++ )
+ CV_SWAP( p[k], q[k], t );
+ }
+ else
+ for( j = 0; j < delta; j += 2 )
+ {
+ uchar* p = data + pair_buf[j]*elem_size, *q = data + pair_buf[j+1]*elem_size, t;
+ for( k = 0; k < elem_size; k++ )
+ CV_SWAP( p[k], q[k], t );
+ }
+ }
+ else
+ {
+ if( idata )
+ for( j = 0; j < delta; j += 2 )
+ {
+ int idx1 = pair_buf[j], idx2 = pair_buf[j+1], row1, row2;
+ int* p, *q, t;
+ row1 = idx1/step; row2 = idx2/step;
+ p = idata + row1*step + (idx1 - row1*cols)*elem_size;
+ q = idata + row2*step + (idx2 - row2*cols)*elem_size;
+
+ for( k = 0; k < elem_size; k++ )
+ CV_SWAP( p[k], q[k], t );
+ }
+ else
+ for( j = 0; j < delta; j += 2 )
+ {
+ int idx1 = pair_buf[j], idx2 = pair_buf[j+1], row1, row2;
+ uchar* p, *q, t;
+ row1 = idx1/step; row2 = idx2/step;
+ p = data + row1*step + (idx1 - row1*cols)*elem_size;
+ q = data + row2*step + (idx2 - row2*cols)*elem_size;
+
+ for( k = 0; k < elem_size; k++ )
+ CV_SWAP( p[k], q[k], t );
+ }
+ }
+ }
+
+ __END__;
+}
+
+
+CV_IMPL CvArr*
+cvRange( CvArr* arr, double start, double end )
+{
+ int ok = 0;
+
+ CV_FUNCNAME( "cvRange" );
+
+ __BEGIN__;
+
+ CvMat stub, *mat = (CvMat*)arr;
+ double delta;
+ int type, step;
+ double val = start;
+ int i, j;
+ int rows, cols;
+
+ if( !CV_IS_MAT(mat) )
+ CV_CALL( mat = cvGetMat( mat, &stub) );
+
+ rows = mat->rows;
+ cols = mat->cols;
+ type = CV_MAT_TYPE(mat->type);
+ delta = (end-start)/(rows*cols);
+
+ if( CV_IS_MAT_CONT(mat->type) )
+ {
+ cols *= rows;
+ rows = 1;
+ step = 1;
+ }
+ else
+ step = mat->step / CV_ELEM_SIZE(type);
+
+ if( type == CV_32SC1 )
+ {
+ int* idata = mat->data.i;
+ int ival = cvRound(val), idelta = cvRound(delta);
+
+ if( fabs(val - ival) < DBL_EPSILON &&
+ fabs(delta - idelta) < DBL_EPSILON )
+ {
+ for( i = 0; i < rows; i++, idata += step )
+ for( j = 0; j < cols; j++, ival += idelta )
+ idata[j] = ival;
+ }
+ else
+ {
+ for( i = 0; i < rows; i++, idata += step )
+ for( j = 0; j < cols; j++, val += delta )
+ idata[j] = cvRound(val);
+ }
+ }
+ else if( type == CV_32FC1 )
+ {
+ float* fdata = mat->data.fl;
+ for( i = 0; i < rows; i++, fdata += step )
+ for( j = 0; j < cols; j++, val += delta )
+ fdata[j] = (float)val;
+ }
+ else
+ CV_ERROR( CV_StsUnsupportedFormat, "The function only supports 32sC1 and 32fC1 datatypes" );
+
+ ok = 1;
+
+ __END__;
+
+ return ok ? arr : 0;
+}
+
+
+#define ICV_LT_BY_IDX(a, b) (aux[a] < aux[b])
+
+static CV_IMPLEMENT_QSORT_EX( icvSortIdx64f, int, ICV_LT_BY_IDX, const double* )
+static CV_IMPLEMENT_QSORT_EX( icvSortIdx32f, int, ICV_LT_BY_IDX, const float* )
+static CV_IMPLEMENT_QSORT_EX( icvSortIdx32s, int, ICV_LT_BY_IDX, const int* )
+static CV_IMPLEMENT_QSORT_EX( icvSortIdx16u, int, ICV_LT_BY_IDX, const ushort* )
+static CV_IMPLEMENT_QSORT_EX( icvSortIdx16s, int, ICV_LT_BY_IDX, const short* )
+static CV_IMPLEMENT_QSORT_EX( icvSortIdx8u, int, ICV_LT_BY_IDX, const uchar* )
+static CV_IMPLEMENT_QSORT_EX( icvSortIdx8s, int, ICV_LT_BY_IDX, const schar* )
+
+static CV_IMPLEMENT_QSORT_EX( icvSort64f, double, CV_LT, int )
+static CV_IMPLEMENT_QSORT_EX( icvSort32f, float, CV_LT, int )
+static CV_IMPLEMENT_QSORT_EX( icvSort32s, int, CV_LT, int )
+static CV_IMPLEMENT_QSORT_EX( icvSort16u, ushort, CV_LT, int )
+static CV_IMPLEMENT_QSORT_EX( icvSort16s, short, CV_LT, int )
+static CV_IMPLEMENT_QSORT_EX( icvSort8u, uchar, CV_LT, int )
+static CV_IMPLEMENT_QSORT_EX( icvSort8s, schar, CV_LT, int )
+
+typedef void (*CvSortFunc)( void* arr, size_t n, int );
+typedef void (*CvSortIdxFunc)( int* arr, size_t n, const void* );
+
+static inline void
+icvCopy1D( const void* src, int s, void* dst, int d, int n, int elemSize )
+{
+ int i;
+ switch( elemSize )
+ {
+ case 1:
+ for( i = 0; i < n; i++ )
+ ((uchar*)dst)[i*d] = ((uchar*)src)[i*s];
+ break;
+ case 2:
+ for( i = 0; i < n; i++ )
+ ((ushort*)dst)[i*d] = ((ushort*)src)[i*s];
+ break;
+ case 4:
+ for( i = 0; i < n; i++ )
+ ((int*)dst)[i*d] = ((int*)src)[i*s];
+ break;
+ case 8:
+ for( i = 0; i < n; i++ )
+ ((int64*)dst)[i*d] = ((int64*)src)[i*s];
+ break;
+ default:
+ assert(0);
+ }
+}
+
+static void
+icvShuffle1D( const uchar* src, const int* idx, uchar* dst, int d, int n, int elemSize )
+{
+ int i;
+ switch( elemSize )
+ {
+ case 1:
+ for( i = 0; i < n; i++ )
+ dst[i*d] = src[idx[i]];
+ break;
+ case 2:
+ for( i = 0; i < n; i++ )
+ ((ushort*)dst)[i*d] = ((ushort*)src)[idx[i]];
+ break;
+ case 4:
+ for( i = 0; i < n; i++ )
+ ((int*)dst)[i*d] = ((int*)src)[idx[i]];
+ break;
+ case 8:
+ for( i = 0; i < n; i++ )
+ ((int64*)dst)[i*d] = ((int64*)src)[idx[i]];
+ break;
+ default:
+ assert(0);
+ }
+}
+
+
+CV_IMPL void
+cvSort( const CvArr* _src, CvArr* _dst, CvArr* _idx, int flags )
+{
+ uchar *tsrc = 0;
+ int* tidx = 0;
+
+ CV_FUNCNAME("cvSort");
+
+ __BEGIN__;
+
+ CvMat sstub, *src = cvGetMat(_src, &sstub);
+ CvMat dstub, *dst = _dst ? cvGetMat(_dst, &dstub) : 0;
+ CvMat istub, *idx = _idx ? cvGetMat(_idx, &istub) : 0;
+ int type = CV_MAT_TYPE(src->type), elemSize = CV_ELEM_SIZE(type);
+ int sstep = src->step, dstep = dst ? dst->step : 0;
+ int istep = idx ? idx->step/sizeof(int) : 0;
+ int i, len = src->cols;
+ CvSortFunc sortFunc = 0;
+ CvSortIdxFunc sortIdxFunc = 0;
+
+ if( CV_MAT_CN( src->type ) != 1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "The input matrix should be a one-channel matrix." );
+ if( idx )
+ {
+ if( CV_MAT_TYPE( idx->type ) != CV_32SC1)
+ CV_ERROR( CV_StsUnsupportedFormat, "The index matrix must be CV_32SC1." );
+
+ if( !CV_ARE_SIZES_EQ( idx, src ))
+ CV_ERROR( CV_StsUnmatchedSizes, "The input matrix and index matrix must be of the same size" );
+ }
+
+ if( dst )
+ {
+ if( !CV_ARE_TYPES_EQ(src, dst) )
+ CV_ERROR( CV_StsUnmatchedFormats, "The input and output matrix must be of the same type" );
+
+ if( !CV_ARE_SIZES_EQ(src, dst) )
+ CV_ERROR( CV_StsUnmatchedSizes, "The input and output matrix must be of the same size" );
+ }
+
+ if( !idx && !dst )
+ CV_ERROR( CV_StsNullPtr, "At least one of index array or destination array must be non-NULL" );
+
+ if( type == CV_8U )
+ sortIdxFunc = (CvSortIdxFunc)icvSortIdx8u, sortFunc = (CvSortFunc)icvSort8u;
+ else if( type == CV_8S )
+ sortIdxFunc = (CvSortIdxFunc)icvSortIdx8s, sortFunc = (CvSortFunc)icvSort8s;
+ else if( type == CV_16U )
+ sortIdxFunc = (CvSortIdxFunc)icvSortIdx16u, sortFunc = (CvSortFunc)icvSort16u;
+ else if( type == CV_16S )
+ sortIdxFunc = (CvSortIdxFunc)icvSortIdx16s, sortFunc = (CvSortFunc)icvSort16s;
+ else if( type == CV_32S )
+ sortIdxFunc = (CvSortIdxFunc)icvSortIdx32s, sortFunc = (CvSortFunc)icvSort32s;
+ else if( type == CV_32F )
+ sortIdxFunc = (CvSortIdxFunc)icvSortIdx32f, sortFunc = (CvSortFunc)icvSort32f;
+ else if( type == CV_64F )
+ sortIdxFunc = (CvSortIdxFunc)icvSortIdx64f, sortFunc = (CvSortFunc)icvSort64f;
+ else
+ CV_ERROR( CV_StsUnsupportedFormat, "Unsupported format of the input array" );
+
+ // single-column case, where all of src, idx & dst arrays are continuous, is
+ // equivalent to "sort every row" mode.
+ if( (flags & CV_SORT_EVERY_COLUMN) &&
+ (src->cols > 1 || !CV_IS_MAT_CONT(src->type &
+ (dst ? dst->type : -1) & (idx ? idx->type : -1))) )
+ {
+ uchar* dptr = dst ? dst->data.ptr : 0;
+ int* idxptr = idx ? idx->data.i : 0;
+
+ len = src->rows;
+ tsrc = (uchar*)cvAlloc(len*elemSize);
+ if( idx )
+ {
+ tidx = (int*)cvAlloc(len*sizeof(tidx[0]));
+ for( i = 0; i < len; i++ )
+ tidx[i] = i;
+ }
+
+ if( flags & CV_SORT_DESCENDING )
+ {
+ dptr += dstep*(src->rows - 1);
+ dstep = -dstep;
+ idxptr += istep*(src->rows - 1);
+ istep = -istep;
+ }
+
+ sstep /= elemSize;
+ dstep /= elemSize;
+
+ for( i = 0; i < src->cols; i++ )
+ {
+ icvCopy1D( src->data.ptr + i*elemSize, sstep, tsrc, 1, len, elemSize );
+ if( tidx )
+ {
+ sortIdxFunc( tidx, len, tsrc );
+ if( dst )
+ icvShuffle1D( tsrc, tidx, dptr + i*elemSize, dstep, len, elemSize );
+ icvCopy1D( tidx, 1, idxptr + i, istep, len, sizeof(int) );
+ }
+ else
+ {
+ sortFunc( tsrc, len, 0 );
+ icvCopy1D( tsrc, 1, dptr + i*elemSize, dstep, len, elemSize );
+ }
+ }
+ }
+ else
+ {
+ int j, t, count = src->rows;
+ if( flags & CV_SORT_EVERY_COLUMN )
+ CV_SWAP( len, count, t );
+
+ if( (flags & CV_SORT_DESCENDING) || (idx && dst && dst->data.ptr == src->data.ptr) )
+ tsrc = (uchar*)cvAlloc(len*elemSize);
+
+ for( i = 0; i < count; i++ )
+ {
+ if( !idx )
+ {
+ const uchar* sptr = src->data.ptr + i*sstep;
+ uchar* dptr = dst->data.ptr + i*dstep;
+ uchar* ptr = flags & CV_SORT_DESCENDING ? tsrc : dptr;
+ if( ptr != sptr )
+ icvCopy1D( sptr, 1, ptr, 1, len, elemSize );
+ sortFunc( ptr, len, 0 );
+ if( flags & CV_SORT_DESCENDING )
+ icvCopy1D( ptr + (len-1)*elemSize, -1, dptr, 1, len, elemSize );
+ }
+ else
+ {
+ int* idx_ = idx->data.i + istep*i;
+ const uchar* sptr = src->data.ptr + sstep*i;
+ uchar* dptr = dst ? dst->data.ptr + dstep*i : 0;
+ for( j = 0; j < len; j++ )
+ idx_[j] = j;
+ if( dptr && dptr == sptr )
+ {
+ icvCopy1D( sptr, 1, tsrc, 1, len, elemSize );
+ sptr = tsrc;
+ }
+ sortIdxFunc( idx_, len, sptr );
+ if( flags & CV_SORT_DESCENDING )
+ for( j = 0; j < len/2; j++ )
+ CV_SWAP(idx_[j], idx_[len-j-1], t);
+ if( dptr )
+ icvShuffle1D( sptr, idx_, dptr, 1, len, elemSize );
+ }
+ }
+ }
+
+ __END__;
+
+ cvFree( &tsrc );
+ cvFree( &tidx );
+}
+
+/* End of file. */
diff --git a/libopencv.mk b/libopencv.mk
new file mode 100644
index 0000000..7f3c317
--- /dev/null
+++ b/libopencv.mk
@@ -0,0 +1,11 @@
+# Add a couple include paths to use stlport.
+OPENCV := $(call my-dir)
+
+# Make sure bionic is first so we can include system headers.
+LOCAL_C_INCLUDES := \
+ $(OPENCV)/cv/include \
+ $(OPENCV)/cxcore/include \
+ $(OPENCV)/cvaux/include \
+ $(OPENCV)/ml/include \
+ $(OPENCV)/otherlibs/highgui \
+ $(LOCAL_C_INCLUDES)
diff --git a/ml/include/ml.h b/ml/include/ml.h
new file mode 100644
index 0000000..b41f22f
--- /dev/null
+++ b/ml/include/ml.h
@@ -0,0 +1,1564 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __ML_H__
+#define __ML_H__
+
+// disable deprecation warning which appears in VisualStudio 8.0
+#if _MSC_VER >= 1400
+#pragma warning( disable : 4996 )
+#endif
+
+#ifndef SKIP_INCLUDES
+
+ #include "cxcore.h"
+ #include <limits.h>
+
+ #if defined WIN32 || defined WIN64
+ #include <windows.h>
+ #endif
+
+#else // SKIP_INCLUDES
+
+ #if defined WIN32 || defined WIN64
+ #define CV_CDECL __cdecl
+ #define CV_STDCALL __stdcall
+ #else
+ #define CV_CDECL
+ #define CV_STDCALL
+ #endif
+
+ #ifndef CV_EXTERN_C
+ #ifdef __cplusplus
+ #define CV_EXTERN_C extern "C"
+ #define CV_DEFAULT(val) = val
+ #else
+ #define CV_EXTERN_C
+ #define CV_DEFAULT(val)
+ #endif
+ #endif
+
+ #ifndef CV_EXTERN_C_FUNCPTR
+ #ifdef __cplusplus
+ #define CV_EXTERN_C_FUNCPTR(x) extern "C" { typedef x; }
+ #else
+ #define CV_EXTERN_C_FUNCPTR(x) typedef x
+ #endif
+ #endif
+
+ #ifndef CV_INLINE
+ #if defined __cplusplus
+ #define CV_INLINE inline
+ #elif (defined WIN32 || defined WIN64) && !defined __GNUC__
+ #define CV_INLINE __inline
+ #else
+ #define CV_INLINE static
+ #endif
+ #endif /* CV_INLINE */
+
+ #if (defined WIN32 || defined WIN64) && defined CVAPI_EXPORTS
+ #define CV_EXPORTS __declspec(dllexport)
+ #else
+ #define CV_EXPORTS
+ #endif
+
+ #ifndef CVAPI
+ #define CVAPI(rettype) CV_EXTERN_C CV_EXPORTS rettype CV_CDECL
+ #endif
+
+#endif // SKIP_INCLUDES
+
+
+#ifdef __cplusplus
+
+// Apple defines a check() macro somewhere in the debug headers
+// that interferes with a method definiton in this header
+#undef check
+
+/****************************************************************************************\
+* Main struct definitions *
+\****************************************************************************************/
+
+/* log(2*PI) */
+#define CV_LOG2PI (1.8378770664093454835606594728112)
+
+/* columns of <trainData> matrix are training samples */
+#define CV_COL_SAMPLE 0
+
+/* rows of <trainData> matrix are training samples */
+#define CV_ROW_SAMPLE 1
+
+#define CV_IS_ROW_SAMPLE(flags) ((flags) & CV_ROW_SAMPLE)
+
+struct CvVectors
+{
+ int type;
+ int dims, count;
+ CvVectors* next;
+ union
+ {
+ uchar** ptr;
+ float** fl;
+ double** db;
+ } data;
+};
+
+#if 0
+/* A structure, representing the lattice range of statmodel parameters.
+ It is used for optimizing statmodel parameters by cross-validation method.
+ The lattice is logarithmic, so <step> must be greater then 1. */
+typedef struct CvParamLattice
+{
+ double min_val;
+ double max_val;
+ double step;
+}
+CvParamLattice;
+
+CV_INLINE CvParamLattice cvParamLattice( double min_val, double max_val,
+ double log_step )
+{
+ CvParamLattice pl;
+ pl.min_val = MIN( min_val, max_val );
+ pl.max_val = MAX( min_val, max_val );
+ pl.step = MAX( log_step, 1. );
+ return pl;
+}
+
+CV_INLINE CvParamLattice cvDefaultParamLattice( void )
+{
+ CvParamLattice pl = {0,0,0};
+ return pl;
+}
+#endif
+
+/* Variable type */
+#define CV_VAR_NUMERICAL 0
+#define CV_VAR_ORDERED 0
+#define CV_VAR_CATEGORICAL 1
+
+#define CV_TYPE_NAME_ML_SVM "opencv-ml-svm"
+#define CV_TYPE_NAME_ML_KNN "opencv-ml-knn"
+#define CV_TYPE_NAME_ML_NBAYES "opencv-ml-bayesian"
+#define CV_TYPE_NAME_ML_EM "opencv-ml-em"
+#define CV_TYPE_NAME_ML_BOOSTING "opencv-ml-boost-tree"
+#define CV_TYPE_NAME_ML_TREE "opencv-ml-tree"
+#define CV_TYPE_NAME_ML_ANN_MLP "opencv-ml-ann-mlp"
+#define CV_TYPE_NAME_ML_CNN "opencv-ml-cnn"
+#define CV_TYPE_NAME_ML_RTREES "opencv-ml-random-trees"
+
+class CV_EXPORTS CvStatModel
+{
+public:
+ CvStatModel();
+ virtual ~CvStatModel();
+
+ virtual void clear();
+
+ virtual void save( const char* filename, const char* name=0 );
+ virtual void load( const char* filename, const char* name=0 );
+
+ virtual void write( CvFileStorage* storage, const char* name );
+ virtual void read( CvFileStorage* storage, CvFileNode* node );
+
+protected:
+ const char* default_model_name;
+};
+
+
+/****************************************************************************************\
+* Normal Bayes Classifier *
+\****************************************************************************************/
+
+/* The structure, representing the grid range of statmodel parameters.
+ It is used for optimizing statmodel accuracy by varying model parameters,
+ the accuracy estimate being computed by cross-validation.
+ The grid is logarithmic, so <step> must be greater then 1. */
+struct CV_EXPORTS CvParamGrid
+{
+ // SVM params type
+ enum { SVM_C=0, SVM_GAMMA=1, SVM_P=2, SVM_NU=3, SVM_COEF=4, SVM_DEGREE=5 };
+
+ CvParamGrid()
+ {
+ min_val = max_val = step = 0;
+ }
+
+ CvParamGrid( double _min_val, double _max_val, double log_step )
+ {
+ min_val = _min_val;
+ max_val = _max_val;
+ step = log_step;
+ }
+ //CvParamGrid( int param_id );
+ bool check() const;
+
+ double min_val;
+ double max_val;
+ double step;
+};
+
+class CV_EXPORTS CvNormalBayesClassifier : public CvStatModel
+{
+public:
+ CvNormalBayesClassifier();
+ virtual ~CvNormalBayesClassifier();
+
+ CvNormalBayesClassifier( const CvMat* _train_data, const CvMat* _responses,
+ const CvMat* _var_idx=0, const CvMat* _sample_idx=0 );
+
+ virtual bool train( const CvMat* _train_data, const CvMat* _responses,
+ const CvMat* _var_idx = 0, const CvMat* _sample_idx=0, bool update=false );
+
+ virtual float predict( const CvMat* _samples, CvMat* results=0 ) const;
+ virtual void clear();
+
+ virtual void write( CvFileStorage* storage, const char* name );
+ virtual void read( CvFileStorage* storage, CvFileNode* node );
+
+protected:
+ int var_count, var_all;
+ CvMat* var_idx;
+ CvMat* cls_labels;
+ CvMat** count;
+ CvMat** sum;
+ CvMat** productsum;
+ CvMat** avg;
+ CvMat** inv_eigen_values;
+ CvMat** cov_rotate_mats;
+ CvMat* c;
+};
+
+
+/****************************************************************************************\
+* K-Nearest Neighbour Classifier *
+\****************************************************************************************/
+
+// k Nearest Neighbors
+class CV_EXPORTS CvKNearest : public CvStatModel
+{
+public:
+
+ CvKNearest();
+ virtual ~CvKNearest();
+
+ CvKNearest( const CvMat* _train_data, const CvMat* _responses,
+ const CvMat* _sample_idx=0, bool _is_regression=false, int max_k=32 );
+
+ virtual bool train( const CvMat* _train_data, const CvMat* _responses,
+ const CvMat* _sample_idx=0, bool is_regression=false,
+ int _max_k=32, bool _update_base=false );
+
+ virtual float find_nearest( const CvMat* _samples, int k, CvMat* results=0,
+ const float** neighbors=0, CvMat* neighbor_responses=0, CvMat* dist=0 ) const;
+
+ virtual void clear();
+ int get_max_k() const;
+ int get_var_count() const;
+ int get_sample_count() const;
+ bool is_regression() const;
+
+protected:
+
+ virtual float write_results( int k, int k1, int start, int end,
+ const float* neighbor_responses, const float* dist, CvMat* _results,
+ CvMat* _neighbor_responses, CvMat* _dist, Cv32suf* sort_buf ) const;
+
+ virtual void find_neighbors_direct( const CvMat* _samples, int k, int start, int end,
+ float* neighbor_responses, const float** neighbors, float* dist ) const;
+
+
+ int max_k, var_count;
+ int total;
+ bool regression;
+ CvVectors* samples;
+};
+
+/****************************************************************************************\
+* Support Vector Machines *
+\****************************************************************************************/
+
+// SVM training parameters
+struct CV_EXPORTS CvSVMParams
+{
+ CvSVMParams();
+ CvSVMParams( int _svm_type, int _kernel_type,
+ double _degree, double _gamma, double _coef0,
+ double _C, double _nu, double _p,
+ CvMat* _class_weights, CvTermCriteria _term_crit );
+
+ int svm_type;
+ int kernel_type;
+ double degree; // for poly
+ double gamma; // for poly/rbf/sigmoid
+ double coef0; // for poly/sigmoid
+
+ double C; // for CV_SVM_C_SVC, CV_SVM_EPS_SVR and CV_SVM_NU_SVR
+ double nu; // for CV_SVM_NU_SVC, CV_SVM_ONE_CLASS, and CV_SVM_NU_SVR
+ double p; // for CV_SVM_EPS_SVR
+ CvMat* class_weights; // for CV_SVM_C_SVC
+ CvTermCriteria term_crit; // termination criteria
+};
+
+
+struct CV_EXPORTS CvSVMKernel
+{
+ typedef void (CvSVMKernel::*Calc)( int vec_count, int vec_size, const float** vecs,
+ const float* another, float* results );
+ CvSVMKernel();
+ CvSVMKernel( const CvSVMParams* _params, Calc _calc_func );
+ virtual bool create( const CvSVMParams* _params, Calc _calc_func );
+ virtual ~CvSVMKernel();
+
+ virtual void clear();
+ virtual void calc( int vcount, int n, const float** vecs, const float* another, float* results );
+
+ const CvSVMParams* params;
+ Calc calc_func;
+
+ virtual void calc_non_rbf_base( int vec_count, int vec_size, const float** vecs,
+ const float* another, float* results,
+ double alpha, double beta );
+
+ virtual void calc_linear( int vec_count, int vec_size, const float** vecs,
+ const float* another, float* results );
+ virtual void calc_rbf( int vec_count, int vec_size, const float** vecs,
+ const float* another, float* results );
+ virtual void calc_poly( int vec_count, int vec_size, const float** vecs,
+ const float* another, float* results );
+ virtual void calc_sigmoid( int vec_count, int vec_size, const float** vecs,
+ const float* another, float* results );
+};
+
+
+struct CvSVMKernelRow
+{
+ CvSVMKernelRow* prev;
+ CvSVMKernelRow* next;
+ float* data;
+};
+
+
+struct CvSVMSolutionInfo
+{
+ double obj;
+ double rho;
+ double upper_bound_p;
+ double upper_bound_n;
+ double r; // for Solver_NU
+};
+
+class CV_EXPORTS CvSVMSolver
+{
+public:
+ typedef bool (CvSVMSolver::*SelectWorkingSet)( int& i, int& j );
+ typedef float* (CvSVMSolver::*GetRow)( int i, float* row, float* dst, bool existed );
+ typedef void (CvSVMSolver::*CalcRho)( double& rho, double& r );
+
+ CvSVMSolver();
+
+ CvSVMSolver( int count, int var_count, const float** samples, schar* y,
+ int alpha_count, double* alpha, double Cp, double Cn,
+ CvMemStorage* storage, CvSVMKernel* kernel, GetRow get_row,
+ SelectWorkingSet select_working_set, CalcRho calc_rho );
+ virtual bool create( int count, int var_count, const float** samples, schar* y,
+ int alpha_count, double* alpha, double Cp, double Cn,
+ CvMemStorage* storage, CvSVMKernel* kernel, GetRow get_row,
+ SelectWorkingSet select_working_set, CalcRho calc_rho );
+ virtual ~CvSVMSolver();
+
+ virtual void clear();
+ virtual bool solve_generic( CvSVMSolutionInfo& si );
+
+ virtual bool solve_c_svc( int count, int var_count, const float** samples, schar* y,
+ double Cp, double Cn, CvMemStorage* storage,
+ CvSVMKernel* kernel, double* alpha, CvSVMSolutionInfo& si );
+ virtual bool solve_nu_svc( int count, int var_count, const float** samples, schar* y,
+ CvMemStorage* storage, CvSVMKernel* kernel,
+ double* alpha, CvSVMSolutionInfo& si );
+ virtual bool solve_one_class( int count, int var_count, const float** samples,
+ CvMemStorage* storage, CvSVMKernel* kernel,
+ double* alpha, CvSVMSolutionInfo& si );
+
+ virtual bool solve_eps_svr( int count, int var_count, const float** samples, const float* y,
+ CvMemStorage* storage, CvSVMKernel* kernel,
+ double* alpha, CvSVMSolutionInfo& si );
+
+ virtual bool solve_nu_svr( int count, int var_count, const float** samples, const float* y,
+ CvMemStorage* storage, CvSVMKernel* kernel,
+ double* alpha, CvSVMSolutionInfo& si );
+
+ virtual float* get_row_base( int i, bool* _existed );
+ virtual float* get_row( int i, float* dst );
+
+ int sample_count;
+ int var_count;
+ int cache_size;
+ int cache_line_size;
+ const float** samples;
+ const CvSVMParams* params;
+ CvMemStorage* storage;
+ CvSVMKernelRow lru_list;
+ CvSVMKernelRow* rows;
+
+ int alpha_count;
+
+ double* G;
+ double* alpha;
+
+ // -1 - lower bound, 0 - free, 1 - upper bound
+ schar* alpha_status;
+
+ schar* y;
+ double* b;
+ float* buf[2];
+ double eps;
+ int max_iter;
+ double C[2]; // C[0] == Cn, C[1] == Cp
+ CvSVMKernel* kernel;
+
+ SelectWorkingSet select_working_set_func;
+ CalcRho calc_rho_func;
+ GetRow get_row_func;
+
+ virtual bool select_working_set( int& i, int& j );
+ virtual bool select_working_set_nu_svm( int& i, int& j );
+ virtual void calc_rho( double& rho, double& r );
+ virtual void calc_rho_nu_svm( double& rho, double& r );
+
+ virtual float* get_row_svc( int i, float* row, float* dst, bool existed );
+ virtual float* get_row_one_class( int i, float* row, float* dst, bool existed );
+ virtual float* get_row_svr( int i, float* row, float* dst, bool existed );
+};
+
+
+struct CvSVMDecisionFunc
+{
+ double rho;
+ int sv_count;
+ double* alpha;
+ int* sv_index;
+};
+
+
+// SVM model
+class CV_EXPORTS CvSVM : public CvStatModel
+{
+public:
+ // SVM type
+ enum { C_SVC=100, NU_SVC=101, ONE_CLASS=102, EPS_SVR=103, NU_SVR=104 };
+
+ // SVM kernel type
+ enum { LINEAR=0, POLY=1, RBF=2, SIGMOID=3 };
+
+ // SVM params type
+ enum { C=0, GAMMA=1, P=2, NU=3, COEF=4, DEGREE=5 };
+
+ CvSVM();
+ virtual ~CvSVM();
+
+ CvSVM( const CvMat* _train_data, const CvMat* _responses,
+ const CvMat* _var_idx=0, const CvMat* _sample_idx=0,
+ CvSVMParams _params=CvSVMParams() );
+
+ virtual bool train( const CvMat* _train_data, const CvMat* _responses,
+ const CvMat* _var_idx=0, const CvMat* _sample_idx=0,
+ CvSVMParams _params=CvSVMParams() );
+ virtual bool train_auto( const CvMat* _train_data, const CvMat* _responses,
+ const CvMat* _var_idx, const CvMat* _sample_idx, CvSVMParams _params,
+ int k_fold = 10,
+ CvParamGrid C_grid = get_default_grid(CvSVM::C),
+ CvParamGrid gamma_grid = get_default_grid(CvSVM::GAMMA),
+ CvParamGrid p_grid = get_default_grid(CvSVM::P),
+ CvParamGrid nu_grid = get_default_grid(CvSVM::NU),
+ CvParamGrid coef_grid = get_default_grid(CvSVM::COEF),
+ CvParamGrid degree_grid = get_default_grid(CvSVM::DEGREE) );
+
+ virtual float predict( const CvMat* _sample ) const;
+
+ virtual int get_support_vector_count() const;
+ virtual const float* get_support_vector(int i) const;
+ virtual CvSVMParams get_params() const { return params; };
+ virtual void clear();
+
+ static CvParamGrid get_default_grid( int param_id );
+
+ virtual void write( CvFileStorage* storage, const char* name );
+ virtual void read( CvFileStorage* storage, CvFileNode* node );
+ int get_var_count() const { return var_idx ? var_idx->cols : var_all; }
+
+protected:
+
+ virtual bool set_params( const CvSVMParams& _params );
+ virtual bool train1( int sample_count, int var_count, const float** samples,
+ const void* _responses, double Cp, double Cn,
+ CvMemStorage* _storage, double* alpha, double& rho );
+ virtual bool do_train( int svm_type, int sample_count, int var_count, const float** samples,
+ const CvMat* _responses, CvMemStorage* _storage, double* alpha );
+ virtual void create_kernel();
+ virtual void create_solver();
+
+ virtual void write_params( CvFileStorage* fs );
+ virtual void read_params( CvFileStorage* fs, CvFileNode* node );
+
+ CvSVMParams params;
+ CvMat* class_labels;
+ int var_all;
+ float** sv;
+ int sv_total;
+ CvMat* var_idx;
+ CvMat* class_weights;
+ CvSVMDecisionFunc* decision_func;
+ CvMemStorage* storage;
+
+ CvSVMSolver* solver;
+ CvSVMKernel* kernel;
+};
+
+/****************************************************************************************\
+* Expectation - Maximization *
+\****************************************************************************************/
+
+struct CV_EXPORTS CvEMParams
+{
+ CvEMParams() : nclusters(10), cov_mat_type(1/*CvEM::COV_MAT_DIAGONAL*/),
+ start_step(0/*CvEM::START_AUTO_STEP*/), probs(0), weights(0), means(0), covs(0)
+ {
+ term_crit=cvTermCriteria( CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 100, FLT_EPSILON );
+ }
+
+ CvEMParams( int _nclusters, int _cov_mat_type=1/*CvEM::COV_MAT_DIAGONAL*/,
+ int _start_step=0/*CvEM::START_AUTO_STEP*/,
+ CvTermCriteria _term_crit=cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 100, FLT_EPSILON),
+ const CvMat* _probs=0, const CvMat* _weights=0, const CvMat* _means=0, const CvMat** _covs=0 ) :
+ nclusters(_nclusters), cov_mat_type(_cov_mat_type), start_step(_start_step),
+ probs(_probs), weights(_weights), means(_means), covs(_covs), term_crit(_term_crit)
+ {}
+
+ int nclusters;
+ int cov_mat_type;
+ int start_step;
+ const CvMat* probs;
+ const CvMat* weights;
+ const CvMat* means;
+ const CvMat** covs;
+ CvTermCriteria term_crit;
+};
+
+
+class CV_EXPORTS CvEM : public CvStatModel
+{
+public:
+ // Type of covariation matrices
+ enum { COV_MAT_SPHERICAL=0, COV_MAT_DIAGONAL=1, COV_MAT_GENERIC=2 };
+
+ // The initial step
+ enum { START_E_STEP=1, START_M_STEP=2, START_AUTO_STEP=0 };
+
+ CvEM();
+ CvEM( const CvMat* samples, const CvMat* sample_idx=0,
+ CvEMParams params=CvEMParams(), CvMat* labels=0 );
+
+ virtual ~CvEM();
+
+ virtual bool train( const CvMat* samples, const CvMat* sample_idx=0,
+ CvEMParams params=CvEMParams(), CvMat* labels=0 );
+
+ virtual float predict( const CvMat* sample, CvMat* probs ) const;
+ virtual void clear();
+
+ int get_nclusters() const;
+ const CvMat* get_means() const;
+ const CvMat** get_covs() const;
+ const CvMat* get_weights() const;
+ const CvMat* get_probs() const;
+
+ inline double get_log_likelihood () const { return log_likelihood; };
+
+protected:
+
+ virtual void set_params( const CvEMParams& params,
+ const CvVectors& train_data );
+ virtual void init_em( const CvVectors& train_data );
+ virtual double run_em( const CvVectors& train_data );
+ virtual void init_auto( const CvVectors& samples );
+ virtual void kmeans( const CvVectors& train_data, int nclusters,
+ CvMat* labels, CvTermCriteria criteria,
+ const CvMat* means );
+ CvEMParams params;
+ double log_likelihood;
+
+ CvMat* means;
+ CvMat** covs;
+ CvMat* weights;
+ CvMat* probs;
+
+ CvMat* log_weight_div_det;
+ CvMat* inv_eigen_values;
+ CvMat** cov_rotate_mats;
+};
+
+/****************************************************************************************\
+* Decision Tree *
+\****************************************************************************************/
+
+struct CvPair32s32f
+{
+ int i;
+ float val;
+};
+
+
+#define CV_DTREE_CAT_DIR(idx,subset) \
+ (2*((subset[(idx)>>5]&(1 << ((idx) & 31)))==0)-1)
+
+struct CvDTreeSplit
+{
+ int var_idx;
+ int inversed;
+ float quality;
+ CvDTreeSplit* next;
+ union
+ {
+ int subset[2];
+ struct
+ {
+ float c;
+ int split_point;
+ }
+ ord;
+ };
+};
+
+
+struct CvDTreeNode
+{
+ int class_idx;
+ int Tn;
+ double value;
+
+ CvDTreeNode* parent;
+ CvDTreeNode* left;
+ CvDTreeNode* right;
+
+ CvDTreeSplit* split;
+
+ int sample_count;
+ int depth;
+ int* num_valid;
+ int offset;
+ int buf_idx;
+ double maxlr;
+
+ // global pruning data
+ int complexity;
+ double alpha;
+ double node_risk, tree_risk, tree_error;
+
+ // cross-validation pruning data
+ int* cv_Tn;
+ double* cv_node_risk;
+ double* cv_node_error;
+
+ int get_num_valid(int vi) { return num_valid ? num_valid[vi] : sample_count; }
+ void set_num_valid(int vi, int n) { if( num_valid ) num_valid[vi] = n; }
+};
+
+
+struct CV_EXPORTS CvDTreeParams
+{
+ int max_categories;
+ int max_depth;
+ int min_sample_count;
+ int cv_folds;
+ bool use_surrogates;
+ bool use_1se_rule;
+ bool truncate_pruned_tree;
+ float regression_accuracy;
+ const float* priors;
+
+ CvDTreeParams() : max_categories(10), max_depth(INT_MAX), min_sample_count(10),
+ cv_folds(10), use_surrogates(true), use_1se_rule(true),
+ truncate_pruned_tree(true), regression_accuracy(0.01f), priors(0)
+ {}
+
+ CvDTreeParams( int _max_depth, int _min_sample_count,
+ float _regression_accuracy, bool _use_surrogates,
+ int _max_categories, int _cv_folds,
+ bool _use_1se_rule, bool _truncate_pruned_tree,
+ const float* _priors ) :
+ max_categories(_max_categories), max_depth(_max_depth),
+ min_sample_count(_min_sample_count), cv_folds (_cv_folds),
+ use_surrogates(_use_surrogates), use_1se_rule(_use_1se_rule),
+ truncate_pruned_tree(_truncate_pruned_tree),
+ regression_accuracy(_regression_accuracy),
+ priors(_priors)
+ {}
+};
+
+
+struct CV_EXPORTS CvDTreeTrainData
+{
+ CvDTreeTrainData();
+ CvDTreeTrainData( const CvMat* _train_data, int _tflag,
+ const CvMat* _responses, const CvMat* _var_idx=0,
+ const CvMat* _sample_idx=0, const CvMat* _var_type=0,
+ const CvMat* _missing_mask=0,
+ const CvDTreeParams& _params=CvDTreeParams(),
+ bool _shared=false, bool _add_labels=false );
+ virtual ~CvDTreeTrainData();
+
+ virtual void set_data( const CvMat* _train_data, int _tflag,
+ const CvMat* _responses, const CvMat* _var_idx=0,
+ const CvMat* _sample_idx=0, const CvMat* _var_type=0,
+ const CvMat* _missing_mask=0,
+ const CvDTreeParams& _params=CvDTreeParams(),
+ bool _shared=false, bool _add_labels=false,
+ bool _update_data=false );
+
+ virtual void get_vectors( const CvMat* _subsample_idx,
+ float* values, uchar* missing, float* responses, bool get_class_idx=false );
+
+ virtual CvDTreeNode* subsample_data( const CvMat* _subsample_idx );
+
+ virtual void write_params( CvFileStorage* fs );
+ virtual void read_params( CvFileStorage* fs, CvFileNode* node );
+
+ // release all the data
+ virtual void clear();
+
+ int get_num_classes() const;
+ int get_var_type(int vi) const;
+ int get_work_var_count() const;
+
+ virtual int* get_class_labels( CvDTreeNode* n );
+ virtual float* get_ord_responses( CvDTreeNode* n );
+ virtual int* get_labels( CvDTreeNode* n );
+ virtual int* get_cat_var_data( CvDTreeNode* n, int vi );
+ virtual CvPair32s32f* get_ord_var_data( CvDTreeNode* n, int vi );
+ virtual int get_child_buf_idx( CvDTreeNode* n );
+
+ ////////////////////////////////////
+
+ virtual bool set_params( const CvDTreeParams& params );
+ virtual CvDTreeNode* new_node( CvDTreeNode* parent, int count,
+ int storage_idx, int offset );
+
+ virtual CvDTreeSplit* new_split_ord( int vi, float cmp_val,
+ int split_point, int inversed, float quality );
+ virtual CvDTreeSplit* new_split_cat( int vi, float quality );
+ virtual void free_node_data( CvDTreeNode* node );
+ virtual void free_train_data();
+ virtual void free_node( CvDTreeNode* node );
+
+ int sample_count, var_all, var_count, max_c_count;
+ int ord_var_count, cat_var_count;
+ bool have_labels, have_priors;
+ bool is_classifier;
+
+ int buf_count, buf_size;
+ bool shared;
+
+ CvMat* cat_count;
+ CvMat* cat_ofs;
+ CvMat* cat_map;
+
+ CvMat* counts;
+ CvMat* buf;
+ CvMat* direction;
+ CvMat* split_buf;
+
+ CvMat* var_idx;
+ CvMat* var_type; // i-th element =
+ // k<0 - ordered
+ // k>=0 - categorical, see k-th element of cat_* arrays
+ CvMat* priors;
+ CvMat* priors_mult;
+
+ CvDTreeParams params;
+
+ CvMemStorage* tree_storage;
+ CvMemStorage* temp_storage;
+
+ CvDTreeNode* data_root;
+
+ CvSet* node_heap;
+ CvSet* split_heap;
+ CvSet* cv_heap;
+ CvSet* nv_heap;
+
+ CvRNG rng;
+};
+
+
+class CV_EXPORTS CvDTree : public CvStatModel
+{
+public:
+ CvDTree();
+ virtual ~CvDTree();
+
+ virtual bool train( const CvMat* _train_data, int _tflag,
+ const CvMat* _responses, const CvMat* _var_idx=0,
+ const CvMat* _sample_idx=0, const CvMat* _var_type=0,
+ const CvMat* _missing_mask=0,
+ CvDTreeParams params=CvDTreeParams() );
+
+ virtual bool train( CvDTreeTrainData* _train_data, const CvMat* _subsample_idx );
+
+ virtual CvDTreeNode* predict( const CvMat* _sample, const CvMat* _missing_data_mask=0,
+ bool preprocessed_input=false ) const;
+ virtual const CvMat* get_var_importance();
+ virtual void clear();
+
+ virtual void read( CvFileStorage* fs, CvFileNode* node );
+ virtual void write( CvFileStorage* fs, const char* name );
+
+ // special read & write methods for trees in the tree ensembles
+ virtual void read( CvFileStorage* fs, CvFileNode* node,
+ CvDTreeTrainData* data );
+ virtual void write( CvFileStorage* fs );
+
+ const CvDTreeNode* get_root() const;
+ int get_pruned_tree_idx() const;
+ CvDTreeTrainData* get_data();
+
+protected:
+
+ virtual bool do_train( const CvMat* _subsample_idx );
+
+ virtual void try_split_node( CvDTreeNode* n );
+ virtual void split_node_data( CvDTreeNode* n );
+ virtual CvDTreeSplit* find_best_split( CvDTreeNode* n );
+ virtual CvDTreeSplit* find_split_ord_class( CvDTreeNode* n, int vi );
+ virtual CvDTreeSplit* find_split_cat_class( CvDTreeNode* n, int vi );
+ virtual CvDTreeSplit* find_split_ord_reg( CvDTreeNode* n, int vi );
+ virtual CvDTreeSplit* find_split_cat_reg( CvDTreeNode* n, int vi );
+ virtual CvDTreeSplit* find_surrogate_split_ord( CvDTreeNode* n, int vi );
+ virtual CvDTreeSplit* find_surrogate_split_cat( CvDTreeNode* n, int vi );
+ virtual double calc_node_dir( CvDTreeNode* node );
+ virtual void complete_node_dir( CvDTreeNode* node );
+ virtual void cluster_categories( const int* vectors, int vector_count,
+ int var_count, int* sums, int k, int* cluster_labels );
+
+ virtual void calc_node_value( CvDTreeNode* node );
+
+ virtual void prune_cv();
+ virtual double update_tree_rnc( int T, int fold );
+ virtual int cut_tree( int T, int fold, double min_alpha );
+ virtual void free_prune_data(bool cut_tree);
+ virtual void free_tree();
+
+ virtual void write_node( CvFileStorage* fs, CvDTreeNode* node );
+ virtual void write_split( CvFileStorage* fs, CvDTreeSplit* split );
+ virtual CvDTreeNode* read_node( CvFileStorage* fs, CvFileNode* node, CvDTreeNode* parent );
+ virtual CvDTreeSplit* read_split( CvFileStorage* fs, CvFileNode* node );
+ virtual void write_tree_nodes( CvFileStorage* fs );
+ virtual void read_tree_nodes( CvFileStorage* fs, CvFileNode* node );
+
+ CvDTreeNode* root;
+
+ int pruned_tree_idx;
+ CvMat* var_importance;
+
+ CvDTreeTrainData* data;
+};
+
+
+/****************************************************************************************\
+* Random Trees Classifier *
+\****************************************************************************************/
+
+class CvRTrees;
+
+class CV_EXPORTS CvForestTree: public CvDTree
+{
+public:
+ CvForestTree();
+ virtual ~CvForestTree();
+
+ virtual bool train( CvDTreeTrainData* _train_data, const CvMat* _subsample_idx, CvRTrees* forest );
+
+ virtual int get_var_count() const {return data ? data->var_count : 0;}
+ virtual void read( CvFileStorage* fs, CvFileNode* node, CvRTrees* forest, CvDTreeTrainData* _data );
+
+ /* dummy methods to avoid warnings: BEGIN */
+ virtual bool train( const CvMat* _train_data, int _tflag,
+ const CvMat* _responses, const CvMat* _var_idx=0,
+ const CvMat* _sample_idx=0, const CvMat* _var_type=0,
+ const CvMat* _missing_mask=0,
+ CvDTreeParams params=CvDTreeParams() );
+
+ virtual bool train( CvDTreeTrainData* _train_data, const CvMat* _subsample_idx );
+ virtual void read( CvFileStorage* fs, CvFileNode* node );
+ virtual void read( CvFileStorage* fs, CvFileNode* node,
+ CvDTreeTrainData* data );
+ /* dummy methods to avoid warnings: END */
+
+protected:
+ virtual CvDTreeSplit* find_best_split( CvDTreeNode* n );
+ CvRTrees* forest;
+};
+
+
+struct CV_EXPORTS CvRTParams : public CvDTreeParams
+{
+ //Parameters for the forest
+ bool calc_var_importance; // true <=> RF processes variable importance
+ int nactive_vars;
+ CvTermCriteria term_crit;
+
+ CvRTParams() : CvDTreeParams( 5, 10, 0, false, 10, 0, false, false, 0 ),
+ calc_var_importance(false), nactive_vars(0)
+ {
+ term_crit = cvTermCriteria( CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 50, 0.1 );
+ }
+
+ CvRTParams( int _max_depth, int _min_sample_count,
+ float _regression_accuracy, bool _use_surrogates,
+ int _max_categories, const float* _priors, bool _calc_var_importance,
+ int _nactive_vars, int max_num_of_trees_in_the_forest,
+ float forest_accuracy, int termcrit_type ) :
+ CvDTreeParams( _max_depth, _min_sample_count, _regression_accuracy,
+ _use_surrogates, _max_categories, 0,
+ false, false, _priors ),
+ calc_var_importance(_calc_var_importance),
+ nactive_vars(_nactive_vars)
+ {
+ term_crit = cvTermCriteria(termcrit_type,
+ max_num_of_trees_in_the_forest, forest_accuracy);
+ }
+};
+
+
+class CV_EXPORTS CvRTrees : public CvStatModel
+{
+public:
+ CvRTrees();
+ virtual ~CvRTrees();
+ virtual bool train( const CvMat* _train_data, int _tflag,
+ const CvMat* _responses, const CvMat* _var_idx=0,
+ const CvMat* _sample_idx=0, const CvMat* _var_type=0,
+ const CvMat* _missing_mask=0,
+ CvRTParams params=CvRTParams() );
+ virtual float predict( const CvMat* sample, const CvMat* missing = 0 ) const;
+ virtual void clear();
+
+ virtual const CvMat* get_var_importance();
+ virtual float get_proximity( const CvMat* sample1, const CvMat* sample2,
+ const CvMat* missing1 = 0, const CvMat* missing2 = 0 ) const;
+
+ virtual void read( CvFileStorage* fs, CvFileNode* node );
+ virtual void write( CvFileStorage* fs, const char* name );
+
+ CvMat* get_active_var_mask();
+ CvRNG* get_rng();
+
+ int get_tree_count() const;
+ CvForestTree* get_tree(int i) const;
+
+protected:
+
+ bool grow_forest( const CvTermCriteria term_crit );
+
+ // array of the trees of the forest
+ CvForestTree** trees;
+ CvDTreeTrainData* data;
+ int ntrees;
+ int nclasses;
+ double oob_error;
+ CvMat* var_importance;
+ int nsamples;
+
+ CvRNG rng;
+ CvMat* active_var_mask;
+};
+
+
+/****************************************************************************************\
+* Boosted tree classifier *
+\****************************************************************************************/
+
+struct CV_EXPORTS CvBoostParams : public CvDTreeParams
+{
+ int boost_type;
+ int weak_count;
+ int split_criteria;
+ double weight_trim_rate;
+
+ CvBoostParams();
+ CvBoostParams( int boost_type, int weak_count, double weight_trim_rate,
+ int max_depth, bool use_surrogates, const float* priors );
+};
+
+
+class CvBoost;
+
+class CV_EXPORTS CvBoostTree: public CvDTree
+{
+public:
+ CvBoostTree();
+ virtual ~CvBoostTree();
+
+ virtual bool train( CvDTreeTrainData* _train_data,
+ const CvMat* subsample_idx, CvBoost* ensemble );
+
+ virtual void scale( double s );
+ virtual void read( CvFileStorage* fs, CvFileNode* node,
+ CvBoost* ensemble, CvDTreeTrainData* _data );
+ virtual void clear();
+
+ /* dummy methods to avoid warnings: BEGIN */
+ virtual bool train( const CvMat* _train_data, int _tflag,
+ const CvMat* _responses, const CvMat* _var_idx=0,
+ const CvMat* _sample_idx=0, const CvMat* _var_type=0,
+ const CvMat* _missing_mask=0,
+ CvDTreeParams params=CvDTreeParams() );
+
+ virtual bool train( CvDTreeTrainData* _train_data, const CvMat* _subsample_idx );
+ virtual void read( CvFileStorage* fs, CvFileNode* node );
+ virtual void read( CvFileStorage* fs, CvFileNode* node,
+ CvDTreeTrainData* data );
+ /* dummy methods to avoid warnings: END */
+
+protected:
+
+ virtual void try_split_node( CvDTreeNode* n );
+ virtual CvDTreeSplit* find_surrogate_split_ord( CvDTreeNode* n, int vi );
+ virtual CvDTreeSplit* find_surrogate_split_cat( CvDTreeNode* n, int vi );
+ virtual CvDTreeSplit* find_split_ord_class( CvDTreeNode* n, int vi );
+ virtual CvDTreeSplit* find_split_cat_class( CvDTreeNode* n, int vi );
+ virtual CvDTreeSplit* find_split_ord_reg( CvDTreeNode* n, int vi );
+ virtual CvDTreeSplit* find_split_cat_reg( CvDTreeNode* n, int vi );
+ virtual void calc_node_value( CvDTreeNode* n );
+ virtual double calc_node_dir( CvDTreeNode* n );
+
+ CvBoost* ensemble;
+};
+
+
+class CV_EXPORTS CvBoost : public CvStatModel
+{
+public:
+ // Boosting type
+ enum { DISCRETE=0, REAL=1, LOGIT=2, GENTLE=3 };
+
+ // Splitting criteria
+ enum { DEFAULT=0, GINI=1, MISCLASS=3, SQERR=4 };
+
+ CvBoost();
+ virtual ~CvBoost();
+
+ CvBoost( const CvMat* _train_data, int _tflag,
+ const CvMat* _responses, const CvMat* _var_idx=0,
+ const CvMat* _sample_idx=0, const CvMat* _var_type=0,
+ const CvMat* _missing_mask=0,
+ CvBoostParams params=CvBoostParams() );
+
+ virtual bool train( const CvMat* _train_data, int _tflag,
+ const CvMat* _responses, const CvMat* _var_idx=0,
+ const CvMat* _sample_idx=0, const CvMat* _var_type=0,
+ const CvMat* _missing_mask=0,
+ CvBoostParams params=CvBoostParams(),
+ bool update=false );
+
+ virtual float predict( const CvMat* _sample, const CvMat* _missing=0,
+ CvMat* weak_responses=0, CvSlice slice=CV_WHOLE_SEQ,
+ bool raw_mode=false ) const;
+
+ virtual void prune( CvSlice slice );
+
+ virtual void clear();
+
+ virtual void write( CvFileStorage* storage, const char* name );
+ virtual void read( CvFileStorage* storage, CvFileNode* node );
+
+ CvSeq* get_weak_predictors();
+
+ CvMat* get_weights();
+ CvMat* get_subtree_weights();
+ CvMat* get_weak_response();
+ const CvBoostParams& get_params() const;
+
+protected:
+
+ virtual bool set_params( const CvBoostParams& _params );
+ virtual void update_weights( CvBoostTree* tree );
+ virtual void trim_weights();
+ virtual void write_params( CvFileStorage* fs );
+ virtual void read_params( CvFileStorage* fs, CvFileNode* node );
+
+ CvDTreeTrainData* data;
+ CvBoostParams params;
+ CvSeq* weak;
+
+ CvMat* orig_response;
+ CvMat* sum_response;
+ CvMat* weak_eval;
+ CvMat* subsample_mask;
+ CvMat* weights;
+ CvMat* subtree_weights;
+ bool have_subsample;
+};
+
+
+/****************************************************************************************\
+* Artificial Neural Networks (ANN) *
+\****************************************************************************************/
+
+/////////////////////////////////// Multi-Layer Perceptrons //////////////////////////////
+
+struct CV_EXPORTS CvANN_MLP_TrainParams
+{
+ CvANN_MLP_TrainParams();
+ CvANN_MLP_TrainParams( CvTermCriteria term_crit, int train_method,
+ double param1, double param2=0 );
+ ~CvANN_MLP_TrainParams();
+
+ enum { BACKPROP=0, RPROP=1 };
+
+ CvTermCriteria term_crit;
+ int train_method;
+
+ // backpropagation parameters
+ double bp_dw_scale, bp_moment_scale;
+
+ // rprop parameters
+ double rp_dw0, rp_dw_plus, rp_dw_minus, rp_dw_min, rp_dw_max;
+};
+
+
+class CV_EXPORTS CvANN_MLP : public CvStatModel
+{
+public:
+ CvANN_MLP();
+ CvANN_MLP( const CvMat* _layer_sizes,
+ int _activ_func=SIGMOID_SYM,
+ double _f_param1=0, double _f_param2=0 );
+
+ virtual ~CvANN_MLP();
+
+ virtual void create( const CvMat* _layer_sizes,
+ int _activ_func=SIGMOID_SYM,
+ double _f_param1=0, double _f_param2=0 );
+
+ virtual int train( const CvMat* _inputs, const CvMat* _outputs,
+ const CvMat* _sample_weights, const CvMat* _sample_idx=0,
+ CvANN_MLP_TrainParams _params = CvANN_MLP_TrainParams(),
+ int flags=0 );
+ virtual float predict( const CvMat* _inputs,
+ CvMat* _outputs ) const;
+
+ virtual void clear();
+
+ // possible activation functions
+ enum { IDENTITY = 0, SIGMOID_SYM = 1, GAUSSIAN = 2 };
+
+ // available training flags
+ enum { UPDATE_WEIGHTS = 1, NO_INPUT_SCALE = 2, NO_OUTPUT_SCALE = 4 };
+
+ virtual void read( CvFileStorage* fs, CvFileNode* node );
+ virtual void write( CvFileStorage* storage, const char* name );
+
+ int get_layer_count() { return layer_sizes ? layer_sizes->cols : 0; }
+ const CvMat* get_layer_sizes() { return layer_sizes; }
+ double* get_weights(int layer)
+ {
+ return layer_sizes && weights &&
+ (unsigned)layer <= (unsigned)layer_sizes->cols ? weights[layer] : 0;
+ }
+
+protected:
+
+ virtual bool prepare_to_train( const CvMat* _inputs, const CvMat* _outputs,
+ const CvMat* _sample_weights, const CvMat* _sample_idx,
+ CvVectors* _ivecs, CvVectors* _ovecs, double** _sw, int _flags );
+
+ // sequential random backpropagation
+ virtual int train_backprop( CvVectors _ivecs, CvVectors _ovecs, const double* _sw );
+
+ // RPROP algorithm
+ virtual int train_rprop( CvVectors _ivecs, CvVectors _ovecs, const double* _sw );
+
+ virtual void calc_activ_func( CvMat* xf, const double* bias ) const;
+ virtual void calc_activ_func_deriv( CvMat* xf, CvMat* deriv, const double* bias ) const;
+ virtual void set_activ_func( int _activ_func=SIGMOID_SYM,
+ double _f_param1=0, double _f_param2=0 );
+ virtual void init_weights();
+ virtual void scale_input( const CvMat* _src, CvMat* _dst ) const;
+ virtual void scale_output( const CvMat* _src, CvMat* _dst ) const;
+ virtual void calc_input_scale( const CvVectors* vecs, int flags );
+ virtual void calc_output_scale( const CvVectors* vecs, int flags );
+
+ virtual void write_params( CvFileStorage* fs );
+ virtual void read_params( CvFileStorage* fs, CvFileNode* node );
+
+ CvMat* layer_sizes;
+ CvMat* wbuf;
+ CvMat* sample_weights;
+ double** weights;
+ double f_param1, f_param2;
+ double min_val, max_val, min_val1, max_val1;
+ int activ_func;
+ int max_count, max_buf_sz;
+ CvANN_MLP_TrainParams params;
+ CvRNG rng;
+};
+
+#if 0
+/****************************************************************************************\
+* Convolutional Neural Network *
+\****************************************************************************************/
+typedef struct CvCNNLayer CvCNNLayer;
+typedef struct CvCNNetwork CvCNNetwork;
+
+#define CV_CNN_LEARN_RATE_DECREASE_HYPERBOLICALLY 1
+#define CV_CNN_LEARN_RATE_DECREASE_SQRT_INV 2
+#define CV_CNN_LEARN_RATE_DECREASE_LOG_INV 3
+
+#define CV_CNN_GRAD_ESTIM_RANDOM 0
+#define CV_CNN_GRAD_ESTIM_BY_WORST_IMG 1
+
+#define ICV_CNN_LAYER 0x55550000
+#define ICV_CNN_CONVOLUTION_LAYER 0x00001111
+#define ICV_CNN_SUBSAMPLING_LAYER 0x00002222
+#define ICV_CNN_FULLCONNECT_LAYER 0x00003333
+
+#define ICV_IS_CNN_LAYER( layer ) \
+ ( ((layer) != NULL) && ((((CvCNNLayer*)(layer))->flags & CV_MAGIC_MASK)\
+ == ICV_CNN_LAYER ))
+
+#define ICV_IS_CNN_CONVOLUTION_LAYER( layer ) \
+ ( (ICV_IS_CNN_LAYER( layer )) && (((CvCNNLayer*) (layer))->flags \
+ & ~CV_MAGIC_MASK) == ICV_CNN_CONVOLUTION_LAYER )
+
+#define ICV_IS_CNN_SUBSAMPLING_LAYER( layer ) \
+ ( (ICV_IS_CNN_LAYER( layer )) && (((CvCNNLayer*) (layer))->flags \
+ & ~CV_MAGIC_MASK) == ICV_CNN_SUBSAMPLING_LAYER )
+
+#define ICV_IS_CNN_FULLCONNECT_LAYER( layer ) \
+ ( (ICV_IS_CNN_LAYER( layer )) && (((CvCNNLayer*) (layer))->flags \
+ & ~CV_MAGIC_MASK) == ICV_CNN_FULLCONNECT_LAYER )
+
+typedef void (CV_CDECL *CvCNNLayerForward)
+ ( CvCNNLayer* layer, const CvMat* input, CvMat* output );
+
+typedef void (CV_CDECL *CvCNNLayerBackward)
+ ( CvCNNLayer* layer, int t, const CvMat* X, const CvMat* dE_dY, CvMat* dE_dX );
+
+typedef void (CV_CDECL *CvCNNLayerRelease)
+ (CvCNNLayer** layer);
+
+typedef void (CV_CDECL *CvCNNetworkAddLayer)
+ (CvCNNetwork* network, CvCNNLayer* layer);
+
+typedef void (CV_CDECL *CvCNNetworkRelease)
+ (CvCNNetwork** network);
+
+#define CV_CNN_LAYER_FIELDS() \
+ /* Indicator of the layer's type */ \
+ int flags; \
+ \
+ /* Number of input images */ \
+ int n_input_planes; \
+ /* Height of each input image */ \
+ int input_height; \
+ /* Width of each input image */ \
+ int input_width; \
+ \
+ /* Number of output images */ \
+ int n_output_planes; \
+ /* Height of each output image */ \
+ int output_height; \
+ /* Width of each output image */ \
+ int output_width; \
+ \
+ /* Learning rate at the first iteration */ \
+ float init_learn_rate; \
+ /* Dynamics of learning rate decreasing */ \
+ int learn_rate_decrease_type; \
+ /* Trainable weights of the layer (including bias) */ \
+ /* i-th row is a set of weights of the i-th output plane */ \
+ CvMat* weights; \
+ \
+ CvCNNLayerForward forward; \
+ CvCNNLayerBackward backward; \
+ CvCNNLayerRelease release; \
+ /* Pointers to the previous and next layers in the network */ \
+ CvCNNLayer* prev_layer; \
+ CvCNNLayer* next_layer
+
+typedef struct CvCNNLayer
+{
+ CV_CNN_LAYER_FIELDS();
+}CvCNNLayer;
+
+typedef struct CvCNNConvolutionLayer
+{
+ CV_CNN_LAYER_FIELDS();
+ // Kernel size (height and width) for convolution.
+ int K;
+ // connections matrix, (i,j)-th element is 1 iff there is a connection between
+ // i-th plane of the current layer and j-th plane of the previous layer;
+ // (i,j)-th element is equal to 0 otherwise
+ CvMat *connect_mask;
+ // value of the learning rate for updating weights at the first iteration
+}CvCNNConvolutionLayer;
+
+typedef struct CvCNNSubSamplingLayer
+{
+ CV_CNN_LAYER_FIELDS();
+ // ratio between the heights (or widths - ratios are supposed to be equal)
+ // of the input and output planes
+ int sub_samp_scale;
+ // amplitude of sigmoid activation function
+ float a;
+ // scale parameter of sigmoid activation function
+ float s;
+ // exp2ssumWX = exp(2<s>*(bias+w*(x1+...+x4))), where x1,...x4 are some elements of X
+ // - is the vector used in computing of the activation function in backward
+ CvMat* exp2ssumWX;
+ // (x1+x2+x3+x4), where x1,...x4 are some elements of X
+ // - is the vector used in computing of the activation function in backward
+ CvMat* sumX;
+}CvCNNSubSamplingLayer;
+
+// Structure of the last layer.
+typedef struct CvCNNFullConnectLayer
+{
+ CV_CNN_LAYER_FIELDS();
+ // amplitude of sigmoid activation function
+ float a;
+ // scale parameter of sigmoid activation function
+ float s;
+ // exp2ssumWX = exp(2*<s>*(W*X)) - is the vector used in computing of the
+ // activation function and it's derivative by the formulae
+ // activ.func. = <a>(exp(2<s>WX)-1)/(exp(2<s>WX)+1) == <a> - 2<a>/(<exp2ssumWX> + 1)
+ // (activ.func.)' = 4<a><s>exp(2<s>WX)/(exp(2<s>WX)+1)^2
+ CvMat* exp2ssumWX;
+}CvCNNFullConnectLayer;
+
+typedef struct CvCNNetwork
+{
+ int n_layers;
+ CvCNNLayer* layers;
+ CvCNNetworkAddLayer add_layer;
+ CvCNNetworkRelease release;
+}CvCNNetwork;
+
+typedef struct CvCNNStatModel
+{
+ CV_STAT_MODEL_FIELDS();
+ CvCNNetwork* network;
+ // etalons are allocated as rows, the i-th etalon has label cls_labeles[i]
+ CvMat* etalons;
+ // classes labels
+ CvMat* cls_labels;
+}CvCNNStatModel;
+
+typedef struct CvCNNStatModelParams
+{
+ CV_STAT_MODEL_PARAM_FIELDS();
+ // network must be created by the functions cvCreateCNNetwork and <add_layer>
+ CvCNNetwork* network;
+ CvMat* etalons;
+ // termination criteria
+ int max_iter;
+ int start_iter;
+ int grad_estim_type;
+}CvCNNStatModelParams;
+
+CVAPI(CvCNNLayer*) cvCreateCNNConvolutionLayer(
+ int n_input_planes, int input_height, int input_width,
+ int n_output_planes, int K,
+ float init_learn_rate, int learn_rate_decrease_type,
+ CvMat* connect_mask CV_DEFAULT(0), CvMat* weights CV_DEFAULT(0) );
+
+CVAPI(CvCNNLayer*) cvCreateCNNSubSamplingLayer(
+ int n_input_planes, int input_height, int input_width,
+ int sub_samp_scale, float a, float s,
+ float init_learn_rate, int learn_rate_decrease_type, CvMat* weights CV_DEFAULT(0) );
+
+CVAPI(CvCNNLayer*) cvCreateCNNFullConnectLayer(
+ int n_inputs, int n_outputs, float a, float s,
+ float init_learn_rate, int learning_type, CvMat* weights CV_DEFAULT(0) );
+
+CVAPI(CvCNNetwork*) cvCreateCNNetwork( CvCNNLayer* first_layer );
+
+CVAPI(CvStatModel*) cvTrainCNNClassifier(
+ const CvMat* train_data, int tflag,
+ const CvMat* responses,
+ const CvStatModelParams* params,
+ const CvMat* CV_DEFAULT(0),
+ const CvMat* sample_idx CV_DEFAULT(0),
+ const CvMat* CV_DEFAULT(0), const CvMat* CV_DEFAULT(0) );
+
+/****************************************************************************************\
+* Estimate classifiers algorithms *
+\****************************************************************************************/
+typedef const CvMat* (CV_CDECL *CvStatModelEstimateGetMat)
+ ( const CvStatModel* estimateModel );
+
+typedef int (CV_CDECL *CvStatModelEstimateNextStep)
+ ( CvStatModel* estimateModel );
+
+typedef void (CV_CDECL *CvStatModelEstimateCheckClassifier)
+ ( CvStatModel* estimateModel,
+ const CvStatModel* model,
+ const CvMat* features,
+ int sample_t_flag,
+ const CvMat* responses );
+
+typedef void (CV_CDECL *CvStatModelEstimateCheckClassifierEasy)
+ ( CvStatModel* estimateModel,
+ const CvStatModel* model );
+
+typedef float (CV_CDECL *CvStatModelEstimateGetCurrentResult)
+ ( const CvStatModel* estimateModel,
+ float* correlation );
+
+typedef void (CV_CDECL *CvStatModelEstimateReset)
+ ( CvStatModel* estimateModel );
+
+//-------------------------------- Cross-validation --------------------------------------
+#define CV_CROSS_VALIDATION_ESTIMATE_CLASSIFIER_PARAM_FIELDS() \
+ CV_STAT_MODEL_PARAM_FIELDS(); \
+ int k_fold; \
+ int is_regression; \
+ CvRNG* rng
+
+typedef struct CvCrossValidationParams
+{
+ CV_CROSS_VALIDATION_ESTIMATE_CLASSIFIER_PARAM_FIELDS();
+} CvCrossValidationParams;
+
+#define CV_CROSS_VALIDATION_ESTIMATE_CLASSIFIER_FIELDS() \
+ CvStatModelEstimateGetMat getTrainIdxMat; \
+ CvStatModelEstimateGetMat getCheckIdxMat; \
+ CvStatModelEstimateNextStep nextStep; \
+ CvStatModelEstimateCheckClassifier check; \
+ CvStatModelEstimateGetCurrentResult getResult; \
+ CvStatModelEstimateReset reset; \
+ int is_regression; \
+ int folds_all; \
+ int samples_all; \
+ int* sampleIdxAll; \
+ int* folds; \
+ int max_fold_size; \
+ int current_fold; \
+ int is_checked; \
+ CvMat* sampleIdxTrain; \
+ CvMat* sampleIdxEval; \
+ CvMat* predict_results; \
+ int correct_results; \
+ int all_results; \
+ double sq_error; \
+ double sum_correct; \
+ double sum_predict; \
+ double sum_cc; \
+ double sum_pp; \
+ double sum_cp
+
+typedef struct CvCrossValidationModel
+{
+ CV_STAT_MODEL_FIELDS();
+ CV_CROSS_VALIDATION_ESTIMATE_CLASSIFIER_FIELDS();
+} CvCrossValidationModel;
+
+CVAPI(CvStatModel*)
+cvCreateCrossValidationEstimateModel
+ ( int samples_all,
+ const CvStatModelParams* estimateParams CV_DEFAULT(0),
+ const CvMat* sampleIdx CV_DEFAULT(0) );
+
+CVAPI(float)
+cvCrossValidation( const CvMat* trueData,
+ int tflag,
+ const CvMat* trueClasses,
+ CvStatModel* (*createClassifier)( const CvMat*,
+ int,
+ const CvMat*,
+ const CvStatModelParams*,
+ const CvMat*,
+ const CvMat*,
+ const CvMat*,
+ const CvMat* ),
+ const CvStatModelParams* estimateParams CV_DEFAULT(0),
+ const CvStatModelParams* trainParams CV_DEFAULT(0),
+ const CvMat* compIdx CV_DEFAULT(0),
+ const CvMat* sampleIdx CV_DEFAULT(0),
+ CvStatModel** pCrValModel CV_DEFAULT(0),
+ const CvMat* typeMask CV_DEFAULT(0),
+ const CvMat* missedMeasurementMask CV_DEFAULT(0) );
+#endif
+
+/****************************************************************************************\
+* Auxilary functions declarations *
+\****************************************************************************************/
+
+/* Generates <sample> from multivariate normal distribution, where <mean> - is an
+ average row vector, <cov> - symmetric covariation matrix */
+CVAPI(void) cvRandMVNormal( CvMat* mean, CvMat* cov, CvMat* sample,
+ CvRNG* rng CV_DEFAULT(0) );
+
+/* Generates sample from gaussian mixture distribution */
+CVAPI(void) cvRandGaussMixture( CvMat* means[],
+ CvMat* covs[],
+ float weights[],
+ int clsnum,
+ CvMat* sample,
+ CvMat* sampClasses CV_DEFAULT(0) );
+
+#define CV_TS_CONCENTRIC_SPHERES 0
+
+/* creates test set */
+CVAPI(void) cvCreateTestSet( int type, CvMat** samples,
+ int num_samples,
+ int num_features,
+ CvMat** responses,
+ int num_classes, ... );
+
+/* Aij <- Aji for i > j if lower_to_upper != 0
+ for i < j if lower_to_upper = 0 */
+CVAPI(void) cvCompleteSymm( CvMat* matrix, int lower_to_upper );
+
+#endif
+
+#endif /*__ML_H__*/
+/* End of file. */
diff --git a/ml/src/_ml.h b/ml/src/_ml.h
new file mode 100644
index 0000000..ebe26e8
--- /dev/null
+++ b/ml/src/_ml.h
@@ -0,0 +1,354 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __ML_INTERNAL_H__
+#define __ML_INTERNAL_H__
+
+#if _MSC_VER >= 1200
+#pragma warning( disable: 4514 4710 4711 4710 )
+#endif
+
+#include "ml.h"
+#include "cxmisc.h"
+
+#include <assert.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#define ML_IMPL CV_IMPL
+
+#define CV_MAT_ELEM_FLAG( mat, type, comp, vect, tflag ) \
+ (( tflag == CV_ROW_SAMPLE ) \
+ ? (CV_MAT_ELEM( mat, type, comp, vect )) \
+ : (CV_MAT_ELEM( mat, type, vect, comp )))
+
+/* Convert matrix to vector */
+#define ICV_MAT2VEC( mat, vdata, vstep, num ) \
+ if( MIN( (mat).rows, (mat).cols ) != 1 ) \
+ CV_ERROR( CV_StsBadArg, "" ); \
+ (vdata) = ((mat).data.ptr); \
+ if( (mat).rows == 1 ) \
+ { \
+ (vstep) = CV_ELEM_SIZE( (mat).type ); \
+ (num) = (mat).cols; \
+ } \
+ else \
+ { \
+ (vstep) = (mat).step; \
+ (num) = (mat).rows; \
+ }
+
+/* get raw data */
+#define ICV_RAWDATA( mat, flags, rdata, sstep, cstep, m, n ) \
+ (rdata) = (mat).data.ptr; \
+ if( CV_IS_ROW_SAMPLE( flags ) ) \
+ { \
+ (sstep) = (mat).step; \
+ (cstep) = CV_ELEM_SIZE( (mat).type ); \
+ (m) = (mat).rows; \
+ (n) = (mat).cols; \
+ } \
+ else \
+ { \
+ (cstep) = (mat).step; \
+ (sstep) = CV_ELEM_SIZE( (mat).type ); \
+ (n) = (mat).rows; \
+ (m) = (mat).cols; \
+ }
+
+#define ICV_IS_MAT_OF_TYPE( mat, mat_type) \
+ (CV_IS_MAT( mat ) && CV_MAT_TYPE( mat->type ) == (mat_type) && \
+ (mat)->cols > 0 && (mat)->rows > 0)
+
+/*
+ uchar* data; int sstep, cstep; - trainData->data
+ uchar* classes; int clstep; int ncl;- trainClasses
+ uchar* tmask; int tmstep; int ntm; - typeMask
+ uchar* missed;int msstep, mcstep; -missedMeasurements...
+ int mm, mn; == m,n == size,dim
+ uchar* sidx;int sistep; - sampleIdx
+ uchar* cidx;int cistep; - compIdx
+ int k, l; == n,m == dim,size (length of cidx, sidx)
+ int m, n; == size,dim
+*/
+#define ICV_DECLARE_TRAIN_ARGS() \
+ uchar* data; \
+ int sstep, cstep; \
+ uchar* classes; \
+ int clstep; \
+ int ncl; \
+ uchar* tmask; \
+ int tmstep; \
+ int ntm; \
+ uchar* missed; \
+ int msstep, mcstep; \
+ int mm, mn; \
+ uchar* sidx; \
+ int sistep; \
+ uchar* cidx; \
+ int cistep; \
+ int k, l; \
+ int m, n; \
+ \
+ data = classes = tmask = missed = sidx = cidx = NULL; \
+ sstep = cstep = clstep = ncl = tmstep = ntm = msstep = mcstep = mm = mn = 0; \
+ sistep = cistep = k = l = m = n = 0;
+
+#define ICV_TRAIN_DATA_REQUIRED( param, flags ) \
+ if( !ICV_IS_MAT_OF_TYPE( (param), CV_32FC1 ) ) \
+ { \
+ CV_ERROR( CV_StsBadArg, "Invalid " #param " parameter" ); \
+ } \
+ else \
+ { \
+ ICV_RAWDATA( *(param), (flags), data, sstep, cstep, m, n ); \
+ k = n; \
+ l = m; \
+ }
+
+#define ICV_TRAIN_CLASSES_REQUIRED( param ) \
+ if( !ICV_IS_MAT_OF_TYPE( (param), CV_32FC1 ) ) \
+ { \
+ CV_ERROR( CV_StsBadArg, "Invalid " #param " parameter" ); \
+ } \
+ else \
+ { \
+ ICV_MAT2VEC( *(param), classes, clstep, ncl ); \
+ if( m != ncl ) \
+ { \
+ CV_ERROR( CV_StsBadArg, "Unmatched sizes" ); \
+ } \
+ }
+
+#define ICV_ARG_NULL( param ) \
+ if( (param) != NULL ) \
+ { \
+ CV_ERROR( CV_StsBadArg, #param " parameter must be NULL" ); \
+ }
+
+#define ICV_MISSED_MEASUREMENTS_OPTIONAL( param, flags ) \
+ if( param ) \
+ { \
+ if( !ICV_IS_MAT_OF_TYPE( param, CV_8UC1 ) ) \
+ { \
+ CV_ERROR( CV_StsBadArg, "Invalid " #param " parameter" ); \
+ } \
+ else \
+ { \
+ ICV_RAWDATA( *(param), (flags), missed, msstep, mcstep, mm, mn ); \
+ if( mm != m || mn != n ) \
+ { \
+ CV_ERROR( CV_StsBadArg, "Unmatched sizes" ); \
+ } \
+ } \
+ }
+
+#define ICV_COMP_IDX_OPTIONAL( param ) \
+ if( param ) \
+ { \
+ if( !ICV_IS_MAT_OF_TYPE( param, CV_32SC1 ) ) \
+ { \
+ CV_ERROR( CV_StsBadArg, "Invalid " #param " parameter" ); \
+ } \
+ else \
+ { \
+ ICV_MAT2VEC( *(param), cidx, cistep, k ); \
+ if( k > n ) \
+ CV_ERROR( CV_StsBadArg, "Invalid " #param " parameter" ); \
+ } \
+ }
+
+#define ICV_SAMPLE_IDX_OPTIONAL( param ) \
+ if( param ) \
+ { \
+ if( !ICV_IS_MAT_OF_TYPE( param, CV_32SC1 ) ) \
+ { \
+ CV_ERROR( CV_StsBadArg, "Invalid " #param " parameter" ); \
+ } \
+ else \
+ { \
+ ICV_MAT2VEC( *sampleIdx, sidx, sistep, l ); \
+ if( l > m ) \
+ CV_ERROR( CV_StsBadArg, "Invalid " #param " parameter" ); \
+ } \
+ }
+
+/****************************************************************************************/
+#define ICV_CONVERT_FLOAT_ARRAY_TO_MATRICE( array, matrice ) \
+{ \
+ CvMat a, b; \
+ int dims = (matrice)->cols; \
+ int nsamples = (matrice)->rows; \
+ int type = CV_MAT_TYPE((matrice)->type); \
+ int i, offset = dims; \
+ \
+ CV_ASSERT( type == CV_32FC1 || type == CV_64FC1 ); \
+ offset *= ((type == CV_32FC1) ? sizeof(float) : sizeof(double));\
+ \
+ b = cvMat( 1, dims, CV_32FC1 ); \
+ cvGetRow( matrice, &a, 0 ); \
+ for( i = 0; i < nsamples; i++, a.data.ptr += offset ) \
+ { \
+ b.data.fl = (float*)array[i]; \
+ CV_CALL( cvConvert( &b, &a ) ); \
+ } \
+}
+
+/****************************************************************************************\
+* Auxiliary functions declarations *
+\****************************************************************************************/
+
+/* Generates a set of classes centers in quantity <num_of_clusters> that are generated as
+ uniform random vectors in parallelepiped, where <data> is concentrated. Vectors in
+ <data> should have horizontal orientation. If <centers> != NULL, the function doesn't
+ allocate any memory and stores generated centers in <centers>, returns <centers>.
+ If <centers> == NULL, the function allocates memory and creates the matrice. Centers
+ are supposed to be oriented horizontally. */
+CvMat* icvGenerateRandomClusterCenters( int seed,
+ const CvMat* data,
+ int num_of_clusters,
+ CvMat* centers CV_DEFAULT(0));
+
+/* Fills the <labels> using <probs> by choosing the maximal probability. Outliers are
+ fixed by <oulier_tresh> and have cluster label (-1). Function also controls that there
+ weren't "empty" clusters by filling empty clusters with the maximal probability vector.
+ If probs_sums != NULL, filles it with the sums of probabilities for each sample (it is
+ useful for normalizing probabilities' matrice of FCM) */
+void icvFindClusterLabels( const CvMat* probs, float outlier_thresh, float r,
+ const CvMat* labels );
+
+typedef struct CvSparseVecElem32f
+{
+ int idx;
+ float val;
+}
+CvSparseVecElem32f;
+
+/* Prepare training data and related parameters */
+#define CV_TRAIN_STATMODEL_DEFRAGMENT_TRAIN_DATA 1
+#define CV_TRAIN_STATMODEL_SAMPLES_AS_ROWS 2
+#define CV_TRAIN_STATMODEL_SAMPLES_AS_COLUMNS 4
+#define CV_TRAIN_STATMODEL_CATEGORICAL_RESPONSE 8
+#define CV_TRAIN_STATMODEL_ORDERED_RESPONSE 16
+#define CV_TRAIN_STATMODEL_RESPONSES_ON_OUTPUT 32
+#define CV_TRAIN_STATMODEL_ALWAYS_COPY_TRAIN_DATA 64
+#define CV_TRAIN_STATMODEL_SPARSE_AS_SPARSE 128
+
+int
+cvPrepareTrainData( const char* /*funcname*/,
+ const CvMat* train_data, int tflag,
+ const CvMat* responses, int response_type,
+ const CvMat* var_idx,
+ const CvMat* sample_idx,
+ bool always_copy_data,
+ const float*** out_train_samples,
+ int* _sample_count,
+ int* _var_count,
+ int* _var_all,
+ CvMat** out_responses,
+ CvMat** out_response_map,
+ CvMat** out_var_idx,
+ CvMat** out_sample_idx=0 );
+
+void
+cvSortSamplesByClasses( const float** samples, const CvMat* classes,
+ int* class_ranges, const uchar** mask CV_DEFAULT(0) );
+
+void
+cvCombineResponseMaps (CvMat* _responses,
+ const CvMat* old_response_map,
+ CvMat* new_response_map,
+ CvMat** out_response_map);
+
+void
+cvPreparePredictData( const CvArr* sample, int dims_all, const CvMat* comp_idx,
+ int class_count, const CvMat* prob, float** row_sample,
+ int as_sparse CV_DEFAULT(0) );
+
+/* copies clustering [or batch "predict"] results
+ (labels and/or centers and/or probs) back to the output arrays */
+void
+cvWritebackLabels( const CvMat* labels, CvMat* dst_labels,
+ const CvMat* centers, CvMat* dst_centers,
+ const CvMat* probs, CvMat* dst_probs,
+ const CvMat* sample_idx, int samples_all,
+ const CvMat* comp_idx, int dims_all );
+#define cvWritebackResponses cvWritebackLabels
+
+#define XML_FIELD_NAME "_name"
+CvFileNode* icvFileNodeGetChild(CvFileNode* father, const char* name);
+CvFileNode* icvFileNodeGetChildArrayElem(CvFileNode* father, const char* name,int index);
+CvFileNode* icvFileNodeGetNext(CvFileNode* n, const char* name);
+
+
+void cvCheckTrainData( const CvMat* train_data, int tflag,
+ const CvMat* missing_mask,
+ int* var_all, int* sample_all );
+
+CvMat* cvPreprocessIndexArray( const CvMat* idx_arr, int data_arr_size, bool check_for_duplicates=false );
+
+CvMat* cvPreprocessVarType( const CvMat* type_mask, const CvMat* var_idx,
+ int var_all, int* response_type );
+
+CvMat* cvPreprocessOrderedResponses( const CvMat* responses,
+ const CvMat* sample_idx, int sample_all );
+
+CvMat* cvPreprocessCategoricalResponses( const CvMat* responses,
+ const CvMat* sample_idx, int sample_all,
+ CvMat** out_response_map, CvMat** class_counts=0 );
+
+const float** cvGetTrainSamples( const CvMat* train_data, int tflag,
+ const CvMat* var_idx, const CvMat* sample_idx,
+ int* _var_count, int* _sample_count,
+ bool always_copy_data=false );
+
+#endif /* __ML_H__ */
diff --git a/ml/src/ml.cpp b/ml/src/ml.cpp
new file mode 100644
index 0000000..33acc48
--- /dev/null
+++ b/ml/src/ml.cpp
@@ -0,0 +1,41 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_ml.h"
diff --git a/ml/src/ml_inner_functions.cpp b/ml/src/ml_inner_functions.cpp
new file mode 100644
index 0000000..eb534fe
--- /dev/null
+++ b/ml/src/ml_inner_functions.cpp
@@ -0,0 +1,1953 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_ml.h"
+
+
+CvStatModel::CvStatModel()
+{
+ default_model_name = "my_stat_model";
+}
+
+
+CvStatModel::~CvStatModel()
+{
+ clear();
+}
+
+
+void CvStatModel::clear()
+{
+}
+
+
+void CvStatModel::save( const char* filename, const char* name )
+{
+ CvFileStorage* fs = 0;
+
+ CV_FUNCNAME( "CvStatModel::save" );
+
+ __BEGIN__;
+
+ CV_CALL( fs = cvOpenFileStorage( filename, 0, CV_STORAGE_WRITE ));
+ if( !fs )
+ CV_ERROR( CV_StsError, "Could not open the file storage. Check the path and permissions" );
+
+ write( fs, name ? name : default_model_name );
+
+ __END__;
+
+ cvReleaseFileStorage( &fs );
+}
+
+
+void CvStatModel::load( const char* filename, const char* name )
+{
+ CvFileStorage* fs = 0;
+
+ CV_FUNCNAME( "CvStatModel::load" );
+
+ __BEGIN__;
+
+ CvFileNode* model_node = 0;
+
+ CV_CALL( fs = cvOpenFileStorage( filename, 0, CV_STORAGE_READ ));
+ if( !fs )
+ EXIT;
+
+ if( name )
+ model_node = cvGetFileNodeByName( fs, 0, name );
+ else
+ {
+ CvFileNode* root = cvGetRootFileNode( fs );
+ if( root->data.seq->total > 0 )
+ model_node = (CvFileNode*)cvGetSeqElem( root->data.seq, 0 );
+ }
+
+ read( fs, model_node );
+
+ __END__;
+
+ cvReleaseFileStorage( &fs );
+}
+
+
+void CvStatModel::write( CvFileStorage*, const char* )
+{
+ OPENCV_ERROR( CV_StsNotImplemented, "CvStatModel::write", "" );
+}
+
+
+void CvStatModel::read( CvFileStorage*, CvFileNode* )
+{
+ OPENCV_ERROR( CV_StsNotImplemented, "CvStatModel::read", "" );
+}
+
+
+/* Calculates upper triangular matrix S, where A is a symmetrical matrix A=S'*S */
+CV_IMPL void cvChol( CvMat* A, CvMat* S )
+{
+ int dim = A->rows;
+
+ int i, j, k;
+ float sum;
+
+ for( i = 0; i < dim; i++ )
+ {
+ for( j = 0; j < i; j++ )
+ CV_MAT_ELEM(*S, float, i, j) = 0;
+
+ sum = 0;
+ for( k = 0; k < i; k++ )
+ sum += CV_MAT_ELEM(*S, float, k, i) * CV_MAT_ELEM(*S, float, k, i);
+
+ CV_MAT_ELEM(*S, float, i, i) = (float)sqrt(CV_MAT_ELEM(*A, float, i, i) - sum);
+
+ for( j = i + 1; j < dim; j++ )
+ {
+ sum = 0;
+ for( k = 0; k < i; k++ )
+ sum += CV_MAT_ELEM(*S, float, k, i) * CV_MAT_ELEM(*S, float, k, j);
+
+ CV_MAT_ELEM(*S, float, i, j) =
+ (CV_MAT_ELEM(*A, float, i, j) - sum) / CV_MAT_ELEM(*S, float, i, i);
+
+ }
+ }
+}
+
+/* Generates <sample> from multivariate normal distribution, where <mean> - is an
+ average row vector, <cov> - symmetric covariation matrix */
+CV_IMPL void cvRandMVNormal( CvMat* mean, CvMat* cov, CvMat* sample, CvRNG* rng )
+{
+ int dim = sample->cols;
+ int amount = sample->rows;
+
+ CvRNG state = rng ? *rng : cvRNG(time(0));
+ cvRandArr(&state, sample, CV_RAND_NORMAL, cvScalarAll(0), cvScalarAll(1) );
+
+ CvMat* utmat = cvCreateMat(dim, dim, sample->type);
+ CvMat* vect = cvCreateMatHeader(1, dim, sample->type);
+
+ cvChol(cov, utmat);
+
+ int i;
+ for( i = 0; i < amount; i++ )
+ {
+ cvGetRow(sample, vect, i);
+ cvMatMulAdd(vect, utmat, mean, vect);
+ }
+
+ cvReleaseMat(&vect);
+ cvReleaseMat(&utmat);
+}
+
+
+/* Generates <sample> of <amount> points from a discrete variate xi,
+ where Pr{xi = k} == probs[k], 0 < k < len - 1. */
+CV_IMPL void cvRandSeries( float probs[], int len, int sample[], int amount )
+{
+ CvMat* univals = cvCreateMat(1, amount, CV_32FC1);
+ float* knots = (float*)cvAlloc( len * sizeof(float) );
+
+ int i, j;
+
+ CvRNG state = cvRNG(-1);
+ cvRandArr(&state, univals, CV_RAND_UNI, cvScalarAll(0), cvScalarAll(1) );
+
+ knots[0] = probs[0];
+ for( i = 1; i < len; i++ )
+ knots[i] = knots[i - 1] + probs[i];
+
+ for( i = 0; i < amount; i++ )
+ for( j = 0; j < len; j++ )
+ {
+ if ( CV_MAT_ELEM(*univals, float, 0, i) <= knots[j] )
+ {
+ sample[i] = j;
+ break;
+ }
+ }
+
+ cvFree(&knots);
+}
+
+/* Generates <sample> from gaussian mixture distribution */
+CV_IMPL void cvRandGaussMixture( CvMat* means[],
+ CvMat* covs[],
+ float weights[],
+ int clsnum,
+ CvMat* sample,
+ CvMat* sampClasses )
+{
+ int dim = sample->cols;
+ int amount = sample->rows;
+
+ int i, clss;
+
+ int* sample_clsnum = (int*)cvAlloc( amount * sizeof(int) );
+ CvMat** utmats = (CvMat**)cvAlloc( clsnum * sizeof(CvMat*) );
+ CvMat* vect = cvCreateMatHeader(1, dim, CV_32FC1);
+
+ CvMat* classes;
+ if( sampClasses )
+ classes = sampClasses;
+ else
+ classes = cvCreateMat(1, amount, CV_32FC1);
+
+ CvRNG state = cvRNG(-1);
+ cvRandArr(&state, sample, CV_RAND_NORMAL, cvScalarAll(0), cvScalarAll(1));
+
+ cvRandSeries(weights, clsnum, sample_clsnum, amount);
+
+ for( i = 0; i < clsnum; i++ )
+ {
+ utmats[i] = cvCreateMat(dim, dim, CV_32FC1);
+ cvChol(covs[i], utmats[i]);
+ }
+
+ for( i = 0; i < amount; i++ )
+ {
+ CV_MAT_ELEM(*classes, float, 0, i) = (float)sample_clsnum[i];
+ cvGetRow(sample, vect, i);
+ clss = sample_clsnum[i];
+ cvMatMulAdd(vect, utmats[clss], means[clss], vect);
+ }
+
+ if( !sampClasses )
+ cvReleaseMat(&classes);
+ for( i = 0; i < clsnum; i++ )
+ cvReleaseMat(&utmats[i]);
+ cvFree(&utmats);
+ cvFree(&sample_clsnum);
+ cvReleaseMat(&vect);
+}
+
+
+CvMat* icvGenerateRandomClusterCenters ( int seed, const CvMat* data,
+ int num_of_clusters, CvMat* _centers )
+{
+ CvMat* centers = _centers;
+
+ CV_FUNCNAME("icvGenerateRandomClusterCenters");
+ __BEGIN__;
+
+ CvRNG rng;
+ CvMat data_comp, centers_comp;
+ CvPoint minLoc, maxLoc; // Not used, just for function "cvMinMaxLoc"
+ double minVal, maxVal;
+ int i;
+ int dim = data ? data->cols : 0;
+
+ if( ICV_IS_MAT_OF_TYPE(data, CV_32FC1) )
+ {
+ if( _centers && !ICV_IS_MAT_OF_TYPE (_centers, CV_32FC1) )
+ {
+ CV_ERROR(CV_StsBadArg,"");
+ }
+ else if( !_centers )
+ CV_CALL(centers = cvCreateMat (num_of_clusters, dim, CV_32FC1));
+ }
+ else if( ICV_IS_MAT_OF_TYPE(data, CV_64FC1) )
+ {
+ if( _centers && !ICV_IS_MAT_OF_TYPE (_centers, CV_64FC1) )
+ {
+ CV_ERROR(CV_StsBadArg,"");
+ }
+ else if( !_centers )
+ CV_CALL(centers = cvCreateMat (num_of_clusters, dim, CV_64FC1));
+ }
+ else
+ CV_ERROR (CV_StsBadArg,"");
+
+ if( num_of_clusters < 1 )
+ CV_ERROR (CV_StsBadArg,"");
+
+ rng = cvRNG(seed);
+ for (i = 0; i < dim; i++)
+ {
+ CV_CALL(cvGetCol (data, &data_comp, i));
+ CV_CALL(cvMinMaxLoc (&data_comp, &minVal, &maxVal, &minLoc, &maxLoc));
+ CV_CALL(cvGetCol (centers, &centers_comp, i));
+ CV_CALL(cvRandArr (&rng, &centers_comp, CV_RAND_UNI, cvScalarAll(minVal), cvScalarAll(maxVal)));
+ }
+
+ __END__;
+
+ if( (cvGetErrStatus () < 0) || (centers != _centers) )
+ cvReleaseMat (&centers);
+
+ return _centers ? _centers : centers;
+} // end of icvGenerateRandomClusterCenters
+
+// By S. Dilman - begin -
+
+#define ICV_RAND_MAX 4294967296 // == 2^32
+
+CV_IMPL void cvRandRoundUni (CvMat* center,
+ float radius_small,
+ float radius_large,
+ CvMat* desired_matrix,
+ CvRNG* rng_state_ptr)
+{
+ float rad, norm, coefficient;
+ int dim, size, i, j;
+ CvMat *cov, sample;
+ CvRNG rng_local;
+
+ CV_FUNCNAME("cvRandRoundUni");
+ __BEGIN__
+
+ rng_local = *rng_state_ptr;
+
+ CV_ASSERT ((radius_small >= 0) &&
+ (radius_large > 0) &&
+ (radius_small <= radius_large));
+ CV_ASSERT (center && desired_matrix && rng_state_ptr);
+ CV_ASSERT (center->rows == 1);
+ CV_ASSERT (center->cols == desired_matrix->cols);
+
+ dim = desired_matrix->cols;
+ size = desired_matrix->rows;
+ cov = cvCreateMat (dim, dim, CV_32FC1);
+ cvSetIdentity (cov);
+ cvRandMVNormal (center, cov, desired_matrix, &rng_local);
+
+ for (i = 0; i < size; i++)
+ {
+ rad = (float)(cvRandReal(&rng_local)*(radius_large - radius_small) + radius_small);
+ cvGetRow (desired_matrix, &sample, i);
+ norm = (float) cvNorm (&sample, 0, CV_L2);
+ coefficient = rad / norm;
+ for (j = 0; j < dim; j++)
+ CV_MAT_ELEM (sample, float, 0, j) *= coefficient;
+ }
+
+ __END__
+
+}
+
+// By S. Dilman - end -
+
+/* Aij <- Aji for i > j if lower_to_upper != 0
+ for i < j if lower_to_upper = 0 */
+void cvCompleteSymm( CvMat* matrix, int lower_to_upper )
+{
+ CV_FUNCNAME("cvCompleteSymm");
+
+ __BEGIN__;
+
+ int rows, cols;
+ int i, j;
+ int step;
+
+ if( !CV_IS_MAT(matrix))
+ CV_ERROR(CV_StsBadArg, "Invalid matrix argument");
+
+ rows = matrix->rows;
+ cols = matrix->cols;
+ step = matrix->step / CV_ELEM_SIZE(matrix->type);
+
+ switch(CV_MAT_TYPE(matrix->type))
+ {
+ case CV_32FC1:
+ {
+ float* dst = matrix->data.fl;
+ if( !lower_to_upper )
+ for( i = 1; i < rows; i++ )
+ {
+ const float* src = (const float*)(matrix->data.fl + i);
+ dst += step;
+ for( j = 0; j < i; j++, src += step )
+ dst[j] = src[0];
+ }
+ else
+ for( i = 0; i < rows-1; i++, dst += step )
+ {
+ const float* src = (const float*)(matrix->data.fl + (i+1)*step + i);
+ for( j = i+1; j < cols; j++, src += step )
+ dst[j] = src[0];
+ }
+ }
+ break;
+ case CV_64FC1:
+ {
+ double* dst = matrix->data.db;
+ if( !lower_to_upper )
+ for( i = 1; i < rows; i++ )
+ {
+ const double* src = (const double*)(matrix->data.db + i);
+ dst += step;
+ for( j = 0; j < i; j++, src += step )
+ dst[j] = src[0];
+ }
+ else
+ for( i = 0; i < rows-1; i++, dst += step )
+ {
+ const double* src = (const double*)(matrix->data.db + (i+1)*step + i);
+ for( j = i+1; j < cols; j++, src += step )
+ dst[j] = src[0];
+ }
+ }
+ break;
+ }
+
+ __END__;
+}
+
+
+static int CV_CDECL
+icvCmpIntegers( const void* a, const void* b )
+{
+ return *(const int*)a - *(const int*)b;
+}
+
+
+static int CV_CDECL
+icvCmpIntegersPtr( const void* _a, const void* _b )
+{
+ int a = **(const int**)_a;
+ int b = **(const int**)_b;
+ return (a < b ? -1 : 0)|(a > b);
+}
+
+
+static int icvCmpSparseVecElems( const void* a, const void* b )
+{
+ return ((CvSparseVecElem32f*)a)->idx - ((CvSparseVecElem32f*)b)->idx;
+}
+
+
+CvMat*
+cvPreprocessIndexArray( const CvMat* idx_arr, int data_arr_size, bool check_for_duplicates )
+{
+ CvMat* idx = 0;
+
+ CV_FUNCNAME( "cvPreprocessIndexArray" );
+
+ __BEGIN__;
+
+ int i, idx_total, idx_selected = 0, step, type, prev = INT_MIN, is_sorted = 1;
+ uchar* srcb = 0;
+ int* srci = 0;
+ int* dsti;
+
+ if( !CV_IS_MAT(idx_arr) )
+ CV_ERROR( CV_StsBadArg, "Invalid index array" );
+
+ if( idx_arr->rows != 1 && idx_arr->cols != 1 )
+ CV_ERROR( CV_StsBadSize, "the index array must be 1-dimensional" );
+
+ idx_total = idx_arr->rows + idx_arr->cols - 1;
+ srcb = idx_arr->data.ptr;
+ srci = idx_arr->data.i;
+
+ type = CV_MAT_TYPE(idx_arr->type);
+ step = CV_IS_MAT_CONT(idx_arr->type) ? 1 : idx_arr->step/CV_ELEM_SIZE(type);
+
+ switch( type )
+ {
+ case CV_8UC1:
+ case CV_8SC1:
+ // idx_arr is array of 1's and 0's -
+ // i.e. it is a mask of the selected components
+ if( idx_total != data_arr_size )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Component mask should contain as many elements as the total number of input variables" );
+
+ for( i = 0; i < idx_total; i++ )
+ idx_selected += srcb[i*step] != 0;
+
+ if( idx_selected == 0 )
+ CV_ERROR( CV_StsOutOfRange, "No components/input_variables is selected!" );
+
+ if( idx_selected == idx_total )
+ EXIT;
+ break;
+ case CV_32SC1:
+ // idx_arr is array of integer indices of selected components
+ if( idx_total > data_arr_size )
+ CV_ERROR( CV_StsOutOfRange,
+ "index array may not contain more elements than the total number of input variables" );
+ idx_selected = idx_total;
+ // check if sorted already
+ for( i = 0; i < idx_total; i++ )
+ {
+ int val = srci[i*step];
+ if( val >= prev )
+ {
+ is_sorted = 0;
+ break;
+ }
+ prev = val;
+ }
+ break;
+ default:
+ CV_ERROR( CV_StsUnsupportedFormat, "Unsupported index array data type "
+ "(it should be 8uC1, 8sC1 or 32sC1)" );
+ }
+
+ CV_CALL( idx = cvCreateMat( 1, idx_selected, CV_32SC1 ));
+ dsti = idx->data.i;
+
+ if( type < CV_32SC1 )
+ {
+ for( i = 0; i < idx_total; i++ )
+ if( srcb[i*step] )
+ *dsti++ = i;
+ }
+ else
+ {
+ for( i = 0; i < idx_total; i++ )
+ dsti[i] = srci[i*step];
+
+ if( !is_sorted )
+ qsort( dsti, idx_total, sizeof(dsti[0]), icvCmpIntegers );
+
+ if( dsti[0] < 0 || dsti[idx_total-1] >= data_arr_size )
+ CV_ERROR( CV_StsOutOfRange, "the index array elements are out of range" );
+
+ if( check_for_duplicates )
+ {
+ for( i = 1; i < idx_total; i++ )
+ if( dsti[i] <= dsti[i-1] )
+ CV_ERROR( CV_StsBadArg, "There are duplicated index array elements" );
+ }
+ }
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ cvReleaseMat( &idx );
+
+ return idx;
+}
+
+
+CvMat*
+cvPreprocessVarType( const CvMat* var_type, const CvMat* var_idx,
+ int var_all, int* response_type )
+{
+ CvMat* out_var_type = 0;
+ CV_FUNCNAME( "cvPreprocessVarType" );
+
+ if( response_type )
+ *response_type = -1;
+
+ __BEGIN__;
+
+ int i, tm_size, tm_step;
+ int* map = 0;
+ const uchar* src;
+ uchar* dst;
+ int var_count = var_all;
+
+ if( !CV_IS_MAT(var_type) )
+ CV_ERROR( var_type ? CV_StsBadArg : CV_StsNullPtr, "Invalid or absent var_type array" );
+
+ if( var_type->rows != 1 && var_type->cols != 1 )
+ CV_ERROR( CV_StsBadSize, "var_type array must be 1-dimensional" );
+
+ if( !CV_IS_MASK_ARR(var_type))
+ CV_ERROR( CV_StsUnsupportedFormat, "type mask must be 8uC1 or 8sC1 array" );
+
+ tm_size = var_type->rows + var_type->cols - 1;
+ tm_step = var_type->step ? var_type->step/CV_ELEM_SIZE(var_type->type) : 1;
+
+ if( /*tm_size != var_count &&*/ tm_size != var_count + 1 )
+ CV_ERROR( CV_StsBadArg,
+ "type mask must be of <input var count> + 1 size" );
+
+ if( response_type && tm_size > var_count )
+ *response_type = var_type->data.ptr[var_count*tm_step] != 0;
+
+ if( var_idx )
+ {
+ if( !CV_IS_MAT(var_idx) || CV_MAT_TYPE(var_idx->type) != CV_32SC1 ||
+ var_idx->rows != 1 && var_idx->cols != 1 || !CV_IS_MAT_CONT(var_idx->type) )
+ CV_ERROR( CV_StsBadArg, "var index array should be continuous 1-dimensional integer vector" );
+ if( var_idx->rows + var_idx->cols - 1 > var_count )
+ CV_ERROR( CV_StsBadSize, "var index array is too large" );
+ map = var_idx->data.i;
+ var_count = var_idx->rows + var_idx->cols - 1;
+ }
+
+ CV_CALL( out_var_type = cvCreateMat( 1, var_count, CV_8UC1 ));
+ src = var_type->data.ptr;
+ dst = out_var_type->data.ptr;
+
+ for( i = 0; i < var_count; i++ )
+ {
+ int idx = map ? map[i] : i;
+ assert( (unsigned)idx < (unsigned)tm_size );
+ dst[i] = (uchar)(src[idx*tm_step] != 0);
+ }
+
+ __END__;
+
+ return out_var_type;
+}
+
+
+CvMat*
+cvPreprocessOrderedResponses( const CvMat* responses, const CvMat* sample_idx, int sample_all )
+{
+ CvMat* out_responses = 0;
+
+ CV_FUNCNAME( "cvPreprocessOrderedResponses" );
+
+ __BEGIN__;
+
+ int i, r_type, r_step;
+ const int* map = 0;
+ float* dst;
+ int sample_count = sample_all;
+
+ if( !CV_IS_MAT(responses) )
+ CV_ERROR( CV_StsBadArg, "Invalid response array" );
+
+ if( responses->rows != 1 && responses->cols != 1 )
+ CV_ERROR( CV_StsBadSize, "Response array must be 1-dimensional" );
+
+ if( responses->rows + responses->cols - 1 != sample_count )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Response array must contain as many elements as the total number of samples" );
+
+ r_type = CV_MAT_TYPE(responses->type);
+ if( r_type != CV_32FC1 && r_type != CV_32SC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Unsupported response type" );
+
+ r_step = responses->step ? responses->step / CV_ELEM_SIZE(responses->type) : 1;
+
+ if( r_type == CV_32FC1 && CV_IS_MAT_CONT(responses->type) && !sample_idx )
+ {
+ out_responses = (CvMat*)responses;
+ EXIT;
+ }
+
+ if( sample_idx )
+ {
+ if( !CV_IS_MAT(sample_idx) || CV_MAT_TYPE(sample_idx->type) != CV_32SC1 ||
+ sample_idx->rows != 1 && sample_idx->cols != 1 || !CV_IS_MAT_CONT(sample_idx->type) )
+ CV_ERROR( CV_StsBadArg, "sample index array should be continuous 1-dimensional integer vector" );
+ if( sample_idx->rows + sample_idx->cols - 1 > sample_count )
+ CV_ERROR( CV_StsBadSize, "sample index array is too large" );
+ map = sample_idx->data.i;
+ sample_count = sample_idx->rows + sample_idx->cols - 1;
+ }
+
+ CV_CALL( out_responses = cvCreateMat( 1, sample_count, CV_32FC1 ));
+
+ dst = out_responses->data.fl;
+ if( r_type == CV_32FC1 )
+ {
+ const float* src = responses->data.fl;
+ for( i = 0; i < sample_count; i++ )
+ {
+ int idx = map ? map[i] : i;
+ assert( (unsigned)idx < (unsigned)sample_all );
+ dst[i] = src[idx*r_step];
+ }
+ }
+ else
+ {
+ const int* src = responses->data.i;
+ for( i = 0; i < sample_count; i++ )
+ {
+ int idx = map ? map[i] : i;
+ assert( (unsigned)idx < (unsigned)sample_all );
+ dst[i] = (float)src[idx*r_step];
+ }
+ }
+
+ __END__;
+
+ return out_responses;
+}
+
+CvMat*
+cvPreprocessCategoricalResponses( const CvMat* responses,
+ const CvMat* sample_idx, int sample_all,
+ CvMat** out_response_map, CvMat** class_counts )
+{
+ CvMat* out_responses = 0;
+ int** response_ptr = 0;
+
+ CV_FUNCNAME( "cvPreprocessCategoricalResponses" );
+
+ if( out_response_map )
+ *out_response_map = 0;
+
+ if( class_counts )
+ *class_counts = 0;
+
+ __BEGIN__;
+
+ int i, r_type, r_step;
+ int cls_count = 1, prev_cls, prev_i;
+ const int* map = 0;
+ const int* srci;
+ const float* srcfl;
+ int* dst;
+ int* cls_map;
+ int* cls_counts = 0;
+ int sample_count = sample_all;
+
+ if( !CV_IS_MAT(responses) )
+ CV_ERROR( CV_StsBadArg, "Invalid response array" );
+
+ if( responses->rows != 1 && responses->cols != 1 )
+ CV_ERROR( CV_StsBadSize, "Response array must be 1-dimensional" );
+
+ if( responses->rows + responses->cols - 1 != sample_count )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Response array must contain as many elements as the total number of samples" );
+
+ r_type = CV_MAT_TYPE(responses->type);
+ if( r_type != CV_32FC1 && r_type != CV_32SC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Unsupported response type" );
+
+ r_step = responses->step ? responses->step / CV_ELEM_SIZE(responses->type) : 1;
+
+ if( sample_idx )
+ {
+ if( !CV_IS_MAT(sample_idx) || CV_MAT_TYPE(sample_idx->type) != CV_32SC1 ||
+ sample_idx->rows != 1 && sample_idx->cols != 1 || !CV_IS_MAT_CONT(sample_idx->type) )
+ CV_ERROR( CV_StsBadArg, "sample index array should be continuous 1-dimensional integer vector" );
+ if( sample_idx->rows + sample_idx->cols - 1 > sample_count )
+ CV_ERROR( CV_StsBadSize, "sample index array is too large" );
+ map = sample_idx->data.i;
+ sample_count = sample_idx->rows + sample_idx->cols - 1;
+ }
+
+ CV_CALL( out_responses = cvCreateMat( 1, sample_count, CV_32SC1 ));
+
+ if( !out_response_map )
+ CV_ERROR( CV_StsNullPtr, "out_response_map pointer is NULL" );
+
+ CV_CALL( response_ptr = (int**)cvAlloc( sample_count*sizeof(response_ptr[0])));
+
+ srci = responses->data.i;
+ srcfl = responses->data.fl;
+ dst = out_responses->data.i;
+
+ for( i = 0; i < sample_count; i++ )
+ {
+ int idx = map ? map[i] : i;
+ assert( (unsigned)idx < (unsigned)sample_all );
+ if( r_type == CV_32SC1 )
+ dst[i] = srci[idx*r_step];
+ else
+ {
+ float rf = srcfl[idx*r_step];
+ int ri = cvRound(rf);
+ if( ri != rf )
+ {
+ char buf[100];
+ sprintf( buf, "response #%d is not integral", idx );
+ CV_ERROR( CV_StsBadArg, buf );
+ }
+ dst[i] = ri;
+ }
+ response_ptr[i] = dst + i;
+ }
+
+ qsort( response_ptr, sample_count, sizeof(int*), icvCmpIntegersPtr );
+
+ // count the classes
+ for( i = 1; i < sample_count; i++ )
+ cls_count += *response_ptr[i] != *response_ptr[i-1];
+
+ if( cls_count < 2 )
+ CV_ERROR( CV_StsBadArg, "There is only a single class" );
+
+ CV_CALL( *out_response_map = cvCreateMat( 1, cls_count, CV_32SC1 ));
+
+ if( class_counts )
+ {
+ CV_CALL( *class_counts = cvCreateMat( 1, cls_count, CV_32SC1 ));
+ cls_counts = (*class_counts)->data.i;
+ }
+
+ // compact the class indices and build the map
+ prev_cls = ~*response_ptr[0];
+ cls_count = -1;
+ cls_map = (*out_response_map)->data.i;
+
+ for( i = 0, prev_i = -1; i < sample_count; i++ )
+ {
+ int cur_cls = *response_ptr[i];
+ if( cur_cls != prev_cls )
+ {
+ if( cls_counts && cls_count >= 0 )
+ cls_counts[cls_count] = i - prev_i;
+ cls_map[++cls_count] = prev_cls = cur_cls;
+ prev_i = i;
+ }
+ *response_ptr[i] = cls_count;
+ }
+
+ if( cls_counts )
+ cls_counts[cls_count] = i - prev_i;
+
+ __END__;
+
+ cvFree( &response_ptr );
+
+ return out_responses;
+}
+
+
+const float**
+cvGetTrainSamples( const CvMat* train_data, int tflag,
+ const CvMat* var_idx, const CvMat* sample_idx,
+ int* _var_count, int* _sample_count,
+ bool always_copy_data )
+{
+ float** samples = 0;
+
+ CV_FUNCNAME( "cvGetTrainSamples" );
+
+ __BEGIN__;
+
+ int i, j, var_count, sample_count, s_step, v_step;
+ bool copy_data;
+ const float* data;
+ const int *s_idx, *v_idx;
+
+ if( !CV_IS_MAT(train_data) )
+ CV_ERROR( CV_StsBadArg, "Invalid or NULL training data matrix" );
+
+ var_count = var_idx ? var_idx->cols + var_idx->rows - 1 :
+ tflag == CV_ROW_SAMPLE ? train_data->cols : train_data->rows;
+ sample_count = sample_idx ? sample_idx->cols + sample_idx->rows - 1 :
+ tflag == CV_ROW_SAMPLE ? train_data->rows : train_data->cols;
+
+ if( _var_count )
+ *_var_count = var_count;
+
+ if( _sample_count )
+ *_sample_count = sample_count;
+
+ copy_data = tflag != CV_ROW_SAMPLE || var_idx || always_copy_data;
+
+ CV_CALL( samples = (float**)cvAlloc(sample_count*sizeof(samples[0]) +
+ (copy_data ? 1 : 0)*var_count*sample_count*sizeof(samples[0][0])) );
+ data = train_data->data.fl;
+ s_step = train_data->step / sizeof(samples[0][0]);
+ v_step = 1;
+ s_idx = sample_idx ? sample_idx->data.i : 0;
+ v_idx = var_idx ? var_idx->data.i : 0;
+
+ if( !copy_data )
+ {
+ for( i = 0; i < sample_count; i++ )
+ samples[i] = (float*)(data + (s_idx ? s_idx[i] : i)*s_step);
+ }
+ else
+ {
+ samples[0] = (float*)(samples + sample_count);
+ if( tflag != CV_ROW_SAMPLE )
+ CV_SWAP( s_step, v_step, i );
+
+ for( i = 0; i < sample_count; i++ )
+ {
+ float* dst = samples[i] = samples[0] + i*var_count;
+ const float* src = data + (s_idx ? s_idx[i] : i)*s_step;
+
+ if( !v_idx )
+ for( j = 0; j < var_count; j++ )
+ dst[j] = src[j*v_step];
+ else
+ for( j = 0; j < var_count; j++ )
+ dst[j] = src[v_idx[j]*v_step];
+ }
+ }
+
+ __END__;
+
+ return (const float**)samples;
+}
+
+
+void
+cvCheckTrainData( const CvMat* train_data, int tflag,
+ const CvMat* missing_mask,
+ int* var_all, int* sample_all )
+{
+ CV_FUNCNAME( "cvCheckTrainData" );
+
+ if( var_all )
+ *var_all = 0;
+
+ if( sample_all )
+ *sample_all = 0;
+
+ __BEGIN__;
+
+ // check parameter types and sizes
+ if( !CV_IS_MAT(train_data) || CV_MAT_TYPE(train_data->type) != CV_32FC1 )
+ CV_ERROR( CV_StsBadArg, "train data must be floating-point matrix" );
+
+ if( missing_mask )
+ {
+ if( !CV_IS_MAT(missing_mask) || !CV_IS_MASK_ARR(missing_mask) ||
+ !CV_ARE_SIZES_EQ(train_data, missing_mask) )
+ CV_ERROR( CV_StsBadArg,
+ "missing value mask must be 8-bit matrix of the same size as training data" );
+ }
+
+ if( tflag != CV_ROW_SAMPLE && tflag != CV_COL_SAMPLE )
+ CV_ERROR( CV_StsBadArg,
+ "Unknown training data layout (must be CV_ROW_SAMPLE or CV_COL_SAMPLE)" );
+
+ if( var_all )
+ *var_all = tflag == CV_ROW_SAMPLE ? train_data->cols : train_data->rows;
+
+ if( sample_all )
+ *sample_all = tflag == CV_ROW_SAMPLE ? train_data->rows : train_data->cols;
+
+ __END__;
+}
+
+
+int
+cvPrepareTrainData( const char* /*funcname*/,
+ const CvMat* train_data, int tflag,
+ const CvMat* responses, int response_type,
+ const CvMat* var_idx,
+ const CvMat* sample_idx,
+ bool always_copy_data,
+ const float*** out_train_samples,
+ int* _sample_count,
+ int* _var_count,
+ int* _var_all,
+ CvMat** out_responses,
+ CvMat** out_response_map,
+ CvMat** out_var_idx,
+ CvMat** out_sample_idx )
+{
+ int ok = 0;
+ CvMat* _var_idx = 0;
+ CvMat* _sample_idx = 0;
+ CvMat* _responses = 0;
+ int sample_all = 0, sample_count = 0, var_all = 0, var_count = 0;
+
+ CV_FUNCNAME( "cvPrepareTrainData" );
+
+ // step 0. clear all the output pointers to ensure we do not try
+ // to call free() with uninitialized pointers
+ if( out_responses )
+ *out_responses = 0;
+
+ if( out_response_map )
+ *out_response_map = 0;
+
+ if( out_var_idx )
+ *out_var_idx = 0;
+
+ if( out_sample_idx )
+ *out_sample_idx = 0;
+
+ if( out_train_samples )
+ *out_train_samples = 0;
+
+ if( _sample_count )
+ *_sample_count = 0;
+
+ if( _var_count )
+ *_var_count = 0;
+
+ if( _var_all )
+ *_var_all = 0;
+
+ __BEGIN__;
+
+ if( !out_train_samples )
+ CV_ERROR( CV_StsBadArg, "output pointer to train samples is NULL" );
+
+ CV_CALL( cvCheckTrainData( train_data, tflag, 0, &var_all, &sample_all ));
+
+ if( sample_idx )
+ CV_CALL( _sample_idx = cvPreprocessIndexArray( sample_idx, sample_all ));
+ if( var_idx )
+ CV_CALL( _var_idx = cvPreprocessIndexArray( var_idx, var_all ));
+
+ if( responses )
+ {
+ if( !out_responses )
+ CV_ERROR( CV_StsNullPtr, "output response pointer is NULL" );
+
+ if( response_type == CV_VAR_NUMERICAL )
+ {
+ CV_CALL( _responses = cvPreprocessOrderedResponses( responses,
+ _sample_idx, sample_all ));
+ }
+ else
+ {
+ CV_CALL( _responses = cvPreprocessCategoricalResponses( responses,
+ _sample_idx, sample_all, out_response_map, 0 ));
+ }
+ }
+
+ CV_CALL( *out_train_samples =
+ cvGetTrainSamples( train_data, tflag, _var_idx, _sample_idx,
+ &var_count, &sample_count, always_copy_data ));
+
+ ok = 1;
+
+ __END__;
+
+ if( ok )
+ {
+ if( out_responses )
+ *out_responses = _responses, _responses = 0;
+
+ if( out_var_idx )
+ *out_var_idx = _var_idx, _var_idx = 0;
+
+ if( out_sample_idx )
+ *out_sample_idx = _sample_idx, _sample_idx = 0;
+
+ if( _sample_count )
+ *_sample_count = sample_count;
+
+ if( _var_count )
+ *_var_count = var_count;
+
+ if( _var_all )
+ *_var_all = var_all;
+ }
+ else
+ {
+ if( out_response_map )
+ cvReleaseMat( out_response_map );
+ cvFree( out_train_samples );
+ }
+
+ if( _responses != responses )
+ cvReleaseMat( &_responses );
+ cvReleaseMat( &_var_idx );
+ cvReleaseMat( &_sample_idx );
+
+ return ok;
+}
+
+
+typedef struct CvSampleResponsePair
+{
+ const float* sample;
+ const uchar* mask;
+ int response;
+ int index;
+}
+CvSampleResponsePair;
+
+
+static int
+CV_CDECL icvCmpSampleResponsePairs( const void* a, const void* b )
+{
+ int ra = ((const CvSampleResponsePair*)a)->response;
+ int rb = ((const CvSampleResponsePair*)b)->response;
+ int ia = ((const CvSampleResponsePair*)a)->index;
+ int ib = ((const CvSampleResponsePair*)b)->index;
+
+ return ra < rb ? -1 : ra > rb ? 1 : ia - ib;
+ //return (ra > rb ? -1 : 0)|(ra < rb);
+}
+
+
+void
+cvSortSamplesByClasses( const float** samples, const CvMat* classes,
+ int* class_ranges, const uchar** mask )
+{
+ CvSampleResponsePair* pairs = 0;
+ CV_FUNCNAME( "cvSortSamplesByClasses" );
+
+ __BEGIN__;
+
+ int i, k = 0, sample_count;
+
+ if( !samples || !classes || !class_ranges )
+ CV_ERROR( CV_StsNullPtr, "INTERNAL ERROR: some of the args are NULL pointers" );
+
+ if( classes->rows != 1 || CV_MAT_TYPE(classes->type) != CV_32SC1 )
+ CV_ERROR( CV_StsBadArg, "classes array must be a single row of integers" );
+
+ sample_count = classes->cols;
+ CV_CALL( pairs = (CvSampleResponsePair*)cvAlloc( (sample_count+1)*sizeof(pairs[0])));
+
+ for( i = 0; i < sample_count; i++ )
+ {
+ pairs[i].sample = samples[i];
+ pairs[i].mask = (mask) ? (mask[i]) : 0;
+ pairs[i].response = classes->data.i[i];
+ pairs[i].index = i;
+ assert( classes->data.i[i] >= 0 );
+ }
+
+ qsort( pairs, sample_count, sizeof(pairs[0]), icvCmpSampleResponsePairs );
+ pairs[sample_count].response = -1;
+ class_ranges[0] = 0;
+
+ for( i = 0; i < sample_count; i++ )
+ {
+ samples[i] = pairs[i].sample;
+ if (mask)
+ mask[i] = pairs[i].mask;
+ classes->data.i[i] = pairs[i].response;
+
+ if( pairs[i].response != pairs[i+1].response )
+ class_ranges[++k] = i+1;
+ }
+
+ __END__;
+
+ cvFree( &pairs );
+}
+
+
+void
+cvPreparePredictData( const CvArr* _sample, int dims_all,
+ const CvMat* comp_idx, int class_count,
+ const CvMat* prob, float** _row_sample,
+ int as_sparse )
+{
+ float* row_sample = 0;
+ int* inverse_comp_idx = 0;
+
+ CV_FUNCNAME( "cvPreparePredictData" );
+
+ __BEGIN__;
+
+ const CvMat* sample = (const CvMat*)_sample;
+ float* sample_data;
+ int sample_step;
+ int is_sparse = CV_IS_SPARSE_MAT(sample);
+ int d, sizes[CV_MAX_DIM];
+ int i, dims_selected;
+ int vec_size;
+
+ if( !is_sparse && !CV_IS_MAT(sample) )
+ CV_ERROR( !sample ? CV_StsNullPtr : CV_StsBadArg, "The sample is not a valid vector" );
+
+ if( cvGetElemType( sample ) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "Input sample must have 32fC1 type" );
+
+ CV_CALL( d = cvGetDims( sample, sizes ));
+
+ if( !(is_sparse && d == 1 || !is_sparse && d == 2 && (sample->rows == 1 || sample->cols == 1)) )
+ CV_ERROR( CV_StsBadSize, "Input sample must be 1-dimensional vector" );
+
+ if( d == 1 )
+ sizes[1] = 1;
+
+ if( sizes[0] + sizes[1] - 1 != dims_all )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The sample size is different from what has been used for training" );
+
+ if( !_row_sample )
+ CV_ERROR( CV_StsNullPtr, "INTERNAL ERROR: The row_sample pointer is NULL" );
+
+ if( comp_idx && (!CV_IS_MAT(comp_idx) || comp_idx->rows != 1 ||
+ CV_MAT_TYPE(comp_idx->type) != CV_32SC1) )
+ CV_ERROR( CV_StsBadArg, "INTERNAL ERROR: invalid comp_idx" );
+
+ dims_selected = comp_idx ? comp_idx->cols : dims_all;
+
+ if( prob )
+ {
+ if( !CV_IS_MAT(prob) )
+ CV_ERROR( CV_StsBadArg, "The output matrix of probabilities is invalid" );
+
+ if( (prob->rows != 1 && prob->cols != 1) ||
+ CV_MAT_TYPE(prob->type) != CV_32FC1 &&
+ CV_MAT_TYPE(prob->type) != CV_64FC1 )
+ CV_ERROR( CV_StsBadSize,
+ "The matrix of probabilities must be 1-dimensional vector of 32fC1 type" );
+
+ if( prob->rows + prob->cols - 1 != class_count )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The vector of probabilities must contain as many elements as "
+ "the number of classes in the training set" );
+ }
+
+ vec_size = !as_sparse ? dims_selected*sizeof(row_sample[0]) :
+ (dims_selected + 1)*sizeof(CvSparseVecElem32f);
+
+ if( CV_IS_MAT(sample) )
+ {
+ sample_data = sample->data.fl;
+ sample_step = sample->step / sizeof(row_sample[0]);
+
+ if( !comp_idx && sample_step <= 1 && !as_sparse )
+ *_row_sample = sample_data;
+ else
+ {
+ CV_CALL( row_sample = (float*)cvAlloc( vec_size ));
+
+ if( !comp_idx )
+ for( i = 0; i < dims_selected; i++ )
+ row_sample[i] = sample_data[sample_step*i];
+ else
+ {
+ int* comp = comp_idx->data.i;
+ if( !sample_step )
+ for( i = 0; i < dims_selected; i++ )
+ row_sample[i] = sample_data[comp[i]];
+ else
+ for( i = 0; i < dims_selected; i++ )
+ row_sample[i] = sample_data[sample_step*comp[i]];
+ }
+
+ *_row_sample = row_sample;
+ }
+
+ if( as_sparse )
+ {
+ const float* src = (const float*)row_sample;
+ CvSparseVecElem32f* dst = (CvSparseVecElem32f*)row_sample;
+
+ dst[dims_selected].idx = -1;
+ for( i = dims_selected - 1; i >= 0; i-- )
+ {
+ dst[i].idx = i;
+ dst[i].val = src[i];
+ }
+ }
+ }
+ else
+ {
+ CvSparseNode* node;
+ CvSparseMatIterator mat_iterator;
+ const CvSparseMat* sparse = (const CvSparseMat*)sample;
+ assert( is_sparse );
+
+ node = cvInitSparseMatIterator( sparse, &mat_iterator );
+ CV_CALL( row_sample = (float*)cvAlloc( vec_size ));
+
+ if( comp_idx )
+ {
+ CV_CALL( inverse_comp_idx = (int*)cvAlloc( dims_all*sizeof(int) ));
+ memset( inverse_comp_idx, -1, dims_all*sizeof(int) );
+ for( i = 0; i < dims_selected; i++ )
+ inverse_comp_idx[comp_idx->data.i[i]] = i;
+ }
+
+ if( !as_sparse )
+ {
+ memset( row_sample, 0, vec_size );
+
+ for( ; node != 0; node = cvGetNextSparseNode(&mat_iterator) )
+ {
+ int idx = *CV_NODE_IDX( sparse, node );
+ if( inverse_comp_idx )
+ {
+ idx = inverse_comp_idx[idx];
+ if( idx < 0 )
+ continue;
+ }
+ row_sample[idx] = *(float*)CV_NODE_VAL( sparse, node );
+ }
+ }
+ else
+ {
+ CvSparseVecElem32f* ptr = (CvSparseVecElem32f*)row_sample;
+
+ for( ; node != 0; node = cvGetNextSparseNode(&mat_iterator) )
+ {
+ int idx = *CV_NODE_IDX( sparse, node );
+ if( inverse_comp_idx )
+ {
+ idx = inverse_comp_idx[idx];
+ if( idx < 0 )
+ continue;
+ }
+ ptr->idx = idx;
+ ptr->val = *(float*)CV_NODE_VAL( sparse, node );
+ ptr++;
+ }
+
+ qsort( row_sample, ptr - (CvSparseVecElem32f*)row_sample,
+ sizeof(ptr[0]), icvCmpSparseVecElems );
+ ptr->idx = -1;
+ }
+
+ *_row_sample = row_sample;
+ }
+
+ __END__;
+
+ if( inverse_comp_idx )
+ cvFree( &inverse_comp_idx );
+
+ if( cvGetErrStatus() < 0 && _row_sample )
+ {
+ cvFree( &row_sample );
+ *_row_sample = 0;
+ }
+}
+
+
+static void
+icvConvertDataToSparse( const uchar* src, int src_step, int src_type,
+ uchar* dst, int dst_step, int dst_type,
+ CvSize size, int* idx )
+{
+ CV_FUNCNAME( "icvConvertDataToSparse" );
+
+ __BEGIN__;
+
+ int i, j;
+ src_type = CV_MAT_TYPE(src_type);
+ dst_type = CV_MAT_TYPE(dst_type);
+
+ if( CV_MAT_CN(src_type) != 1 || CV_MAT_CN(dst_type) != 1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "The function supports only single-channel arrays" );
+
+ if( src_step == 0 )
+ src_step = CV_ELEM_SIZE(src_type);
+
+ if( dst_step == 0 )
+ dst_step = CV_ELEM_SIZE(dst_type);
+
+ // if there is no "idx" and if both arrays are continuous,
+ // do the whole processing (copying or conversion) in a single loop
+ if( !idx && CV_ELEM_SIZE(src_type)*size.width == src_step &&
+ CV_ELEM_SIZE(dst_type)*size.width == dst_step )
+ {
+ size.width *= size.height;
+ size.height = 1;
+ }
+
+ if( src_type == dst_type )
+ {
+ int full_width = CV_ELEM_SIZE(dst_type)*size.width;
+
+ if( full_width == sizeof(int) ) // another common case: copy int's or float's
+ for( i = 0; i < size.height; i++, src += src_step )
+ *(int*)(dst + dst_step*(idx ? idx[i] : i)) = *(int*)src;
+ else
+ for( i = 0; i < size.height; i++, src += src_step )
+ memcpy( dst + dst_step*(idx ? idx[i] : i), src, full_width );
+ }
+ else if( src_type == CV_32SC1 && (dst_type == CV_32FC1 || dst_type == CV_64FC1) )
+ for( i = 0; i < size.height; i++, src += src_step )
+ {
+ uchar* _dst = dst + dst_step*(idx ? idx[i] : i);
+ if( dst_type == CV_32FC1 )
+ for( j = 0; j < size.width; j++ )
+ ((float*)_dst)[j] = (float)((int*)src)[j];
+ else
+ for( j = 0; j < size.width; j++ )
+ ((double*)_dst)[j] = ((int*)src)[j];
+ }
+ else if( (src_type == CV_32FC1 || src_type == CV_64FC1) && dst_type == CV_32SC1 )
+ for( i = 0; i < size.height; i++, src += src_step )
+ {
+ uchar* _dst = dst + dst_step*(idx ? idx[i] : i);
+ if( src_type == CV_32FC1 )
+ for( j = 0; j < size.width; j++ )
+ ((int*)_dst)[j] = cvRound(((float*)src)[j]);
+ else
+ for( j = 0; j < size.width; j++ )
+ ((int*)_dst)[j] = cvRound(((double*)src)[j]);
+ }
+ else if( src_type == CV_32FC1 && dst_type == CV_64FC1 ||
+ src_type == CV_64FC1 && dst_type == CV_32FC1 )
+ for( i = 0; i < size.height; i++, src += src_step )
+ {
+ uchar* _dst = dst + dst_step*(idx ? idx[i] : i);
+ if( src_type == CV_32FC1 )
+ for( j = 0; j < size.width; j++ )
+ ((double*)_dst)[j] = ((float*)src)[j];
+ else
+ for( j = 0; j < size.width; j++ )
+ ((float*)_dst)[j] = (float)((double*)src)[j];
+ }
+ else
+ CV_ERROR( CV_StsUnsupportedFormat, "Unsupported combination of input and output vectors" );
+
+ __END__;
+}
+
+
+void
+cvWritebackLabels( const CvMat* labels, CvMat* dst_labels,
+ const CvMat* centers, CvMat* dst_centers,
+ const CvMat* probs, CvMat* dst_probs,
+ const CvMat* sample_idx, int samples_all,
+ const CvMat* comp_idx, int dims_all )
+{
+ CV_FUNCNAME( "cvWritebackLabels" );
+
+ __BEGIN__;
+
+ int samples_selected = samples_all, dims_selected = dims_all;
+
+ if( dst_labels && !CV_IS_MAT(dst_labels) )
+ CV_ERROR( CV_StsBadArg, "Array of output labels is not a valid matrix" );
+
+ if( dst_centers )
+ if( !ICV_IS_MAT_OF_TYPE(dst_centers, CV_32FC1) &&
+ !ICV_IS_MAT_OF_TYPE(dst_centers, CV_64FC1) )
+ CV_ERROR( CV_StsBadArg, "Array of cluster centers is not a valid matrix" );
+
+ if( dst_probs && !CV_IS_MAT(dst_probs) )
+ CV_ERROR( CV_StsBadArg, "Probability matrix is not valid" );
+
+ if( sample_idx )
+ {
+ CV_ASSERT( sample_idx->rows == 1 && CV_MAT_TYPE(sample_idx->type) == CV_32SC1 );
+ samples_selected = sample_idx->cols;
+ }
+
+ if( comp_idx )
+ {
+ CV_ASSERT( comp_idx->rows == 1 && CV_MAT_TYPE(comp_idx->type) == CV_32SC1 );
+ dims_selected = comp_idx->cols;
+ }
+
+ if( dst_labels && (!labels || labels->data.ptr != dst_labels->data.ptr) )
+ {
+ if( !labels )
+ CV_ERROR( CV_StsNullPtr, "NULL labels" );
+
+ CV_ASSERT( labels->rows == 1 );
+
+ if( dst_labels->rows != 1 && dst_labels->cols != 1 )
+ CV_ERROR( CV_StsBadSize, "Array of output labels should be 1d vector" );
+
+ if( dst_labels->rows + dst_labels->cols - 1 != samples_all )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Size of vector of output labels is not equal to the total number of input samples" );
+
+ CV_ASSERT( labels->cols == samples_selected );
+
+ CV_CALL( icvConvertDataToSparse( labels->data.ptr, labels->step, labels->type,
+ dst_labels->data.ptr, dst_labels->step, dst_labels->type,
+ cvSize( 1, samples_selected ), sample_idx ? sample_idx->data.i : 0 ));
+ }
+
+ if( dst_centers && (!centers || centers->data.ptr != dst_centers->data.ptr) )
+ {
+ int i;
+
+ if( !centers )
+ CV_ERROR( CV_StsNullPtr, "NULL centers" );
+
+ if( centers->rows != dst_centers->rows )
+ CV_ERROR( CV_StsUnmatchedSizes, "Invalid number of rows in matrix of output centers" );
+
+ if( dst_centers->cols != dims_all )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Number of columns in matrix of output centers is "
+ "not equal to the total number of components in the input samples" );
+
+ CV_ASSERT( centers->cols == dims_selected );
+
+ for( i = 0; i < centers->rows; i++ )
+ CV_CALL( icvConvertDataToSparse( centers->data.ptr + i*centers->step, 0, centers->type,
+ dst_centers->data.ptr + i*dst_centers->step, 0, dst_centers->type,
+ cvSize( 1, dims_selected ), comp_idx ? comp_idx->data.i : 0 ));
+ }
+
+ if( dst_probs && (!probs || probs->data.ptr != dst_probs->data.ptr) )
+ {
+ if( !probs )
+ CV_ERROR( CV_StsNullPtr, "NULL probs" );
+
+ if( probs->cols != dst_probs->cols )
+ CV_ERROR( CV_StsUnmatchedSizes, "Invalid number of columns in output probability matrix" );
+
+ if( dst_probs->rows != samples_all )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "Number of rows in output probability matrix is "
+ "not equal to the total number of input samples" );
+
+ CV_ASSERT( probs->rows == samples_selected );
+
+ CV_CALL( icvConvertDataToSparse( probs->data.ptr, probs->step, probs->type,
+ dst_probs->data.ptr, dst_probs->step, dst_probs->type,
+ cvSize( probs->cols, samples_selected ),
+ sample_idx ? sample_idx->data.i : 0 ));
+ }
+
+ __END__;
+}
+
+#if 0
+CV_IMPL void
+cvStatModelMultiPredict( const CvStatModel* stat_model,
+ const CvArr* predict_input,
+ int flags, CvMat* predict_output,
+ CvMat* probs, const CvMat* sample_idx )
+{
+ CvMemStorage* storage = 0;
+ CvMat* sample_idx_buffer = 0;
+ CvSparseMat** sparse_rows = 0;
+ int samples_selected = 0;
+
+ CV_FUNCNAME( "cvStatModelMultiPredict" );
+
+ __BEGIN__;
+
+ int i;
+ int predict_output_step = 1, sample_idx_step = 1;
+ int type;
+ int d, sizes[CV_MAX_DIM];
+ int tflag = flags == CV_COL_SAMPLE;
+ int samples_all, dims_all;
+ int is_sparse = CV_IS_SPARSE_MAT(predict_input);
+ CvMat predict_input_part;
+ CvArr* sample = &predict_input_part;
+ CvMat probs_part;
+ CvMat* probs1 = probs ? &probs_part : 0;
+
+ if( !CV_IS_STAT_MODEL(stat_model) )
+ CV_ERROR( !stat_model ? CV_StsNullPtr : CV_StsBadArg, "Invalid statistical model" );
+
+ if( !stat_model->predict )
+ CV_ERROR( CV_StsNotImplemented, "There is no \"predict\" method" );
+
+ if( !predict_input || !predict_output )
+ CV_ERROR( CV_StsNullPtr, "NULL input or output matrices" );
+
+ if( !is_sparse && !CV_IS_MAT(predict_input) )
+ CV_ERROR( CV_StsBadArg, "predict_input should be a matrix or a sparse matrix" );
+
+ if( !CV_IS_MAT(predict_output) )
+ CV_ERROR( CV_StsBadArg, "predict_output should be a matrix" );
+
+ type = cvGetElemType( predict_input );
+ if( type != CV_32FC1 ||
+ (CV_MAT_TYPE(predict_output->type) != CV_32FC1 &&
+ CV_MAT_TYPE(predict_output->type) != CV_32SC1 ))
+ CV_ERROR( CV_StsUnsupportedFormat, "The input or output matrix has unsupported format" );
+
+ CV_CALL( d = cvGetDims( predict_input, sizes ));
+ if( d > 2 )
+ CV_ERROR( CV_StsBadSize, "The input matrix should be 1- or 2-dimensional" );
+
+ if( !tflag )
+ {
+ samples_all = samples_selected = sizes[0];
+ dims_all = sizes[1];
+ }
+ else
+ {
+ samples_all = samples_selected = sizes[1];
+ dims_all = sizes[0];
+ }
+
+ if( sample_idx )
+ {
+ if( !CV_IS_MAT(sample_idx) )
+ CV_ERROR( CV_StsBadArg, "Invalid sample_idx matrix" );
+
+ if( sample_idx->cols != 1 && sample_idx->rows != 1 )
+ CV_ERROR( CV_StsBadSize, "sample_idx must be 1-dimensional matrix" );
+
+ samples_selected = sample_idx->rows + sample_idx->cols - 1;
+
+ if( CV_MAT_TYPE(sample_idx->type) == CV_32SC1 )
+ {
+ if( samples_selected > samples_all )
+ CV_ERROR( CV_StsBadSize, "sample_idx is too large vector" );
+ }
+ else if( samples_selected != samples_all )
+ CV_ERROR( CV_StsUnmatchedSizes, "sample_idx has incorrect size" );
+
+ sample_idx_step = sample_idx->step ?
+ sample_idx->step / CV_ELEM_SIZE(sample_idx->type) : 1;
+ }
+
+ if( predict_output->rows != 1 && predict_output->cols != 1 )
+ CV_ERROR( CV_StsBadSize, "predict_output should be a 1-dimensional matrix" );
+
+ if( predict_output->rows + predict_output->cols - 1 != samples_all )
+ CV_ERROR( CV_StsUnmatchedSizes, "predict_output and predict_input have uncoordinated sizes" );
+
+ predict_output_step = predict_output->step ?
+ predict_output->step / CV_ELEM_SIZE(predict_output->type) : 1;
+
+ if( probs )
+ {
+ if( !CV_IS_MAT(probs) )
+ CV_ERROR( CV_StsBadArg, "Invalid matrix of probabilities" );
+
+ if( probs->rows != samples_all )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "matrix of probabilities must have as many rows as the total number of samples" );
+
+ if( CV_MAT_TYPE(probs->type) != CV_32FC1 )
+ CV_ERROR( CV_StsUnsupportedFormat, "matrix of probabilities must have 32fC1 type" );
+ }
+
+ if( is_sparse )
+ {
+ CvSparseNode* node;
+ CvSparseMatIterator mat_iterator;
+ CvSparseMat* sparse = (CvSparseMat*)predict_input;
+
+ if( sample_idx && CV_MAT_TYPE(sample_idx->type) == CV_32SC1 )
+ {
+ CV_CALL( sample_idx_buffer = cvCreateMat( 1, samples_all, CV_8UC1 ));
+ cvZero( sample_idx_buffer );
+ for( i = 0; i < samples_selected; i++ )
+ sample_idx_buffer->data.ptr[sample_idx->data.i[i*sample_idx_step]] = 1;
+ samples_selected = samples_all;
+ sample_idx = sample_idx_buffer;
+ sample_idx_step = 1;
+ }
+
+ CV_CALL( sparse_rows = (CvSparseMat**)cvAlloc( samples_selected*sizeof(sparse_rows[0])));
+ for( i = 0; i < samples_selected; i++ )
+ {
+ if( sample_idx && sample_idx->data.ptr[i*sample_idx_step] == 0 )
+ continue;
+ CV_CALL( sparse_rows[i] = cvCreateSparseMat( 1, &dims_all, type ));
+ if( !storage )
+ storage = sparse_rows[i]->heap->storage;
+ else
+ {
+ // hack: to decrease memory footprint, make all the sparse matrices
+ // reside in the same storage
+ int elem_size = sparse_rows[i]->heap->elem_size;
+ cvReleaseMemStorage( &sparse_rows[i]->heap->storage );
+ sparse_rows[i]->heap = cvCreateSet( 0, sizeof(CvSet), elem_size, storage );
+ }
+ }
+
+ // put each row (or column) of predict_input into separate sparse matrix.
+ node = cvInitSparseMatIterator( sparse, &mat_iterator );
+ for( ; node != 0; node = cvGetNextSparseNode( &mat_iterator ))
+ {
+ int* idx = CV_NODE_IDX( sparse, node );
+ int idx0 = idx[tflag ^ 1];
+ int idx1 = idx[tflag];
+
+ if( sample_idx && sample_idx->data.ptr[idx0*sample_idx_step] == 0 )
+ continue;
+
+ assert( sparse_rows[idx0] != 0 );
+ *(float*)cvPtrND( sparse, &idx1, 0, 1, 0 ) = *(float*)CV_NODE_VAL( sparse, node );
+ }
+ }
+
+ for( i = 0; i < samples_selected; i++ )
+ {
+ int idx = i;
+ float response;
+
+ if( sample_idx )
+ {
+ if( CV_MAT_TYPE(sample_idx->type) == CV_32SC1 )
+ {
+ idx = sample_idx->data.i[i*sample_idx_step];
+ if( (unsigned)idx >= (unsigned)samples_all )
+ CV_ERROR( CV_StsOutOfRange, "Some of sample_idx elements are out of range" );
+ }
+ else if( CV_MAT_TYPE(sample_idx->type) == CV_8UC1 &&
+ sample_idx->data.ptr[i*sample_idx_step] == 0 )
+ continue;
+ }
+
+ if( !is_sparse )
+ {
+ if( !tflag )
+ cvGetRow( predict_input, &predict_input_part, idx );
+ else
+ {
+ cvGetCol( predict_input, &predict_input_part, idx );
+ }
+ }
+ else
+ sample = sparse_rows[idx];
+
+ if( probs )
+ cvGetRow( probs, probs1, idx );
+
+ CV_CALL( response = stat_model->predict( stat_model, (CvMat*)sample, probs1 ));
+
+ if( CV_MAT_TYPE(predict_output->type) == CV_32FC1 )
+ predict_output->data.fl[idx*predict_output_step] = response;
+ else
+ {
+ CV_ASSERT( cvRound(response) == response );
+ predict_output->data.i[idx*predict_output_step] = cvRound(response);
+ }
+ }
+
+ __END__;
+
+ if( sparse_rows )
+ {
+ int i;
+ for( i = 0; i < samples_selected; i++ )
+ if( sparse_rows[i] )
+ {
+ sparse_rows[i]->heap->storage = 0;
+ cvReleaseSparseMat( &sparse_rows[i] );
+ }
+ cvFree( &sparse_rows );
+ }
+
+ cvReleaseMat( &sample_idx_buffer );
+ cvReleaseMemStorage( &storage );
+}
+#endif
+
+// By P. Yarykin - begin -
+
+void cvCombineResponseMaps (CvMat* _responses,
+ const CvMat* old_response_map,
+ CvMat* new_response_map,
+ CvMat** out_response_map)
+{
+ int** old_data = NULL;
+ int** new_data = NULL;
+
+ CV_FUNCNAME ("cvCombineResponseMaps");
+ __BEGIN__
+
+ int i,j;
+ int old_n, new_n, out_n;
+ int samples, free_response;
+ int* first;
+ int* responses;
+ int* out_data;
+
+ if( out_response_map )
+ *out_response_map = 0;
+
+// Check input data.
+ if ((!ICV_IS_MAT_OF_TYPE (_responses, CV_32SC1)) ||
+ (!ICV_IS_MAT_OF_TYPE (old_response_map, CV_32SC1)) ||
+ (!ICV_IS_MAT_OF_TYPE (new_response_map, CV_32SC1)))
+ {
+ CV_ERROR (CV_StsBadArg, "Some of input arguments is not the CvMat")
+ }
+
+// Prepare sorted responses.
+ first = new_response_map->data.i;
+ new_n = new_response_map->cols;
+ CV_CALL (new_data = (int**)cvAlloc (new_n * sizeof (new_data[0])));
+ for (i = 0; i < new_n; i++)
+ new_data[i] = first + i;
+ qsort (new_data, new_n, sizeof(int*), icvCmpIntegersPtr);
+
+ first = old_response_map->data.i;
+ old_n = old_response_map->cols;
+ CV_CALL (old_data = (int**)cvAlloc (old_n * sizeof (old_data[0])));
+ for (i = 0; i < old_n; i++)
+ old_data[i] = first + i;
+ qsort (old_data, old_n, sizeof(int*), icvCmpIntegersPtr);
+
+// Count the number of different responses.
+ for (i = 0, j = 0, out_n = 0; i < old_n && j < new_n; out_n++)
+ {
+ if (*old_data[i] == *new_data[j])
+ {
+ i++;
+ j++;
+ }
+ else if (*old_data[i] < *new_data[j])
+ i++;
+ else
+ j++;
+ }
+ out_n += old_n - i + new_n - j;
+
+// Create and fill the result response maps.
+ CV_CALL (*out_response_map = cvCreateMat (1, out_n, CV_32SC1));
+ out_data = (*out_response_map)->data.i;
+ memcpy (out_data, first, old_n * sizeof (int));
+
+ free_response = old_n;
+ for (i = 0, j = 0; i < old_n && j < new_n; )
+ {
+ if (*old_data[i] == *new_data[j])
+ {
+ *new_data[j] = (int)(old_data[i] - first);
+ i++;
+ j++;
+ }
+ else if (*old_data[i] < *new_data[j])
+ i++;
+ else
+ {
+ out_data[free_response] = *new_data[j];
+ *new_data[j] = free_response++;
+ j++;
+ }
+ }
+ for (; j < new_n; j++)
+ {
+ out_data[free_response] = *new_data[j];
+ *new_data[j] = free_response++;
+ }
+ CV_ASSERT (free_response == out_n);
+
+// Change <responses> according to out response map.
+ samples = _responses->cols + _responses->rows - 1;
+ responses = _responses->data.i;
+ first = new_response_map->data.i;
+ for (i = 0; i < samples; i++)
+ {
+ responses[i] = first[responses[i]];
+ }
+
+ __END__
+
+ cvFree(&old_data);
+ cvFree(&new_data);
+
+}
+
+
+int icvGetNumberOfCluster( double* prob_vector, int num_of_clusters, float r,
+ float outlier_thresh, int normalize_probs )
+{
+ int max_prob_loc = 0;
+
+ CV_FUNCNAME("icvGetNumberOfCluster");
+ __BEGIN__;
+
+ double prob, maxprob, sum;
+ int i;
+
+ CV_ASSERT(prob_vector);
+ CV_ASSERT(num_of_clusters >= 0);
+
+ maxprob = prob_vector[0];
+ max_prob_loc = 0;
+ sum = maxprob;
+ for( i = 1; i < num_of_clusters; i++ )
+ {
+ prob = prob_vector[i];
+ sum += prob;
+ if( prob > maxprob )
+ {
+ max_prob_loc = i;
+ maxprob = prob;
+ }
+ }
+ if( normalize_probs && fabs(sum - 1.) > FLT_EPSILON )
+ {
+ for( i = 0; i < num_of_clusters; i++ )
+ prob_vector[i] /= sum;
+ }
+ if( fabs(r - 1.) > FLT_EPSILON && fabs(sum - 1.) < outlier_thresh )
+ max_prob_loc = -1;
+
+ __END__;
+
+ return max_prob_loc;
+
+} // End of icvGetNumberOfCluster
+
+
+void icvFindClusterLabels( const CvMat* probs, float outlier_thresh, float r,
+ const CvMat* labels )
+{
+ CvMat* counts = 0;
+
+ CV_FUNCNAME("icvFindClusterLabels");
+ __BEGIN__;
+
+ int nclusters, nsamples;
+ int i, j;
+ double* probs_data;
+
+ CV_ASSERT( ICV_IS_MAT_OF_TYPE(probs, CV_64FC1) );
+ CV_ASSERT( ICV_IS_MAT_OF_TYPE(labels, CV_32SC1) );
+
+ nclusters = probs->cols;
+ nsamples = probs->rows;
+ CV_ASSERT( nsamples == labels->cols );
+
+ CV_CALL( counts = cvCreateMat( 1, nclusters + 1, CV_32SC1 ) );
+ CV_CALL( cvSetZero( counts ));
+ for( i = 0; i < nsamples; i++ )
+ {
+ labels->data.i[i] = icvGetNumberOfCluster( probs->data.db + i*probs->cols,
+ nclusters, r, outlier_thresh, 1 );
+ counts->data.i[labels->data.i[i] + 1]++;
+ }
+ CV_ASSERT((int)cvSum(counts).val[0] == nsamples);
+ // Filling empty clusters with the vector, that has the maximal probability
+ for( j = 0; j < nclusters; j++ ) // outliers are ignored
+ {
+ int maxprob_loc = -1;
+ double maxprob = 0;
+
+ if( counts->data.i[j+1] ) // j-th class is not empty
+ continue;
+ // look for the presentative, which is not lonely in it's cluster
+ // and that has a maximal probability among all these vectors
+ probs_data = probs->data.db;
+ for( i = 0; i < nsamples; i++, probs_data++ )
+ {
+ int label = labels->data.i[i];
+ double prob;
+ if( counts->data.i[label+1] == 0 ||
+ (counts->data.i[label+1] <= 1 && label != -1) )
+ continue;
+ prob = *probs_data;
+ if( prob >= maxprob )
+ {
+ maxprob = prob;
+ maxprob_loc = i;
+ }
+ }
+ // maxprob_loc == 0 <=> number of vectors less then number of clusters
+ CV_ASSERT( maxprob_loc >= 0 );
+ counts->data.i[labels->data.i[maxprob_loc] + 1]--;
+ labels->data.i[maxprob_loc] = j;
+ counts->data.i[j + 1]++;
+ }
+
+ __END__;
+
+ cvReleaseMat( &counts );
+} // End of icvFindClusterLabels
+
+/* End of file */
diff --git a/ml/src/mlann_mlp.cpp b/ml/src/mlann_mlp.cpp
new file mode 100644
index 0000000..7446b79
--- /dev/null
+++ b/ml/src/mlann_mlp.cpp
@@ -0,0 +1,1520 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_ml.h"
+
+CvANN_MLP_TrainParams::CvANN_MLP_TrainParams()
+{
+ term_crit = cvTermCriteria( CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 1000, 0.01 );
+ train_method = RPROP;
+ bp_dw_scale = bp_moment_scale = 0.1;
+ rp_dw0 = 0.1; rp_dw_plus = 1.2; rp_dw_minus = 0.5;
+ rp_dw_min = FLT_EPSILON; rp_dw_max = 50.;
+}
+
+
+CvANN_MLP_TrainParams::CvANN_MLP_TrainParams( CvTermCriteria _term_crit,
+ int _train_method,
+ double _param1, double _param2 )
+{
+ term_crit = _term_crit;
+ train_method = _train_method;
+ bp_dw_scale = bp_moment_scale = 0.1;
+ rp_dw0 = 1.; rp_dw_plus = 1.2; rp_dw_minus = 0.5;
+ rp_dw_min = FLT_EPSILON; rp_dw_max = 50.;
+
+ if( train_method == RPROP )
+ {
+ rp_dw0 = _param1;
+ if( rp_dw0 < FLT_EPSILON )
+ rp_dw0 = 1.;
+ rp_dw_min = _param2;
+ rp_dw_min = MAX( rp_dw_min, 0 );
+ }
+ else if( train_method == BACKPROP )
+ {
+ bp_dw_scale = _param1;
+ if( bp_dw_scale <= 0 )
+ bp_dw_scale = 0.1;
+ bp_dw_scale = MAX( bp_dw_scale, 1e-3 );
+ bp_dw_scale = MIN( bp_dw_scale, 1 );
+ bp_moment_scale = _param2;
+ if( bp_moment_scale < 0 )
+ bp_moment_scale = 0.1;
+ bp_moment_scale = MIN( bp_moment_scale, 1 );
+ }
+ else
+ train_method = RPROP;
+}
+
+
+CvANN_MLP_TrainParams::~CvANN_MLP_TrainParams()
+{
+}
+
+
+CvANN_MLP::CvANN_MLP()
+{
+ layer_sizes = wbuf = 0;
+ min_val = max_val = min_val1 = max_val1 = 0.;
+ weights = 0;
+ rng = cvRNG(-1);
+ default_model_name = "my_nn";
+ clear();
+}
+
+
+CvANN_MLP::CvANN_MLP( const CvMat* _layer_sizes,
+ int _activ_func,
+ double _f_param1, double _f_param2 )
+{
+ layer_sizes = wbuf = 0;
+ min_val = max_val = min_val1 = max_val1 = 0.;
+ weights = 0;
+ rng = cvRNG(-1);
+ default_model_name = "my_nn";
+ create( _layer_sizes, _activ_func, _f_param1, _f_param2 );
+}
+
+
+CvANN_MLP::~CvANN_MLP()
+{
+ clear();
+}
+
+
+void CvANN_MLP::clear()
+{
+ cvReleaseMat( &layer_sizes );
+ cvReleaseMat( &wbuf );
+ cvFree( &weights );
+ activ_func = SIGMOID_SYM;
+ f_param1 = f_param2 = 1;
+ max_buf_sz = 1 << 12;
+}
+
+
+void CvANN_MLP::set_activ_func( int _activ_func, double _f_param1, double _f_param2 )
+{
+ CV_FUNCNAME( "CvANN_MLP::set_activ_func" );
+
+ __BEGIN__;
+
+ if( _activ_func < 0 || _activ_func > GAUSSIAN )
+ CV_ERROR( CV_StsOutOfRange, "Unknown activation function" );
+
+ activ_func = _activ_func;
+
+ switch( activ_func )
+ {
+ case SIGMOID_SYM:
+ max_val = 0.95; min_val = -max_val;
+ max_val1 = 0.98; min_val1 = -max_val1;
+ if( fabs(_f_param1) < FLT_EPSILON )
+ _f_param1 = 2./3;
+ if( fabs(_f_param2) < FLT_EPSILON )
+ _f_param2 = 1.7159;
+ break;
+ case GAUSSIAN:
+ max_val = 1.; min_val = 0.05;
+ max_val1 = 1.; min_val1 = 0.02;
+ if( fabs(_f_param1) < FLT_EPSILON )
+ _f_param1 = 1.;
+ if( fabs(_f_param2) < FLT_EPSILON )
+ _f_param2 = 1.;
+ break;
+ default:
+ min_val = max_val = min_val1 = max_val1 = 0.;
+ _f_param1 = 1.;
+ _f_param2 = 0.;
+ }
+
+ f_param1 = _f_param1;
+ f_param2 = _f_param2;
+
+ __END__;
+}
+
+
+void CvANN_MLP::init_weights()
+{
+ int i, j, k;
+
+ for( i = 1; i < layer_sizes->cols; i++ )
+ {
+ int n1 = layer_sizes->data.i[i-1];
+ int n2 = layer_sizes->data.i[i];
+ double val = 0, G = n2 > 2 ? 0.7*pow((double)n1,1./(n2-1)) : 1.;
+ double* w = weights[i];
+
+ // initialize weights using Nguyen-Widrow algorithm
+ for( j = 0; j < n2; j++ )
+ {
+ double s = 0;
+ for( k = 0; k <= n1; k++ )
+ {
+ val = cvRandReal(&rng)*2-1.;
+ w[k*n2 + j] = val;
+ s += val;
+ }
+
+ if( i < layer_sizes->cols - 1 )
+ {
+ s = 1./(s - val);
+ for( k = 0; k <= n1; k++ )
+ w[k*n2 + j] *= s;
+ w[n1*n2 + j] *= G*(-1+j*2./n2);
+ }
+ }
+ }
+}
+
+
+void CvANN_MLP::create( const CvMat* _layer_sizes, int _activ_func,
+ double _f_param1, double _f_param2 )
+{
+ CV_FUNCNAME( "CvANN_MLP::create" );
+
+ __BEGIN__;
+
+ int i, l_step, l_count, buf_sz = 0;
+ int *l_src, *l_dst;
+
+ clear();
+
+ if( !CV_IS_MAT(_layer_sizes) ||
+ _layer_sizes->cols != 1 && _layer_sizes->rows != 1 ||
+ CV_MAT_TYPE(_layer_sizes->type) != CV_32SC1 )
+ CV_ERROR( CV_StsBadArg,
+ "The array of layer neuron counters must be an integer vector" );
+
+ CV_CALL( set_activ_func( _activ_func, _f_param1, _f_param2 ));
+
+ l_count = _layer_sizes->rows + _layer_sizes->cols - 1;
+ l_src = _layer_sizes->data.i;
+ l_step = CV_IS_MAT_CONT(_layer_sizes->type) ? 1 :
+ _layer_sizes->step / sizeof(l_src[0]);
+ CV_CALL( layer_sizes = cvCreateMat( 1, l_count, CV_32SC1 ));
+ l_dst = layer_sizes->data.i;
+
+ max_count = 0;
+ for( i = 0; i < l_count; i++ )
+ {
+ int n = l_src[i*l_step];
+ if( n < 1 + (0 < i && i < l_count-1))
+ CV_ERROR( CV_StsOutOfRange,
+ "there should be at least one input and one output "
+ "and every hidden layer must have more than 1 neuron" );
+ l_dst[i] = n;
+ max_count = MAX( max_count, n );
+ if( i > 0 )
+ buf_sz += (l_dst[i-1]+1)*n;
+ }
+
+ buf_sz += (l_dst[0] + l_dst[l_count-1]*2)*2;
+
+ CV_CALL( wbuf = cvCreateMat( 1, buf_sz, CV_64F ));
+ CV_CALL( weights = (double**)cvAlloc( (l_count+1)*sizeof(weights[0]) ));
+
+ weights[0] = wbuf->data.db;
+ weights[1] = weights[0] + l_dst[0]*2;
+ for( i = 1; i < l_count; i++ )
+ weights[i+1] = weights[i] + (l_dst[i-1] + 1)*l_dst[i];
+ weights[l_count+1] = weights[l_count] + l_dst[l_count-1]*2;
+
+ __END__;
+}
+
+
+float CvANN_MLP::predict( const CvMat* _inputs, CvMat* _outputs ) const
+{
+ CV_FUNCNAME( "CvANN_MLP::predict" );
+
+ __BEGIN__;
+
+ double* buf;
+ int i, j, n, dn = 0, l_count, dn0, buf_sz, min_buf_sz;
+
+ if( !layer_sizes )
+ CV_ERROR( CV_StsError, "The network has not been initialized" );
+
+ if( !CV_IS_MAT(_inputs) || !CV_IS_MAT(_outputs) ||
+ !CV_ARE_TYPES_EQ(_inputs,_outputs) ||
+ CV_MAT_TYPE(_inputs->type) != CV_32FC1 &&
+ CV_MAT_TYPE(_inputs->type) != CV_64FC1 ||
+ _inputs->rows != _outputs->rows )
+ CV_ERROR( CV_StsBadArg, "Both input and output must be floating-point matrices "
+ "of the same type and have the same number of rows" );
+
+ if( _inputs->cols != layer_sizes->data.i[0] )
+ CV_ERROR( CV_StsBadSize, "input matrix must have the same number of columns as "
+ "the number of neurons in the input layer" );
+
+ if( _outputs->cols != layer_sizes->data.i[layer_sizes->cols - 1] )
+ CV_ERROR( CV_StsBadSize, "output matrix must have the same number of columns as "
+ "the number of neurons in the output layer" );
+ n = dn0 = _inputs->rows;
+ min_buf_sz = 2*max_count;
+ buf_sz = n*min_buf_sz;
+
+ if( buf_sz > max_buf_sz )
+ {
+ dn0 = max_buf_sz/min_buf_sz;
+ dn0 = MAX( dn0, 1 );
+ buf_sz = dn0*min_buf_sz;
+ }
+
+ buf = (double*)cvStackAlloc( buf_sz*sizeof(buf[0]) );
+ l_count = layer_sizes->cols;
+
+ for( i = 0; i < n; i += dn )
+ {
+ CvMat hdr[2], _w, *layer_in = &hdr[0], *layer_out = &hdr[1], *temp;
+ dn = MIN( dn0, n - i );
+
+ cvGetRows( _inputs, layer_in, i, i + dn );
+ cvInitMatHeader( layer_out, dn, layer_in->cols, CV_64F, buf );
+
+ scale_input( layer_in, layer_out );
+ CV_SWAP( layer_in, layer_out, temp );
+
+ for( j = 1; j < l_count; j++ )
+ {
+ double* data = buf + (j&1 ? max_count*dn0 : 0);
+ int cols = layer_sizes->data.i[j];
+
+ cvInitMatHeader( layer_out, dn, cols, CV_64F, data );
+ cvInitMatHeader( &_w, layer_in->cols, layer_out->cols, CV_64F, weights[j] );
+ cvGEMM( layer_in, &_w, 1, 0, 0, layer_out );
+ calc_activ_func( layer_out, _w.data.db + _w.rows*_w.cols );
+
+ CV_SWAP( layer_in, layer_out, temp );
+ }
+
+ cvGetRows( _outputs, layer_out, i, i + dn );
+ scale_output( layer_in, layer_out );
+ }
+
+ __END__;
+
+ return 0.f;
+}
+
+
+void CvANN_MLP::scale_input( const CvMat* _src, CvMat* _dst ) const
+{
+ int i, j, cols = _src->cols;
+ double* dst = _dst->data.db;
+ const double* w = weights[0];
+ int step = _src->step;
+
+ if( CV_MAT_TYPE( _src->type ) == CV_32F )
+ {
+ const float* src = _src->data.fl;
+ step /= sizeof(src[0]);
+
+ for( i = 0; i < _src->rows; i++, src += step, dst += cols )
+ for( j = 0; j < cols; j++ )
+ dst[j] = src[j]*w[j*2] + w[j*2+1];
+ }
+ else
+ {
+ const double* src = _src->data.db;
+ step /= sizeof(src[0]);
+
+ for( i = 0; i < _src->rows; i++, src += step, dst += cols )
+ for( j = 0; j < cols; j++ )
+ dst[j] = src[j]*w[j*2] + w[j*2+1];
+ }
+}
+
+
+void CvANN_MLP::scale_output( const CvMat* _src, CvMat* _dst ) const
+{
+ int i, j, cols = _src->cols;
+ const double* src = _src->data.db;
+ const double* w = weights[layer_sizes->cols];
+ int step = _dst->step;
+
+ if( CV_MAT_TYPE( _dst->type ) == CV_32F )
+ {
+ float* dst = _dst->data.fl;
+ step /= sizeof(dst[0]);
+
+ for( i = 0; i < _src->rows; i++, src += cols, dst += step )
+ for( j = 0; j < cols; j++ )
+ dst[j] = (float)(src[j]*w[j*2] + w[j*2+1]);
+ }
+ else
+ {
+ double* dst = _dst->data.db;
+ step /= sizeof(dst[0]);
+
+ for( i = 0; i < _src->rows; i++, src += cols, dst += step )
+ for( j = 0; j < cols; j++ )
+ dst[j] = src[j]*w[j*2] + w[j*2+1];
+ }
+}
+
+
+void CvANN_MLP::calc_activ_func( CvMat* sums, const double* bias ) const
+{
+ int i, j, n = sums->rows, cols = sums->cols;
+ double* data = sums->data.db;
+ double scale = 0, scale2 = f_param2;
+
+ switch( activ_func )
+ {
+ case IDENTITY:
+ scale = 1.;
+ break;
+ case SIGMOID_SYM:
+ scale = -f_param1;
+ break;
+ case GAUSSIAN:
+ scale = -f_param1*f_param1;
+ break;
+ default:
+ ;
+ }
+
+ assert( CV_IS_MAT_CONT(sums->type) );
+
+ if( activ_func != GAUSSIAN )
+ {
+ for( i = 0; i < n; i++, data += cols )
+ for( j = 0; j < cols; j++ )
+ data[j] = (data[j] + bias[j])*scale;
+
+ if( activ_func == IDENTITY )
+ return;
+ }
+ else
+ {
+ for( i = 0; i < n; i++, data += cols )
+ for( j = 0; j < cols; j++ )
+ {
+ double t = data[j] + bias[j];
+ data[j] = t*t*scale;
+ }
+ }
+
+ cvExp( sums, sums );
+
+ n *= cols;
+ data -= n;
+
+ switch( activ_func )
+ {
+ case SIGMOID_SYM:
+ for( i = 0; i <= n - 4; i += 4 )
+ {
+ double x0 = 1.+data[i], x1 = 1.+data[i+1], x2 = 1.+data[i+2], x3 = 1.+data[i+3];
+ double a = x0*x1, b = x2*x3, d = scale2/(a*b), t0, t1;
+ a *= d; b *= d;
+ t0 = (2 - x0)*b*x1; t1 = (2 - x1)*b*x0;
+ data[i] = t0; data[i+1] = t1;
+ t0 = (2 - x2)*a*x3; t1 = (2 - x3)*a*x2;
+ data[i+2] = t0; data[i+3] = t1;
+ }
+
+ for( ; i < n; i++ )
+ {
+ double t = scale2*(1. - data[i])/(1. + data[i]);
+ data[i] = t;
+ }
+ break;
+
+ case GAUSSIAN:
+ for( i = 0; i < n; i++ )
+ data[i] = scale2*data[i];
+ break;
+
+ default:
+ ;
+ }
+}
+
+
+void CvANN_MLP::calc_activ_func_deriv( CvMat* _xf, CvMat* _df,
+ const double* bias ) const
+{
+ int i, j, n = _xf->rows, cols = _xf->cols;
+ double* xf = _xf->data.db;
+ double* df = _df->data.db;
+ double scale, scale2 = f_param2;
+ assert( CV_IS_MAT_CONT( _xf->type & _df->type ) );
+
+ if( activ_func == IDENTITY )
+ {
+ for( i = 0; i < n; i++, xf += cols, df += cols )
+ for( j = 0; j < cols; j++ )
+ {
+ xf[j] += bias[j];
+ df[j] = 1;
+ }
+ return;
+ }
+ else if( activ_func == GAUSSIAN )
+ {
+ scale = -f_param1*f_param1;
+ scale2 *= scale;
+ for( i = 0; i < n; i++, xf += cols, df += cols )
+ for( j = 0; j < cols; j++ )
+ {
+ double t = xf[j] + bias[j];
+ df[j] = t*2*scale2;
+ xf[j] = t*t*scale;
+ }
+ }
+ else
+ {
+ scale = -f_param1;
+ for( i = 0; i < n; i++, xf += cols, df += cols )
+ for( j = 0; j < cols; j++ )
+ xf[j] = (xf[j] + bias[j])*scale;
+ }
+
+ cvExp( _xf, _xf );
+
+ n *= cols;
+ xf -= n; df -= n;
+
+ // ((1+exp(-ax))^-1)'=a*((1+exp(-ax))^-2)*exp(-ax);
+ // ((1-exp(-ax))/(1+exp(-ax)))'=(a*exp(-ax)*(1+exp(-ax)) + a*exp(-ax)*(1-exp(-ax)))/(1+exp(-ax))^2=
+ // 2*a*exp(-ax)/(1+exp(-ax))^2
+ switch( activ_func )
+ {
+ case SIGMOID_SYM:
+ scale *= -2*f_param2;
+ for( i = 0; i <= n - 4; i += 4 )
+ {
+ double x0 = 1.+xf[i], x1 = 1.+xf[i+1], x2 = 1.+xf[i+2], x3 = 1.+xf[i+3];
+ double a = x0*x1, b = x2*x3, d = 1./(a*b), t0, t1;
+ a *= d; b *= d;
+
+ t0 = b*x1; t1 = b*x0;
+ df[i] = scale*xf[i]*t0*t0;
+ df[i+1] = scale*xf[i+1]*t1*t1;
+ t0 *= scale2*(2 - x0); t1 *= scale2*(2 - x1);
+ xf[i] = t0; xf[i+1] = t1;
+
+ t0 = a*x3; t1 = a*x2;
+ df[i+2] = scale*xf[i+2]*t0*t0;
+ df[i+3] = scale*xf[i+3]*t1*t1;
+ t0 *= scale2*(2 - x2); t1 *= scale2*(2 - x3);
+ xf[i+2] = t0; xf[i+3] = t1;
+ }
+
+ for( ; i < n; i++ )
+ {
+ double t0 = 1./(1. + xf[i]);
+ double t1 = scale*xf[i]*t0*t0;
+ t0 *= scale2*(1. - xf[i]);
+ df[i] = t1;
+ xf[i] = t0;
+ }
+ break;
+
+ case GAUSSIAN:
+ for( i = 0; i < n; i++ )
+ df[i] *= xf[i];
+ break;
+ default:
+ ;
+ }
+}
+
+
+void CvANN_MLP::calc_input_scale( const CvVectors* vecs, int flags )
+{
+ bool reset_weights = (flags & UPDATE_WEIGHTS) == 0;
+ bool no_scale = (flags & NO_INPUT_SCALE) != 0;
+ double* scale = weights[0];
+ int count = vecs->count;
+
+ if( reset_weights )
+ {
+ int i, j, vcount = layer_sizes->data.i[0];
+ int type = vecs->type;
+ double a = no_scale ? 1. : 0.;
+
+ for( j = 0; j < vcount; j++ )
+ scale[2*j] = a, scale[j*2+1] = 0.;
+
+ if( no_scale )
+ return;
+
+ for( i = 0; i < count; i++ )
+ {
+ const float* f = vecs->data.fl[i];
+ const double* d = vecs->data.db[i];
+ for( j = 0; j < vcount; j++ )
+ {
+ double t = type == CV_32F ? (double)f[j] : d[j];
+ scale[j*2] += t;
+ scale[j*2+1] += t*t;
+ }
+ }
+
+ for( j = 0; j < vcount; j++ )
+ {
+ double s = scale[j*2], s2 = scale[j*2+1];
+ double m = s/count, sigma2 = s2/count - m*m;
+ scale[j*2] = sigma2 < DBL_EPSILON ? 1 : 1./sqrt(sigma2);
+ scale[j*2+1] = -m*scale[j*2];
+ }
+ }
+}
+
+
+void CvANN_MLP::calc_output_scale( const CvVectors* vecs, int flags )
+{
+ int i, j, vcount = layer_sizes->data.i[layer_sizes->cols-1];
+ int type = vecs->type;
+ double m = min_val, M = max_val, m1 = min_val1, M1 = max_val1;
+ bool reset_weights = (flags & UPDATE_WEIGHTS) == 0;
+ bool no_scale = (flags & NO_OUTPUT_SCALE) != 0;
+ int l_count = layer_sizes->cols;
+ double* scale = weights[l_count];
+ double* inv_scale = weights[l_count+1];
+ int count = vecs->count;
+
+ CV_FUNCNAME( "CvANN_MLP::calc_output_scale" );
+
+ __BEGIN__;
+
+ if( reset_weights )
+ {
+ double a0 = no_scale ? 1 : DBL_MAX, b0 = no_scale ? 0 : -DBL_MAX;
+
+ for( j = 0; j < vcount; j++ )
+ {
+ scale[2*j] = inv_scale[2*j] = a0;
+ scale[j*2+1] = inv_scale[2*j+1] = b0;
+ }
+
+ if( no_scale )
+ EXIT;
+ }
+
+ for( i = 0; i < count; i++ )
+ {
+ const float* f = vecs->data.fl[i];
+ const double* d = vecs->data.db[i];
+
+ for( j = 0; j < vcount; j++ )
+ {
+ double t = type == CV_32F ? (double)f[j] : d[j];
+
+ if( reset_weights )
+ {
+ double mj = scale[j*2], Mj = scale[j*2+1];
+ if( mj > t ) mj = t;
+ if( Mj < t ) Mj = t;
+
+ scale[j*2] = mj;
+ scale[j*2+1] = Mj;
+ }
+ else
+ {
+ t = t*scale[j*2] + scale[2*j+1];
+ if( t < m1 || t > M1 )
+ CV_ERROR( CV_StsOutOfRange,
+ "Some of new output training vector components run exceed the original range too much" );
+ }
+ }
+ }
+
+ if( reset_weights )
+ for( j = 0; j < vcount; j++ )
+ {
+ // map mj..Mj to m..M
+ double mj = scale[j*2], Mj = scale[j*2+1];
+ double a, b;
+ double delta = Mj - mj;
+ if( delta < DBL_EPSILON )
+ a = 1, b = (M + m - Mj - mj)*0.5;
+ else
+ a = (M - m)/delta, b = m - mj*a;
+ inv_scale[j*2] = a; inv_scale[j*2+1] = b;
+ a = 1./a; b = -b*a;
+ scale[j*2] = a; scale[j*2+1] = b;
+ }
+
+ __END__;
+}
+
+
+bool CvANN_MLP::prepare_to_train( const CvMat* _inputs, const CvMat* _outputs,
+ const CvMat* _sample_weights, const CvMat* _sample_idx,
+ CvVectors* _ivecs, CvVectors* _ovecs, double** _sw, int _flags )
+{
+ bool ok = false;
+ CvMat* sample_idx = 0;
+ CvVectors ivecs, ovecs;
+ double* sw = 0;
+ int count = 0;
+
+ CV_FUNCNAME( "CvANN_MLP::prepare_to_train" );
+
+ ivecs.data.ptr = ovecs.data.ptr = 0;
+ assert( _ivecs && _ovecs );
+
+ __BEGIN__;
+
+ const int* sidx = 0;
+ int i, sw_type = 0, sw_count = 0;
+ int sw_step = 0;
+ double sw_sum = 0;
+
+ if( !layer_sizes )
+ CV_ERROR( CV_StsError,
+ "The network has not been created. Use method create or the appropriate constructor" );
+
+ if( !CV_IS_MAT(_inputs) || CV_MAT_TYPE(_inputs->type) != CV_32FC1 &&
+ CV_MAT_TYPE(_inputs->type) != CV_64FC1 || _inputs->cols != layer_sizes->data.i[0] )
+ CV_ERROR( CV_StsBadArg,
+ "input training data should be a floating-point matrix with"
+ "the number of rows equal to the number of training samples and "
+ "the number of columns equal to the size of 0-th (input) layer" );
+
+ if( !CV_IS_MAT(_outputs) || CV_MAT_TYPE(_outputs->type) != CV_32FC1 &&
+ CV_MAT_TYPE(_outputs->type) != CV_64FC1 ||
+ _outputs->cols != layer_sizes->data.i[layer_sizes->cols - 1] )
+ CV_ERROR( CV_StsBadArg,
+ "output training data should be a floating-point matrix with"
+ "the number of rows equal to the number of training samples and "
+ "the number of columns equal to the size of last (output) layer" );
+
+ if( _inputs->rows != _outputs->rows )
+ CV_ERROR( CV_StsUnmatchedSizes, "The numbers of input and output samples do not match" );
+
+ if( _sample_idx )
+ {
+ CV_CALL( sample_idx = cvPreprocessIndexArray( _sample_idx, _inputs->rows ));
+ sidx = sample_idx->data.i;
+ count = sample_idx->cols + sample_idx->rows - 1;
+ }
+ else
+ count = _inputs->rows;
+
+ if( _sample_weights )
+ {
+ if( !CV_IS_MAT(_sample_weights) )
+ CV_ERROR( CV_StsBadArg, "sample_weights (if passed) must be a valid matrix" );
+
+ sw_type = CV_MAT_TYPE(_sample_weights->type);
+ sw_count = _sample_weights->cols + _sample_weights->rows - 1;
+
+ if( sw_type != CV_32FC1 && sw_type != CV_64FC1 ||
+ _sample_weights->cols != 1 && _sample_weights->rows != 1 ||
+ sw_count != count && sw_count != _inputs->rows )
+ CV_ERROR( CV_StsBadArg,
+ "sample_weights must be 1d floating-point vector containing weights "
+ "of all or selected training samples" );
+
+ sw_step = CV_IS_MAT_CONT(_sample_weights->type) ? 1 :
+ _sample_weights->step/CV_ELEM_SIZE(sw_type);
+
+ CV_CALL( sw = (double*)cvAlloc( count*sizeof(sw[0]) ));
+ }
+
+ CV_CALL( ivecs.data.ptr = (uchar**)cvAlloc( count*sizeof(ivecs.data.ptr[0]) ));
+ CV_CALL( ovecs.data.ptr = (uchar**)cvAlloc( count*sizeof(ovecs.data.ptr[0]) ));
+
+ ivecs.type = CV_MAT_TYPE(_inputs->type);
+ ovecs.type = CV_MAT_TYPE(_outputs->type);
+ ivecs.count = ovecs.count = count;
+
+ for( i = 0; i < count; i++ )
+ {
+ int idx = sidx ? sidx[i] : i;
+ ivecs.data.ptr[i] = _inputs->data.ptr + idx*_inputs->step;
+ ovecs.data.ptr[i] = _outputs->data.ptr + idx*_outputs->step;
+ if( sw )
+ {
+ int si = sw_count == count ? i : idx;
+ double w = sw_type == CV_32FC1 ?
+ (double)_sample_weights->data.fl[si*sw_step] :
+ _sample_weights->data.db[si*sw_step];
+ sw[i] = w;
+ if( w < 0 )
+ CV_ERROR( CV_StsOutOfRange, "some of sample weights are negative" );
+ sw_sum += w;
+ }
+ }
+
+ // normalize weights
+ if( sw )
+ {
+ sw_sum = sw_sum > DBL_EPSILON ? 1./sw_sum : 0;
+ for( i = 0; i < count; i++ )
+ sw[i] *= sw_sum;
+ }
+
+ calc_input_scale( &ivecs, _flags );
+ CV_CALL( calc_output_scale( &ovecs, _flags ));
+
+ ok = true;
+
+ __END__;
+
+ if( !ok )
+ {
+ cvFree( &ivecs.data.ptr );
+ cvFree( &ovecs.data.ptr );
+ cvFree( &sw );
+ }
+
+ cvReleaseMat( &sample_idx );
+ *_ivecs = ivecs;
+ *_ovecs = ovecs;
+ *_sw = sw;
+
+ return ok;
+}
+
+
+int CvANN_MLP::train( const CvMat* _inputs, const CvMat* _outputs,
+ const CvMat* _sample_weights, const CvMat* _sample_idx,
+ CvANN_MLP_TrainParams _params, int flags )
+{
+ const int MAX_ITER = 1000;
+ const double DEFAULT_EPSILON = FLT_EPSILON;
+
+ double* sw = 0;
+ CvVectors x0, u;
+ int iter = -1;
+
+ x0.data.ptr = u.data.ptr = 0;
+
+ CV_FUNCNAME( "CvANN_MLP::train" );
+
+ __BEGIN__;
+
+ int max_iter;
+ double epsilon;
+
+ params = _params;
+
+ // initialize training data
+ CV_CALL( prepare_to_train( _inputs, _outputs, _sample_weights,
+ _sample_idx, &x0, &u, &sw, flags ));
+
+ // ... and link weights
+ if( !(flags & UPDATE_WEIGHTS) )
+ init_weights();
+
+ max_iter = params.term_crit.type & CV_TERMCRIT_ITER ? params.term_crit.max_iter : MAX_ITER;
+ max_iter = MIN( max_iter, MAX_ITER );
+ max_iter = MAX( max_iter, 1 );
+
+ epsilon = params.term_crit.type & CV_TERMCRIT_EPS ? params.term_crit.epsilon : DEFAULT_EPSILON;
+ epsilon = MAX(epsilon, DBL_EPSILON);
+
+ params.term_crit.type = CV_TERMCRIT_ITER + CV_TERMCRIT_EPS;
+ params.term_crit.max_iter = max_iter;
+ params.term_crit.epsilon = epsilon;
+
+ if( params.train_method == CvANN_MLP_TrainParams::BACKPROP )
+ {
+ CV_CALL( iter = train_backprop( x0, u, sw ));
+ }
+ else
+ {
+ CV_CALL( iter = train_rprop( x0, u, sw ));
+ }
+
+ __END__;
+
+ cvFree( &x0.data.ptr );
+ cvFree( &u.data.ptr );
+ cvFree( &sw );
+
+ return iter;
+}
+
+
+int CvANN_MLP::train_backprop( CvVectors x0, CvVectors u, const double* sw )
+{
+ CvMat* dw = 0;
+ CvMat* buf = 0;
+ double **x = 0, **df = 0;
+ CvMat* _idx = 0;
+ int iter = -1, count = x0.count;
+
+ CV_FUNCNAME( "CvANN_MLP::train_backprop" );
+
+ __BEGIN__;
+
+ int i, j, k, ivcount, ovcount, l_count, total = 0, max_iter;
+ double *buf_ptr;
+ double prev_E = DBL_MAX*0.5, E = 0, epsilon;
+
+ max_iter = params.term_crit.max_iter*count;
+ epsilon = params.term_crit.epsilon*count;
+
+ l_count = layer_sizes->cols;
+ ivcount = layer_sizes->data.i[0];
+ ovcount = layer_sizes->data.i[l_count-1];
+
+ // allocate buffers
+ for( i = 0; i < l_count; i++ )
+ total += layer_sizes->data.i[i] + 1;
+
+ CV_CALL( dw = cvCreateMat( wbuf->rows, wbuf->cols, wbuf->type ));
+ cvZero( dw );
+ CV_CALL( buf = cvCreateMat( 1, (total + max_count)*2, CV_64F ));
+ CV_CALL( _idx = cvCreateMat( 1, count, CV_32SC1 ));
+ for( i = 0; i < count; i++ )
+ _idx->data.i[i] = i;
+
+ CV_CALL( x = (double**)cvAlloc( total*2*sizeof(x[0]) ));
+ df = x + total;
+ buf_ptr = buf->data.db;
+
+ for( j = 0; j < l_count; j++ )
+ {
+ x[j] = buf_ptr;
+ df[j] = x[j] + layer_sizes->data.i[j];
+ buf_ptr += (df[j] - x[j])*2;
+ }
+
+ // run back-propagation loop
+ /*
+ y_i = w_i*x_{i-1}
+ x_i = f(y_i)
+ E = 1/2*||u - x_N||^2
+ grad_N = (x_N - u)*f'(y_i)
+ dw_i(t) = momentum*dw_i(t-1) + dw_scale*x_{i-1}*grad_i
+ w_i(t+1) = w_i(t) + dw_i(t)
+ grad_{i-1} = w_i^t*grad_i
+ */
+ for( iter = 0; iter < max_iter; iter++ )
+ {
+ int idx = iter % count;
+ double* w = weights[0];
+ double sweight = sw ? count*sw[idx] : 1.;
+ CvMat _w, _dw, hdr1, hdr2, ghdr1, ghdr2, _df;
+ CvMat *x1 = &hdr1, *x2 = &hdr2, *grad1 = &ghdr1, *grad2 = &ghdr2, *temp;
+
+ if( idx == 0 )
+ {
+ if( fabs(prev_E - E) < epsilon )
+ break;
+ prev_E = E;
+ E = 0;
+
+ // shuffle indices
+ for( i = 0; i < count; i++ )
+ {
+ int tt;
+ j = (unsigned)cvRandInt(&rng) % count;
+ k = (unsigned)cvRandInt(&rng) % count;
+ CV_SWAP( _idx->data.i[j], _idx->data.i[k], tt );
+ }
+ }
+
+ idx = _idx->data.i[idx];
+
+ if( x0.type == CV_32F )
+ {
+ const float* x0data = x0.data.fl[idx];
+ for( j = 0; j < ivcount; j++ )
+ x[0][j] = x0data[j]*w[j*2] + w[j*2 + 1];
+ }
+ else
+ {
+ const double* x0data = x0.data.db[idx];
+ for( j = 0; j < ivcount; j++ )
+ x[0][j] = x0data[j]*w[j*2] + w[j*2 + 1];
+ }
+
+ cvInitMatHeader( x1, 1, ivcount, CV_64F, x[0] );
+
+ // forward pass, compute y[i]=w*x[i-1], x[i]=f(y[i]), df[i]=f'(y[i])
+ for( i = 1; i < l_count; i++ )
+ {
+ cvInitMatHeader( x2, 1, layer_sizes->data.i[i], CV_64F, x[i] );
+ cvInitMatHeader( &_w, x1->cols, x2->cols, CV_64F, weights[i] );
+ cvGEMM( x1, &_w, 1, 0, 0, x2 );
+ _df = *x2;
+ _df.data.db = df[i];
+ calc_activ_func_deriv( x2, &_df, _w.data.db + _w.rows*_w.cols );
+ CV_SWAP( x1, x2, temp );
+ }
+
+ cvInitMatHeader( grad1, 1, ovcount, CV_64F, buf_ptr );
+ *grad2 = *grad1;
+ grad2->data.db = buf_ptr + max_count;
+
+ w = weights[l_count+1];
+
+ // calculate error
+ if( u.type == CV_32F )
+ {
+ const float* udata = u.data.fl[idx];
+ for( k = 0; k < ovcount; k++ )
+ {
+ double t = udata[k]*w[k*2] + w[k*2+1] - x[l_count-1][k];
+ grad1->data.db[k] = t*sweight;
+ E += t*t;
+ }
+ }
+ else
+ {
+ const double* udata = u.data.db[idx];
+ for( k = 0; k < ovcount; k++ )
+ {
+ double t = udata[k]*w[k*2] + w[k*2+1] - x[l_count-1][k];
+ grad1->data.db[k] = t*sweight;
+ E += t*t;
+ }
+ }
+ E *= sweight;
+
+ // backward pass, update weights
+ for( i = l_count-1; i > 0; i-- )
+ {
+ int n1 = layer_sizes->data.i[i-1], n2 = layer_sizes->data.i[i];
+ cvInitMatHeader( &_df, 1, n2, CV_64F, df[i] );
+ cvMul( grad1, &_df, grad1 );
+ cvInitMatHeader( &_w, n1+1, n2, CV_64F, weights[i] );
+ cvInitMatHeader( &_dw, n1+1, n2, CV_64F, dw->data.db + (weights[i] - weights[0]) );
+ cvInitMatHeader( x1, n1+1, 1, CV_64F, x[i-1] );
+ x[i-1][n1] = 1.;
+ cvGEMM( x1, grad1, params.bp_dw_scale, &_dw, params.bp_moment_scale, &_dw );
+ cvAdd( &_w, &_dw, &_w );
+ if( i > 1 )
+ {
+ grad2->cols = n1;
+ _w.rows = n1;
+ cvGEMM( grad1, &_w, 1, 0, 0, grad2, CV_GEMM_B_T );
+ }
+ CV_SWAP( grad1, grad2, temp );
+ }
+ }
+
+ iter /= count;
+
+ __END__;
+
+ cvReleaseMat( &dw );
+ cvReleaseMat( &buf );
+ cvReleaseMat( &_idx );
+ cvFree( &x );
+
+ return iter;
+}
+
+
+int CvANN_MLP::train_rprop( CvVectors x0, CvVectors u, const double* sw )
+{
+ const int max_buf_sz = 1 << 16;
+ CvMat* dw = 0;
+ CvMat* dEdw = 0;
+ CvMat* prev_dEdw_sign = 0;
+ CvMat* buf = 0;
+ double **x = 0, **df = 0;
+ int iter = -1, count = x0.count;
+
+ CV_FUNCNAME( "CvANN_MLP::train" );
+
+ __BEGIN__;
+
+ int i, ivcount, ovcount, l_count, total = 0, max_iter, buf_sz, dcount0, dcount=0;
+ double *buf_ptr;
+ double prev_E = DBL_MAX*0.5, epsilon;
+ double dw_plus, dw_minus, dw_min, dw_max;
+ double inv_count;
+
+ max_iter = params.term_crit.max_iter;
+ epsilon = params.term_crit.epsilon;
+ dw_plus = params.rp_dw_plus;
+ dw_minus = params.rp_dw_minus;
+ dw_min = params.rp_dw_min;
+ dw_max = params.rp_dw_max;
+
+ l_count = layer_sizes->cols;
+ ivcount = layer_sizes->data.i[0];
+ ovcount = layer_sizes->data.i[l_count-1];
+
+ // allocate buffers
+ for( i = 0; i < l_count; i++ )
+ total += layer_sizes->data.i[i];
+
+ CV_CALL( dw = cvCreateMat( wbuf->rows, wbuf->cols, wbuf->type ));
+ cvSet( dw, cvScalarAll(params.rp_dw0) );
+ CV_CALL( dEdw = cvCreateMat( wbuf->rows, wbuf->cols, wbuf->type ));
+ cvZero( dEdw );
+ CV_CALL( prev_dEdw_sign = cvCreateMat( wbuf->rows, wbuf->cols, CV_8SC1 ));
+ cvZero( prev_dEdw_sign );
+
+ inv_count = 1./count;
+ dcount0 = max_buf_sz/(2*total);
+ dcount0 = MAX( dcount0, 1 );
+ dcount0 = MIN( dcount0, count );
+ buf_sz = dcount0*(total + max_count)*2;
+
+ CV_CALL( buf = cvCreateMat( 1, buf_sz, CV_64F ));
+
+ CV_CALL( x = (double**)cvAlloc( total*2*sizeof(x[0]) ));
+ df = x + total;
+ buf_ptr = buf->data.db;
+
+ for( i = 0; i < l_count; i++ )
+ {
+ x[i] = buf_ptr;
+ df[i] = x[i] + layer_sizes->data.i[i]*dcount0;
+ buf_ptr += (df[i] - x[i])*2;
+ }
+
+ // run rprop loop
+ /*
+ y_i(t) = w_i(t)*x_{i-1}(t)
+ x_i(t) = f(y_i(t))
+ E = sum_over_all_samples(1/2*||u - x_N||^2)
+ grad_N = (x_N - u)*f'(y_i)
+
+ MIN(dw_i{jk}(t)*dw_plus, dw_max), if dE/dw_i{jk}(t)*dE/dw_i{jk}(t-1) > 0
+ dw_i{jk}(t) = MAX(dw_i{jk}(t)*dw_minus, dw_min), if dE/dw_i{jk}(t)*dE/dw_i{jk}(t-1) < 0
+ dw_i{jk}(t-1) else
+
+ if (dE/dw_i{jk}(t)*dE/dw_i{jk}(t-1) < 0)
+ dE/dw_i{jk}(t)<-0
+ else
+ w_i{jk}(t+1) = w_i{jk}(t) + dw_i{jk}(t)
+ grad_{i-1}(t) = w_i^t(t)*grad_i(t)
+ */
+ for( iter = 0; iter < max_iter; iter++ )
+ {
+ int n1, n2, si, j, k;
+ double* w;
+ CvMat _w, _dEdw, hdr1, hdr2, ghdr1, ghdr2, _df;
+ CvMat *x1, *x2, *grad1, *grad2, *temp;
+ double E = 0;
+
+ // first, iterate through all the samples and compute dEdw
+ for( si = 0; si < count; si += dcount )
+ {
+ dcount = MIN( count - si, dcount0 );
+ w = weights[0];
+ grad1 = &ghdr1; grad2 = &ghdr2;
+ x1 = &hdr1; x2 = &hdr2;
+
+ // grab and preprocess input data
+ if( x0.type == CV_32F )
+ for( i = 0; i < dcount; i++ )
+ {
+ const float* x0data = x0.data.fl[si+i];
+ double* xdata = x[0]+i*ivcount;
+ for( j = 0; j < ivcount; j++ )
+ xdata[j] = x0data[j]*w[j*2] + w[j*2+1];
+ }
+ else
+ for( i = 0; i < dcount; i++ )
+ {
+ const double* x0data = x0.data.db[si+i];
+ double* xdata = x[0]+i*ivcount;
+ for( j = 0; j < ivcount; j++ )
+ xdata[j] = x0data[j]*w[j*2] + w[j*2+1];
+ }
+
+ cvInitMatHeader( x1, dcount, ivcount, CV_64F, x[0] );
+
+ // forward pass, compute y[i]=w*x[i-1], x[i]=f(y[i]), df[i]=f'(y[i])
+ for( i = 1; i < l_count; i++ )
+ {
+ cvInitMatHeader( x2, dcount, layer_sizes->data.i[i], CV_64F, x[i] );
+ cvInitMatHeader( &_w, x1->cols, x2->cols, CV_64F, weights[i] );
+ cvGEMM( x1, &_w, 1, 0, 0, x2 );
+ _df = *x2;
+ _df.data.db = df[i];
+ calc_activ_func_deriv( x2, &_df, _w.data.db + _w.rows*_w.cols );
+ CV_SWAP( x1, x2, temp );
+ }
+
+ cvInitMatHeader( grad1, dcount, ovcount, CV_64F, buf_ptr );
+ w = weights[l_count+1];
+ grad2->data.db = buf_ptr + max_count*dcount;
+
+ // calculate error
+ if( u.type == CV_32F )
+ for( i = 0; i < dcount; i++ )
+ {
+ const float* udata = u.data.fl[si+i];
+ const double* xdata = x[l_count-1] + i*ovcount;
+ double* gdata = grad1->data.db + i*ovcount;
+ double sweight = sw ? sw[si+i] : inv_count, E1 = 0;
+
+ for( j = 0; j < ovcount; j++ )
+ {
+ double t = udata[j]*w[j*2] + w[j*2+1] - xdata[j];
+ gdata[j] = t*sweight;
+ E1 += t*t;
+ }
+ E += sweight*E1;
+ }
+ else
+ for( i = 0; i < dcount; i++ )
+ {
+ const double* udata = u.data.db[si+i];
+ const double* xdata = x[l_count-1] + i*ovcount;
+ double* gdata = grad1->data.db + i*ovcount;
+ double sweight = sw ? sw[si+i] : inv_count, E1 = 0;
+
+ for( j = 0; j < ovcount; j++ )
+ {
+ double t = udata[j]*w[j*2] + w[j*2+1] - xdata[j];
+ gdata[j] = t*sweight;
+ E1 += t*t;
+ }
+ E += sweight*E1;
+ }
+
+ // backward pass, update dEdw
+ for( i = l_count-1; i > 0; i-- )
+ {
+ n1 = layer_sizes->data.i[i-1]; n2 = layer_sizes->data.i[i];
+ cvInitMatHeader( &_df, dcount, n2, CV_64F, df[i] );
+ cvMul( grad1, &_df, grad1 );
+ cvInitMatHeader( &_dEdw, n1, n2, CV_64F, dEdw->data.db+(weights[i]-weights[0]) );
+ cvInitMatHeader( x1, dcount, n1, CV_64F, x[i-1] );
+ cvGEMM( x1, grad1, 1, &_dEdw, 1, &_dEdw, CV_GEMM_A_T );
+ // update bias part of dEdw
+ for( k = 0; k < dcount; k++ )
+ {
+ double* dst = _dEdw.data.db + n1*n2;
+ const double* src = grad1->data.db + k*n2;
+ for( j = 0; j < n2; j++ )
+ dst[j] += src[j];
+ }
+ cvInitMatHeader( &_w, n1, n2, CV_64F, weights[i] );
+ cvInitMatHeader( grad2, dcount, n1, CV_64F, grad2->data.db );
+
+ if( i > 1 )
+ cvGEMM( grad1, &_w, 1, 0, 0, grad2, CV_GEMM_B_T );
+ CV_SWAP( grad1, grad2, temp );
+ }
+ }
+
+ // now update weights
+ for( i = 1; i < l_count; i++ )
+ {
+ n1 = layer_sizes->data.i[i-1]; n2 = layer_sizes->data.i[i];
+ for( k = 0; k <= n1; k++ )
+ {
+ double* wk = weights[i]+k*n2;
+ size_t delta = wk - weights[0];
+ double* dwk = dw->data.db + delta;
+ double* dEdwk = dEdw->data.db + delta;
+ char* prevEk = (char*)(prev_dEdw_sign->data.ptr + delta);
+
+ for( j = 0; j < n2; j++ )
+ {
+ double Eval = dEdwk[j];
+ double dval = dwk[j];
+ double wval = wk[j];
+ int s = CV_SIGN(Eval);
+ int ss = prevEk[j]*s;
+ if( ss > 0 )
+ {
+ dval *= dw_plus;
+ dval = MIN( dval, dw_max );
+ dwk[j] = dval;
+ wk[j] = wval + dval*s;
+ }
+ else if( ss < 0 )
+ {
+ dval *= dw_minus;
+ dval = MAX( dval, dw_min );
+ prevEk[j] = 0;
+ dwk[j] = dval;
+ wk[j] = wval + dval*s;
+ }
+ else
+ {
+ prevEk[j] = (char)s;
+ wk[j] = wval + dval*s;
+ }
+ dEdwk[j] = 0.;
+ }
+ }
+ }
+
+ if( fabs(prev_E - E) < epsilon )
+ break;
+ prev_E = E;
+ E = 0;
+ }
+
+ __END__;
+
+ cvReleaseMat( &dw );
+ cvReleaseMat( &dEdw );
+ cvReleaseMat( &prev_dEdw_sign );
+ cvReleaseMat( &buf );
+ cvFree( &x );
+
+ return iter;
+}
+
+
+void CvANN_MLP::write_params( CvFileStorage* fs )
+{
+ //CV_FUNCNAME( "CvANN_MLP::write_params" );
+
+ __BEGIN__;
+
+ const char* activ_func_name = activ_func == IDENTITY ? "IDENTITY" :
+ activ_func == SIGMOID_SYM ? "SIGMOID_SYM" :
+ activ_func == GAUSSIAN ? "GAUSSIAN" : 0;
+
+ if( activ_func_name )
+ cvWriteString( fs, "activation_function", activ_func_name );
+ else
+ cvWriteInt( fs, "activation_function", activ_func );
+
+ if( activ_func != IDENTITY )
+ {
+ cvWriteReal( fs, "f_param1", f_param1 );
+ cvWriteReal( fs, "f_param2", f_param2 );
+ }
+
+ cvWriteReal( fs, "min_val", min_val );
+ cvWriteReal( fs, "max_val", max_val );
+ cvWriteReal( fs, "min_val1", min_val1 );
+ cvWriteReal( fs, "max_val1", max_val1 );
+
+ cvStartWriteStruct( fs, "training_params", CV_NODE_MAP );
+ if( params.train_method == CvANN_MLP_TrainParams::BACKPROP )
+ {
+ cvWriteString( fs, "train_method", "BACKPROP" );
+ cvWriteReal( fs, "dw_scale", params.bp_dw_scale );
+ cvWriteReal( fs, "moment_scale", params.bp_moment_scale );
+ }
+ else if( params.train_method == CvANN_MLP_TrainParams::RPROP )
+ {
+ cvWriteString( fs, "train_method", "RPROP" );
+ cvWriteReal( fs, "dw0", params.rp_dw0 );
+ cvWriteReal( fs, "dw_plus", params.rp_dw_plus );
+ cvWriteReal( fs, "dw_minus", params.rp_dw_minus );
+ cvWriteReal( fs, "dw_min", params.rp_dw_min );
+ cvWriteReal( fs, "dw_max", params.rp_dw_max );
+ }
+
+ cvStartWriteStruct( fs, "term_criteria", CV_NODE_MAP + CV_NODE_FLOW );
+ if( params.term_crit.type & CV_TERMCRIT_EPS )
+ cvWriteReal( fs, "epsilon", params.term_crit.epsilon );
+ if( params.term_crit.type & CV_TERMCRIT_ITER )
+ cvWriteInt( fs, "iterations", params.term_crit.max_iter );
+ cvEndWriteStruct( fs );
+
+ cvEndWriteStruct( fs );
+
+ __END__;
+}
+
+
+void CvANN_MLP::write( CvFileStorage* fs, const char* name )
+{
+ CV_FUNCNAME( "CvANN_MLP::write" );
+
+ __BEGIN__;
+
+ int i, l_count = layer_sizes->cols;
+
+ if( !layer_sizes )
+ CV_ERROR( CV_StsError, "The network has not been initialized" );
+
+ cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_ML_ANN_MLP );
+
+ cvWrite( fs, "layer_sizes", layer_sizes );
+
+ write_params( fs );
+
+ cvStartWriteStruct( fs, "input_scale", CV_NODE_SEQ + CV_NODE_FLOW );
+ cvWriteRawData( fs, weights[0], layer_sizes->data.i[0]*2, "d" );
+ cvEndWriteStruct( fs );
+
+ cvStartWriteStruct( fs, "output_scale", CV_NODE_SEQ + CV_NODE_FLOW );
+ cvWriteRawData( fs, weights[l_count], layer_sizes->data.i[l_count-1]*2, "d" );
+ cvEndWriteStruct( fs );
+
+ cvStartWriteStruct( fs, "inv_output_scale", CV_NODE_SEQ + CV_NODE_FLOW );
+ cvWriteRawData( fs, weights[l_count+1], layer_sizes->data.i[l_count-1]*2, "d" );
+ cvEndWriteStruct( fs );
+
+ cvStartWriteStruct( fs, "weights", CV_NODE_SEQ );
+ for( i = 1; i < l_count; i++ )
+ {
+ cvStartWriteStruct( fs, 0, CV_NODE_SEQ + CV_NODE_FLOW );
+ cvWriteRawData( fs, weights[i], (layer_sizes->data.i[i-1]+1)*layer_sizes->data.i[i], "d" );
+ cvEndWriteStruct( fs );
+ }
+
+ cvEndWriteStruct( fs );
+
+ __END__;
+}
+
+
+void CvANN_MLP::read_params( CvFileStorage* fs, CvFileNode* node )
+{
+ //CV_FUNCNAME( "CvANN_MLP::read_params" );
+
+ __BEGIN__;
+
+ const char* activ_func_name = cvReadStringByName( fs, node, "activation_function", 0 );
+ CvFileNode* tparams_node;
+
+ if( activ_func_name )
+ activ_func = strcmp( activ_func_name, "SIGMOID_SYM" ) == 0 ? SIGMOID_SYM :
+ strcmp( activ_func_name, "IDENTITY" ) == 0 ? IDENTITY :
+ strcmp( activ_func_name, "GAUSSIAN" ) == 0 ? GAUSSIAN : 0;
+ else
+ activ_func = cvReadIntByName( fs, node, "activation_function" );
+
+ f_param1 = cvReadRealByName( fs, node, "f_param1", 0 );
+ f_param2 = cvReadRealByName( fs, node, "f_param2", 0 );
+
+ set_activ_func( activ_func, f_param1, f_param2 );
+
+ min_val = cvReadRealByName( fs, node, "min_val", 0. );
+ max_val = cvReadRealByName( fs, node, "max_val", 1. );
+ min_val1 = cvReadRealByName( fs, node, "min_val1", 0. );
+ max_val1 = cvReadRealByName( fs, node, "max_val1", 1. );
+
+ tparams_node = cvGetFileNodeByName( fs, node, "training_params" );
+ params = CvANN_MLP_TrainParams();
+
+ if( tparams_node )
+ {
+ const char* tmethod_name = cvReadStringByName( fs, tparams_node, "train_method", "" );
+ CvFileNode* tcrit_node;
+
+ if( strcmp( tmethod_name, "BACKPROP" ) == 0 )
+ {
+ params.train_method = CvANN_MLP_TrainParams::BACKPROP;
+ params.bp_dw_scale = cvReadRealByName( fs, tparams_node, "dw_scale", 0 );
+ params.bp_moment_scale = cvReadRealByName( fs, tparams_node, "moment_scale", 0 );
+ }
+ else if( strcmp( tmethod_name, "RPROP" ) == 0 )
+ {
+ params.train_method = CvANN_MLP_TrainParams::RPROP;
+ params.rp_dw0 = cvReadRealByName( fs, tparams_node, "dw0", 0 );
+ params.rp_dw_plus = cvReadRealByName( fs, tparams_node, "dw_plus", 0 );
+ params.rp_dw_minus = cvReadRealByName( fs, tparams_node, "dw_minus", 0 );
+ params.rp_dw_min = cvReadRealByName( fs, tparams_node, "dw_min", 0 );
+ params.rp_dw_max = cvReadRealByName( fs, tparams_node, "dw_max", 0 );
+ }
+
+ tcrit_node = cvGetFileNodeByName( fs, tparams_node, "term_criteria" );
+ if( tcrit_node )
+ {
+ params.term_crit.epsilon = cvReadRealByName( fs, tcrit_node, "epsilon", -1 );
+ params.term_crit.max_iter = cvReadIntByName( fs, tcrit_node, "iterations", -1 );
+ params.term_crit.type = (params.term_crit.epsilon >= 0 ? CV_TERMCRIT_EPS : 0) +
+ (params.term_crit.max_iter >= 0 ? CV_TERMCRIT_ITER : 0);
+ }
+ }
+
+ __END__;
+}
+
+
+void CvANN_MLP::read( CvFileStorage* fs, CvFileNode* node )
+{
+ CvMat* _layer_sizes = 0;
+
+ CV_FUNCNAME( "CvANN_MLP::read" );
+
+ __BEGIN__;
+
+ CvFileNode* w;
+ CvSeqReader reader;
+ int i, l_count;
+
+ _layer_sizes = (CvMat*)cvReadByName( fs, node, "layer_sizes" );
+ CV_CALL( create( _layer_sizes, SIGMOID_SYM, 0, 0 ));
+ l_count = layer_sizes->cols;
+
+ CV_CALL( read_params( fs, node ));
+
+ w = cvGetFileNodeByName( fs, node, "input_scale" );
+ if( !w || CV_NODE_TYPE(w->tag) != CV_NODE_SEQ ||
+ w->data.seq->total != layer_sizes->data.i[0]*2 )
+ CV_ERROR( CV_StsParseError, "input_scale tag is not found or is invalid" );
+
+ CV_CALL( cvReadRawData( fs, w, weights[0], "d" ));
+
+ w = cvGetFileNodeByName( fs, node, "output_scale" );
+ if( !w || CV_NODE_TYPE(w->tag) != CV_NODE_SEQ ||
+ w->data.seq->total != layer_sizes->data.i[l_count-1]*2 )
+ CV_ERROR( CV_StsParseError, "output_scale tag is not found or is invalid" );
+
+ CV_CALL( cvReadRawData( fs, w, weights[l_count], "d" ));
+
+ w = cvGetFileNodeByName( fs, node, "inv_output_scale" );
+ if( !w || CV_NODE_TYPE(w->tag) != CV_NODE_SEQ ||
+ w->data.seq->total != layer_sizes->data.i[l_count-1]*2 )
+ CV_ERROR( CV_StsParseError, "inv_output_scale tag is not found or is invalid" );
+
+ CV_CALL( cvReadRawData( fs, w, weights[l_count+1], "d" ));
+
+ w = cvGetFileNodeByName( fs, node, "weights" );
+ if( !w || CV_NODE_TYPE(w->tag) != CV_NODE_SEQ ||
+ w->data.seq->total != l_count - 1 )
+ CV_ERROR( CV_StsParseError, "weights tag is not found or is invalid" );
+
+ cvStartReadSeq( w->data.seq, &reader );
+
+ for( i = 1; i < l_count; i++ )
+ {
+ w = (CvFileNode*)reader.ptr;
+ CV_CALL( cvReadRawData( fs, w, weights[i], "d" ));
+ CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
+ }
+
+ __END__;
+}
+
+/* End of file. */
diff --git a/ml/src/mlboost.cpp b/ml/src/mlboost.cpp
new file mode 100644
index 0000000..1e76039
--- /dev/null
+++ b/ml/src/mlboost.cpp
@@ -0,0 +1,1655 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_ml.h"
+
+static inline double
+log_ratio( double val )
+{
+ const double eps = 1e-5;
+
+ val = MAX( val, eps );
+ val = MIN( val, 1. - eps );
+ return log( val/(1. - val) );
+}
+
+
+CvBoostParams::CvBoostParams()
+{
+ boost_type = CvBoost::REAL;
+ weak_count = 100;
+ weight_trim_rate = 0.95;
+ cv_folds = 0;
+ max_depth = 1;
+}
+
+
+CvBoostParams::CvBoostParams( int _boost_type, int _weak_count,
+ double _weight_trim_rate, int _max_depth,
+ bool _use_surrogates, const float* _priors )
+{
+ boost_type = _boost_type;
+ weak_count = _weak_count;
+ weight_trim_rate = _weight_trim_rate;
+ split_criteria = CvBoost::DEFAULT;
+ cv_folds = 0;
+ max_depth = _max_depth;
+ use_surrogates = _use_surrogates;
+ priors = _priors;
+}
+
+
+
+///////////////////////////////// CvBoostTree ///////////////////////////////////
+
+CvBoostTree::CvBoostTree()
+{
+ ensemble = 0;
+}
+
+
+CvBoostTree::~CvBoostTree()
+{
+ clear();
+}
+
+
+void
+CvBoostTree::clear()
+{
+ CvDTree::clear();
+ ensemble = 0;
+}
+
+
+bool
+CvBoostTree::train( CvDTreeTrainData* _train_data,
+ const CvMat* _subsample_idx, CvBoost* _ensemble )
+{
+ clear();
+ ensemble = _ensemble;
+ data = _train_data;
+ data->shared = true;
+
+ return do_train( _subsample_idx );
+}
+
+
+bool
+CvBoostTree::train( const CvMat*, int, const CvMat*, const CvMat*,
+ const CvMat*, const CvMat*, const CvMat*, CvDTreeParams )
+{
+ assert(0);
+ return false;
+}
+
+
+bool
+CvBoostTree::train( CvDTreeTrainData*, const CvMat* )
+{
+ assert(0);
+ return false;
+}
+
+
+void
+CvBoostTree::scale( double scale )
+{
+ CvDTreeNode* node = root;
+
+ // traverse the tree and scale all the node values
+ for(;;)
+ {
+ CvDTreeNode* parent;
+ for(;;)
+ {
+ node->value *= scale;
+ if( !node->left )
+ break;
+ node = node->left;
+ }
+
+ for( parent = node->parent; parent && parent->right == node;
+ node = parent, parent = parent->parent )
+ ;
+
+ if( !parent )
+ break;
+
+ node = parent->right;
+ }
+}
+
+
+void
+CvBoostTree::try_split_node( CvDTreeNode* node )
+{
+ CvDTree::try_split_node( node );
+
+ if( !node->left )
+ {
+ // if the node has not been split,
+ // store the responses for the corresponding training samples
+ double* weak_eval = ensemble->get_weak_response()->data.db;
+ int* labels = data->get_labels( node );
+ int i, count = node->sample_count;
+ double value = node->value;
+
+ for( i = 0; i < count; i++ )
+ weak_eval[labels[i]] = value;
+ }
+}
+
+
+double
+CvBoostTree::calc_node_dir( CvDTreeNode* node )
+{
+ char* dir = (char*)data->direction->data.ptr;
+ const double* weights = ensemble->get_subtree_weights()->data.db;
+ int i, n = node->sample_count, vi = node->split->var_idx;
+ double L, R;
+
+ assert( !node->split->inversed );
+
+ if( data->get_var_type(vi) >= 0 ) // split on categorical var
+ {
+ const int* cat_labels = data->get_cat_var_data( node, vi );
+ const int* subset = node->split->subset;
+ double sum = 0, sum_abs = 0;
+
+ for( i = 0; i < n; i++ )
+ {
+ int idx = cat_labels[i];
+ double w = weights[i];
+ int d = idx >= 0 ? CV_DTREE_CAT_DIR(idx,subset) : 0;
+ sum += d*w; sum_abs += (d & 1)*w;
+ dir[i] = (char)d;
+ }
+
+ R = (sum_abs + sum) * 0.5;
+ L = (sum_abs - sum) * 0.5;
+ }
+ else // split on ordered var
+ {
+ const CvPair32s32f* sorted = data->get_ord_var_data(node,vi);
+ int split_point = node->split->ord.split_point;
+ int n1 = node->get_num_valid(vi);
+
+ assert( 0 <= split_point && split_point < n1-1 );
+ L = R = 0;
+
+ for( i = 0; i <= split_point; i++ )
+ {
+ int idx = sorted[i].i;
+ double w = weights[idx];
+ dir[idx] = (char)-1;
+ L += w;
+ }
+
+ for( ; i < n1; i++ )
+ {
+ int idx = sorted[i].i;
+ double w = weights[idx];
+ dir[idx] = (char)1;
+ R += w;
+ }
+
+ for( ; i < n; i++ )
+ dir[sorted[i].i] = (char)0;
+ }
+
+ node->maxlr = MAX( L, R );
+ return node->split->quality/(L + R);
+}
+
+
+CvDTreeSplit*
+CvBoostTree::find_split_ord_class( CvDTreeNode* node, int vi )
+{
+ const float epsilon = FLT_EPSILON*2;
+ const CvPair32s32f* sorted = data->get_ord_var_data(node, vi);
+ const int* responses = data->get_class_labels(node);
+ const double* weights = ensemble->get_subtree_weights()->data.db;
+ int n = node->sample_count;
+ int n1 = node->get_num_valid(vi);
+ const double* rcw0 = weights + n;
+ double lcw[2] = {0,0}, rcw[2];
+ int i, best_i = -1;
+ double best_val = 0;
+ int boost_type = ensemble->get_params().boost_type;
+ int split_criteria = ensemble->get_params().split_criteria;
+
+ rcw[0] = rcw0[0]; rcw[1] = rcw0[1];
+ for( i = n1; i < n; i++ )
+ {
+ int idx = sorted[i].i;
+ double w = weights[idx];
+ rcw[responses[idx]] -= w;
+ }
+
+ if( split_criteria != CvBoost::GINI && split_criteria != CvBoost::MISCLASS )
+ split_criteria = boost_type == CvBoost::DISCRETE ? CvBoost::MISCLASS : CvBoost::GINI;
+
+ if( split_criteria == CvBoost::GINI )
+ {
+ double L = 0, R = rcw[0] + rcw[1];
+ double lsum2 = 0, rsum2 = rcw[0]*rcw[0] + rcw[1]*rcw[1];
+
+ for( i = 0; i < n1 - 1; i++ )
+ {
+ int idx = sorted[i].i;
+ double w = weights[idx], w2 = w*w;
+ double lv, rv;
+ idx = responses[idx];
+ L += w; R -= w;
+ lv = lcw[idx]; rv = rcw[idx];
+ lsum2 += 2*lv*w + w2;
+ rsum2 -= 2*rv*w - w2;
+ lcw[idx] = lv + w; rcw[idx] = rv - w;
+
+ if( sorted[i].val + epsilon < sorted[i+1].val )
+ {
+ double val = (lsum2*R + rsum2*L)/(L*R);
+ if( best_val < val )
+ {
+ best_val = val;
+ best_i = i;
+ }
+ }
+ }
+ }
+ else
+ {
+ for( i = 0; i < n1 - 1; i++ )
+ {
+ int idx = sorted[i].i;
+ double w = weights[idx];
+ idx = responses[idx];
+ lcw[idx] += w;
+ rcw[idx] -= w;
+
+ if( sorted[i].val + epsilon < sorted[i+1].val )
+ {
+ double val = lcw[0] + rcw[1], val2 = lcw[1] + rcw[0];
+ val = MAX(val, val2);
+ if( best_val < val )
+ {
+ best_val = val;
+ best_i = i;
+ }
+ }
+ }
+ }
+
+ return best_i >= 0 ? data->new_split_ord( vi,
+ (sorted[best_i].val + sorted[best_i+1].val)*0.5f, best_i,
+ 0, (float)best_val ) : 0;
+}
+
+
+#define CV_CMP_NUM_PTR(a,b) (*(a) < *(b))
+static CV_IMPLEMENT_QSORT_EX( icvSortDblPtr, double*, CV_CMP_NUM_PTR, int )
+
+CvDTreeSplit*
+CvBoostTree::find_split_cat_class( CvDTreeNode* node, int vi )
+{
+ CvDTreeSplit* split;
+ const int* cat_labels = data->get_cat_var_data(node, vi);
+ const int* responses = data->get_class_labels(node);
+ int ci = data->get_var_type(vi);
+ int n = node->sample_count;
+ int mi = data->cat_count->data.i[ci];
+ double lcw[2]={0,0}, rcw[2]={0,0};
+ double* cjk = (double*)cvStackAlloc(2*(mi+1)*sizeof(cjk[0]))+2;
+ const double* weights = ensemble->get_subtree_weights()->data.db;
+ double** dbl_ptr = (double**)cvStackAlloc( mi*sizeof(dbl_ptr[0]) );
+ int i, j, k, idx;
+ double L = 0, R;
+ double best_val = 0;
+ int best_subset = -1, subset_i;
+ int boost_type = ensemble->get_params().boost_type;
+ int split_criteria = ensemble->get_params().split_criteria;
+
+ // init array of counters:
+ // c_{jk} - number of samples that have vi-th input variable = j and response = k.
+ for( j = -1; j < mi; j++ )
+ cjk[j*2] = cjk[j*2+1] = 0;
+
+ for( i = 0; i < n; i++ )
+ {
+ double w = weights[i];
+ j = cat_labels[i];
+ k = responses[i];
+ cjk[j*2 + k] += w;
+ }
+
+ for( j = 0; j < mi; j++ )
+ {
+ rcw[0] += cjk[j*2];
+ rcw[1] += cjk[j*2+1];
+ dbl_ptr[j] = cjk + j*2 + 1;
+ }
+
+ R = rcw[0] + rcw[1];
+
+ if( split_criteria != CvBoost::GINI && split_criteria != CvBoost::MISCLASS )
+ split_criteria = boost_type == CvBoost::DISCRETE ? CvBoost::MISCLASS : CvBoost::GINI;
+
+ // sort rows of c_jk by increasing c_j,1
+ // (i.e. by the weight of samples in j-th category that belong to class 1)
+ icvSortDblPtr( dbl_ptr, mi, 0 );
+
+ for( subset_i = 0; subset_i < mi-1; subset_i++ )
+ {
+ idx = (int)(dbl_ptr[subset_i] - cjk)/2;
+ const double* crow = cjk + idx*2;
+ double w0 = crow[0], w1 = crow[1];
+ double weight = w0 + w1;
+
+ if( weight < FLT_EPSILON )
+ continue;
+
+ lcw[0] += w0; rcw[0] -= w0;
+ lcw[1] += w1; rcw[1] -= w1;
+
+ if( split_criteria == CvBoost::GINI )
+ {
+ double lsum2 = lcw[0]*lcw[0] + lcw[1]*lcw[1];
+ double rsum2 = rcw[0]*rcw[0] + rcw[1]*rcw[1];
+
+ L += weight;
+ R -= weight;
+
+ if( L > FLT_EPSILON && R > FLT_EPSILON )
+ {
+ double val = (lsum2*R + rsum2*L)/(L*R);
+ if( best_val < val )
+ {
+ best_val = val;
+ best_subset = subset_i;
+ }
+ }
+ }
+ else
+ {
+ double val = lcw[0] + rcw[1];
+ double val2 = lcw[1] + rcw[0];
+
+ val = MAX(val, val2);
+ if( best_val < val )
+ {
+ best_val = val;
+ best_subset = subset_i;
+ }
+ }
+ }
+
+ if( best_subset < 0 )
+ return 0;
+
+ split = data->new_split_cat( vi, (float)best_val );
+
+ for( i = 0; i <= best_subset; i++ )
+ {
+ idx = (int)(dbl_ptr[i] - cjk) >> 1;
+ split->subset[idx >> 5] |= 1 << (idx & 31);
+ }
+
+ return split;
+}
+
+
+CvDTreeSplit*
+CvBoostTree::find_split_ord_reg( CvDTreeNode* node, int vi )
+{
+ const float epsilon = FLT_EPSILON*2;
+ const CvPair32s32f* sorted = data->get_ord_var_data(node, vi);
+ const float* responses = data->get_ord_responses(node);
+ const double* weights = ensemble->get_subtree_weights()->data.db;
+ int n = node->sample_count;
+ int n1 = node->get_num_valid(vi);
+ int i, best_i = -1;
+ double best_val = 0, lsum = 0, rsum = node->value*n;
+ double L = 0, R = weights[n];
+
+ // compensate for missing values
+ for( i = n1; i < n; i++ )
+ {
+ int idx = sorted[i].i;
+ double w = weights[idx];
+ rsum -= responses[idx]*w;
+ R -= w;
+ }
+
+ // find the optimal split
+ for( i = 0; i < n1 - 1; i++ )
+ {
+ int idx = sorted[i].i;
+ double w = weights[idx];
+ double t = responses[idx]*w;
+ L += w; R -= w;
+ lsum += t; rsum -= t;
+
+ if( sorted[i].val + epsilon < sorted[i+1].val )
+ {
+ double val = (lsum*lsum*R + rsum*rsum*L)/(L*R);
+ if( best_val < val )
+ {
+ best_val = val;
+ best_i = i;
+ }
+ }
+ }
+
+ return best_i >= 0 ? data->new_split_ord( vi,
+ (sorted[best_i].val + sorted[best_i+1].val)*0.5f, best_i,
+ 0, (float)best_val ) : 0;
+}
+
+
+CvDTreeSplit*
+CvBoostTree::find_split_cat_reg( CvDTreeNode* node, int vi )
+{
+ CvDTreeSplit* split;
+ const int* cat_labels = data->get_cat_var_data(node, vi);
+ const float* responses = data->get_ord_responses(node);
+ const double* weights = ensemble->get_subtree_weights()->data.db;
+ int ci = data->get_var_type(vi);
+ int n = node->sample_count;
+ int mi = data->cat_count->data.i[ci];
+ double* sum = (double*)cvStackAlloc( (mi+1)*sizeof(sum[0]) ) + 1;
+ double* counts = (double*)cvStackAlloc( (mi+1)*sizeof(counts[0]) ) + 1;
+ double** sum_ptr = (double**)cvStackAlloc( mi*sizeof(sum_ptr[0]) );
+ double L = 0, R = 0, best_val = 0, lsum = 0, rsum = 0;
+ int i, best_subset = -1, subset_i;
+
+ for( i = -1; i < mi; i++ )
+ sum[i] = counts[i] = 0;
+
+ // calculate sum response and weight of each category of the input var
+ for( i = 0; i < n; i++ )
+ {
+ int idx = cat_labels[i];
+ double w = weights[i];
+ double s = sum[idx] + responses[i]*w;
+ double nc = counts[idx] + w;
+ sum[idx] = s;
+ counts[idx] = nc;
+ }
+
+ // calculate average response in each category
+ for( i = 0; i < mi; i++ )
+ {
+ R += counts[i];
+ rsum += sum[i];
+ sum[i] /= counts[i];
+ sum_ptr[i] = sum + i;
+ }
+
+ icvSortDblPtr( sum_ptr, mi, 0 );
+
+ // revert back to unnormalized sums
+ // (there should be a very little loss in accuracy)
+ for( i = 0; i < mi; i++ )
+ sum[i] *= counts[i];
+
+ for( subset_i = 0; subset_i < mi-1; subset_i++ )
+ {
+ int idx = (int)(sum_ptr[subset_i] - sum);
+ double ni = counts[idx];
+
+ if( ni > FLT_EPSILON )
+ {
+ double s = sum[idx];
+ lsum += s; L += ni;
+ rsum -= s; R -= ni;
+
+ if( L > FLT_EPSILON && R > FLT_EPSILON )
+ {
+ double val = (lsum*lsum*R + rsum*rsum*L)/(L*R);
+ if( best_val < val )
+ {
+ best_val = val;
+ best_subset = subset_i;
+ }
+ }
+ }
+ }
+
+ if( best_subset < 0 )
+ return 0;
+
+ split = data->new_split_cat( vi, (float)best_val );
+ for( i = 0; i <= best_subset; i++ )
+ {
+ int idx = (int)(sum_ptr[i] - sum);
+ split->subset[idx >> 5] |= 1 << (idx & 31);
+ }
+
+ return split;
+}
+
+
+CvDTreeSplit*
+CvBoostTree::find_surrogate_split_ord( CvDTreeNode* node, int vi )
+{
+ const float epsilon = FLT_EPSILON*2;
+ const CvPair32s32f* sorted = data->get_ord_var_data(node, vi);
+ const double* weights = ensemble->get_subtree_weights()->data.db;
+ const char* dir = (char*)data->direction->data.ptr;
+ int n1 = node->get_num_valid(vi);
+ // LL - number of samples that both the primary and the surrogate splits send to the left
+ // LR - ... primary split sends to the left and the surrogate split sends to the right
+ // RL - ... primary split sends to the right and the surrogate split sends to the left
+ // RR - ... both send to the right
+ int i, best_i = -1, best_inversed = 0;
+ double best_val;
+ double LL = 0, RL = 0, LR, RR;
+ double worst_val = node->maxlr;
+ double sum = 0, sum_abs = 0;
+ best_val = worst_val;
+
+ for( i = 0; i < n1; i++ )
+ {
+ int idx = sorted[i].i;
+ double w = weights[idx];
+ int d = dir[idx];
+ sum += d*w; sum_abs += (d & 1)*w;
+ }
+
+ // sum_abs = R + L; sum = R - L
+ RR = (sum_abs + sum)*0.5;
+ LR = (sum_abs - sum)*0.5;
+
+ // initially all the samples are sent to the right by the surrogate split,
+ // LR of them are sent to the left by primary split, and RR - to the right.
+ // now iteratively compute LL, LR, RL and RR for every possible surrogate split value.
+ for( i = 0; i < n1 - 1; i++ )
+ {
+ int idx = sorted[i].i;
+ double w = weights[idx];
+ int d = dir[idx];
+
+ if( d < 0 )
+ {
+ LL += w; LR -= w;
+ if( LL + RR > best_val && sorted[i].val + epsilon < sorted[i+1].val )
+ {
+ best_val = LL + RR;
+ best_i = i; best_inversed = 0;
+ }
+ }
+ else if( d > 0 )
+ {
+ RL += w; RR -= w;
+ if( RL + LR > best_val && sorted[i].val + epsilon < sorted[i+1].val )
+ {
+ best_val = RL + LR;
+ best_i = i; best_inversed = 1;
+ }
+ }
+ }
+
+ return best_i >= 0 && best_val > node->maxlr ? data->new_split_ord( vi,
+ (sorted[best_i].val + sorted[best_i+1].val)*0.5f, best_i,
+ best_inversed, (float)best_val ) : 0;
+}
+
+
+CvDTreeSplit*
+CvBoostTree::find_surrogate_split_cat( CvDTreeNode* node, int vi )
+{
+ const int* cat_labels = data->get_cat_var_data(node, vi);
+ const char* dir = (char*)data->direction->data.ptr;
+ const double* weights = ensemble->get_subtree_weights()->data.db;
+ int n = node->sample_count;
+ // LL - number of samples that both the primary and the surrogate splits send to the left
+ // LR - ... primary split sends to the left and the surrogate split sends to the right
+ // RL - ... primary split sends to the right and the surrogate split sends to the left
+ // RR - ... both send to the right
+ CvDTreeSplit* split = data->new_split_cat( vi, 0 );
+ int i, mi = data->cat_count->data.i[data->get_var_type(vi)];
+ double best_val = 0;
+ double* lc = (double*)cvStackAlloc( (mi+1)*2*sizeof(lc[0]) ) + 1;
+ double* rc = lc + mi + 1;
+
+ for( i = -1; i < mi; i++ )
+ lc[i] = rc[i] = 0;
+
+ // 1. for each category calculate the weight of samples
+ // sent to the left (lc) and to the right (rc) by the primary split
+ for( i = 0; i < n; i++ )
+ {
+ int idx = cat_labels[i];
+ double w = weights[i];
+ int d = dir[i];
+ double sum = lc[idx] + d*w;
+ double sum_abs = rc[idx] + (d & 1)*w;
+ lc[idx] = sum; rc[idx] = sum_abs;
+ }
+
+ for( i = 0; i < mi; i++ )
+ {
+ double sum = lc[i];
+ double sum_abs = rc[i];
+ lc[i] = (sum_abs - sum) * 0.5;
+ rc[i] = (sum_abs + sum) * 0.5;
+ }
+
+ // 2. now form the split.
+ // in each category send all the samples to the same direction as majority
+ for( i = 0; i < mi; i++ )
+ {
+ double lval = lc[i], rval = rc[i];
+ if( lval > rval )
+ {
+ split->subset[i >> 5] |= 1 << (i & 31);
+ best_val += lval;
+ }
+ else
+ best_val += rval;
+ }
+
+ split->quality = (float)best_val;
+ if( split->quality <= node->maxlr )
+ cvSetRemoveByPtr( data->split_heap, split ), split = 0;
+
+ return split;
+}
+
+
+void
+CvBoostTree::calc_node_value( CvDTreeNode* node )
+{
+ int i, count = node->sample_count;
+ const double* weights = ensemble->get_weights()->data.db;
+ const int* labels = data->get_labels(node);
+ double* subtree_weights = ensemble->get_subtree_weights()->data.db;
+ double rcw[2] = {0,0};
+ int boost_type = ensemble->get_params().boost_type;
+ //const double* priors = data->priors->data.db;
+
+ if( data->is_classifier )
+ {
+ const int* responses = data->get_class_labels(node);
+
+ for( i = 0; i < count; i++ )
+ {
+ int idx = labels[i];
+ double w = weights[idx]/*priors[responses[i]]*/;
+ rcw[responses[i]] += w;
+ subtree_weights[i] = w;
+ }
+
+ node->class_idx = rcw[1] > rcw[0];
+
+ if( boost_type == CvBoost::DISCRETE )
+ {
+ // ignore cat_map for responses, and use {-1,1},
+ // as the whole ensemble response is computes as sign(sum_i(weak_response_i)
+ node->value = node->class_idx*2 - 1;
+ }
+ else
+ {
+ double p = rcw[1]/(rcw[0] + rcw[1]);
+ assert( boost_type == CvBoost::REAL );
+
+ // store log-ratio of the probability
+ node->value = 0.5*log_ratio(p);
+ }
+ }
+ else
+ {
+ // in case of regression tree:
+ // * node value is 1/n*sum_i(Y_i), where Y_i is i-th response,
+ // n is the number of samples in the node.
+ // * node risk is the sum of squared errors: sum_i((Y_i - <node_value>)^2)
+ double sum = 0, sum2 = 0, iw;
+ const float* values = data->get_ord_responses(node);
+
+ for( i = 0; i < count; i++ )
+ {
+ int idx = labels[i];
+ double w = weights[idx]/*priors[values[i] > 0]*/;
+ double t = values[i];
+ rcw[0] += w;
+ subtree_weights[i] = w;
+ sum += t*w;
+ sum2 += t*t*w;
+ }
+
+ iw = 1./rcw[0];
+ node->value = sum*iw;
+ node->node_risk = sum2 - (sum*iw)*sum;
+
+ // renormalize the risk, as in try_split_node the unweighted formula
+ // sqrt(risk)/n is used, rather than sqrt(risk)/sum(weights_i)
+ node->node_risk *= count*iw*count*iw;
+ }
+
+ // store summary weights
+ subtree_weights[count] = rcw[0];
+ subtree_weights[count+1] = rcw[1];
+}
+
+
+void CvBoostTree::read( CvFileStorage* fs, CvFileNode* fnode, CvBoost* _ensemble, CvDTreeTrainData* _data )
+{
+ CvDTree::read( fs, fnode, _data );
+ ensemble = _ensemble;
+}
+
+
+void CvBoostTree::read( CvFileStorage*, CvFileNode* )
+{
+ assert(0);
+}
+
+void CvBoostTree::read( CvFileStorage* _fs, CvFileNode* _node,
+ CvDTreeTrainData* _data )
+{
+ CvDTree::read( _fs, _node, _data );
+}
+
+
+/////////////////////////////////// CvBoost /////////////////////////////////////
+
+CvBoost::CvBoost()
+{
+ data = 0;
+ weak = 0;
+ default_model_name = "my_boost_tree";
+ orig_response = sum_response = weak_eval = subsample_mask =
+ weights = subtree_weights = 0;
+
+ clear();
+}
+
+
+void CvBoost::prune( CvSlice slice )
+{
+ if( weak )
+ {
+ CvSeqReader reader;
+ int i, count = cvSliceLength( slice, weak );
+
+ cvStartReadSeq( weak, &reader );
+ cvSetSeqReaderPos( &reader, slice.start_index );
+
+ for( i = 0; i < count; i++ )
+ {
+ CvBoostTree* w;
+ CV_READ_SEQ_ELEM( w, reader );
+ delete w;
+ }
+
+ cvSeqRemoveSlice( weak, slice );
+ }
+}
+
+
+void CvBoost::clear()
+{
+ if( weak )
+ {
+ prune( CV_WHOLE_SEQ );
+ cvReleaseMemStorage( &weak->storage );
+ }
+ if( data )
+ delete data;
+ weak = 0;
+ data = 0;
+ cvReleaseMat( &orig_response );
+ cvReleaseMat( &sum_response );
+ cvReleaseMat( &weak_eval );
+ cvReleaseMat( &subsample_mask );
+ cvReleaseMat( &weights );
+ have_subsample = false;
+}
+
+
+CvBoost::~CvBoost()
+{
+ clear();
+}
+
+
+CvBoost::CvBoost( const CvMat* _train_data, int _tflag,
+ const CvMat* _responses, const CvMat* _var_idx,
+ const CvMat* _sample_idx, const CvMat* _var_type,
+ const CvMat* _missing_mask, CvBoostParams _params )
+{
+ weak = 0;
+ data = 0;
+ default_model_name = "my_boost_tree";
+ orig_response = sum_response = weak_eval = subsample_mask = weights = 0;
+
+ train( _train_data, _tflag, _responses, _var_idx, _sample_idx,
+ _var_type, _missing_mask, _params );
+}
+
+
+bool
+CvBoost::set_params( const CvBoostParams& _params )
+{
+ bool ok = false;
+
+ CV_FUNCNAME( "CvBoost::set_params" );
+
+ __BEGIN__;
+
+ params = _params;
+ if( params.boost_type != DISCRETE && params.boost_type != REAL &&
+ params.boost_type != LOGIT && params.boost_type != GENTLE )
+ CV_ERROR( CV_StsBadArg, "Unknown/unsupported boosting type" );
+
+ params.weak_count = MAX( params.weak_count, 1 );
+ params.weight_trim_rate = MAX( params.weight_trim_rate, 0. );
+ params.weight_trim_rate = MIN( params.weight_trim_rate, 1. );
+ if( params.weight_trim_rate < FLT_EPSILON )
+ params.weight_trim_rate = 1.f;
+
+ if( params.boost_type == DISCRETE &&
+ params.split_criteria != GINI && params.split_criteria != MISCLASS )
+ params.split_criteria = MISCLASS;
+ if( params.boost_type == REAL &&
+ params.split_criteria != GINI && params.split_criteria != MISCLASS )
+ params.split_criteria = GINI;
+ if( (params.boost_type == LOGIT || params.boost_type == GENTLE) &&
+ params.split_criteria != SQERR )
+ params.split_criteria = SQERR;
+
+ ok = true;
+
+ __END__;
+
+ return ok;
+}
+
+
+bool
+CvBoost::train( const CvMat* _train_data, int _tflag,
+ const CvMat* _responses, const CvMat* _var_idx,
+ const CvMat* _sample_idx, const CvMat* _var_type,
+ const CvMat* _missing_mask,
+ CvBoostParams _params, bool _update )
+{
+ bool ok = false;
+ CvMemStorage* storage = 0;
+
+ CV_FUNCNAME( "CvBoost::train" );
+
+ __BEGIN__;
+
+ int i;
+
+ set_params( _params );
+
+ if( !_update || !data )
+ {
+ clear();
+ data = new CvDTreeTrainData( _train_data, _tflag, _responses, _var_idx,
+ _sample_idx, _var_type, _missing_mask, _params, true, true );
+
+ if( data->get_num_classes() != 2 )
+ CV_ERROR( CV_StsNotImplemented,
+ "Boosted trees can only be used for 2-class classification." );
+ CV_CALL( storage = cvCreateMemStorage() );
+ weak = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvBoostTree*), storage );
+ storage = 0;
+ }
+ else
+ {
+ data->set_data( _train_data, _tflag, _responses, _var_idx,
+ _sample_idx, _var_type, _missing_mask, _params, true, true, true );
+ }
+
+ update_weights( 0 );
+
+ for( i = 0; i < params.weak_count; i++ )
+ {
+ CvBoostTree* tree = new CvBoostTree;
+ if( !tree->train( data, subsample_mask, this ) )
+ {
+ delete tree;
+ continue;
+ }
+ //cvCheckArr( get_weak_response());
+ cvSeqPush( weak, &tree );
+ update_weights( tree );
+ trim_weights();
+ }
+
+ data->is_classifier = true;
+ ok = true;
+
+ __END__;
+
+ return ok;
+}
+
+
+void
+CvBoost::update_weights( CvBoostTree* tree )
+{
+ CV_FUNCNAME( "CvBoost::update_weights" );
+
+ __BEGIN__;
+
+ int i, count = data->sample_count;
+ double sumw = 0.;
+
+ if( !tree ) // before training the first tree, initialize weights and other parameters
+ {
+ const int* class_labels = data->get_class_labels(data->data_root);
+ // in case of logitboost and gentle adaboost each weak tree is a regression tree,
+ // so we need to convert class labels to floating-point values
+ float* responses = data->get_ord_responses(data->data_root);
+ int* labels = data->get_labels(data->data_root);
+ double w0 = 1./count;
+ double p[2] = { 1, 1 };
+
+ cvReleaseMat( &orig_response );
+ cvReleaseMat( &sum_response );
+ cvReleaseMat( &weak_eval );
+ cvReleaseMat( &subsample_mask );
+ cvReleaseMat( &weights );
+
+ CV_CALL( orig_response = cvCreateMat( 1, count, CV_32S ));
+ CV_CALL( weak_eval = cvCreateMat( 1, count, CV_64F ));
+ CV_CALL( subsample_mask = cvCreateMat( 1, count, CV_8U ));
+ CV_CALL( weights = cvCreateMat( 1, count, CV_64F ));
+ CV_CALL( subtree_weights = cvCreateMat( 1, count + 2, CV_64F ));
+
+ if( data->have_priors )
+ {
+ // compute weight scale for each class from their prior probabilities
+ int c1 = 0;
+ for( i = 0; i < count; i++ )
+ c1 += class_labels[i];
+ p[0] = data->priors->data.db[0]*(c1 < count ? 1./(count - c1) : 0.);
+ p[1] = data->priors->data.db[1]*(c1 > 0 ? 1./c1 : 0.);
+ p[0] /= p[0] + p[1];
+ p[1] = 1. - p[0];
+ }
+
+ for( i = 0; i < count; i++ )
+ {
+ // save original categorical responses {0,1}, convert them to {-1,1}
+ orig_response->data.i[i] = class_labels[i]*2 - 1;
+ // make all the samples active at start.
+ // later, in trim_weights() deactivate/reactive again some, if need
+ subsample_mask->data.ptr[i] = (uchar)1;
+ // make all the initial weights the same.
+ weights->data.db[i] = w0*p[class_labels[i]];
+ // set the labels to find (from within weak tree learning proc)
+ // the particular sample weight, and where to store the response.
+ labels[i] = i;
+ }
+
+ if( params.boost_type == LOGIT )
+ {
+ CV_CALL( sum_response = cvCreateMat( 1, count, CV_64F ));
+
+ for( i = 0; i < count; i++ )
+ {
+ sum_response->data.db[i] = 0;
+ responses[i] = orig_response->data.i[i] > 0 ? 2.f : -2.f;
+ }
+
+ // in case of logitboost each weak tree is a regression tree.
+ // the target function values are recalculated for each of the trees
+ data->is_classifier = false;
+ }
+ else if( params.boost_type == GENTLE )
+ {
+ for( i = 0; i < count; i++ )
+ responses[i] = (float)orig_response->data.i[i];
+
+ data->is_classifier = false;
+ }
+ }
+ else
+ {
+ // at this moment, for all the samples that participated in the training of the most
+ // recent weak classifier we know the responses. For other samples we need to compute them
+ if( have_subsample )
+ {
+ float* values = (float*)(data->buf->data.ptr + data->buf->step);
+ uchar* missing = data->buf->data.ptr + data->buf->step*2;
+ CvMat _sample, _mask;
+
+ // invert the subsample mask
+ cvXorS( subsample_mask, cvScalar(1.), subsample_mask );
+ data->get_vectors( subsample_mask, values, missing, 0 );
+ //data->get_vectors( 0, values, missing, 0 );
+
+ _sample = cvMat( 1, data->var_count, CV_32F );
+ _mask = cvMat( 1, data->var_count, CV_8U );
+
+ // run tree through all the non-processed samples
+ for( i = 0; i < count; i++ )
+ if( subsample_mask->data.ptr[i] )
+ {
+ _sample.data.fl = values;
+ _mask.data.ptr = missing;
+ values += _sample.cols;
+ missing += _mask.cols;
+ weak_eval->data.db[i] = tree->predict( &_sample, &_mask, true )->value;
+ }
+ }
+
+ // now update weights and other parameters for each type of boosting
+ if( params.boost_type == DISCRETE )
+ {
+ // Discrete AdaBoost:
+ // weak_eval[i] (=f(x_i)) is in {-1,1}
+ // err = sum(w_i*(f(x_i) != y_i))/sum(w_i)
+ // C = log((1-err)/err)
+ // w_i *= exp(C*(f(x_i) != y_i))
+
+ double C, err = 0.;
+ double scale[] = { 1., 0. };
+
+ for( i = 0; i < count; i++ )
+ {
+ double w = weights->data.db[i];
+ sumw += w;
+ err += w*(weak_eval->data.db[i] != orig_response->data.i[i]);
+ }
+
+ if( sumw != 0 )
+ err /= sumw;
+ C = err = -log_ratio( err );
+ scale[1] = exp(err);
+
+ sumw = 0;
+ for( i = 0; i < count; i++ )
+ {
+ double w = weights->data.db[i]*
+ scale[weak_eval->data.db[i] != orig_response->data.i[i]];
+ sumw += w;
+ weights->data.db[i] = w;
+ }
+
+ tree->scale( C );
+ }
+ else if( params.boost_type == REAL )
+ {
+ // Real AdaBoost:
+ // weak_eval[i] = f(x_i) = 0.5*log(p(x_i)/(1-p(x_i))), p(x_i)=P(y=1|x_i)
+ // w_i *= exp(-y_i*f(x_i))
+
+ for( i = 0; i < count; i++ )
+ weak_eval->data.db[i] *= -orig_response->data.i[i];
+
+ cvExp( weak_eval, weak_eval );
+
+ for( i = 0; i < count; i++ )
+ {
+ double w = weights->data.db[i]*weak_eval->data.db[i];
+ sumw += w;
+ weights->data.db[i] = w;
+ }
+ }
+ else if( params.boost_type == LOGIT )
+ {
+ // LogitBoost:
+ // weak_eval[i] = f(x_i) in [-z_max,z_max]
+ // sum_response = F(x_i).
+ // F(x_i) += 0.5*f(x_i)
+ // p(x_i) = exp(F(x_i))/(exp(F(x_i)) + exp(-F(x_i))=1/(1+exp(-2*F(x_i)))
+ // reuse weak_eval: weak_eval[i] <- p(x_i)
+ // w_i = p(x_i)*1(1 - p(x_i))
+ // z_i = ((y_i+1)/2 - p(x_i))/(p(x_i)*(1 - p(x_i)))
+ // store z_i to the data->data_root as the new target responses
+
+ const double lb_weight_thresh = FLT_EPSILON;
+ const double lb_z_max = 10.;
+ float* responses = data->get_ord_responses(data->data_root);
+
+ /*if( weak->total == 7 )
+ putchar('*');*/
+
+ for( i = 0; i < count; i++ )
+ {
+ double s = sum_response->data.db[i] + 0.5*weak_eval->data.db[i];
+ sum_response->data.db[i] = s;
+ weak_eval->data.db[i] = -2*s;
+ }
+
+ cvExp( weak_eval, weak_eval );
+
+ for( i = 0; i < count; i++ )
+ {
+ double p = 1./(1. + weak_eval->data.db[i]);
+ double w = p*(1 - p), z;
+ w = MAX( w, lb_weight_thresh );
+ weights->data.db[i] = w;
+ sumw += w;
+ if( orig_response->data.i[i] > 0 )
+ {
+ z = 1./p;
+ responses[i] = (float)MIN(z, lb_z_max);
+ }
+ else
+ {
+ z = 1./(1-p);
+ responses[i] = (float)-MIN(z, lb_z_max);
+ }
+ }
+ }
+ else
+ {
+ // Gentle AdaBoost:
+ // weak_eval[i] = f(x_i) in [-1,1]
+ // w_i *= exp(-y_i*f(x_i))
+ assert( params.boost_type == GENTLE );
+
+ for( i = 0; i < count; i++ )
+ weak_eval->data.db[i] *= -orig_response->data.i[i];
+
+ cvExp( weak_eval, weak_eval );
+
+ for( i = 0; i < count; i++ )
+ {
+ double w = weights->data.db[i] * weak_eval->data.db[i];
+ weights->data.db[i] = w;
+ sumw += w;
+ }
+ }
+ }
+
+ // renormalize weights
+ if( sumw > FLT_EPSILON )
+ {
+ sumw = 1./sumw;
+ for( i = 0; i < count; ++i )
+ weights->data.db[i] *= sumw;
+ }
+
+ __END__;
+}
+
+
+static CV_IMPLEMENT_QSORT_EX( icvSort_64f, double, CV_LT, int )
+
+
+void
+CvBoost::trim_weights()
+{
+ CV_FUNCNAME( "CvBoost::trim_weights" );
+
+ __BEGIN__;
+
+ int i, count = data->sample_count, nz_count = 0;
+ double sum, threshold;
+
+ if( params.weight_trim_rate <= 0. || params.weight_trim_rate >= 1. )
+ EXIT;
+
+ // use weak_eval as temporary buffer for sorted weights
+ cvCopy( weights, weak_eval );
+
+ icvSort_64f( weak_eval->data.db, count, 0 );
+
+ // as weight trimming occurs immediately after updating the weights,
+ // where they are renormalized, we assume that the weight sum = 1.
+ sum = 1. - params.weight_trim_rate;
+
+ for( i = 0; i < count; i++ )
+ {
+ double w = weak_eval->data.db[i];
+ if( sum > w )
+ break;
+ sum -= w;
+ }
+
+ threshold = i < count ? weak_eval->data.db[i] : DBL_MAX;
+
+ for( i = 0; i < count; i++ )
+ {
+ double w = weights->data.db[i];
+ int f = w > threshold;
+ subsample_mask->data.ptr[i] = (uchar)f;
+ nz_count += f;
+ }
+
+ have_subsample = nz_count < count;
+
+ __END__;
+}
+
+
+float
+CvBoost::predict( const CvMat* _sample, const CvMat* _missing,
+ CvMat* weak_responses, CvSlice slice,
+ bool raw_mode ) const
+{
+ float* buf = 0;
+ bool allocated = false;
+ float value = -FLT_MAX;
+
+ CV_FUNCNAME( "CvBoost::predict" );
+
+ __BEGIN__;
+
+ int i, weak_count, var_count;
+ CvMat sample, missing;
+ CvSeqReader reader;
+ double sum = 0;
+ int cls_idx;
+ int wstep = 0;
+ const int* vtype;
+ const int* cmap;
+ const int* cofs;
+
+ if( !weak )
+ CV_ERROR( CV_StsError, "The boosted tree ensemble has not been trained yet" );
+
+ if( !CV_IS_MAT(_sample) || CV_MAT_TYPE(_sample->type) != CV_32FC1 ||
+ _sample->cols != 1 && _sample->rows != 1 ||
+ _sample->cols + _sample->rows - 1 != data->var_all && !raw_mode ||
+ _sample->cols + _sample->rows - 1 != data->var_count && raw_mode )
+ CV_ERROR( CV_StsBadArg,
+ "the input sample must be 1d floating-point vector with the same "
+ "number of elements as the total number of variables used for training" );
+
+ if( _missing )
+ {
+ if( !CV_IS_MAT(_missing) || !CV_IS_MASK_ARR(_missing) ||
+ !CV_ARE_SIZES_EQ(_missing, _sample) )
+ CV_ERROR( CV_StsBadArg,
+ "the missing data mask must be 8-bit vector of the same size as input sample" );
+ }
+
+ weak_count = cvSliceLength( slice, weak );
+ if( weak_count >= weak->total )
+ {
+ weak_count = weak->total;
+ slice.start_index = 0;
+ }
+
+ if( weak_responses )
+ {
+ if( !CV_IS_MAT(weak_responses) ||
+ CV_MAT_TYPE(weak_responses->type) != CV_32FC1 ||
+ weak_responses->cols != 1 && weak_responses->rows != 1 ||
+ weak_responses->cols + weak_responses->rows - 1 != weak_count )
+ CV_ERROR( CV_StsBadArg,
+ "The output matrix of weak classifier responses must be valid "
+ "floating-point vector of the same number of components as the length of input slice" );
+ wstep = CV_IS_MAT_CONT(weak_responses->type) ? 1 : weak_responses->step/sizeof(float);
+ }
+
+ var_count = data->var_count;
+ vtype = data->var_type->data.i;
+ cmap = data->cat_map->data.i;
+ cofs = data->cat_ofs->data.i;
+
+ // if need, preprocess the input vector
+ if( !raw_mode && (data->cat_var_count > 0 || data->var_idx) )
+ {
+ int bufsize;
+ int step, mstep = 0;
+ const float* src_sample;
+ const uchar* src_mask = 0;
+ float* dst_sample;
+ uchar* dst_mask;
+ const int* vidx = data->var_idx && !raw_mode ? data->var_idx->data.i : 0;
+ bool have_mask = _missing != 0;
+
+ bufsize = var_count*(sizeof(float) + sizeof(uchar));
+ if( bufsize <= CV_MAX_LOCAL_SIZE )
+ buf = (float*)cvStackAlloc( bufsize );
+ else
+ {
+ CV_CALL( buf = (float*)cvAlloc( bufsize ));
+ allocated = true;
+ }
+ dst_sample = buf;
+ dst_mask = (uchar*)(buf + var_count);
+
+ src_sample = _sample->data.fl;
+ step = CV_IS_MAT_CONT(_sample->type) ? 1 : _sample->step/sizeof(src_sample[0]);
+
+ if( _missing )
+ {
+ src_mask = _missing->data.ptr;
+ mstep = CV_IS_MAT_CONT(_missing->type) ? 1 : _missing->step;
+ }
+
+ for( i = 0; i < var_count; i++ )
+ {
+ int idx = vidx ? vidx[i] : i;
+ float val = src_sample[idx*step];
+ int ci = vtype[i];
+ uchar m = src_mask ? src_mask[i] : (uchar)0;
+
+ if( ci >= 0 )
+ {
+ int a = cofs[ci], b = cofs[ci+1], c = a;
+ int ival = cvRound(val);
+ if( ival != val )
+ CV_ERROR( CV_StsBadArg,
+ "one of input categorical variable is not an integer" );
+
+ while( a < b )
+ {
+ c = (a + b) >> 1;
+ if( ival < cmap[c] )
+ b = c;
+ else if( ival > cmap[c] )
+ a = c+1;
+ else
+ break;
+ }
+
+ if( c < 0 || ival != cmap[c] )
+ {
+ m = 1;
+ have_mask = true;
+ }
+ else
+ {
+ val = (float)(c - cofs[ci]);
+ }
+ }
+
+ dst_sample[i] = val;
+ dst_mask[i] = m;
+ }
+
+ sample = cvMat( 1, var_count, CV_32F, dst_sample );
+ _sample = &sample;
+
+ if( have_mask )
+ {
+ missing = cvMat( 1, var_count, CV_8UC1, dst_mask );
+ _missing = &missing;
+ }
+ }
+
+ cvStartReadSeq( weak, &reader );
+ cvSetSeqReaderPos( &reader, slice.start_index );
+
+ for( i = 0; i < weak_count; i++ )
+ {
+ CvBoostTree* wtree;
+ double val;
+
+ CV_READ_SEQ_ELEM( wtree, reader );
+
+ val = wtree->predict( _sample, _missing, true )->value;
+ if( weak_responses )
+ weak_responses->data.fl[i*wstep] = (float)val;
+
+ sum += val;
+ }
+
+ cls_idx = sum >= 0;
+ if( raw_mode )
+ value = (float)cls_idx;
+ else
+ value = (float)cmap[cofs[vtype[var_count]] + cls_idx];
+
+ __END__;
+
+ if( allocated )
+ cvFree( &buf );
+
+ return value;
+}
+
+
+
+void CvBoost::write_params( CvFileStorage* fs )
+{
+ CV_FUNCNAME( "CvBoost::write_params" );
+
+ __BEGIN__;
+
+ const char* boost_type_str =
+ params.boost_type == DISCRETE ? "DiscreteAdaboost" :
+ params.boost_type == REAL ? "RealAdaboost" :
+ params.boost_type == LOGIT ? "LogitBoost" :
+ params.boost_type == GENTLE ? "GentleAdaboost" : 0;
+
+ const char* split_crit_str =
+ params.split_criteria == DEFAULT ? "Default" :
+ params.split_criteria == GINI ? "Gini" :
+ params.boost_type == MISCLASS ? "Misclassification" :
+ params.boost_type == SQERR ? "SquaredErr" : 0;
+
+ if( boost_type_str )
+ cvWriteString( fs, "boosting_type", boost_type_str );
+ else
+ cvWriteInt( fs, "boosting_type", params.boost_type );
+
+ if( split_crit_str )
+ cvWriteString( fs, "splitting_criteria", split_crit_str );
+ else
+ cvWriteInt( fs, "splitting_criteria", params.split_criteria );
+
+ cvWriteInt( fs, "ntrees", params.weak_count );
+ cvWriteReal( fs, "weight_trimming_rate", params.weight_trim_rate );
+
+ data->write_params( fs );
+
+ __END__;
+}
+
+
+void CvBoost::read_params( CvFileStorage* fs, CvFileNode* fnode )
+{
+ CV_FUNCNAME( "CvBoost::read_params" );
+
+ __BEGIN__;
+
+ CvFileNode* temp;
+
+ if( !fnode || !CV_NODE_IS_MAP(fnode->tag) )
+ return;
+
+ data = new CvDTreeTrainData();
+ CV_CALL( data->read_params(fs, fnode));
+ data->shared = true;
+
+ params.max_depth = data->params.max_depth;
+ params.min_sample_count = data->params.min_sample_count;
+ params.max_categories = data->params.max_categories;
+ params.priors = data->params.priors;
+ params.regression_accuracy = data->params.regression_accuracy;
+ params.use_surrogates = data->params.use_surrogates;
+
+ temp = cvGetFileNodeByName( fs, fnode, "boosting_type" );
+ if( !temp )
+ return;
+
+ if( temp && CV_NODE_IS_STRING(temp->tag) )
+ {
+ const char* boost_type_str = cvReadString( temp, "" );
+ params.boost_type = strcmp( boost_type_str, "DiscreteAdaboost" ) == 0 ? DISCRETE :
+ strcmp( boost_type_str, "RealAdaboost" ) == 0 ? REAL :
+ strcmp( boost_type_str, "LogitBoost" ) == 0 ? LOGIT :
+ strcmp( boost_type_str, "GentleAdaboost" ) == 0 ? GENTLE : -1;
+ }
+ else
+ params.boost_type = cvReadInt( temp, -1 );
+
+ if( params.boost_type < DISCRETE || params.boost_type > GENTLE )
+ CV_ERROR( CV_StsBadArg, "Unknown boosting type" );
+
+ temp = cvGetFileNodeByName( fs, fnode, "splitting_criteria" );
+ if( temp && CV_NODE_IS_STRING(temp->tag) )
+ {
+ const char* split_crit_str = cvReadString( temp, "" );
+ params.split_criteria = strcmp( split_crit_str, "Default" ) == 0 ? DEFAULT :
+ strcmp( split_crit_str, "Gini" ) == 0 ? GINI :
+ strcmp( split_crit_str, "Misclassification" ) == 0 ? MISCLASS :
+ strcmp( split_crit_str, "SquaredErr" ) == 0 ? SQERR : -1;
+ }
+ else
+ params.split_criteria = cvReadInt( temp, -1 );
+
+ if( params.split_criteria < DEFAULT || params.boost_type > SQERR )
+ CV_ERROR( CV_StsBadArg, "Unknown boosting type" );
+
+ params.weak_count = cvReadIntByName( fs, fnode, "ntrees" );
+ params.weight_trim_rate = cvReadRealByName( fs, fnode, "weight_trimming_rate", 0. );
+
+ __END__;
+}
+
+
+
+void
+CvBoost::read( CvFileStorage* fs, CvFileNode* node )
+{
+ CV_FUNCNAME( "CvRTrees::read" );
+
+ __BEGIN__;
+
+ CvSeqReader reader;
+ CvFileNode* trees_fnode;
+ CvMemStorage* storage;
+ int i, ntrees;
+
+ clear();
+ read_params( fs, node );
+
+ if( !data )
+ EXIT;
+
+ trees_fnode = cvGetFileNodeByName( fs, node, "trees" );
+ if( !trees_fnode || !CV_NODE_IS_SEQ(trees_fnode->tag) )
+ CV_ERROR( CV_StsParseError, "<trees> tag is missing" );
+
+ cvStartReadSeq( trees_fnode->data.seq, &reader );
+ ntrees = trees_fnode->data.seq->total;
+
+ if( ntrees != params.weak_count )
+ CV_ERROR( CV_StsUnmatchedSizes,
+ "The number of trees stored does not match <ntrees> tag value" );
+
+ CV_CALL( storage = cvCreateMemStorage() );
+ weak = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvBoostTree*), storage );
+
+ for( i = 0; i < ntrees; i++ )
+ {
+ CvBoostTree* tree = new CvBoostTree();
+ CV_CALL(tree->read( fs, (CvFileNode*)reader.ptr, this, data ));
+ CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
+ cvSeqPush( weak, &tree );
+ }
+
+ __END__;
+}
+
+
+void
+CvBoost::write( CvFileStorage* fs, const char* name )
+{
+ CV_FUNCNAME( "CvBoost::write" );
+
+ __BEGIN__;
+
+ CvSeqReader reader;
+ int i;
+
+ cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_ML_BOOSTING );
+
+ if( !weak )
+ CV_ERROR( CV_StsBadArg, "The classifier has not been trained yet" );
+
+ write_params( fs );
+ cvStartWriteStruct( fs, "trees", CV_NODE_SEQ );
+
+ cvStartReadSeq( weak, &reader );
+
+ for( i = 0; i < weak->total; i++ )
+ {
+ CvBoostTree* tree;
+ CV_READ_SEQ_ELEM( tree, reader );
+ cvStartWriteStruct( fs, 0, CV_NODE_MAP );
+ tree->write( fs );
+ cvEndWriteStruct( fs );
+ }
+
+ cvEndWriteStruct( fs );
+ cvEndWriteStruct( fs );
+
+ __END__;
+}
+
+
+CvMat*
+CvBoost::get_weights()
+{
+ return weights;
+}
+
+
+CvMat*
+CvBoost::get_subtree_weights()
+{
+ return subtree_weights;
+}
+
+
+CvMat*
+CvBoost::get_weak_response()
+{
+ return weak_eval;
+}
+
+
+const CvBoostParams&
+CvBoost::get_params() const
+{
+ return params;
+}
+
+CvSeq* CvBoost::get_weak_predictors()
+{
+ return weak;
+}
+
+/* End of file. */
diff --git a/ml/src/mlcnn.cpp b/ml/src/mlcnn.cpp
new file mode 100644
index 0000000..285bb9f
--- /dev/null
+++ b/ml/src/mlcnn.cpp
@@ -0,0 +1,1675 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_ml.h"
+
+#if 0
+/****************************************************************************************\
+* Auxilary functions declarations *
+\****************************************************************************************/
+/*---------------------- functions for the CNN classifier ------------------------------*/
+static float icvCNNModelPredict(
+ const CvStatModel* cnn_model,
+ const CvMat* image,
+ CvMat* probs CV_DEFAULT(0) );
+
+static void icvCNNModelUpdate(
+ CvStatModel* cnn_model, const CvMat* images, int tflag,
+ const CvMat* responses, const CvStatModelParams* params,
+ const CvMat* CV_DEFAULT(0), const CvMat* sample_idx CV_DEFAULT(0),
+ const CvMat* CV_DEFAULT(0), const CvMat* CV_DEFAULT(0));
+
+static void icvCNNModelRelease( CvStatModel** cnn_model );
+
+static void icvTrainCNNetwork( CvCNNetwork* network,
+ const float** images,
+ const CvMat* responses,
+ const CvMat* etalons,
+ int grad_estim_type,
+ int max_iter,
+ int start_iter );
+
+/*------------------------- functions for the CNN network ------------------------------*/
+static void icvCNNetworkAddLayer( CvCNNetwork* network, CvCNNLayer* layer );
+static void icvCNNetworkRelease( CvCNNetwork** network );
+
+/* In all layer functions we denote input by X and output by Y, where
+ X and Y are column-vectors, so that
+ length(X)==<n_input_planes>*<input_height>*<input_width>,
+ length(Y)==<n_output_planes>*<output_height>*<output_width>.
+*/
+/*------------------------ functions for convolutional layer ---------------------------*/
+static void icvCNNConvolutionRelease( CvCNNLayer** p_layer );
+
+static void icvCNNConvolutionForward( CvCNNLayer* layer, const CvMat* X, CvMat* Y );
+
+static void icvCNNConvolutionBackward( CvCNNLayer* layer, int t,
+ const CvMat* X, const CvMat* dE_dY, CvMat* dE_dX );
+
+/*------------------------ functions for sub-sampling layer ----------------------------*/
+static void icvCNNSubSamplingRelease( CvCNNLayer** p_layer );
+
+static void icvCNNSubSamplingForward( CvCNNLayer* layer, const CvMat* X, CvMat* Y );
+
+static void icvCNNSubSamplingBackward( CvCNNLayer* layer, int t,
+ const CvMat* X, const CvMat* dE_dY, CvMat* dE_dX );
+
+/*------------------------ functions for full connected layer --------------------------*/
+static void icvCNNFullConnectRelease( CvCNNLayer** p_layer );
+
+static void icvCNNFullConnectForward( CvCNNLayer* layer, const CvMat* X, CvMat* Y );
+
+static void icvCNNFullConnectBackward( CvCNNLayer* layer, int,
+ const CvMat*, const CvMat* dE_dY, CvMat* dE_dX );
+
+/****************************************************************************************\
+* Functions implementations *
+\****************************************************************************************/
+
+#define ICV_CHECK_CNN_NETWORK(network) \
+{ \
+ CvCNNLayer* first_layer, *layer, *last_layer; \
+ int n_layers, i; \
+ if( !network ) \
+ CV_ERROR( CV_StsNullPtr, \
+ "Null <network> pointer. Network must be created by user." ); \
+ n_layers = network->n_layers; \
+ first_layer = last_layer = network->layers; \
+ for( i = 0, layer = first_layer; i < n_layers && layer; i++ ) \
+ { \
+ if( !ICV_IS_CNN_LAYER(layer) ) \
+ CV_ERROR( CV_StsNullPtr, "Invalid network" ); \
+ last_layer = layer; \
+ layer = layer->next_layer; \
+ } \
+ \
+ if( i == 0 || i != n_layers || first_layer->prev_layer || layer ) \
+ CV_ERROR( CV_StsNullPtr, "Invalid network" ); \
+ \
+ if( first_layer->n_input_planes != 1 ) \
+ CV_ERROR( CV_StsBadArg, "First layer must contain only one input plane" ); \
+ \
+ if( img_size != first_layer->input_height*first_layer->input_width ) \
+ CV_ERROR( CV_StsBadArg, "Invalid input sizes of the first layer" ); \
+ \
+ if( params->etalons->cols != last_layer->n_output_planes* \
+ last_layer->output_height*last_layer->output_width ) \
+ CV_ERROR( CV_StsBadArg, "Invalid output sizes of the last layer" ); \
+}
+
+#define ICV_CHECK_CNN_MODEL_PARAMS(params) \
+{ \
+ if( !params ) \
+ CV_ERROR( CV_StsNullPtr, "Null <params> pointer" ); \
+ \
+ if( !ICV_IS_MAT_OF_TYPE(params->etalons, CV_32FC1) ) \
+ CV_ERROR( CV_StsBadArg, "<etalons> must be CV_32FC1 type" ); \
+ if( params->etalons->rows != cnn_model->cls_labels->cols ) \
+ CV_ERROR( CV_StsBadArg, "Invalid <etalons> size" ); \
+ \
+ if( params->grad_estim_type != CV_CNN_GRAD_ESTIM_RANDOM && \
+ params->grad_estim_type != CV_CNN_GRAD_ESTIM_BY_WORST_IMG ) \
+ CV_ERROR( CV_StsBadArg, "Invalid <grad_estim_type>" ); \
+ \
+ if( params->start_iter < 0 ) \
+ CV_ERROR( CV_StsBadArg, "Parameter <start_iter> must be positive or zero" ); \
+ \
+ if( params->max_iter < 1 ) \
+ params->max_iter = 1; \
+}
+
+/****************************************************************************************\
+* Classifier functions *
+\****************************************************************************************/
+ML_IMPL CvStatModel*
+cvTrainCNNClassifier( const CvMat* _train_data, int tflag,
+ const CvMat* _responses,
+ const CvStatModelParams* _params,
+ const CvMat*, const CvMat* _sample_idx, const CvMat*, const CvMat* )
+{
+ CvCNNStatModel* cnn_model = 0;
+ const float** out_train_data = 0;
+ CvMat* responses = 0;
+
+ CV_FUNCNAME("cvTrainCNNClassifier");
+ __BEGIN__;
+
+ int n_images;
+ int img_size;
+ CvCNNStatModelParams* params = (CvCNNStatModelParams*)_params;
+
+ CV_CALL(cnn_model = (CvCNNStatModel*)cvCreateStatModel(
+ CV_STAT_MODEL_MAGIC_VAL|CV_CNN_MAGIC_VAL, sizeof(CvCNNStatModel),
+ icvCNNModelRelease, icvCNNModelPredict, icvCNNModelUpdate ));
+
+ CV_CALL(cvPrepareTrainData( "cvTrainCNNClassifier",
+ _train_data, tflag, _responses, CV_VAR_CATEGORICAL,
+ 0, _sample_idx, false, &out_train_data,
+ &n_images, &img_size, &img_size, &responses,
+ &cnn_model->cls_labels, 0 ));
+
+ ICV_CHECK_CNN_MODEL_PARAMS(params);
+ ICV_CHECK_CNN_NETWORK(params->network);
+
+ cnn_model->network = params->network;
+ CV_CALL(cnn_model->etalons = (CvMat*)cvClone( params->etalons ));
+
+ CV_CALL( icvTrainCNNetwork( cnn_model->network, out_train_data, responses,
+ cnn_model->etalons, params->grad_estim_type, params->max_iter,
+ params->start_iter ));
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 && cnn_model )
+ {
+ cnn_model->release( (CvStatModel**)&cnn_model );
+ }
+ cvFree( &out_train_data );
+ cvReleaseMat( &responses );
+
+ return (CvStatModel*)cnn_model;
+}
+
+/****************************************************************************************/
+static void icvTrainCNNetwork( CvCNNetwork* network,
+ const float** images,
+ const CvMat* responses,
+ const CvMat* etalons,
+ int grad_estim_type,
+ int max_iter,
+ int start_iter )
+{
+ CvMat** X = 0;
+ CvMat** dE_dX = 0;
+ const int n_layers = network->n_layers;
+ int k;
+
+ CV_FUNCNAME("icvTrainCNNetwork");
+ __BEGIN__;
+
+ CvCNNLayer* first_layer = network->layers;
+ const int img_height = first_layer->input_height;
+ const int img_width = first_layer->input_width;
+ const int img_size = img_width*img_height;
+ const int n_images = responses->cols;
+ CvMat image = cvMat( 1, img_size, CV_32FC1 );
+ CvCNNLayer* layer;
+ int n;
+ CvRNG rng = cvRNG(-1);
+
+ CV_CALL(X = (CvMat**)cvAlloc( (n_layers+1)*sizeof(CvMat*) ));
+ CV_CALL(dE_dX = (CvMat**)cvAlloc( (n_layers+1)*sizeof(CvMat*) ));
+ memset( X, 0, (n_layers+1)*sizeof(CvMat*) );
+ memset( dE_dX, 0, (n_layers+1)*sizeof(CvMat*) );
+
+ CV_CALL(X[0] = cvCreateMat( img_height*img_width,1,CV_32FC1 ));
+ CV_CALL(dE_dX[0] = cvCreateMat( 1, X[0]->rows, CV_32FC1 ));
+ for( k = 0, layer = first_layer; k < n_layers; k++, layer = layer->next_layer )
+ {
+ CV_CALL(X[k+1] = cvCreateMat( layer->n_output_planes*layer->output_height*
+ layer->output_width, 1, CV_32FC1 ));
+ CV_CALL(dE_dX[k+1] = cvCreateMat( 1, X[k+1]->rows, CV_32FC1 ));
+ }
+
+ for( n = 1; n <= max_iter; n++ )
+ {
+ float loss, max_loss = 0;
+ int i;
+ int worst_img_idx = -1;
+ int* right_etal_idx = responses->data.i;
+ CvMat etalon;
+
+ // Find the worst image (which produces the greatest loss) or use the random image
+ if( grad_estim_type == CV_CNN_GRAD_ESTIM_BY_WORST_IMG )
+ {
+ for( i = 0; i < n_images; i++, right_etal_idx++ )
+ {
+ image.data.fl = (float*)images[i];
+ cvTranspose( &image, X[0] );
+
+ for( k = 0, layer = first_layer; k < n_layers; k++, layer = layer->next_layer )
+ CV_CALL(layer->forward( layer, X[k], X[k+1] ));
+
+ cvTranspose( X[n_layers], dE_dX[n_layers] );
+ cvGetRow( etalons, &etalon, *right_etal_idx );
+ loss = (float)cvNorm( dE_dX[n_layers], &etalon );
+ if( loss > max_loss )
+ {
+ max_loss = loss;
+ worst_img_idx = i;
+ }
+ }
+ }
+ else
+ worst_img_idx = cvRandInt(&rng) % n_images;
+
+ // Train network on the worst image
+ // 1) Compute the network output on the <image>
+ image.data.fl = (float*)images[worst_img_idx];
+ CV_CALL(cvTranspose( &image, X[0] ));
+
+ for( k = 0, layer = first_layer; k < n_layers - 1; k++, layer = layer->next_layer )
+ CV_CALL(layer->forward( layer, X[k], X[k+1] ));
+ CV_CALL(layer->forward( layer, X[k], X[k+1] ));
+
+ // 2) Compute the gradient
+ cvTranspose( X[n_layers], dE_dX[n_layers] );
+ cvGetRow( etalons, &etalon, responses->data.i[worst_img_idx] );
+ cvSub( dE_dX[n_layers], &etalon, dE_dX[n_layers] );
+
+ // 3) Update weights by the gradient descent
+ for( k = n_layers; k > 0; k--, layer = layer->prev_layer )
+ CV_CALL(layer->backward( layer, n + start_iter, X[k-1], dE_dX[k], dE_dX[k-1] ));
+ }
+
+ __END__;
+
+ for( k = 0; k <= n_layers; k++ )
+ {
+ cvReleaseMat( &X[k] );
+ cvReleaseMat( &dE_dX[k] );
+ }
+ cvFree( &X );
+ cvFree( &dE_dX );
+}
+
+/****************************************************************************************/
+static float icvCNNModelPredict( const CvStatModel* model,
+ const CvMat* _image,
+ CvMat* probs )
+{
+ CvMat** X = 0;
+ float* img_data = 0;
+ int n_layers = 0;
+ int best_etal_idx = -1;
+ int k;
+
+ CV_FUNCNAME("icvCNNModelPredict");
+ __BEGIN__;
+
+ CvCNNStatModel* cnn_model = (CvCNNStatModel*)model;
+ CvCNNLayer* first_layer, *layer = 0;
+ int img_height, img_width, img_size;
+ int nclasses, i;
+ float loss, min_loss = FLT_MAX;
+ float* probs_data;
+ CvMat etalon, image;
+
+ if( !CV_IS_CNN(model) )
+ CV_ERROR( CV_StsBadArg, "Invalid model" );
+
+ nclasses = cnn_model->cls_labels->cols;
+ n_layers = cnn_model->network->n_layers;
+ first_layer = cnn_model->network->layers;
+ img_height = first_layer->input_height;
+ img_width = first_layer->input_width;
+ img_size = img_height*img_width;
+
+ cvPreparePredictData( _image, img_size, 0, nclasses, probs, &img_data );
+
+ CV_CALL(X = (CvMat**)cvAlloc( (n_layers+1)*sizeof(CvMat*) ));
+ memset( X, 0, (n_layers+1)*sizeof(CvMat*) );
+
+ CV_CALL(X[0] = cvCreateMat( img_size,1,CV_32FC1 ));
+ for( k = 0, layer = first_layer; k < n_layers; k++, layer = layer->next_layer )
+ {
+ CV_CALL(X[k+1] = cvCreateMat( layer->n_output_planes*layer->output_height*
+ layer->output_width, 1, CV_32FC1 ));
+ }
+
+ image = cvMat( 1, img_size, CV_32FC1, img_data );
+ cvTranspose( &image, X[0] );
+ for( k = 0, layer = first_layer; k < n_layers; k++, layer = layer->next_layer )
+ CV_CALL(layer->forward( layer, X[k], X[k+1] ));
+
+ probs_data = probs ? probs->data.fl : 0;
+ etalon = cvMat( cnn_model->etalons->cols, 1, CV_32FC1, cnn_model->etalons->data.fl );
+ for( i = 0; i < nclasses; i++, etalon.data.fl += cnn_model->etalons->cols )
+ {
+ loss = (float)cvNorm( X[n_layers], &etalon );
+ if( loss < min_loss )
+ {
+ min_loss = loss;
+ best_etal_idx = i;
+ }
+ if( probs )
+ *probs_data++ = -loss;
+ }
+
+ if( probs )
+ {
+ cvExp( probs, probs );
+ CvScalar sum = cvSum( probs );
+ cvConvertScale( probs, probs, 1./sum.val[0] );
+ }
+
+ __END__;
+
+ for( k = 0; k <= n_layers; k++ )
+ cvReleaseMat( &X[k] );
+ cvFree( &X );
+ if( img_data != _image->data.fl )
+ cvFree( &img_data );
+
+ return ((float) ((CvCNNStatModel*)model)->cls_labels->data.i[best_etal_idx]);
+}
+
+/****************************************************************************************/
+static void icvCNNModelUpdate(
+ CvStatModel* _cnn_model, const CvMat* _train_data, int tflag,
+ const CvMat* _responses, const CvStatModelParams* _params,
+ const CvMat*, const CvMat* _sample_idx,
+ const CvMat*, const CvMat* )
+{
+ const float** out_train_data = 0;
+ CvMat* responses = 0;
+ CvMat* cls_labels = 0;
+
+ CV_FUNCNAME("icvCNNModelUpdate");
+ __BEGIN__;
+
+ int n_images, img_size, i;
+ CvCNNStatModelParams* params = (CvCNNStatModelParams*)_params;
+ CvCNNStatModel* cnn_model = (CvCNNStatModel*)_cnn_model;
+
+ if( !CV_IS_CNN(cnn_model) )
+ CV_ERROR( CV_StsBadArg, "Invalid model" );
+
+ CV_CALL(cvPrepareTrainData( "cvTrainCNNClassifier",
+ _train_data, tflag, _responses, CV_VAR_CATEGORICAL,
+ 0, _sample_idx, false, &out_train_data,
+ &n_images, &img_size, &img_size, &responses,
+ &cls_labels, 0, 0 ));
+
+ ICV_CHECK_CNN_MODEL_PARAMS(params);
+
+ // Number of classes must be the same as when classifiers was created
+ if( !CV_ARE_SIZES_EQ(cls_labels, cnn_model->cls_labels) )
+ CV_ERROR( CV_StsBadArg, "Number of classes must be left unchanged" );
+ for( i = 0; i < cls_labels->cols; i++ )
+ {
+ if( cls_labels->data.i[i] != cnn_model->cls_labels->data.i[i] )
+ CV_ERROR( CV_StsBadArg, "Number of classes must be left unchanged" );
+ }
+
+ CV_CALL( icvTrainCNNetwork( cnn_model->network, out_train_data, responses,
+ cnn_model->etalons, params->grad_estim_type, params->max_iter,
+ params->start_iter ));
+
+ __END__;
+
+ cvFree( &out_train_data );
+ cvReleaseMat( &responses );
+}
+
+/****************************************************************************************/
+static void icvCNNModelRelease( CvStatModel** cnn_model )
+{
+ CV_FUNCNAME("icvCNNModelRelease");
+ __BEGIN__;
+
+ CvCNNStatModel* cnn;
+ if( !cnn_model )
+ CV_ERROR( CV_StsNullPtr, "Null double pointer" );
+
+ cnn = *(CvCNNStatModel**)cnn_model;
+
+ cvReleaseMat( &cnn->cls_labels );
+ cvReleaseMat( &cnn->etalons );
+ cnn->network->release( &cnn->network );
+
+ cvFree( &cnn );
+
+ __END__;
+
+}
+
+/****************************************************************************************\
+* Network functions *
+\****************************************************************************************/
+ML_IMPL CvCNNetwork* cvCreateCNNetwork( CvCNNLayer* first_layer )
+{
+ CvCNNetwork* network = 0;
+
+ CV_FUNCNAME( "cvCreateCNNetwork" );
+ __BEGIN__;
+
+ if( !ICV_IS_CNN_LAYER(first_layer) )
+ CV_ERROR( CV_StsBadArg, "Invalid layer" );
+
+ CV_CALL(network = (CvCNNetwork*)cvAlloc( sizeof(CvCNNetwork) ));
+ memset( network, 0, sizeof(CvCNNetwork) );
+
+ network->layers = first_layer;
+ network->n_layers = 1;
+ network->release = icvCNNetworkRelease;
+ network->add_layer = icvCNNetworkAddLayer;
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 && network )
+ cvFree( &network );
+
+ return network;
+
+}
+
+/****************************************************************************************/
+static void icvCNNetworkAddLayer( CvCNNetwork* network, CvCNNLayer* layer )
+{
+ CV_FUNCNAME( "icvCNNetworkAddLayer" );
+ __BEGIN__;
+
+ CvCNNLayer* prev_layer;
+
+ if( network == NULL )
+ CV_ERROR( CV_StsNullPtr, "Null <network> pointer" );
+
+ prev_layer = network->layers;
+ while( prev_layer->next_layer )
+ prev_layer = prev_layer->next_layer;
+
+ if( ICV_IS_CNN_FULLCONNECT_LAYER(layer) )
+ {
+ if( layer->n_input_planes != prev_layer->output_width*prev_layer->output_height*
+ prev_layer->n_output_planes )
+ CV_ERROR( CV_StsBadArg, "Unmatched size of the new layer" );
+ if( layer->input_height != 1 || layer->output_height != 1 ||
+ layer->input_width != 1 || layer->output_width != 1 )
+ CV_ERROR( CV_StsBadArg, "Invalid size of the new layer" );
+ }
+ else if( ICV_IS_CNN_CONVOLUTION_LAYER(layer) || ICV_IS_CNN_SUBSAMPLING_LAYER(layer) )
+ {
+ if( prev_layer->n_output_planes != layer->n_input_planes ||
+ prev_layer->output_height != layer->input_height ||
+ prev_layer->output_width != layer->input_width )
+ CV_ERROR( CV_StsBadArg, "Unmatched size of the new layer" );
+ }
+ else
+ CV_ERROR( CV_StsBadArg, "Invalid layer" );
+
+ layer->prev_layer = prev_layer;
+ prev_layer->next_layer = layer;
+ network->n_layers++;
+
+ __END__;
+}
+
+/****************************************************************************************/
+static void icvCNNetworkRelease( CvCNNetwork** network_pptr )
+{
+ CV_FUNCNAME( "icvReleaseCNNetwork" );
+ __BEGIN__;
+
+ CvCNNetwork* network = 0;
+ CvCNNLayer* layer = 0, *next_layer = 0;
+ int k;
+
+ if( network_pptr == NULL )
+ CV_ERROR( CV_StsBadArg, "Null double pointer" );
+ if( *network_pptr == NULL )
+ return;
+
+ network = *network_pptr;
+ layer = network->layers;
+ if( layer == NULL )
+ CV_ERROR( CV_StsBadArg, "CNN is empty (does not contain any layer)" );
+
+ // k is the number of the layer to be deleted
+ for( k = 0; k < network->n_layers && layer; k++ )
+ {
+ next_layer = layer->next_layer;
+ layer->release( &layer );
+ layer = next_layer;
+ }
+
+ if( k != network->n_layers || layer)
+ CV_ERROR( CV_StsBadArg, "Invalid network" );
+
+ cvFree( &network );
+
+ __END__;
+}
+
+/****************************************************************************************\
+* Layer functions *
+\****************************************************************************************/
+static CvCNNLayer* icvCreateCNNLayer( int layer_type, int header_size,
+ int n_input_planes, int input_height, int input_width,
+ int n_output_planes, int output_height, int output_width,
+ float init_learn_rate, int learn_rate_decrease_type,
+ CvCNNLayerRelease release, CvCNNLayerForward forward, CvCNNLayerBackward backward )
+{
+ CvCNNLayer* layer = 0;
+
+ CV_FUNCNAME("icvCreateCNNLayer");
+ __BEGIN__;
+
+ CV_ASSERT( release && forward && backward )
+ CV_ASSERT( header_size >= sizeof(CvCNNLayer) )
+
+ if( n_input_planes < 1 || n_output_planes < 1 ||
+ input_height < 1 || input_width < 1 ||
+ output_height < 1 || output_width < 1 ||
+ input_height < output_height ||
+ input_width < output_width )
+ CV_ERROR( CV_StsBadArg, "Incorrect input or output parameters" );
+ if( init_learn_rate < FLT_EPSILON )
+ CV_ERROR( CV_StsBadArg, "Initial learning rate must be positive" );
+ if( learn_rate_decrease_type != CV_CNN_LEARN_RATE_DECREASE_HYPERBOLICALLY &&
+ learn_rate_decrease_type != CV_CNN_LEARN_RATE_DECREASE_SQRT_INV &&
+ learn_rate_decrease_type != CV_CNN_LEARN_RATE_DECREASE_LOG_INV )
+ CV_ERROR( CV_StsBadArg, "Invalid type of learning rate dynamics" );
+
+ CV_CALL(layer = (CvCNNLayer*)cvAlloc( header_size ));
+ memset( layer, 0, header_size );
+
+ layer->flags = ICV_CNN_LAYER|layer_type;
+ CV_ASSERT( ICV_IS_CNN_LAYER(layer) )
+
+ layer->n_input_planes = n_input_planes;
+ layer->input_height = input_height;
+ layer->input_width = input_width;
+
+ layer->n_output_planes = n_output_planes;
+ layer->output_height = output_height;
+ layer->output_width = output_width;
+
+ layer->init_learn_rate = init_learn_rate;
+ layer->learn_rate_decrease_type = learn_rate_decrease_type;
+
+ layer->release = release;
+ layer->forward = forward;
+ layer->backward = backward;
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 && layer)
+ cvFree( &layer );
+
+ return layer;
+}
+
+/****************************************************************************************/
+ML_IMPL CvCNNLayer* cvCreateCNNConvolutionLayer(
+ int n_input_planes, int input_height, int input_width,
+ int n_output_planes, int K,
+ float init_learn_rate, int learn_rate_decrease_type,
+ CvMat* connect_mask, CvMat* weights )
+
+{
+ CvCNNConvolutionLayer* layer = 0;
+
+ CV_FUNCNAME("cvCreateCNNConvolutionLayer");
+ __BEGIN__;
+
+ const int output_height = input_height - K + 1;
+ const int output_width = input_width - K + 1;
+
+ if( K < 1 || init_learn_rate <= 0 )
+ CV_ERROR( CV_StsBadArg, "Incorrect parameters" );
+
+ CV_CALL(layer = (CvCNNConvolutionLayer*)icvCreateCNNLayer( ICV_CNN_CONVOLUTION_LAYER,
+ sizeof(CvCNNConvolutionLayer), n_input_planes, input_height, input_width,
+ n_output_planes, output_height, output_width,
+ init_learn_rate, learn_rate_decrease_type,
+ icvCNNConvolutionRelease, icvCNNConvolutionForward, icvCNNConvolutionBackward ));
+
+ layer->K = K;
+ CV_CALL(layer->weights = cvCreateMat( n_output_planes, K*K+1, CV_32FC1 ));
+ CV_CALL(layer->connect_mask = cvCreateMat( n_output_planes, n_input_planes, CV_8UC1));
+
+ if( weights )
+ {
+ if( !ICV_IS_MAT_OF_TYPE( weights, CV_32FC1 ) )
+ CV_ERROR( CV_StsBadSize, "Type of initial weights matrix must be CV_32FC1" );
+ if( !CV_ARE_SIZES_EQ( weights, layer->weights ) )
+ CV_ERROR( CV_StsBadSize, "Invalid size of initial weights matrix" );
+ CV_CALL(cvCopy( weights, layer->weights ));
+ }
+ else
+ {
+ CvRNG rng = cvRNG( 0xFFFFFFFF );
+ cvRandArr( &rng, layer->weights, CV_RAND_UNI, cvRealScalar(-1), cvRealScalar(1) );
+ }
+
+ if( connect_mask )
+ {
+ if( !ICV_IS_MAT_OF_TYPE( connect_mask, CV_8UC1 ) )
+ CV_ERROR( CV_StsBadSize, "Type of connection matrix must be CV_32FC1" );
+ if( !CV_ARE_SIZES_EQ( connect_mask, layer->connect_mask ) )
+ CV_ERROR( CV_StsBadSize, "Invalid size of connection matrix" );
+ CV_CALL(cvCopy( connect_mask, layer->connect_mask ));
+ }
+ else
+ CV_CALL(cvSet( layer->connect_mask, cvRealScalar(1) ));
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 && layer )
+ {
+ cvReleaseMat( &layer->weights );
+ cvReleaseMat( &layer->connect_mask );
+ cvFree( &layer );
+ }
+
+ return (CvCNNLayer*)layer;
+}
+
+/****************************************************************************************/
+ML_IMPL CvCNNLayer* cvCreateCNNSubSamplingLayer(
+ int n_input_planes, int input_height, int input_width,
+ int sub_samp_scale, float a, float s,
+ float init_learn_rate, int learn_rate_decrease_type, CvMat* weights )
+
+{
+ CvCNNSubSamplingLayer* layer = 0;
+
+ CV_FUNCNAME("cvCreateCNNSubSamplingLayer");
+ __BEGIN__;
+
+ const int output_height = input_height/sub_samp_scale;
+ const int output_width = input_width/sub_samp_scale;
+ const int n_output_planes = n_input_planes;
+
+ if( sub_samp_scale < 1 || a <= 0 || s <= 0)
+ CV_ERROR( CV_StsBadArg, "Incorrect parameters" );
+
+ CV_CALL(layer = (CvCNNSubSamplingLayer*)icvCreateCNNLayer( ICV_CNN_SUBSAMPLING_LAYER,
+ sizeof(CvCNNSubSamplingLayer), n_input_planes, input_height, input_width,
+ n_output_planes, output_height, output_width,
+ init_learn_rate, learn_rate_decrease_type,
+ icvCNNSubSamplingRelease, icvCNNSubSamplingForward, icvCNNSubSamplingBackward ));
+
+ layer->sub_samp_scale = sub_samp_scale;
+ layer->a = a;
+ layer->s = s;
+
+ CV_CALL(layer->sumX =
+ cvCreateMat( n_output_planes*output_width*output_height, 1, CV_32FC1 ));
+ CV_CALL(layer->exp2ssumWX =
+ cvCreateMat( n_output_planes*output_width*output_height, 1, CV_32FC1 ));
+
+ cvZero( layer->sumX );
+ cvZero( layer->exp2ssumWX );
+
+ CV_CALL(layer->weights = cvCreateMat( n_output_planes, 2, CV_32FC1 ));
+ if( weights )
+ {
+ if( !ICV_IS_MAT_OF_TYPE( weights, CV_32FC1 ) )
+ CV_ERROR( CV_StsBadSize, "Type of initial weights matrix must be CV_32FC1" );
+ if( !CV_ARE_SIZES_EQ( weights, layer->weights ) )
+ CV_ERROR( CV_StsBadSize, "Invalid size of initial weights matrix" );
+ CV_CALL(cvCopy( weights, layer->weights ));
+ }
+ else
+ {
+ CvRNG rng = cvRNG( 0xFFFFFFFF );
+ cvRandArr( &rng, layer->weights, CV_RAND_UNI, cvRealScalar(-1), cvRealScalar(1) );
+ }
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 && layer )
+ {
+ cvReleaseMat( &layer->exp2ssumWX );
+ cvFree( &layer );
+ }
+
+ return (CvCNNLayer*)layer;
+}
+
+/****************************************************************************************/
+ML_IMPL CvCNNLayer* cvCreateCNNFullConnectLayer(
+ int n_inputs, int n_outputs, float a, float s,
+ float init_learn_rate, int learn_rate_decrease_type, CvMat* weights )
+{
+ CvCNNFullConnectLayer* layer = 0;
+
+ CV_FUNCNAME("cvCreateCNNFullConnectLayer");
+ __BEGIN__;
+
+ if( a <= 0 || s <= 0 || init_learn_rate <= 0)
+ CV_ERROR( CV_StsBadArg, "Incorrect parameters" );
+
+ CV_CALL(layer = (CvCNNFullConnectLayer*)icvCreateCNNLayer( ICV_CNN_FULLCONNECT_LAYER,
+ sizeof(CvCNNFullConnectLayer), n_inputs, 1, 1, n_outputs, 1, 1,
+ init_learn_rate, learn_rate_decrease_type,
+ icvCNNFullConnectRelease, icvCNNFullConnectForward, icvCNNFullConnectBackward ));
+
+ layer->a = a;
+ layer->s = s;
+
+ CV_CALL(layer->exp2ssumWX = cvCreateMat( n_outputs, 1, CV_32FC1 ));
+ cvZero( layer->exp2ssumWX );
+
+ CV_CALL(layer->weights = cvCreateMat( n_outputs, n_inputs+1, CV_32FC1 ));
+ if( weights )
+ {
+ if( !ICV_IS_MAT_OF_TYPE( weights, CV_32FC1 ) )
+ CV_ERROR( CV_StsBadSize, "Type of initial weights matrix must be CV_32FC1" );
+ if( !CV_ARE_SIZES_EQ( weights, layer->weights ) )
+ CV_ERROR( CV_StsBadSize, "Invalid size of initial weights matrix" );
+ CV_CALL(cvCopy( weights, layer->weights ));
+ }
+ else
+ {
+ CvRNG rng = cvRNG( 0xFFFFFFFF );
+ cvRandArr( &rng, layer->weights, CV_RAND_UNI, cvRealScalar(-1), cvRealScalar(1) );
+ }
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 && layer )
+ {
+ cvReleaseMat( &layer->exp2ssumWX );
+ cvReleaseMat( &layer->weights );
+ cvFree( &layer );
+ }
+
+ return (CvCNNLayer*)layer;
+}
+
+
+/****************************************************************************************\
+* Layer FORWARD functions *
+\****************************************************************************************/
+static void icvCNNConvolutionForward( CvCNNLayer* _layer,
+ const CvMat* X,
+ CvMat* Y )
+{
+ CV_FUNCNAME("icvCNNConvolutionForward");
+
+ if( !ICV_IS_CNN_CONVOLUTION_LAYER(_layer) )
+ CV_ERROR( CV_StsBadArg, "Invalid layer" );
+
+ {__BEGIN__;
+
+ const CvCNNConvolutionLayer* layer = (CvCNNConvolutionLayer*) _layer;
+
+ const int K = layer->K;
+ const int n_weights_for_Yplane = K*K + 1;
+
+ const int nXplanes = layer->n_input_planes;
+ const int Xheight = layer->input_height;
+ const int Xwidth = layer->input_width ;
+ const int Xsize = Xwidth*Xheight;
+
+ const int nYplanes = layer->n_output_planes;
+ const int Yheight = layer->output_height;
+ const int Ywidth = layer->output_width;
+ const int Ysize = Ywidth*Yheight;
+
+ int xx, yy, ni, no, kx, ky;
+ float *Yplane = 0, *Xplane = 0, *w = 0;
+ uchar* connect_mask_data = 0;
+
+ CV_ASSERT( X->rows == nXplanes*Xsize && X->cols == 1 );
+ CV_ASSERT( Y->rows == nYplanes*Ysize && Y->cols == 1 );
+
+ cvSetZero( Y );
+
+ Yplane = Y->data.fl;
+ connect_mask_data = layer->connect_mask->data.ptr;
+ w = layer->weights->data.fl;
+ for( no = 0; no < nYplanes; no++, Yplane += Ysize, w += n_weights_for_Yplane )
+ {
+ Xplane = X->data.fl;
+ for( ni = 0; ni < nXplanes; ni++, Xplane += Xsize, connect_mask_data++ )
+ {
+ if( *connect_mask_data )
+ {
+ float* Yelem = Yplane;
+
+ // Xheight-K+1 == Yheight && Xwidth-K+1 == Ywidth
+ for( yy = 0; yy < Xheight-K+1; yy++ )
+ {
+ for( xx = 0; xx < Xwidth-K+1; xx++, Yelem++ )
+ {
+ float* templ = Xplane+yy*Xwidth+xx;
+ float WX = 0;
+ for( ky = 0; ky < K; ky++, templ += Xwidth-K )
+ {
+ for( kx = 0; kx < K; kx++, templ++ )
+ {
+ WX += *templ*w[ky*K+kx];
+ }
+ }
+ *Yelem += WX + w[K*K];
+ }
+ }
+ }
+ }
+ }
+ }__END__;
+}
+
+/****************************************************************************************/
+static void icvCNNSubSamplingForward( CvCNNLayer* _layer,
+ const CvMat* X,
+ CvMat* Y )
+{
+ CV_FUNCNAME("icvCNNSubSamplingForward");
+
+ if( !ICV_IS_CNN_SUBSAMPLING_LAYER(_layer) )
+ CV_ERROR( CV_StsBadArg, "Invalid layer" );
+
+ {__BEGIN__;
+
+ const CvCNNSubSamplingLayer* layer = (CvCNNSubSamplingLayer*) _layer;
+
+ const int sub_sampl_scale = layer->sub_samp_scale;
+ const int nplanes = layer->n_input_planes;
+
+ const int Xheight = layer->input_height;
+ const int Xwidth = layer->input_width ;
+ const int Xsize = Xwidth*Xheight;
+
+ const int Yheight = layer->output_height;
+ const int Ywidth = layer->output_width;
+ const int Ysize = Ywidth*Yheight;
+
+ int xx, yy, ni, kx, ky;
+ float* sumX_data = 0, *w = 0;
+ CvMat sumX_sub_col, exp2ssumWX_sub_col;
+
+ CV_ASSERT(X->rows == nplanes*Xsize && X->cols == 1);
+ CV_ASSERT(layer->exp2ssumWX->cols == 1 && layer->exp2ssumWX->rows == nplanes*Ysize);
+
+ // update inner variable layer->exp2ssumWX, which will be used in back-progation
+ cvZero( layer->sumX );
+ cvZero( layer->exp2ssumWX );
+
+ for( ky = 0; ky < sub_sampl_scale; ky++ )
+ for( kx = 0; kx < sub_sampl_scale; kx++ )
+ {
+ float* Xplane = X->data.fl;
+ sumX_data = layer->sumX->data.fl;
+ for( ni = 0; ni < nplanes; ni++, Xplane += Xsize )
+ {
+ for( yy = 0; yy < Yheight; yy++ )
+ for( xx = 0; xx < Ywidth; xx++, sumX_data++ )
+ *sumX_data += Xplane[((yy+ky)*Xwidth+(xx+kx))];
+ }
+ }
+
+ w = layer->weights->data.fl;
+ cvGetRows( layer->sumX, &sumX_sub_col, 0, Ysize );
+ cvGetRows( layer->exp2ssumWX, &exp2ssumWX_sub_col, 0, Ysize );
+ for( ni = 0; ni < nplanes; ni++, w += 2 )
+ {
+ CV_CALL(cvConvertScale( &sumX_sub_col, &exp2ssumWX_sub_col, w[0], w[1] ));
+ sumX_sub_col.data.fl += Ysize;
+ exp2ssumWX_sub_col.data.fl += Ysize;
+ }
+
+ CV_CALL(cvScale( layer->exp2ssumWX, layer->exp2ssumWX, 2.0*layer->s ));
+ CV_CALL(cvExp( layer->exp2ssumWX, layer->exp2ssumWX ));
+ CV_CALL(cvMinS( layer->exp2ssumWX, FLT_MAX, layer->exp2ssumWX ));
+//#ifdef _DEBUG
+ {
+ float* exp2ssumWX_data = layer->exp2ssumWX->data.fl;
+ for( ni = 0; ni < layer->exp2ssumWX->rows; ni++, exp2ssumWX_data++ )
+ {
+ if( *exp2ssumWX_data == FLT_MAX )
+ cvSetErrStatus( 1 );
+ }
+ }
+//#endif
+ // compute the output variable Y == ( a - 2a/(layer->exp2ssumWX + 1))
+ CV_CALL(cvAddS( layer->exp2ssumWX, cvRealScalar(1), Y ));
+ CV_CALL(cvDiv( 0, Y, Y, -2.0*layer->a ));
+ CV_CALL(cvAddS( Y, cvRealScalar(layer->a), Y ));
+
+ }__END__;
+}
+
+/****************************************************************************************/
+static void icvCNNFullConnectForward( CvCNNLayer* _layer, const CvMat* X, CvMat* Y )
+{
+ CV_FUNCNAME("icvCNNFullConnectForward");
+
+ if( !ICV_IS_CNN_FULLCONNECT_LAYER(_layer) )
+ CV_ERROR( CV_StsBadArg, "Invalid layer" );
+
+ {__BEGIN__;
+
+ const CvCNNFullConnectLayer* layer = (CvCNNFullConnectLayer*)_layer;
+ CvMat* weights = layer->weights;
+ CvMat sub_weights, bias;
+
+ CV_ASSERT(X->cols == 1 && X->rows == layer->n_input_planes);
+ CV_ASSERT(Y->cols == 1 && Y->rows == layer->n_output_planes);
+
+ CV_CALL(cvGetSubRect( weights, &sub_weights,
+ cvRect(0, 0, weights->cols-1, weights->rows )));
+ CV_CALL(cvGetCol( weights, &bias, weights->cols-1));
+
+ // update inner variable layer->exp2ssumWX, which will be used in Back-Propagation
+ CV_CALL(cvGEMM( &sub_weights, X, 2*layer->s, &bias, 2*layer->s, layer->exp2ssumWX ));
+ CV_CALL(cvExp( layer->exp2ssumWX, layer->exp2ssumWX ));
+ CV_CALL(cvMinS( layer->exp2ssumWX, FLT_MAX, layer->exp2ssumWX ));
+//#ifdef _DEBUG
+ {
+ float* exp2ssumWX_data = layer->exp2ssumWX->data.fl;
+ int i;
+ for( i = 0; i < layer->exp2ssumWX->rows; i++, exp2ssumWX_data++ )
+ {
+ if( *exp2ssumWX_data == FLT_MAX )
+ cvSetErrStatus( 1 );
+ }
+ }
+//#endif
+ // compute the output variable Y == ( a - 2a/(layer->exp2ssumWX + 1))
+ CV_CALL(cvAddS( layer->exp2ssumWX, cvRealScalar(1), Y ));
+ CV_CALL(cvDiv( 0, Y, Y, -2.0*layer->a ));
+ CV_CALL(cvAddS( Y, cvRealScalar(layer->a), Y ));
+
+ }__END__;
+}
+
+/****************************************************************************************\
+* Layer BACKWARD functions *
+\****************************************************************************************/
+
+/* <dE_dY>, <dE_dX> should be row-vectors.
+ Function computes partial derivatives <dE_dX>
+ of the loss function with respect to the planes components
+ of the previous layer (X).
+ It is a basic function for back propagation method.
+ Input parameter <dE_dY> is the partial derivative of the
+ loss function with respect to the planes components
+ of the current layer. */
+static void icvCNNConvolutionBackward(
+ CvCNNLayer* _layer, int t, const CvMat* X, const CvMat* dE_dY, CvMat* dE_dX )
+{
+ CvMat* dY_dX = 0;
+ CvMat* dY_dW = 0;
+ CvMat* dE_dW = 0;
+
+ CV_FUNCNAME("icvCNNConvolutionBackward");
+
+ if( !ICV_IS_CNN_CONVOLUTION_LAYER(_layer) )
+ CV_ERROR( CV_StsBadArg, "Invalid layer" );
+
+ {__BEGIN__;
+
+ const CvCNNConvolutionLayer* layer = (CvCNNConvolutionLayer*) _layer;
+
+ const int K = layer->K;
+
+ const int n_X_planes = layer->n_input_planes;
+ const int X_plane_height = layer->input_height;
+ const int X_plane_width = layer->input_width;
+ const int X_plane_size = X_plane_height*X_plane_width;
+
+ const int n_Y_planes = layer->n_output_planes;
+ const int Y_plane_height = layer->output_height;
+ const int Y_plane_width = layer->output_width;
+ const int Y_plane_size = Y_plane_height*Y_plane_width;
+
+ int no, ni, yy, xx, ky, kx;
+ int X_idx = 0, Y_idx = 0;
+
+ float *X_plane = 0, *w = 0;
+
+ CvMat* weights = layer->weights;
+
+ CV_ASSERT( t >= 1 );
+ CV_ASSERT( n_Y_planes == weights->rows );
+
+ dY_dX = cvCreateMat( n_Y_planes*Y_plane_size, X->rows, CV_32FC1 );
+ dY_dW = cvCreateMat( dY_dX->rows, weights->cols*weights->rows, CV_32FC1 );
+ dE_dW = cvCreateMat( 1, dY_dW->cols, CV_32FC1 );
+
+ cvZero( dY_dX );
+ cvZero( dY_dW );
+
+ // compute gradient of the loss function with respect to X and W
+ for( no = 0; no < n_Y_planes; no++, Y_idx += Y_plane_size )
+ {
+ w = weights->data.fl + no*(K*K+1);
+ X_idx = 0;
+ X_plane = X->data.fl;
+ for( ni = 0; ni < n_X_planes; ni++, X_plane += X_plane_size )
+ {
+ if( layer->connect_mask->data.ptr[ni*n_Y_planes+no] )
+ {
+ for( yy = 0; yy < X_plane_height - K + 1; yy++ )
+ {
+ for( xx = 0; xx < X_plane_width - K + 1; xx++ )
+ {
+ for( ky = 0; ky < K; ky++ )
+ {
+ for( kx = 0; kx < K; kx++ )
+ {
+ CV_MAT_ELEM(*dY_dX, float, Y_idx+yy*Y_plane_width+xx,
+ X_idx+(yy+ky)*X_plane_width+(xx+kx)) = w[ky*K+kx];
+
+ // dY_dWi, i=1,...,K*K
+ CV_MAT_ELEM(*dY_dW, float, Y_idx+yy*Y_plane_width+xx,
+ no*(K*K+1)+ky*K+kx) +=
+ X_plane[(yy+ky)*X_plane_width+(xx+kx)];
+ }
+ }
+ // dY_dW(K*K+1)==1 because W(K*K+1) is bias
+ CV_MAT_ELEM(*dY_dW, float, Y_idx+yy*Y_plane_width+xx,
+ no*(K*K+1)+K*K) += 1;
+ }
+ }
+ }
+ X_idx += X_plane_size;
+ }
+ }
+
+ CV_CALL(cvMatMul( dE_dY, dY_dW, dE_dW ));
+ CV_CALL(cvMatMul( dE_dY, dY_dX, dE_dX ));
+
+ // update weights
+ {
+ CvMat dE_dW_mat;
+ float eta;
+ if( layer->learn_rate_decrease_type == CV_CNN_LEARN_RATE_DECREASE_LOG_INV )
+ eta = -layer->init_learn_rate/logf(1+(float)t);
+ else if( layer->learn_rate_decrease_type == CV_CNN_LEARN_RATE_DECREASE_SQRT_INV )
+ eta = -layer->init_learn_rate/sqrtf((float)t);
+ else
+ eta = -layer->init_learn_rate/(float)t;
+ cvReshape( dE_dW, &dE_dW_mat, 0, weights->rows );
+ cvScaleAdd( &dE_dW_mat, cvRealScalar(eta), weights, weights );
+ }
+
+ }__END__;
+
+ cvReleaseMat( &dY_dX );
+ cvReleaseMat( &dY_dW );
+ cvReleaseMat( &dE_dW );
+}
+
+/****************************************************************************************/
+static void icvCNNSubSamplingBackward(
+ CvCNNLayer* _layer, int t, const CvMat*, const CvMat* dE_dY, CvMat* dE_dX )
+{
+ // derivative of activation function
+ CvMat* dY_dX_elems = 0; // elements of matrix dY_dX
+ CvMat* dY_dW_elems = 0; // elements of matrix dY_dW
+ CvMat* dE_dW = 0;
+
+ CV_FUNCNAME("icvCNNSubSamplingBackward");
+
+ if( !ICV_IS_CNN_SUBSAMPLING_LAYER(_layer) )
+ CV_ERROR( CV_StsBadArg, "Invalid layer" );
+
+ {__BEGIN__;
+
+ const CvCNNSubSamplingLayer* layer = (CvCNNSubSamplingLayer*) _layer;
+
+ const int Xwidth = layer->input_width;
+ const int Ywidth = layer->output_width;
+ const int Yheight = layer->output_height;
+ const int Ysize = Ywidth * Yheight;
+ const int scale = layer->sub_samp_scale;
+ const int k_max = layer->n_output_planes * Yheight;
+
+ int k, i, j, m;
+ float* dY_dX_current_elem = 0, *dE_dX_start = 0, *dE_dW_data = 0, *w = 0;
+ CvMat dy_dw0, dy_dw1;
+ CvMat activ_func_der, sumX_row;
+ CvMat dE_dY_sub_row, dY_dX_sub_col, dy_dw0_sub_row, dy_dw1_sub_row;
+
+ CV_CALL(dY_dX_elems = cvCreateMat( layer->sumX->rows, 1, CV_32FC1 ));
+ CV_CALL(dY_dW_elems = cvCreateMat( 2, layer->sumX->rows, CV_32FC1 ));
+ CV_CALL(dE_dW = cvCreateMat( 1, 2*layer->n_output_planes, CV_32FC1 ));
+
+ // compute derivative of activ.func.
+ // ==<dY_dX_elems> = 4as*(layer->exp2ssumWX)/(layer->exp2ssumWX + 1)^2
+ CV_CALL(cvAddS( layer->exp2ssumWX, cvRealScalar(1), dY_dX_elems ));
+ CV_CALL(cvPow( dY_dX_elems, dY_dX_elems, -2.0 ));
+ CV_CALL(cvMul( dY_dX_elems, layer->exp2ssumWX, dY_dX_elems, 4.0*layer->a*layer->s ));
+
+ // compute <dE_dW>
+ // a) compute <dY_dW_elems>
+ cvReshape( dY_dX_elems, &activ_func_der, 0, 1 );
+ cvGetRow( dY_dW_elems, &dy_dw0, 0 );
+ cvGetRow( dY_dW_elems, &dy_dw1, 1 );
+ CV_CALL(cvCopy( &activ_func_der, &dy_dw0 ));
+ CV_CALL(cvCopy( &activ_func_der, &dy_dw1 ));
+
+ cvReshape( layer->sumX, &sumX_row, 0, 1 );
+ cvMul( &dy_dw0, &sumX_row, &dy_dw0 );
+
+ // b) compute <dE_dW> = <dE_dY>*<dY_dW_elems>
+ cvGetCols( dE_dY, &dE_dY_sub_row, 0, Ysize );
+ cvGetCols( &dy_dw0, &dy_dw0_sub_row, 0, Ysize );
+ cvGetCols( &dy_dw1, &dy_dw1_sub_row, 0, Ysize );
+ dE_dW_data = dE_dW->data.fl;
+ for( i = 0; i < layer->n_output_planes; i++ )
+ {
+ *dE_dW_data++ = (float)cvDotProduct( &dE_dY_sub_row, &dy_dw0_sub_row );
+ *dE_dW_data++ = (float)cvDotProduct( &dE_dY_sub_row, &dy_dw1_sub_row );
+
+ dE_dY_sub_row.data.fl += Ysize;
+ dy_dw0_sub_row.data.fl += Ysize;
+ dy_dw1_sub_row.data.fl += Ysize;
+ }
+
+ // compute <dY_dX> = layer->weights*<dY_dX>
+ w = layer->weights->data.fl;
+ cvGetRows( dY_dX_elems, &dY_dX_sub_col, 0, Ysize );
+ for( i = 0; i < layer->n_input_planes; i++, w++, dY_dX_sub_col.data.fl += Ysize )
+ CV_CALL(cvConvertScale( &dY_dX_sub_col, &dY_dX_sub_col, (float)*w ));
+
+ // compute <dE_dX>
+ CV_CALL(cvReshape( dY_dX_elems, dY_dX_elems, 0, 1 ));
+ CV_CALL(cvMul( dY_dX_elems, dE_dY, dY_dX_elems ));
+
+ dY_dX_current_elem = dY_dX_elems->data.fl;
+ dE_dX_start = dE_dX->data.fl;
+ for( k = 0; k < k_max; k++ )
+ {
+ for( i = 0; i < Ywidth; i++, dY_dX_current_elem++ )
+ {
+ float* dE_dX_current_elem = dE_dX_start;
+ for( j = 0; j < scale; j++, dE_dX_current_elem += Xwidth - scale )
+ {
+ for( m = 0; m < scale; m++, dE_dX_current_elem++ )
+ *dE_dX_current_elem = *dY_dX_current_elem;
+ }
+ dE_dX_start += scale;
+ }
+ dE_dX_start += Xwidth * (scale - 1);
+ }
+
+ // update weights
+ {
+ CvMat dE_dW_mat, *weights = layer->weights;
+ float eta;
+ if( layer->learn_rate_decrease_type == CV_CNN_LEARN_RATE_DECREASE_LOG_INV )
+ eta = -layer->init_learn_rate/logf(1+(float)t);
+ else if( layer->learn_rate_decrease_type == CV_CNN_LEARN_RATE_DECREASE_SQRT_INV )
+ eta = -layer->init_learn_rate/sqrtf((float)t);
+ else
+ eta = -layer->init_learn_rate/(float)t;
+ cvReshape( dE_dW, &dE_dW_mat, 0, weights->rows );
+ cvScaleAdd( &dE_dW_mat, cvRealScalar(eta), weights, weights );
+ }
+
+ }__END__;
+
+ cvReleaseMat( &dY_dX_elems );
+ cvReleaseMat( &dY_dW_elems );
+ cvReleaseMat( &dE_dW );
+}
+
+/****************************************************************************************/
+/* <dE_dY>, <dE_dX> should be row-vectors.
+ Function computes partial derivatives <dE_dX>, <dE_dW>
+ of the loss function with respect to the planes components
+ of the previous layer (X) and the weights of the current layer (W)
+ and updates weights od the current layer by using <dE_dW>.
+ It is a basic function for back propagation method.
+ Input parameter <dE_dY> is the partial derivative of the
+ loss function with respect to the planes components
+ of the current layer. */
+static void icvCNNFullConnectBackward( CvCNNLayer* _layer,
+ int t,
+ const CvMat* X,
+ const CvMat* dE_dY,
+ CvMat* dE_dX )
+{
+ CvMat* dE_dY_activ_func_der = 0;
+ CvMat* dE_dW = 0;
+
+ CV_FUNCNAME( "icvCNNFullConnectBackward" );
+
+ if( !ICV_IS_CNN_FULLCONNECT_LAYER(_layer) )
+ CV_ERROR( CV_StsBadArg, "Invalid layer" );
+
+ {__BEGIN__;
+
+ const CvCNNFullConnectLayer* layer = (CvCNNFullConnectLayer*)_layer;
+ const int n_outputs = layer->n_output_planes;
+ const int n_inputs = layer->n_input_planes;
+
+ int i;
+ float* dE_dY_activ_func_der_data;
+ CvMat* weights = layer->weights;
+ CvMat sub_weights, Xtemplate, Xrow, exp2ssumWXrow;
+
+ CV_ASSERT(X->cols == 1 && X->rows == n_inputs);
+ CV_ASSERT(dE_dY->rows == 1 && dE_dY->cols == n_outputs );
+ CV_ASSERT(dE_dX->rows == 1 && dE_dX->cols == n_inputs );
+
+ // we violate the convetion about vector's orientation because
+ // here is more convenient to make this parameter a row-vector
+ CV_CALL(dE_dY_activ_func_der = cvCreateMat( 1, n_outputs, CV_32FC1 ));
+ CV_CALL(dE_dW = cvCreateMat( 1, weights->rows*weights->cols, CV_32FC1 ));
+
+ // 1) compute gradients dE_dX and dE_dW
+ // activ_func_der == 4as*(layer->exp2ssumWX)/(layer->exp2ssumWX + 1)^2
+ CV_CALL(cvReshape( layer->exp2ssumWX, &exp2ssumWXrow, 0, layer->exp2ssumWX->cols ));
+ CV_CALL(cvAddS( &exp2ssumWXrow, cvRealScalar(1), dE_dY_activ_func_der ));
+ CV_CALL(cvPow( dE_dY_activ_func_der, dE_dY_activ_func_der, -2.0 ));
+ CV_CALL(cvMul( dE_dY_activ_func_der, &exp2ssumWXrow, dE_dY_activ_func_der,
+ 4.0*layer->a*layer->s ));
+ CV_CALL(cvMul( dE_dY, dE_dY_activ_func_der, dE_dY_activ_func_der ));
+
+ // sub_weights = d(W*(X|1))/dX
+ CV_CALL(cvGetSubRect( weights, &sub_weights,
+ cvRect(0, 0, weights->cols-1, weights->rows) ));
+ CV_CALL(cvMatMul( dE_dY_activ_func_der, &sub_weights, dE_dX ));
+
+ cvReshape( X, &Xrow, 0, 1 );
+ dE_dY_activ_func_der_data = dE_dY_activ_func_der->data.fl;
+ Xtemplate = cvMat( 1, n_inputs, CV_32FC1, dE_dW->data.fl );
+ for( i = 0; i < n_outputs; i++, Xtemplate.data.fl += n_inputs + 1 )
+ {
+ CV_CALL(cvConvertScale( &Xrow, &Xtemplate, *dE_dY_activ_func_der_data ));
+ Xtemplate.data.fl[n_inputs] = *dE_dY_activ_func_der_data++;
+ }
+
+ // 2) update weights
+ {
+ CvMat dE_dW_mat;
+ float eta;
+ if( layer->learn_rate_decrease_type == CV_CNN_LEARN_RATE_DECREASE_LOG_INV )
+ eta = -layer->init_learn_rate/logf(1+(float)t);
+ else if( layer->learn_rate_decrease_type == CV_CNN_LEARN_RATE_DECREASE_SQRT_INV )
+ eta = -layer->init_learn_rate/sqrtf((float)t);
+ else
+ eta = -layer->init_learn_rate/(float)t;
+ cvReshape( dE_dW, &dE_dW_mat, 0, n_outputs );
+ cvScaleAdd( &dE_dW_mat, cvRealScalar(eta), weights, weights );
+ }
+
+ }__END__;
+
+ cvReleaseMat( &dE_dY_activ_func_der );
+ cvReleaseMat( &dE_dW );
+}
+
+/****************************************************************************************\
+* Layer RELEASE functions *
+\****************************************************************************************/
+static void icvCNNConvolutionRelease( CvCNNLayer** p_layer )
+{
+ CV_FUNCNAME("icvCNNConvolutionRelease");
+ __BEGIN__;
+
+ CvCNNConvolutionLayer* layer = 0;
+
+ if( !p_layer )
+ CV_ERROR( CV_StsNullPtr, "Null double pointer" );
+
+ layer = *(CvCNNConvolutionLayer**)p_layer;
+
+ if( !layer )
+ return;
+ if( !ICV_IS_CNN_CONVOLUTION_LAYER(layer) )
+ CV_ERROR( CV_StsBadArg, "Invalid layer" );
+
+ cvReleaseMat( &layer->weights );
+ cvReleaseMat( &layer->connect_mask );
+ cvFree( p_layer );
+
+ __END__;
+}
+
+/****************************************************************************************/
+static void icvCNNSubSamplingRelease( CvCNNLayer** p_layer )
+{
+ CV_FUNCNAME("icvCNNSubSamplingRelease");
+ __BEGIN__;
+
+ CvCNNSubSamplingLayer* layer = 0;
+
+ if( !p_layer )
+ CV_ERROR( CV_StsNullPtr, "Null double pointer" );
+
+ layer = *(CvCNNSubSamplingLayer**)p_layer;
+
+ if( !layer )
+ return;
+ if( !ICV_IS_CNN_SUBSAMPLING_LAYER(layer) )
+ CV_ERROR( CV_StsBadArg, "Invalid layer" );
+
+ cvReleaseMat( &layer->exp2ssumWX );
+ cvReleaseMat( &layer->weights );
+ cvFree( p_layer );
+
+ __END__;
+}
+
+/****************************************************************************************/
+static void icvCNNFullConnectRelease( CvCNNLayer** p_layer )
+{
+ CV_FUNCNAME("icvCNNFullConnectRelease");
+ __BEGIN__;
+
+ CvCNNFullConnectLayer* layer = 0;
+
+ if( !p_layer )
+ CV_ERROR( CV_StsNullPtr, "Null double pointer" );
+
+ layer = *(CvCNNFullConnectLayer**)p_layer;
+
+ if( !layer )
+ return;
+ if( !ICV_IS_CNN_FULLCONNECT_LAYER(layer) )
+ CV_ERROR( CV_StsBadArg, "Invalid layer" );
+
+ cvReleaseMat( &layer->exp2ssumWX );
+ cvReleaseMat( &layer->weights );
+ cvFree( p_layer );
+
+ __END__;
+}
+
+/****************************************************************************************\
+* Read/Write CNN classifier *
+\****************************************************************************************/
+static int icvIsCNNModel( const void* ptr )
+{
+ return CV_IS_CNN(ptr);
+}
+
+/****************************************************************************************/
+static void icvReleaseCNNModel( void** ptr )
+{
+ CV_FUNCNAME("icvReleaseCNNModel");
+ __BEGIN__;
+
+ if( !ptr )
+ CV_ERROR( CV_StsNullPtr, "NULL double pointer" );
+ CV_ASSERT(CV_IS_CNN(*ptr));
+
+ icvCNNModelRelease( (CvStatModel**)ptr );
+
+ __END__;
+}
+
+/****************************************************************************************/
+static CvCNNLayer* icvReadCNNLayer( CvFileStorage* fs, CvFileNode* node )
+{
+ CvCNNLayer* layer = 0;
+ CvMat* weights = 0;
+ CvMat* connect_mask = 0;
+
+ CV_FUNCNAME("icvReadCNNLayer");
+ __BEGIN__;
+
+ int n_input_planes, input_height, input_width;
+ int n_output_planes, output_height, output_width;
+ int learn_type, layer_type;
+ float init_learn_rate;
+
+ CV_CALL(n_input_planes = cvReadIntByName( fs, node, "n_input_planes", -1 ));
+ CV_CALL(input_height = cvReadIntByName( fs, node, "input_height", -1 ));
+ CV_CALL(input_width = cvReadIntByName( fs, node, "input_width", -1 ));
+ CV_CALL(n_output_planes = cvReadIntByName( fs, node, "n_output_planes", -1 ));
+ CV_CALL(output_height = cvReadIntByName( fs, node, "output_height", -1 ));
+ CV_CALL(output_width = cvReadIntByName( fs, node, "output_width", -1 ));
+ CV_CALL(layer_type = cvReadIntByName( fs, node, "layer_type", -1 ));
+
+ CV_CALL(init_learn_rate = (float)cvReadRealByName( fs, node, "init_learn_rate", -1 ));
+ CV_CALL(learn_type = cvReadIntByName( fs, node, "learn_rate_decrease_type", -1 ));
+ CV_CALL(weights = (CvMat*)cvReadByName( fs, node, "weights" ));
+
+ if( n_input_planes < 0 || input_height < 0 || input_width < 0 ||
+ n_output_planes < 0 || output_height < 0 || output_width < 0 ||
+ init_learn_rate < 0 || learn_type < 0 || layer_type < 0 || !weights )
+ CV_ERROR( CV_StsParseError, "" );
+
+ if( layer_type == ICV_CNN_CONVOLUTION_LAYER )
+ {
+ const int K = input_height - output_height + 1;
+ if( K <= 0 || K != input_width - output_width + 1 )
+ CV_ERROR( CV_StsBadArg, "Invalid <K>" );
+
+ CV_CALL(connect_mask = (CvMat*)cvReadByName( fs, node, "connect_mask" ));
+ if( !connect_mask )
+ CV_ERROR( CV_StsParseError, "Missing <connect mask>" );
+
+ CV_CALL(layer = cvCreateCNNConvolutionLayer(
+ n_input_planes, input_height, input_width, n_output_planes, K,
+ init_learn_rate, learn_type, connect_mask, weights ));
+ }
+ else if( layer_type == ICV_CNN_SUBSAMPLING_LAYER )
+ {
+ float a, s;
+ const int sub_samp_scale = input_height/output_height;
+
+ if( sub_samp_scale <= 0 || sub_samp_scale != input_width/output_width )
+ CV_ERROR( CV_StsBadArg, "Invalid <sub_samp_scale>" );
+
+ CV_CALL(a = (float)cvReadRealByName( fs, node, "a", -1 ));
+ CV_CALL(s = (float)cvReadRealByName( fs, node, "s", -1 ));
+ if( a < 0 || s < 0 )
+ CV_ERROR( CV_StsParseError, "Missing <a> or <s>" );
+
+ CV_CALL(layer = cvCreateCNNSubSamplingLayer(
+ n_input_planes, input_height, input_width, sub_samp_scale,
+ a, s, init_learn_rate, learn_type, weights ));
+ }
+ else if( layer_type == ICV_CNN_FULLCONNECT_LAYER )
+ {
+ float a, s;
+ CV_CALL(a = (float)cvReadRealByName( fs, node, "a", -1 ));
+ CV_CALL(s = (float)cvReadRealByName( fs, node, "s", -1 ));
+ if( a < 0 || s < 0 )
+ CV_ERROR( CV_StsParseError, "" );
+ if( input_height != 1 || input_width != 1 ||
+ output_height != 1 || output_width != 1 )
+ CV_ERROR( CV_StsBadArg, "" );
+
+ CV_CALL(layer = cvCreateCNNFullConnectLayer( n_input_planes, n_output_planes,
+ a, s, init_learn_rate, learn_type, weights ));
+ }
+ else
+ CV_ERROR( CV_StsBadArg, "Invalid <layer_type>" );
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 && layer )
+ layer->release( &layer );
+
+ cvReleaseMat( &weights );
+ cvReleaseMat( &connect_mask );
+
+ return layer;
+}
+
+/****************************************************************************************/
+static void icvWriteCNNLayer( CvFileStorage* fs, CvCNNLayer* layer )
+{
+ CV_FUNCNAME ("icvWriteCNNLayer");
+ __BEGIN__;
+
+ if( !ICV_IS_CNN_LAYER(layer) )
+ CV_ERROR( CV_StsBadArg, "Invalid layer" );
+
+ CV_CALL( cvStartWriteStruct( fs, NULL, CV_NODE_MAP, "opencv-ml-cnn-layer" ));
+
+ CV_CALL(cvWriteInt( fs, "n_input_planes", layer->n_input_planes ));
+ CV_CALL(cvWriteInt( fs, "input_height", layer->input_height ));
+ CV_CALL(cvWriteInt( fs, "input_width", layer->input_width ));
+ CV_CALL(cvWriteInt( fs, "n_output_planes", layer->n_output_planes ));
+ CV_CALL(cvWriteInt( fs, "output_height", layer->output_height ));
+ CV_CALL(cvWriteInt( fs, "output_width", layer->output_width ));
+ CV_CALL(cvWriteInt( fs, "learn_rate_decrease_type", layer->learn_rate_decrease_type));
+ CV_CALL(cvWriteReal( fs, "init_learn_rate", layer->init_learn_rate ));
+ CV_CALL(cvWrite( fs, "weights", layer->weights ));
+
+ if( ICV_IS_CNN_CONVOLUTION_LAYER( layer ))
+ {
+ CvCNNConvolutionLayer* l = (CvCNNConvolutionLayer*)layer;
+ CV_CALL(cvWriteInt( fs, "layer_type", ICV_CNN_CONVOLUTION_LAYER ));
+ CV_CALL(cvWrite( fs, "connect_mask", l->connect_mask ));
+ }
+ else if( ICV_IS_CNN_SUBSAMPLING_LAYER( layer ) )
+ {
+ CvCNNSubSamplingLayer* l = (CvCNNSubSamplingLayer*)layer;
+ CV_CALL(cvWriteInt( fs, "layer_type", ICV_CNN_SUBSAMPLING_LAYER ));
+ CV_CALL(cvWriteReal( fs, "a", l->a ));
+ CV_CALL(cvWriteReal( fs, "s", l->s ));
+ }
+ else if( ICV_IS_CNN_FULLCONNECT_LAYER( layer ) )
+ {
+ CvCNNFullConnectLayer* l = (CvCNNFullConnectLayer*)layer;
+ CV_CALL(cvWriteInt( fs, "layer_type", ICV_CNN_FULLCONNECT_LAYER ));
+ CV_CALL(cvWriteReal( fs, "a", l->a ));
+ CV_CALL(cvWriteReal( fs, "s", l->s ));
+ }
+ else
+ CV_ERROR( CV_StsBadArg, "Invalid layer" );
+
+ CV_CALL( cvEndWriteStruct( fs )); //"opencv-ml-cnn-layer"
+
+ __END__;
+}
+
+/****************************************************************************************/
+static void* icvReadCNNModel( CvFileStorage* fs, CvFileNode* root_node )
+{
+ CvCNNStatModel* cnn = 0;
+ CvCNNLayer* layer = 0;
+
+ CV_FUNCNAME("icvReadCNNModel");
+ __BEGIN__;
+
+ CvFileNode* node;
+ CvSeq* seq;
+ CvSeqReader reader;
+ int i;
+
+ CV_CALL(cnn = (CvCNNStatModel*)cvCreateStatModel(
+ CV_STAT_MODEL_MAGIC_VAL|CV_CNN_MAGIC_VAL, sizeof(CvCNNStatModel),
+ icvCNNModelRelease, icvCNNModelPredict, icvCNNModelUpdate ));
+
+ CV_CALL(cnn->etalons = (CvMat*)cvReadByName( fs, root_node, "etalons" ));
+ CV_CALL(cnn->cls_labels = (CvMat*)cvReadByName( fs, root_node, "cls_labels" ));
+
+ if( !cnn->etalons || !cnn->cls_labels )
+ CV_ERROR( CV_StsParseError, "No <etalons> or <cls_labels> in CNN model" );
+
+ CV_CALL( node = cvGetFileNodeByName( fs, root_node, "network" ));
+ seq = node->data.seq;
+ if( !CV_NODE_IS_SEQ(node->tag) )
+ CV_ERROR( CV_StsBadArg, "" );
+
+ CV_CALL( cvStartReadSeq( seq, &reader, 0 ));
+ CV_CALL(layer = icvReadCNNLayer( fs, (CvFileNode*)reader.ptr ));
+ CV_CALL(cnn->network = cvCreateCNNetwork( layer ));
+
+ for( i = 1; i < seq->total; i++ )
+ {
+ CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
+ CV_CALL(layer = icvReadCNNLayer( fs, (CvFileNode*)reader.ptr ));
+ CV_CALL(cnn->network->add_layer( cnn->network, layer ));
+ }
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ {
+ if( cnn ) cnn->release( (CvStatModel**)&cnn );
+ if( layer ) layer->release( &layer );
+ }
+ return (void*)cnn;
+}
+
+/****************************************************************************************/
+static void
+icvWriteCNNModel( CvFileStorage* fs, const char* name,
+ const void* struct_ptr, CvAttrList )
+
+{
+ CV_FUNCNAME ("icvWriteCNNModel");
+ __BEGIN__;
+
+ CvCNNStatModel* cnn = (CvCNNStatModel*)struct_ptr;
+ int n_layers, i;
+ CvCNNLayer* layer;
+
+ if( !CV_IS_CNN(cnn) )
+ CV_ERROR( CV_StsBadArg, "Invalid pointer" );
+
+ n_layers = cnn->network->n_layers;
+
+ CV_CALL( cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_ML_CNN ));
+
+ CV_CALL(cvWrite( fs, "etalons", cnn->etalons ));
+ CV_CALL(cvWrite( fs, "cls_labels", cnn->cls_labels ));
+
+ CV_CALL( cvStartWriteStruct( fs, "network", CV_NODE_SEQ ));
+
+ layer = cnn->network->layers;
+ for( i = 0; i < n_layers && layer; i++, layer = layer->next_layer )
+ CV_CALL(icvWriteCNNLayer( fs, layer ));
+ if( i < n_layers || layer )
+ CV_ERROR( CV_StsBadArg, "Invalid network" );
+
+ CV_CALL( cvEndWriteStruct( fs )); //"network"
+ CV_CALL( cvEndWriteStruct( fs )); //"opencv-ml-cnn"
+
+ __END__;
+}
+
+static int icvRegisterCNNStatModelType()
+{
+ CvTypeInfo info;
+
+ info.header_size = sizeof( info );
+ info.is_instance = icvIsCNNModel;
+ info.release = icvReleaseCNNModel;
+ info.read = icvReadCNNModel;
+ info.write = icvWriteCNNModel;
+ info.clone = NULL;
+ info.type_name = CV_TYPE_NAME_ML_CNN;
+ cvRegisterType( &info );
+
+ return 1;
+} // End of icvRegisterCNNStatModelType
+
+static int cnn = icvRegisterCNNStatModelType();
+
+#endif
+
+// End of file
diff --git a/ml/src/mlem.cpp b/ml/src/mlem.cpp
new file mode 100644
index 0000000..313f3fa
--- /dev/null
+++ b/ml/src/mlem.cpp
@@ -0,0 +1,1110 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright( C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+//(including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort(including negligence or otherwise) arising in any way out of
+// the use of this software, even ifadvised of the possibility of such damage.
+//
+//M*/
+
+#include "_ml.h"
+
+
+/*
+ CvEM:
+ * params.nclusters - number of clusters to cluster samples to.
+ * means - calculated by the EM algorithm set of gaussians' means.
+ * log_weight_div_det - auxilary vector that k-th component is equal to
+ (-2)*ln(weights_k/det(Sigma_k)^0.5),
+ where <weights_k> is the weight,
+ <Sigma_k> is the covariation matrice of k-th cluster.
+ * inv_eigen_values - set of 1*dims matrices, <inv_eigen_values>[k] contains
+ inversed eigen values of covariation matrice of the k-th cluster.
+ In the case of <cov_mat_type> == COV_MAT_DIAGONAL,
+ inv_eigen_values[k] = Sigma_k^(-1).
+ * covs_rotate_mats - used only if cov_mat_type == COV_MAT_GENERIC, in all the
+ other cases it is NULL. <covs_rotate_mats>[k] is the orthogonal
+ matrice, obtained by the SVD-decomposition of Sigma_k.
+ Both <inv_eigen_values> and <covs_rotate_mats> fields are used for representation of
+ covariation matrices and simplifying EM calculations.
+ For fixed k denote
+ u = covs_rotate_mats[k],
+ v = inv_eigen_values[k],
+ w = v^(-1);
+ if <cov_mat_type> == COV_MAT_GENERIC, then Sigma_k = u w u',
+ else Sigma_k = w.
+ Symbol ' means transposition.
+ */
+
+
+CvEM::CvEM()
+{
+ means = weights = probs = inv_eigen_values = log_weight_div_det = 0;
+ covs = cov_rotate_mats = 0;
+}
+
+CvEM::CvEM( const CvMat* samples, const CvMat* sample_idx,
+ CvEMParams params, CvMat* labels )
+{
+ means = weights = probs = inv_eigen_values = log_weight_div_det = 0;
+ covs = cov_rotate_mats = 0;
+
+ // just invoke the train() method
+ train(samples, sample_idx, params, labels);
+}
+
+CvEM::~CvEM()
+{
+ clear();
+}
+
+
+void CvEM::clear()
+{
+ int i;
+
+ cvReleaseMat( &means );
+ cvReleaseMat( &weights );
+ cvReleaseMat( &probs );
+ cvReleaseMat( &inv_eigen_values );
+ cvReleaseMat( &log_weight_div_det );
+
+ if( covs || cov_rotate_mats )
+ {
+ for( i = 0; i < params.nclusters; i++ )
+ {
+ if( covs )
+ cvReleaseMat( &covs[i] );
+ if( cov_rotate_mats )
+ cvReleaseMat( &cov_rotate_mats[i] );
+ }
+ cvFree( &covs );
+ cvFree( &cov_rotate_mats );
+ }
+}
+
+
+void CvEM::set_params( const CvEMParams& _params, const CvVectors& train_data )
+{
+ CV_FUNCNAME( "CvEM::set_params" );
+
+ __BEGIN__;
+
+ int k;
+
+ params = _params;
+ params.term_crit = cvCheckTermCriteria( params.term_crit, 1e-6, 10000 );
+
+ if( params.cov_mat_type != COV_MAT_SPHERICAL &&
+ params.cov_mat_type != COV_MAT_DIAGONAL &&
+ params.cov_mat_type != COV_MAT_GENERIC )
+ CV_ERROR( CV_StsBadArg, "Unknown covariation matrix type" );
+
+ switch( params.start_step )
+ {
+ case START_M_STEP:
+ if( !params.probs )
+ CV_ERROR( CV_StsNullPtr, "Probabilities must be specified when EM algorithm starts with M-step" );
+ break;
+ case START_E_STEP:
+ if( !params.means )
+ CV_ERROR( CV_StsNullPtr, "Mean's must be specified when EM algorithm starts with E-step" );
+ break;
+ case START_AUTO_STEP:
+ break;
+ default:
+ CV_ERROR( CV_StsBadArg, "Unknown start_step" );
+ }
+
+ if( params.nclusters < 1 )
+ CV_ERROR( CV_StsOutOfRange, "The number of clusters (mixtures) should be > 0" );
+
+ if( params.probs )
+ {
+ const CvMat* p = params.weights;
+ if( !CV_IS_MAT(p) ||
+ CV_MAT_TYPE(p->type) != CV_32FC1 &&
+ CV_MAT_TYPE(p->type) != CV_64FC1 ||
+ p->rows != train_data.count ||
+ p->cols != params.nclusters )
+ CV_ERROR( CV_StsBadArg, "The array of probabilities must be a valid "
+ "floating-point matrix (CvMat) of 'nsamples' x 'nclusters' size" );
+ }
+
+ if( params.means )
+ {
+ const CvMat* m = params.means;
+ if( !CV_IS_MAT(m) ||
+ CV_MAT_TYPE(m->type) != CV_32FC1 &&
+ CV_MAT_TYPE(m->type) != CV_64FC1 ||
+ m->rows != params.nclusters ||
+ m->cols != train_data.dims )
+ CV_ERROR( CV_StsBadArg, "The array of mean's must be a valid "
+ "floating-point matrix (CvMat) of 'nsamples' x 'dims' size" );
+ }
+
+ if( params.weights )
+ {
+ const CvMat* w = params.weights;
+ if( !CV_IS_MAT(w) ||
+ CV_MAT_TYPE(w->type) != CV_32FC1 &&
+ CV_MAT_TYPE(w->type) != CV_64FC1 ||
+ w->rows != 1 && w->cols != 1 ||
+ w->rows + w->cols - 1 != params.nclusters )
+ CV_ERROR( CV_StsBadArg, "The array of weights must be a valid "
+ "1d floating-point vector (CvMat) of 'nclusters' elements" );
+ }
+
+ if( params.covs )
+ for( k = 0; k < params.nclusters; k++ )
+ {
+ const CvMat* cov = params.covs[k];
+ if( !CV_IS_MAT(cov) ||
+ CV_MAT_TYPE(cov->type) != CV_32FC1 &&
+ CV_MAT_TYPE(cov->type) != CV_64FC1 ||
+ cov->rows != cov->cols || cov->cols != train_data.dims )
+ CV_ERROR( CV_StsBadArg,
+ "Each of covariation matrices must be a valid square "
+ "floating-point matrix (CvMat) of 'dims' x 'dims'" );
+ }
+
+ __END__;
+}
+
+
+/****************************************************************************************/
+float
+CvEM::predict( const CvMat* _sample, CvMat* _probs ) const
+{
+ float* sample_data = 0;
+ void* buffer = 0;
+ int allocated_buffer = 0;
+ int cls = 0;
+
+ CV_FUNCNAME( "CvEM::predict" );
+ __BEGIN__;
+
+ int i, k, dims;
+ int nclusters;
+ int cov_mat_type = params.cov_mat_type;
+ double opt = FLT_MAX;
+ size_t size;
+ CvMat diff, expo;
+
+ dims = means->cols;
+ nclusters = params.nclusters;
+
+ CV_CALL( cvPreparePredictData( _sample, dims, 0, params.nclusters, _probs, &sample_data ));
+
+// allocate memory and initializing headers for calculating
+ size = sizeof(double) * (nclusters + dims);
+ if( size <= CV_MAX_LOCAL_SIZE )
+ buffer = cvStackAlloc( size );
+ else
+ {
+ CV_CALL( buffer = cvAlloc( size ));
+ allocated_buffer = 1;
+ }
+ expo = cvMat( 1, nclusters, CV_64FC1, buffer );
+ diff = cvMat( 1, dims, CV_64FC1, (double*)buffer + nclusters );
+
+// calculate the probabilities
+ for( k = 0; k < nclusters; k++ )
+ {
+ const double* mean_k = (const double*)(means->data.ptr + means->step*k);
+ const double* w = (const double*)(inv_eigen_values->data.ptr + inv_eigen_values->step*k);
+ double cur = log_weight_div_det->data.db[k];
+ CvMat* u = cov_rotate_mats[k];
+ // cov = u w u' --> cov^(-1) = u w^(-1) u'
+ if( cov_mat_type == COV_MAT_SPHERICAL )
+ {
+ double w0 = w[0];
+ for( i = 0; i < dims; i++ )
+ {
+ double val = sample_data[i] - mean_k[i];
+ cur += val*val*w0;
+ }
+ }
+ else
+ {
+ for( i = 0; i < dims; i++ )
+ diff.data.db[i] = sample_data[i] - mean_k[i];
+ if( cov_mat_type == COV_MAT_GENERIC )
+ cvGEMM( &diff, u, 1, 0, 0, &diff, CV_GEMM_B_T );
+ for( i = 0; i < dims; i++ )
+ {
+ double val = diff.data.db[i];
+ cur += val*val*w[i];
+ }
+ }
+
+ expo.data.db[k] = cur;
+ if( cur < opt )
+ {
+ cls = k;
+ opt = cur;
+ }
+ /* probability = (2*pi)^(-dims/2)*exp( -0.5 * cur ) */
+ }
+
+ if( _probs )
+ {
+ CV_CALL( cvConvertScale( &expo, &expo, -0.5 ));
+ CV_CALL( cvExp( &expo, &expo ));
+ if( _probs->cols == 1 )
+ CV_CALL( cvReshape( &expo, &expo, 0, nclusters ));
+ CV_CALL( cvConvertScale( &expo, _probs, 1./cvSum( &expo ).val[0] ));
+ }
+
+ __END__;
+
+ if( sample_data != _sample->data.fl )
+ cvFree( &sample_data );
+ if( allocated_buffer )
+ cvFree( &buffer );
+
+ return (float)cls;
+}
+
+
+
+bool CvEM::train( const CvMat* _samples, const CvMat* _sample_idx,
+ CvEMParams _params, CvMat* labels )
+{
+ bool result = false;
+ CvVectors train_data;
+ CvMat* sample_idx = 0;
+
+ train_data.data.fl = 0;
+ train_data.count = 0;
+
+ CV_FUNCNAME("cvEM");
+
+ __BEGIN__;
+
+ int i, nsamples, nclusters, dims;
+
+ clear();
+
+ CV_CALL( cvPrepareTrainData( "cvEM",
+ _samples, CV_ROW_SAMPLE, 0, CV_VAR_CATEGORICAL,
+ 0, _sample_idx, false, (const float***)&train_data.data.fl,
+ &train_data.count, &train_data.dims, &train_data.dims,
+ 0, 0, 0, &sample_idx ));
+
+ CV_CALL( set_params( _params, train_data ));
+ nsamples = train_data.count;
+ nclusters = params.nclusters;
+ dims = train_data.dims;
+
+ if( labels && (!CV_IS_MAT(labels) || CV_MAT_TYPE(labels->type) != CV_32SC1 ||
+ labels->cols != 1 && labels->rows != 1 || labels->cols + labels->rows - 1 != nsamples ))
+ CV_ERROR( CV_StsBadArg,
+ "labels array (when passed) must be a valid 1d integer vector of <sample_count> elements" );
+
+ if( nsamples <= nclusters )
+ CV_ERROR( CV_StsOutOfRange,
+ "The number of samples should be greater than the number of clusters" );
+
+ CV_CALL( log_weight_div_det = cvCreateMat( 1, nclusters, CV_64FC1 ));
+ CV_CALL( probs = cvCreateMat( nsamples, nclusters, CV_64FC1 ));
+ CV_CALL( means = cvCreateMat( nclusters, dims, CV_64FC1 ));
+ CV_CALL( weights = cvCreateMat( 1, nclusters, CV_64FC1 ));
+ CV_CALL( inv_eigen_values = cvCreateMat( nclusters,
+ params.cov_mat_type == COV_MAT_SPHERICAL ? 1 : dims, CV_64FC1 ));
+ CV_CALL( covs = (CvMat**)cvAlloc( nclusters * sizeof(*covs) ));
+ CV_CALL( cov_rotate_mats = (CvMat**)cvAlloc( nclusters * sizeof(cov_rotate_mats[0]) ));
+
+ for( i = 0; i < nclusters; i++ )
+ {
+ CV_CALL( covs[i] = cvCreateMat( dims, dims, CV_64FC1 ));
+ CV_CALL( cov_rotate_mats[i] = cvCreateMat( dims, dims, CV_64FC1 ));
+ cvZero( cov_rotate_mats[i] );
+ }
+
+ init_em( train_data );
+ log_likelihood = run_em( train_data );
+ if( log_likelihood <= -DBL_MAX/10000. )
+ EXIT;
+
+ if( labels )
+ {
+ if( nclusters == 1 )
+ cvZero( labels );
+ else
+ {
+ CvMat sample = cvMat( 1, dims, CV_32F );
+ CvMat prob = cvMat( 1, nclusters, CV_64F );
+ int lstep = CV_IS_MAT_CONT(labels->type) ? 1 : labels->step/sizeof(int);
+
+ for( i = 0; i < nsamples; i++ )
+ {
+ int idx = sample_idx ? sample_idx->data.i[i] : i;
+ sample.data.ptr = _samples->data.ptr + _samples->step*idx;
+ prob.data.ptr = probs->data.ptr + probs->step*i;
+
+ labels->data.i[i*lstep] = cvRound(predict(&sample, &prob));
+ }
+ }
+ }
+
+ result = true;
+
+ __END__;
+
+ if( sample_idx != _sample_idx )
+ cvReleaseMat( &sample_idx );
+
+ cvFree( &train_data.data.ptr );
+
+ return result;
+}
+
+
+void CvEM::init_em( const CvVectors& train_data )
+{
+ CvMat *w = 0, *u = 0, *tcov = 0;
+
+ CV_FUNCNAME( "CvEM::init_em" );
+
+ __BEGIN__;
+
+ double maxval = 0;
+ int i, force_symm_plus = 0;
+ int nclusters = params.nclusters, nsamples = train_data.count, dims = train_data.dims;
+
+ if( params.start_step == START_AUTO_STEP || nclusters == 1 || nclusters == nsamples )
+ init_auto( train_data );
+ else if( params.start_step == START_M_STEP )
+ {
+ for( i = 0; i < nsamples; i++ )
+ {
+ CvMat prob;
+ cvGetRow( params.probs, &prob, i );
+ cvMaxS( &prob, 0., &prob );
+ cvMinMaxLoc( &prob, 0, &maxval );
+ if( maxval < FLT_EPSILON )
+ cvSet( &prob, cvScalar(1./nclusters) );
+ else
+ cvNormalize( &prob, &prob, 1., 0, CV_L1 );
+ }
+ EXIT; // do not preprocess covariation matrices,
+ // as in this case they are initialized at the first iteration of EM
+ }
+ else
+ {
+ CV_ASSERT( params.start_step == START_E_STEP && params.means );
+ if( params.weights && params.covs )
+ {
+ cvConvert( params.means, means );
+ cvReshape( weights, weights, 1, params.weights->rows );
+ cvConvert( params.weights, weights );
+ cvReshape( weights, weights, 1, 1 );
+ cvMaxS( weights, 0., weights );
+ cvMinMaxLoc( weights, 0, &maxval );
+ if( maxval < FLT_EPSILON )
+ cvSet( &weights, cvScalar(1./nclusters) );
+ cvNormalize( weights, weights, 1., 0, CV_L1 );
+ for( i = 0; i < nclusters; i++ )
+ CV_CALL( cvConvert( params.covs[i], covs[i] ));
+ force_symm_plus = 1;
+ }
+ else
+ init_auto( train_data );
+ }
+
+ CV_CALL( tcov = cvCreateMat( dims, dims, CV_64FC1 ));
+ CV_CALL( w = cvCreateMat( dims, dims, CV_64FC1 ));
+ if( params.cov_mat_type == COV_MAT_GENERIC )
+ CV_CALL( u = cvCreateMat( dims, dims, CV_64FC1 ));
+
+ for( i = 0; i < nclusters; i++ )
+ {
+ if( force_symm_plus )
+ {
+ cvTranspose( covs[i], tcov );
+ cvAddWeighted( covs[i], 0.5, tcov, 0.5, 0, tcov );
+ }
+ else
+ cvCopy( covs[i], tcov );
+ cvSVD( tcov, w, u, 0, CV_SVD_MODIFY_A + CV_SVD_U_T + CV_SVD_V_T );
+ if( params.cov_mat_type == COV_MAT_SPHERICAL )
+ cvSetIdentity( covs[i], cvScalar(cvTrace(w).val[0]/dims) );
+ else if( params.cov_mat_type == COV_MAT_DIAGONAL )
+ cvCopy( w, covs[i] );
+ else
+ {
+ // generic case: covs[i] = (u')'*max(w,0)*u'
+ cvGEMM( u, w, 1, 0, 0, tcov, CV_GEMM_A_T );
+ cvGEMM( tcov, u, 1, 0, 0, covs[i], 0 );
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &w );
+ cvReleaseMat( &u );
+ cvReleaseMat( &tcov );
+}
+
+
+void CvEM::init_auto( const CvVectors& train_data )
+{
+ CvMat* hdr = 0;
+ const void** vec = 0;
+ CvMat* class_ranges = 0;
+ CvMat* labels = 0;
+
+ CV_FUNCNAME( "CvEM::init_auto" );
+
+ __BEGIN__;
+
+ int nclusters = params.nclusters, nsamples = train_data.count, dims = train_data.dims;
+ int i, j;
+
+ if( nclusters == nsamples )
+ {
+ CvMat src = cvMat( 1, dims, CV_32F );
+ CvMat dst = cvMat( 1, dims, CV_64F );
+ for( i = 0; i < nsamples; i++ )
+ {
+ src.data.ptr = train_data.data.ptr[i];
+ dst.data.ptr = means->data.ptr + means->step*i;
+ cvConvert( &src, &dst );
+ cvZero( covs[i] );
+ cvSetIdentity( cov_rotate_mats[i] );
+ }
+ cvSetIdentity( probs );
+ cvSet( weights, cvScalar(1./nclusters) );
+ }
+ else
+ {
+ int max_count = 0;
+
+ CV_CALL( class_ranges = cvCreateMat( 1, nclusters+1, CV_32SC1 ));
+ if( nclusters > 1 )
+ {
+ CV_CALL( labels = cvCreateMat( 1, nsamples, CV_32SC1 ));
+ kmeans( train_data, nclusters, labels, cvTermCriteria( CV_TERMCRIT_ITER,
+ params.means ? 1 : 10, 0.5 ), params.means );
+ CV_CALL( cvSortSamplesByClasses( (const float**)train_data.data.fl,
+ labels, class_ranges->data.i ));
+ }
+ else
+ {
+ class_ranges->data.i[0] = 0;
+ class_ranges->data.i[1] = nsamples;
+ }
+
+ for( i = 0; i < nclusters; i++ )
+ {
+ int left = class_ranges->data.i[i], right = class_ranges->data.i[i+1];
+ max_count = MAX( max_count, right - left );
+ }
+ CV_CALL( hdr = (CvMat*)cvAlloc( max_count*sizeof(hdr[0]) ));
+ CV_CALL( vec = (const void**)cvAlloc( max_count*sizeof(vec[0]) ));
+ hdr[0] = cvMat( 1, dims, CV_32F );
+ for( i = 0; i < max_count; i++ )
+ {
+ vec[i] = hdr + i;
+ hdr[i] = hdr[0];
+ }
+
+ for( i = 0; i < nclusters; i++ )
+ {
+ int left = class_ranges->data.i[i], right = class_ranges->data.i[i+1];
+ int cluster_size = right - left;
+ CvMat avg;
+
+ if( cluster_size <= 0 )
+ continue;
+
+ for( j = left; j < right; j++ )
+ hdr[j - left].data.fl = train_data.data.fl[j];
+
+ CV_CALL( cvGetRow( means, &avg, i ));
+ CV_CALL( cvCalcCovarMatrix( vec, cluster_size, covs[i],
+ &avg, CV_COVAR_NORMAL | CV_COVAR_SCALE ));
+ weights->data.db[i] = (double)cluster_size/(double)nsamples;
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &class_ranges );
+ cvReleaseMat( &labels );
+ cvFree( &hdr );
+ cvFree( &vec );
+}
+
+
+void CvEM::kmeans( const CvVectors& train_data, int nclusters, CvMat* labels,
+ CvTermCriteria termcrit, const CvMat* centers0 )
+{
+ CvMat* centers = 0;
+ CvMat* old_centers = 0;
+ CvMat* counters = 0;
+
+ CV_FUNCNAME( "CvEM::kmeans" );
+
+ __BEGIN__;
+
+ CvRNG rng = cvRNG(-1);
+ int i, j, k, nsamples, dims;
+ int iter = 0;
+ double max_dist = DBL_MAX;
+
+ termcrit = cvCheckTermCriteria( termcrit, 1e-6, 100 );
+ termcrit.epsilon *= termcrit.epsilon;
+ nsamples = train_data.count;
+ dims = train_data.dims;
+ nclusters = MIN( nclusters, nsamples );
+
+ CV_CALL( centers = cvCreateMat( nclusters, dims, CV_64FC1 ));
+ CV_CALL( old_centers = cvCreateMat( nclusters, dims, CV_64FC1 ));
+ CV_CALL( counters = cvCreateMat( 1, nclusters, CV_32SC1 ));
+ cvZero( old_centers );
+
+ if( centers0 )
+ {
+ CV_CALL( cvConvert( centers0, centers ));
+ }
+ else
+ {
+ for( i = 0; i < nsamples; i++ )
+ labels->data.i[i] = i*nclusters/nsamples;
+ cvRandShuffle( labels, &rng );
+ }
+
+ for( ;; )
+ {
+ CvMat* temp;
+
+ if( iter > 0 || centers0 )
+ {
+ for( i = 0; i < nsamples; i++ )
+ {
+ const float* s = train_data.data.fl[i];
+ int k_best = 0;
+ double min_dist = DBL_MAX;
+
+ for( k = 0; k < nclusters; k++ )
+ {
+ const double* c = (double*)(centers->data.ptr + k*centers->step);
+ double dist = 0;
+
+ for( j = 0; j <= dims - 4; j += 4 )
+ {
+ double t0 = c[j] - s[j];
+ double t1 = c[j+1] - s[j+1];
+ dist += t0*t0 + t1*t1;
+ t0 = c[j+2] - s[j+2];
+ t1 = c[j+3] - s[j+3];
+ dist += t0*t0 + t1*t1;
+ }
+
+ for( ; j < dims; j++ )
+ {
+ double t = c[j] - s[j];
+ dist += t*t;
+ }
+
+ if( min_dist > dist )
+ {
+ min_dist = dist;
+ k_best = k;
+ }
+ }
+
+ labels->data.i[i] = k_best;
+ }
+ }
+
+ if( ++iter > termcrit.max_iter )
+ break;
+
+ CV_SWAP( centers, old_centers, temp );
+ cvZero( centers );
+ cvZero( counters );
+
+ // update centers
+ for( i = 0; i < nsamples; i++ )
+ {
+ const float* s = train_data.data.fl[i];
+ k = labels->data.i[i];
+ double* c = (double*)(centers->data.ptr + k*centers->step);
+
+ for( j = 0; j <= dims - 4; j += 4 )
+ {
+ double t0 = c[j] + s[j];
+ double t1 = c[j+1] + s[j+1];
+
+ c[j] = t0;
+ c[j+1] = t1;
+
+ t0 = c[j+2] + s[j+2];
+ t1 = c[j+3] + s[j+3];
+
+ c[j+2] = t0;
+ c[j+3] = t1;
+ }
+ for( ; j < dims; j++ )
+ c[j] += s[j];
+ counters->data.i[k]++;
+ }
+
+ if( iter > 1 )
+ max_dist = 0;
+
+ for( k = 0; k < nclusters; k++ )
+ {
+ double* c = (double*)(centers->data.ptr + k*centers->step);
+ if( counters->data.i[k] != 0 )
+ {
+ double scale = 1./counters->data.i[k];
+ for( j = 0; j < dims; j++ )
+ c[j] *= scale;
+ }
+ else
+ {
+ const float* s;
+ for( j = 0; j < 10; j++ )
+ {
+ i = cvRandInt( &rng ) % nsamples;
+ if( counters->data.i[labels->data.i[i]] > 1 )
+ break;
+ }
+ s = train_data.data.fl[i];
+ for( j = 0; j < dims; j++ )
+ c[j] = s[j];
+ }
+
+ if( iter > 1 )
+ {
+ double dist = 0;
+ const double* c_o = (double*)(old_centers->data.ptr + k*old_centers->step);
+ for( j = 0; j < dims; j++ )
+ {
+ double t = c[j] - c_o[j];
+ dist += t*t;
+ }
+ if( max_dist < dist )
+ max_dist = dist;
+ }
+ }
+
+ if( max_dist < termcrit.epsilon )
+ break;
+ }
+
+ cvZero( counters );
+ for( i = 0; i < nsamples; i++ )
+ counters->data.i[labels->data.i[i]]++;
+
+ // ensure that we do not have empty clusters
+ for( k = 0; k < nclusters; k++ )
+ if( counters->data.i[k] == 0 )
+ for(;;)
+ {
+ i = cvRandInt(&rng) % nsamples;
+ j = labels->data.i[i];
+ if( counters->data.i[j] > 1 )
+ {
+ labels->data.i[i] = k;
+ counters->data.i[j]--;
+ counters->data.i[k]++;
+ break;
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &centers );
+ cvReleaseMat( &old_centers );
+ cvReleaseMat( &counters );
+}
+
+
+/****************************************************************************************/
+/* log_weight_div_det[k] = -2*log(weights_k) + log(det(Sigma_k)))
+
+ covs[k] = cov_rotate_mats[k] * cov_eigen_values[k] * (cov_rotate_mats[k])'
+ cov_rotate_mats[k] are orthogonal matrices of eigenvectors and
+ cov_eigen_values[k] are diagonal matrices (represented by 1D vectors) of eigen values.
+
+ The <alpha_ik> is the probability of the vector x_i to belong to the k-th cluster:
+ <alpha_ik> ~ weights_k * exp{ -0.5[ln(det(Sigma_k)) + (x_i - mu_k)' Sigma_k^(-1) (x_i - mu_k)] }
+ We calculate these probabilities here by the equivalent formulae:
+ Denote
+ S_ik = -0.5(log(det(Sigma_k)) + (x_i - mu_k)' Sigma_k^(-1) (x_i - mu_k)) + log(weights_k),
+ M_i = max_k S_ik = S_qi, so that the q-th class is the one where maximum reaches. Then
+ alpha_ik = exp{ S_ik - M_i } / ( 1 + sum_j!=q exp{ S_ji - M_i })
+*/
+double CvEM::run_em( const CvVectors& train_data )
+{
+ CvMat* centered_sample = 0;
+ CvMat* covs_item = 0;
+ CvMat* log_det = 0;
+ CvMat* log_weights = 0;
+ CvMat* cov_eigen_values = 0;
+ CvMat* samples = 0;
+ CvMat* sum_probs = 0;
+ log_likelihood = -DBL_MAX;
+
+ CV_FUNCNAME( "CvEM::run_em" );
+ __BEGIN__;
+
+ int nsamples = train_data.count, dims = train_data.dims, nclusters = params.nclusters;
+ double min_variation = FLT_EPSILON;
+ double min_det_value = MAX( DBL_MIN, pow( min_variation, dims ));
+ double likelihood_bias = -CV_LOG2PI * (double)nsamples * (double)dims / 2., _log_likelihood = -DBL_MAX;
+ int start_step = params.start_step;
+
+ int i, j, k, n;
+ int is_general = 0, is_diagonal = 0, is_spherical = 0;
+ double prev_log_likelihood = -DBL_MAX / 1000., det, d;
+ CvMat whdr, iwhdr, diag, *w, *iw;
+ double* w_data;
+ double* sp_data;
+
+ if( nclusters == 1 )
+ {
+ double log_weight;
+ CV_CALL( cvSet( probs, cvScalar(1.)) );
+
+ if( params.cov_mat_type == COV_MAT_SPHERICAL )
+ {
+ d = cvTrace(*covs).val[0]/dims;
+ d = MAX( d, FLT_EPSILON );
+ inv_eigen_values->data.db[0] = 1./d;
+ log_weight = pow( d, dims*0.5 );
+ }
+ else
+ {
+ w_data = inv_eigen_values->data.db;
+
+ if( params.cov_mat_type == COV_MAT_GENERIC )
+ cvSVD( *covs, inv_eigen_values, *cov_rotate_mats, 0, CV_SVD_U_T );
+ else
+ cvTranspose( cvGetDiag(*covs, &diag), inv_eigen_values );
+
+ cvMaxS( inv_eigen_values, FLT_EPSILON, inv_eigen_values );
+ for( j = 0, det = 1.; j < dims; j++ )
+ det *= w_data[j];
+ log_weight = sqrt(det);
+ cvDiv( 0, inv_eigen_values, inv_eigen_values );
+ }
+
+ log_weight_div_det->data.db[0] = -2*log(weights->data.db[0]/log_weight);
+ log_likelihood = DBL_MAX/1000.;
+ EXIT;
+ }
+
+ if( params.cov_mat_type == COV_MAT_GENERIC )
+ is_general = 1;
+ else if( params.cov_mat_type == COV_MAT_DIAGONAL )
+ is_diagonal = 1;
+ else if( params.cov_mat_type == COV_MAT_SPHERICAL )
+ is_spherical = 1;
+ /* In the case of <cov_mat_type> == COV_MAT_DIAGONAL, the k-th row of cov_eigen_values
+ contains the diagonal elements (variations). In the case of
+ <cov_mat_type> == COV_MAT_SPHERICAL - the 0-ths elements of the vectors cov_eigen_values[k]
+ are to be equal to the mean of the variations over all the dimensions. */
+
+ CV_CALL( log_det = cvCreateMat( 1, nclusters, CV_64FC1 ));
+ CV_CALL( log_weights = cvCreateMat( 1, nclusters, CV_64FC1 ));
+ CV_CALL( covs_item = cvCreateMat( dims, dims, CV_64FC1 ));
+ CV_CALL( centered_sample = cvCreateMat( 1, dims, CV_64FC1 ));
+ CV_CALL( cov_eigen_values = cvCreateMat( inv_eigen_values->rows, inv_eigen_values->cols, CV_64FC1 ));
+ CV_CALL( samples = cvCreateMat( nsamples, dims, CV_64FC1 ));
+ CV_CALL( sum_probs = cvCreateMat( 1, nclusters, CV_64FC1 ));
+ sp_data = sum_probs->data.db;
+
+ // copy the training data into double-precision matrix
+ for( i = 0; i < nsamples; i++ )
+ {
+ const float* src = train_data.data.fl[i];
+ double* dst = (double*)(samples->data.ptr + samples->step*i);
+
+ for( j = 0; j < dims; j++ )
+ dst[j] = src[j];
+ }
+
+ if( start_step != START_M_STEP )
+ {
+ for( k = 0; k < nclusters; k++ )
+ {
+ if( is_general || is_diagonal )
+ {
+ w = cvGetRow( cov_eigen_values, &whdr, k );
+ if( is_general )
+ cvSVD( covs[k], w, cov_rotate_mats[k], 0, CV_SVD_U_T );
+ else
+ cvTranspose( cvGetDiag( covs[k], &diag ), w );
+ w_data = w->data.db;
+ for( j = 0, det = 1.; j < dims; j++ )
+ det *= w_data[j];
+ if( det < min_det_value )
+ {
+ if( start_step == START_AUTO_STEP )
+ det = min_det_value;
+ else
+ EXIT;
+ }
+ log_det->data.db[k] = det;
+ }
+ else
+ {
+ d = cvTrace(covs[k]).val[0]/(double)dims;
+ if( d < min_variation )
+ {
+ if( start_step == START_AUTO_STEP )
+ d = min_variation;
+ else
+ EXIT;
+ }
+ cov_eigen_values->data.db[k] = d;
+ log_det->data.db[k] = d;
+ }
+ }
+
+ cvLog( log_det, log_det );
+ if( is_spherical )
+ cvScale( log_det, log_det, dims );
+ }
+
+ for( n = 0; n < params.term_crit.max_iter; n++ )
+ {
+ if( n > 0 || start_step != START_M_STEP )
+ {
+ // e-step: compute probs_ik from means_k, covs_k and weights_k.
+ CV_CALL(cvLog( weights, log_weights ));
+
+ // S_ik = -0.5[log(det(Sigma_k)) + (x_i - mu_k)' Sigma_k^(-1) (x_i - mu_k)] + log(weights_k)
+ for( k = 0; k < nclusters; k++ )
+ {
+ CvMat* u = cov_rotate_mats[k];
+ const double* mean = (double*)(means->data.ptr + means->step*k);
+ w = cvGetRow( cov_eigen_values, &whdr, k );
+ iw = cvGetRow( inv_eigen_values, &iwhdr, k );
+ cvDiv( 0, w, iw );
+
+ w_data = (double*)(inv_eigen_values->data.ptr + inv_eigen_values->step*k);
+
+ for( i = 0; i < nsamples; i++ )
+ {
+ double *csample = centered_sample->data.db, p = log_det->data.db[k];
+ const double* sample = (double*)(samples->data.ptr + samples->step*i);
+ double* pp = (double*)(probs->data.ptr + probs->step*i);
+ for( j = 0; j < dims; j++ )
+ csample[j] = sample[j] - mean[j];
+ if( is_general )
+ cvGEMM( centered_sample, u, 1, 0, 0, centered_sample, CV_GEMM_B_T );
+ for( j = 0; j < dims; j++ )
+ p += csample[j]*csample[j]*w_data[is_spherical ? 0 : j];
+ pp[k] = -0.5*p + log_weights->data.db[k];
+
+ // S_ik <- S_ik - max_j S_ij
+ if( k == nclusters - 1 )
+ {
+ double max_val = 0;
+ for( j = 0; j < nclusters; j++ )
+ max_val = MAX( max_val, pp[j] );
+ for( j = 0; j < nclusters; j++ )
+ pp[j] -= max_val;
+ }
+ }
+ }
+
+ CV_CALL(cvExp( probs, probs )); // exp( S_ik )
+ cvZero( sum_probs );
+
+ // alpha_ik = exp( S_ik ) / sum_j exp( S_ij ),
+ // log_likelihood = sum_i log (sum_j exp(S_ij))
+ for( i = 0, _log_likelihood = likelihood_bias; i < nsamples; i++ )
+ {
+ double* pp = (double*)(probs->data.ptr + probs->step*i), sum = 0;
+ for( j = 0; j < nclusters; j++ )
+ sum += pp[j];
+ sum = 1./MAX( sum, DBL_EPSILON );
+ for( j = 0; j < nclusters; j++ )
+ {
+ double p = pp[j] *= sum;
+ sp_data[j] += p;
+ }
+ _log_likelihood -= log( sum );
+ }
+
+ // check termination criteria
+ if( fabs( (_log_likelihood - prev_log_likelihood) / prev_log_likelihood ) < params.term_crit.epsilon )
+ break;
+ prev_log_likelihood = _log_likelihood;
+ }
+
+ // m-step: update means_k, covs_k and weights_k from probs_ik
+ cvGEMM( probs, samples, 1, 0, 0, means, CV_GEMM_A_T );
+
+ for( k = 0; k < nclusters; k++ )
+ {
+ double sum = sp_data[k], inv_sum = 1./sum;
+ CvMat* cov = covs[k], _mean, _sample;
+
+ w = cvGetRow( cov_eigen_values, &whdr, k );
+ w_data = w->data.db;
+ cvGetRow( means, &_mean, k );
+ cvGetRow( samples, &_sample, k );
+
+ // update weights_k
+ weights->data.db[k] = sum;
+
+ // update means_k
+ cvScale( &_mean, &_mean, inv_sum );
+
+ // compute covs_k
+ cvZero( cov );
+ cvZero( w );
+
+ for( i = 0; i < nsamples; i++ )
+ {
+ double p = probs->data.db[i*nclusters + k]*inv_sum;
+ _sample.data.db = (double*)(samples->data.ptr + samples->step*i);
+
+ if( is_general )
+ {
+ cvMulTransposed( &_sample, covs_item, 1, &_mean );
+ cvScaleAdd( covs_item, cvRealScalar(p), cov, cov );
+ }
+ else
+ for( j = 0; j < dims; j++ )
+ {
+ double val = _sample.data.db[j] - _mean.data.db[j];
+ w_data[is_spherical ? 0 : j] += p*val*val;
+ }
+ }
+
+ if( is_spherical )
+ {
+ d = w_data[0]/(double)dims;
+ d = MAX( d, min_variation );
+ w->data.db[0] = d;
+ log_det->data.db[k] = d;
+ }
+ else
+ {
+ if( is_general )
+ cvSVD( cov, w, cov_rotate_mats[k], 0, CV_SVD_U_T );
+ cvMaxS( w, min_variation, w );
+ for( j = 0, det = 1.; j < dims; j++ )
+ det *= w_data[j];
+ log_det->data.db[k] = det;
+ }
+ }
+
+ cvConvertScale( weights, weights, 1./(double)nsamples, 0 );
+ cvMaxS( weights, DBL_MIN, weights );
+
+ cvLog( log_det, log_det );
+ if( is_spherical )
+ cvScale( log_det, log_det, dims );
+ } // end of iteration process
+
+ //log_weight_div_det[k] = -2*log(weights_k/det(Sigma_k))^0.5) = -2*log(weights_k) + log(det(Sigma_k)))
+ if( log_weight_div_det )
+ {
+ cvScale( log_weights, log_weight_div_det, -2 );
+ cvAdd( log_weight_div_det, log_det, log_weight_div_det );
+ }
+
+ /* Now finalize all the covariation matrices:
+ 1) if <cov_mat_type> == COV_MAT_DIAGONAL we used array of <w> as diagonals.
+ Now w[k] should be copied back to the diagonals of covs[k];
+ 2) if <cov_mat_type> == COV_MAT_SPHERICAL we used the 0-th element of w[k]
+ as an average variation in each cluster. The value of the 0-th element of w[k]
+ should be copied to the all of the diagonal elements of covs[k]. */
+ if( is_spherical )
+ {
+ for( k = 0; k < nclusters; k++ )
+ cvSetIdentity( covs[k], cvScalar(cov_eigen_values->data.db[k]));
+ }
+ else if( is_diagonal )
+ {
+ for( k = 0; k < nclusters; k++ )
+ cvTranspose( cvGetRow( cov_eigen_values, &whdr, k ),
+ cvGetDiag( covs[k], &diag ));
+ }
+ cvDiv( 0, cov_eigen_values, inv_eigen_values );
+
+ log_likelihood = _log_likelihood;
+
+ __END__;
+
+ cvReleaseMat( &log_det );
+ cvReleaseMat( &log_weights );
+ cvReleaseMat( &covs_item );
+ cvReleaseMat( &centered_sample );
+ cvReleaseMat( &cov_eigen_values );
+ cvReleaseMat( &samples );
+ cvReleaseMat( &sum_probs );
+
+ return log_likelihood;
+}
+
+
+int CvEM::get_nclusters() const
+{
+ return params.nclusters;
+}
+
+const CvMat* CvEM::get_means() const
+{
+ return means;
+}
+
+const CvMat** CvEM::get_covs() const
+{
+ return (const CvMat**)covs;
+}
+
+const CvMat* CvEM::get_weights() const
+{
+ return weights;
+}
+
+const CvMat* CvEM::get_probs() const
+{
+ return probs;
+}
+
+/* End of file. */
diff --git a/ml/src/mlestimate.cpp b/ml/src/mlestimate.cpp
new file mode 100644
index 0000000..1d03a44
--- /dev/null
+++ b/ml/src/mlestimate.cpp
@@ -0,0 +1,728 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_ml.h"
+
+#if 0
+
+ML_IMPL int
+icvCmpIntegers (const void* a, const void* b) {return *(const int*)a - *(const int*)b;}
+
+/****************************************************************************************\
+* Cross-validation algorithms realizations *
+\****************************************************************************************/
+
+// Return pointer to trainIdx. Function DOES NOT FILL this matrix!
+ML_IMPL
+const CvMat* cvCrossValGetTrainIdxMatrix (const CvStatModel* estimateModel)
+{
+ CvMat* result = NULL;
+
+ CV_FUNCNAME ("cvCrossValGetTrainIdxMatrix");
+ __BEGIN__
+
+ if (!CV_IS_CROSSVAL(estimateModel))
+ {
+ CV_ERROR (CV_StsBadArg, "Pointer point to not CvCrossValidationModel");
+ }
+
+ result = ((CvCrossValidationModel*)estimateModel)->sampleIdxTrain;
+
+ __END__
+
+ return result;
+} // End of cvCrossValGetTrainIdxMatrix
+
+/****************************************************************************************/
+// Return pointer to checkIdx. Function DOES NOT FILL this matrix!
+ML_IMPL
+const CvMat* cvCrossValGetCheckIdxMatrix (const CvStatModel* estimateModel)
+{
+ CvMat* result = NULL;
+
+ CV_FUNCNAME ("cvCrossValGetCheckIdxMatrix");
+ __BEGIN__
+
+ if (!CV_IS_CROSSVAL (estimateModel))
+ {
+ CV_ERROR (CV_StsBadArg, "Pointer point to not CvCrossValidationModel");
+ }
+
+ result = ((CvCrossValidationModel*)estimateModel)->sampleIdxEval;
+
+ __END__
+
+ return result;
+} // End of cvCrossValGetCheckIdxMatrix
+
+/****************************************************************************************/
+// Create new Idx-matrix for next classifiers training and return code of result.
+// Result is 0 if function can't make next step (error input or folds are finished),
+// it is 1 if all was correct, and it is 2 if current fold wasn't' checked.
+ML_IMPL
+int cvCrossValNextStep (CvStatModel* estimateModel)
+{
+ int result = 0;
+
+ CV_FUNCNAME ("cvCrossValGetNextTrainIdx");
+ __BEGIN__
+
+ CvCrossValidationModel* crVal = (CvCrossValidationModel*) estimateModel;
+ int k, fold;
+
+ if (!CV_IS_CROSSVAL (estimateModel))
+ {
+ CV_ERROR (CV_StsBadArg, "Pointer point to not CvCrossValidationModel");
+ }
+
+ fold = ++crVal->current_fold;
+
+ if (fold >= crVal->folds_all)
+ {
+ if (fold == crVal->folds_all)
+ EXIT;
+ else
+ {
+ CV_ERROR (CV_StsInternal, "All iterations has end long ago");
+ }
+ }
+
+ k = crVal->folds[fold + 1] - crVal->folds[fold];
+ crVal->sampleIdxTrain->data.i = crVal->sampleIdxAll + crVal->folds[fold + 1];
+ crVal->sampleIdxTrain->cols = crVal->samples_all - k;
+ crVal->sampleIdxEval->data.i = crVal->sampleIdxAll + crVal->folds[fold];
+ crVal->sampleIdxEval->cols = k;
+
+ if (crVal->is_checked)
+ {
+ crVal->is_checked = 0;
+ result = 1;
+ }
+ else
+ {
+ result = 2;
+ }
+
+ __END__
+
+ return result;
+}
+
+/****************************************************************************************/
+// Do checking part of loop of cross-validations metod.
+ML_IMPL
+void cvCrossValCheckClassifier (CvStatModel* estimateModel,
+ const CvStatModel* model,
+ const CvMat* trainData,
+ int sample_t_flag,
+ const CvMat* trainClasses)
+{
+ CV_FUNCNAME ("cvCrossValCheckClassifier ");
+ __BEGIN__
+
+ CvCrossValidationModel* crVal = (CvCrossValidationModel*) estimateModel;
+ int i, j, k;
+ int* data;
+ float* responses_fl;
+ int step;
+ float* responses_result;
+ int* responses_i;
+ double te, te1;
+ double sum_c, sum_p, sum_pp, sum_cp, sum_cc, sq_err;
+
+// Check input data to correct values.
+ if (!CV_IS_CROSSVAL (estimateModel))
+ {
+ CV_ERROR (CV_StsBadArg,"First parameter point to not CvCrossValidationModel");
+ }
+ if (!CV_IS_STAT_MODEL (model))
+ {
+ CV_ERROR (CV_StsBadArg, "Second parameter point to not CvStatModel");
+ }
+ if (!CV_IS_MAT (trainData))
+ {
+ CV_ERROR (CV_StsBadArg, "Third parameter point to not CvMat");
+ }
+ if (!CV_IS_MAT (trainClasses))
+ {
+ CV_ERROR (CV_StsBadArg, "Fifth parameter point to not CvMat");
+ }
+ if (crVal->is_checked)
+ {
+ CV_ERROR (CV_StsInternal, "This iterations already was checked");
+ }
+
+// Initialize.
+ k = crVal->sampleIdxEval->cols;
+ data = crVal->sampleIdxEval->data.i;
+
+// Eval tested feature vectors.
+ CV_CALL (cvStatModelMultiPredict (model, trainData, sample_t_flag,
+ crVal->predict_results, NULL, crVal->sampleIdxEval));
+// Count number if correct results.
+ responses_result = crVal->predict_results->data.fl;
+ if (crVal->is_regression)
+ {
+ sum_c = sum_p = sum_pp = sum_cp = sum_cc = sq_err = 0;
+ if (CV_MAT_TYPE (trainClasses->type) == CV_32FC1)
+ {
+ responses_fl = trainClasses->data.fl;
+ step = trainClasses->rows == 1 ? 1 : trainClasses->step / sizeof(float);
+ for (i = 0; i < k; i++)
+ {
+ te = responses_result[*data];
+ te1 = responses_fl[*data * step];
+ sum_c += te1;
+ sum_p += te;
+ sum_cc += te1 * te1;
+ sum_pp += te * te;
+ sum_cp += te1 * te;
+ te -= te1;
+ sq_err += te * te;
+
+ data++;
+ }
+ }
+ else
+ {
+ responses_i = trainClasses->data.i;
+ step = trainClasses->rows == 1 ? 1 : trainClasses->step / sizeof(int);
+ for (i = 0; i < k; i++)
+ {
+ te = responses_result[*data];
+ te1 = responses_i[*data * step];
+ sum_c += te1;
+ sum_p += te;
+ sum_cc += te1 * te1;
+ sum_pp += te * te;
+ sum_cp += te1 * te;
+ te -= te1;
+ sq_err += te * te;
+
+ data++;
+ }
+ }
+ // Fixing new internal values of accuracy.
+ crVal->sum_correct += sum_c;
+ crVal->sum_predict += sum_p;
+ crVal->sum_cc += sum_cc;
+ crVal->sum_pp += sum_pp;
+ crVal->sum_cp += sum_cp;
+ crVal->sq_error += sq_err;
+ }
+ else
+ {
+ if (CV_MAT_TYPE (trainClasses->type) == CV_32FC1)
+ {
+ responses_fl = trainClasses->data.fl;
+ step = trainClasses->rows == 1 ? 1 : trainClasses->step / sizeof(float);
+ for (i = 0, j = 0; i < k; i++)
+ {
+ if (cvRound (responses_result[*data]) == cvRound (responses_fl[*data * step]))
+ j++;
+ data++;
+ }
+ }
+ else
+ {
+ responses_i = trainClasses->data.i;
+ step = trainClasses->rows == 1 ? 1 : trainClasses->step / sizeof(int);
+ for (i = 0, j = 0; i < k; i++)
+ {
+ if (cvRound (responses_result[*data]) == responses_i[*data * step])
+ j++;
+ data++;
+ }
+ }
+ // Fixing new internal values of accuracy.
+ crVal->correct_results += j;
+ }
+// Fixing that this fold already checked.
+ crVal->all_results += k;
+ crVal->is_checked = 1;
+
+ __END__
+} // End of cvCrossValCheckClassifier
+
+/****************************************************************************************/
+// Return current accuracy.
+ML_IMPL
+float cvCrossValGetResult (const CvStatModel* estimateModel,
+ float* correlation)
+{
+ float result = 0;
+
+ CV_FUNCNAME ("cvCrossValGetResult");
+ __BEGIN__
+
+ double te, te1;
+ CvCrossValidationModel* crVal = (CvCrossValidationModel*)estimateModel;
+
+ if (!CV_IS_CROSSVAL (estimateModel))
+ {
+ CV_ERROR (CV_StsBadArg, "Pointer point to not CvCrossValidationModel");
+ }
+
+ if (crVal->all_results)
+ {
+ if (crVal->is_regression)
+ {
+ result = ((float)crVal->sq_error) / crVal->all_results;
+ if (correlation)
+ {
+ te = crVal->all_results * crVal->sum_cp -
+ crVal->sum_correct * crVal->sum_predict;
+ te *= te;
+ te1 = (crVal->all_results * crVal->sum_cc -
+ crVal->sum_correct * crVal->sum_correct) *
+ (crVal->all_results * crVal->sum_pp -
+ crVal->sum_predict * crVal->sum_predict);
+ *correlation = (float)(te / te1);
+
+ }
+ }
+ else
+ {
+ result = ((float)crVal->correct_results) / crVal->all_results;
+ }
+ }
+
+ __END__
+
+ return result;
+}
+
+/****************************************************************************************/
+// Reset cross-validation EstimateModel to state the same as it was immidiatly after
+// its creating.
+ML_IMPL
+void cvCrossValReset (CvStatModel* estimateModel)
+{
+ CV_FUNCNAME ("cvCrossValReset");
+ __BEGIN__
+
+ CvCrossValidationModel* crVal = (CvCrossValidationModel*)estimateModel;
+
+ if (!CV_IS_CROSSVAL (estimateModel))
+ {
+ CV_ERROR (CV_StsBadArg, "Pointer point to not CvCrossValidationModel");
+ }
+
+ crVal->current_fold = -1;
+ crVal->is_checked = 1;
+ crVal->all_results = 0;
+ crVal->correct_results = 0;
+ crVal->sq_error = 0;
+ crVal->sum_correct = 0;
+ crVal->sum_predict = 0;
+ crVal->sum_cc = 0;
+ crVal->sum_pp = 0;
+ crVal->sum_cp = 0;
+
+ __END__
+}
+
+/****************************************************************************************/
+// This function is standart CvStatModel field to release cross-validation EstimateModel.
+ML_IMPL
+void cvReleaseCrossValidationModel (CvStatModel** model)
+{
+ CvCrossValidationModel* pModel;
+
+ CV_FUNCNAME ("cvReleaseCrossValidationModel");
+ __BEGIN__
+
+ if (!model)
+ {
+ CV_ERROR (CV_StsNullPtr, "");
+ }
+
+ pModel = (CvCrossValidationModel*)*model;
+ if (!pModel)
+ {
+ return;
+ }
+ if (!CV_IS_CROSSVAL (pModel))
+ {
+ CV_ERROR (CV_StsBadArg, "");
+ }
+
+ cvFree (&pModel->sampleIdxAll);
+ cvFree (&pModel->folds);
+ cvReleaseMat (&pModel->sampleIdxEval);
+ cvReleaseMat (&pModel->sampleIdxTrain);
+ cvReleaseMat (&pModel->predict_results);
+
+ cvFree (model);
+
+ __END__
+} // End of cvReleaseCrossValidationModel.
+
+/****************************************************************************************/
+// This function create cross-validation EstimateModel.
+ML_IMPL CvStatModel*
+cvCreateCrossValidationEstimateModel(
+ int samples_all,
+ const CvStatModelParams* estimateParams,
+ const CvMat* sampleIdx)
+{
+ CvStatModel* model = NULL;
+ CvCrossValidationModel* crVal = NULL;
+
+ CV_FUNCNAME ("cvCreateCrossValidationEstimateModel");
+ __BEGIN__
+
+ int k_fold = 10;
+
+ int i, j, k, s_len;
+ int samples_selected;
+ CvRNG rng;
+ CvRNG* prng;
+ int* res_s_data;
+ int* te_s_data;
+ int* folds;
+
+ rng = cvRNG(cvGetTickCount());
+ cvRandInt (&rng); cvRandInt (&rng); cvRandInt (&rng); cvRandInt (&rng);
+// Check input parameters.
+ if (estimateParams)
+ k_fold = ((CvCrossValidationParams*)estimateParams)->k_fold;
+ if (!k_fold)
+ {
+ CV_ERROR (CV_StsBadArg, "Error in parameters of cross-validation (k_fold == 0)!");
+ }
+ if (samples_all <= 0)
+ {
+ CV_ERROR (CV_StsBadArg, "<samples_all> should be positive!");
+ }
+
+// Alloc memory and fill standart StatModel's fields.
+ CV_CALL (crVal = (CvCrossValidationModel*)cvCreateStatModel (
+ CV_STAT_MODEL_MAGIC_VAL | CV_CROSSVAL_MAGIC_VAL,
+ sizeof(CvCrossValidationModel),
+ cvReleaseCrossValidationModel,
+ NULL, NULL));
+ crVal->current_fold = -1;
+ crVal->folds_all = k_fold;
+ if (estimateParams && ((CvCrossValidationParams*)estimateParams)->is_regression)
+ crVal->is_regression = 1;
+ else
+ crVal->is_regression = 0;
+ if (estimateParams && ((CvCrossValidationParams*)estimateParams)->rng)
+ prng = ((CvCrossValidationParams*)estimateParams)->rng;
+ else
+ prng = &rng;
+
+ // Check and preprocess sample indices.
+ if (sampleIdx)
+ {
+ int s_step;
+ int s_type = 0;
+
+ if (!CV_IS_MAT (sampleIdx))
+ CV_ERROR (CV_StsBadArg, "Invalid sampleIdx array");
+
+ if (sampleIdx->rows != 1 && sampleIdx->cols != 1)
+ CV_ERROR (CV_StsBadSize, "sampleIdx array must be 1-dimensional");
+
+ s_len = sampleIdx->rows + sampleIdx->cols - 1;
+ s_step = sampleIdx->rows == 1 ?
+ 1 : sampleIdx->step / CV_ELEM_SIZE(sampleIdx->type);
+
+ s_type = CV_MAT_TYPE (sampleIdx->type);
+
+ switch (s_type)
+ {
+ case CV_8UC1:
+ case CV_8SC1:
+ {
+ uchar* s_data = sampleIdx->data.ptr;
+
+ // sampleIdx is array of 1's and 0's -
+ // i.e. it is a mask of the selected samples
+ if( s_len != samples_all )
+ CV_ERROR (CV_StsUnmatchedSizes,
+ "Sample mask should contain as many elements as the total number of samples");
+
+ samples_selected = 0;
+ for (i = 0; i < s_len; i++)
+ samples_selected += s_data[i * s_step] != 0;
+
+ if (samples_selected == 0)
+ CV_ERROR (CV_StsOutOfRange, "No samples is selected!");
+ }
+ s_len = samples_selected;
+ break;
+ case CV_32SC1:
+ if (s_len > samples_all)
+ CV_ERROR (CV_StsOutOfRange,
+ "sampleIdx array may not contain more elements than the total number of samples");
+ samples_selected = s_len;
+ break;
+ default:
+ CV_ERROR (CV_StsUnsupportedFormat, "Unsupported sampleIdx array data type "
+ "(it should be 8uC1, 8sC1 or 32sC1)");
+ }
+
+ // Alloc additional memory for internal Idx and fill it.
+/*!!*/ CV_CALL (res_s_data = crVal->sampleIdxAll =
+ (int*)cvAlloc (2 * s_len * sizeof(int)));
+
+ if (s_type < CV_32SC1)
+ {
+ uchar* s_data = sampleIdx->data.ptr;
+ for (i = 0; i < s_len; i++)
+ if (s_data[i * s_step])
+ {
+ *res_s_data++ = i;
+ }
+ res_s_data = crVal->sampleIdxAll;
+ }
+ else
+ {
+ int* s_data = sampleIdx->data.i;
+ int out_of_order = 0;
+
+ for (i = 0; i < s_len; i++)
+ {
+ res_s_data[i] = s_data[i * s_step];
+ if (i > 0 && res_s_data[i] < res_s_data[i - 1])
+ out_of_order = 1;
+ }
+
+ if (out_of_order)
+ qsort (res_s_data, s_len, sizeof(res_s_data[0]), icvCmpIntegers);
+
+ if (res_s_data[0] < 0 ||
+ res_s_data[s_len - 1] >= samples_all)
+ CV_ERROR (CV_StsBadArg, "There are out-of-range sample indices");
+ for (i = 1; i < s_len; i++)
+ if (res_s_data[i] <= res_s_data[i - 1])
+ CV_ERROR (CV_StsBadArg, "There are duplicated");
+ }
+ }
+ else // if (sampleIdx)
+ {
+ // Alloc additional memory for internal Idx and fill it.
+ s_len = samples_all;
+ CV_CALL (res_s_data = crVal->sampleIdxAll = (int*)cvAlloc (2 * s_len * sizeof(int)));
+ for (i = 0; i < s_len; i++)
+ {
+ *res_s_data++ = i;
+ }
+ res_s_data = crVal->sampleIdxAll;
+ } // if (sampleIdx) ... else
+
+// Resort internal Idx.
+ te_s_data = res_s_data + s_len;
+ for (i = s_len; i > 1; i--)
+ {
+ j = cvRandInt (prng) % i;
+ k = *(--te_s_data);
+ *te_s_data = res_s_data[j];
+ res_s_data[j] = k;
+ }
+
+// Duplicate resorted internal Idx.
+// It will be used to simplify operation of getting trainIdx.
+ te_s_data = res_s_data + s_len;
+ for (i = 0; i < s_len; i++)
+ {
+ *te_s_data++ = *res_s_data++;
+ }
+
+// Cut sampleIdxAll to parts.
+ if (k_fold > 0)
+ {
+ if (k_fold > s_len)
+ {
+ CV_ERROR (CV_StsBadArg,
+ "Error in parameters of cross-validation ('k_fold' > #samples)!");
+ }
+ folds = crVal->folds = (int*) cvAlloc ((k_fold + 1) * sizeof (int));
+ *folds++ = 0;
+ for (i = 1; i < k_fold; i++)
+ {
+ *folds++ = cvRound (i * s_len * 1. / k_fold);
+ }
+ *folds = s_len;
+ folds = crVal->folds;
+
+ crVal->max_fold_size = (s_len - 1) / k_fold + 1;
+ }
+ else
+ {
+ k = -k_fold;
+ crVal->max_fold_size = k;
+ if (k >= s_len)
+ {
+ CV_ERROR (CV_StsBadArg,
+ "Error in parameters of cross-validation (-'k_fold' > #samples)!");
+ }
+ crVal->folds_all = k = (s_len - 1) / k + 1;
+
+ folds = crVal->folds = (int*) cvAlloc ((k + 1) * sizeof (int));
+ for (i = 0; i < k; i++)
+ {
+ *folds++ = -i * k_fold;
+ }
+ *folds = s_len;
+ folds = crVal->folds;
+ }
+
+// Prepare other internal fields to working.
+ CV_CALL (crVal->predict_results = cvCreateMat (1, samples_all, CV_32FC1));
+ CV_CALL (crVal->sampleIdxEval = cvCreateMatHeader (1, 1, CV_32SC1));
+ CV_CALL (crVal->sampleIdxTrain = cvCreateMatHeader (1, 1, CV_32SC1));
+ crVal->sampleIdxEval->cols = 0;
+ crVal->sampleIdxTrain->cols = 0;
+ crVal->samples_all = s_len;
+ crVal->is_checked = 1;
+
+ crVal->getTrainIdxMat = cvCrossValGetTrainIdxMatrix;
+ crVal->getCheckIdxMat = cvCrossValGetCheckIdxMatrix;
+ crVal->nextStep = cvCrossValNextStep;
+ crVal->check = cvCrossValCheckClassifier;
+ crVal->getResult = cvCrossValGetResult;
+ crVal->reset = cvCrossValReset;
+
+ model = (CvStatModel*)crVal;
+
+ __END__
+
+ if (!model)
+ {
+ cvReleaseCrossValidationModel ((CvStatModel**)&crVal);
+ }
+
+ return model;
+} // End of cvCreateCrossValidationEstimateModel
+
+
+/****************************************************************************************\
+* Extended interface with backcalls for models *
+\****************************************************************************************/
+ML_IMPL float
+cvCrossValidation (const CvMat* trueData,
+ int tflag,
+ const CvMat* trueClasses,
+ CvStatModel* (*createClassifier) (const CvMat*,
+ int,
+ const CvMat*,
+ const CvClassifierTrainParams*,
+ const CvMat*,
+ const CvMat*,
+ const CvMat*,
+ const CvMat*),
+ const CvClassifierTrainParams* estimateParams,
+ const CvClassifierTrainParams* trainParams,
+ const CvMat* compIdx,
+ const CvMat* sampleIdx,
+ CvStatModel** pCrValModel,
+ const CvMat* typeMask,
+ const CvMat* missedMeasurementMask)
+{
+ CvCrossValidationModel* crVal = NULL;
+ float result = 0;
+ CvStatModel* pClassifier = NULL;
+
+ CV_FUNCNAME ("cvCrossValidation");
+ __BEGIN__
+
+ const CvMat* trainDataIdx;
+ int samples_all;
+
+// checking input data
+ if ((createClassifier) == NULL)
+ {
+ CV_ERROR (CV_StsNullPtr, "Null pointer to functiion which create classifier");
+ }
+ if (pCrValModel && *pCrValModel && !CV_IS_CROSSVAL(*pCrValModel))
+ {
+ CV_ERROR (CV_StsBadArg,
+ "<pCrValModel> point to not cross-validation model");
+ }
+
+// initialization
+ if (pCrValModel && *pCrValModel)
+ {
+ crVal = (CvCrossValidationModel*)*pCrValModel;
+ crVal->reset ((CvStatModel*)crVal);
+ }
+ else
+ {
+ samples_all = ((tflag) ? trueData->rows : trueData->cols);
+ CV_CALL (crVal = (CvCrossValidationModel*)
+ cvCreateCrossValidationEstimateModel (samples_all, estimateParams, sampleIdx));
+ }
+
+ CV_CALL (trainDataIdx = crVal->getTrainIdxMat ((CvStatModel*)crVal));
+
+// operation loop
+ for (; crVal->nextStep((CvStatModel*)crVal) != 0; )
+ {
+ CV_CALL (pClassifier = createClassifier (trueData, tflag, trueClasses,
+ trainParams, compIdx, trainDataIdx, typeMask, missedMeasurementMask));
+ CV_CALL (crVal->check ((CvStatModel*)crVal, pClassifier,
+ trueData, tflag, trueClasses));
+
+ pClassifier->release (&pClassifier);
+ }
+
+// Get result and fill output field.
+ CV_CALL (result = crVal->getResult ((CvStatModel*)crVal, 0));
+
+ if (pCrValModel && !*pCrValModel)
+ *pCrValModel = (CvStatModel*)crVal;
+
+ __END__
+
+// Free all memory that should be freed.
+ if (pClassifier)
+ pClassifier->release (&pClassifier);
+ if (crVal && (!pCrValModel || !*pCrValModel))
+ crVal->release ((CvStatModel**)&crVal);
+
+ return result;
+} // End of cvCrossValidation
+
+#endif
+
+/* End of file */
diff --git a/ml/src/mlknearest.cpp b/ml/src/mlknearest.cpp
new file mode 100644
index 0000000..348d5b3
--- /dev/null
+++ b/ml/src/mlknearest.cpp
@@ -0,0 +1,401 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_ml.h"
+
+/****************************************************************************************\
+* K-Nearest Neighbors Classifier *
+\****************************************************************************************/
+
+// k Nearest Neighbors
+CvKNearest::CvKNearest()
+{
+ samples = 0;
+ clear();
+}
+
+
+CvKNearest::~CvKNearest()
+{
+ clear();
+}
+
+
+CvKNearest::CvKNearest( const CvMat* _train_data, const CvMat* _responses,
+ const CvMat* _sample_idx, bool _is_regression, int _max_k )
+{
+ samples = 0;
+ train( _train_data, _responses, _sample_idx, _is_regression, _max_k, false );
+}
+
+
+void CvKNearest::clear()
+{
+ while( samples )
+ {
+ CvVectors* next_samples = samples->next;
+ cvFree( &samples->data.fl );
+ cvFree( &samples );
+ samples = next_samples;
+ }
+ var_count = 0;
+ total = 0;
+ max_k = 0;
+}
+
+
+int CvKNearest::get_max_k() const { return max_k; }
+
+int CvKNearest::get_var_count() const { return var_count; }
+
+bool CvKNearest::is_regression() const { return regression; }
+
+int CvKNearest::get_sample_count() const { return total; }
+
+bool CvKNearest::train( const CvMat* _train_data, const CvMat* _responses,
+ const CvMat* _sample_idx, bool _is_regression,
+ int _max_k, bool _update_base )
+{
+ bool ok = false;
+ CvMat* responses = 0;
+
+ CV_FUNCNAME( "CvKNearest::train" );
+
+ __BEGIN__;
+
+ CvVectors* _samples;
+ float** _data;
+ int _count, _dims, _dims_all, _rsize;
+
+ if( !_update_base )
+ clear();
+
+ // Prepare training data and related parameters.
+ // Treat categorical responses as ordered - to prevent class label compression and
+ // to enable entering new classes in the updates
+ CV_CALL( cvPrepareTrainData( "CvKNearest::train", _train_data, CV_ROW_SAMPLE,
+ _responses, CV_VAR_ORDERED, 0, _sample_idx, true, (const float***)&_data,
+ &_count, &_dims, &_dims_all, &responses, 0, 0 ));
+
+ if( _update_base && _dims != var_count )
+ CV_ERROR( CV_StsBadArg, "The newly added data have different dimensionality" );
+
+ if( !_update_base )
+ {
+ if( _max_k < 1 )
+ CV_ERROR( CV_StsOutOfRange, "max_k must be a positive number" );
+
+ regression = _is_regression;
+ var_count = _dims;
+ max_k = _max_k;
+ }
+
+ _rsize = _count*sizeof(float);
+ CV_CALL( _samples = (CvVectors*)cvAlloc( sizeof(*_samples) + _rsize ));
+ _samples->next = samples;
+ _samples->type = CV_32F;
+ _samples->data.fl = _data;
+ _samples->count = _count;
+ total += _count;
+
+ samples = _samples;
+ memcpy( _samples + 1, responses->data.fl, _rsize );
+
+ ok = true;
+
+ __END__;
+
+ return ok;
+}
+
+
+
+void CvKNearest::find_neighbors_direct( const CvMat* _samples, int k, int start, int end,
+ float* neighbor_responses, const float** neighbors, float* dist ) const
+{
+ int i, j, count = end - start, k1 = 0, k2 = 0, d = var_count;
+ CvVectors* s = samples;
+
+ for( ; s != 0; s = s->next )
+ {
+ int n = s->count;
+ for( j = 0; j < n; j++ )
+ {
+ for( i = 0; i < count; i++ )
+ {
+ double sum = 0;
+ Cv32suf si;
+ const float* v = s->data.fl[j];
+ const float* u = (float*)(_samples->data.ptr + _samples->step*(start + i));
+ Cv32suf* dd = (Cv32suf*)(dist + i*k);
+ float* nr;
+ const float** nn;
+ int t, ii, ii1;
+
+ for( t = 0; t <= d - 4; t += 4 )
+ {
+ double t0 = u[t] - v[t], t1 = u[t+1] - v[t+1];
+ double t2 = u[t+2] - v[t+2], t3 = u[t+3] - v[t+3];
+ sum += t0*t0 + t1*t1 + t2*t2 + t3*t3;
+ }
+
+ for( ; t < d; t++ )
+ {
+ double t0 = u[t] - v[t];
+ sum += t0*t0;
+ }
+
+ si.f = (float)sum;
+ for( ii = k1-1; ii >= 0; ii-- )
+ if( si.i > dd[ii].i )
+ break;
+ if( ii >= k-1 )
+ continue;
+
+ nr = neighbor_responses + i*k;
+ nn = neighbors ? neighbors + (start + i)*k : 0;
+ for( ii1 = k2 - 1; ii1 > ii; ii1-- )
+ {
+ dd[ii1+1].i = dd[ii1].i;
+ nr[ii1+1] = nr[ii1];
+ if( nn ) nn[ii1+1] = nn[ii1];
+ }
+ dd[ii+1].i = si.i;
+ nr[ii+1] = ((float*)(s + 1))[j];
+ if( nn )
+ nn[ii+1] = v;
+ }
+ k1 = MIN( k1+1, k );
+ k2 = MIN( k1, k-1 );
+ }
+ }
+}
+
+
+float CvKNearest::write_results( int k, int k1, int start, int end,
+ const float* neighbor_responses, const float* dist,
+ CvMat* _results, CvMat* _neighbor_responses,
+ CvMat* _dist, Cv32suf* sort_buf ) const
+{
+ float result = 0.f;
+ int i, j, j1, count = end - start;
+ double inv_scale = 1./k1;
+ int rstep = _results && !CV_IS_MAT_CONT(_results->type) ? _results->step/sizeof(result) : 1;
+
+ for( i = 0; i < count; i++ )
+ {
+ const Cv32suf* nr = (const Cv32suf*)(neighbor_responses + i*k);
+ float* dst;
+ float r;
+ if( _results || start+i == 0 )
+ {
+ if( regression )
+ {
+ double s = 0;
+ for( j = 0; j < k1; j++ )
+ s += nr[j].f;
+ r = (float)(s*inv_scale);
+ }
+ else
+ {
+ int prev_start = 0, best_count = 0, cur_count;
+ Cv32suf best_val;
+
+ for( j = 0; j < k1; j++ )
+ sort_buf[j].i = nr[j].i;
+
+ for( j = k1-1; j > 0; j-- )
+ {
+ bool swap_fl = false;
+ for( j1 = 0; j1 < j; j1++ )
+ if( sort_buf[j1].i > sort_buf[j1+1].i )
+ {
+ int t;
+ CV_SWAP( sort_buf[j1].i, sort_buf[j1+1].i, t );
+ swap_fl = true;
+ }
+ if( !swap_fl )
+ break;
+ }
+
+ best_val.i = 0;
+ for( j = 1; j <= k1; j++ )
+ if( j == k1 || sort_buf[j].i != sort_buf[j-1].i )
+ {
+ cur_count = j - prev_start;
+ if( best_count < cur_count )
+ {
+ best_count = cur_count;
+ best_val.i = sort_buf[j-1].i;
+ }
+ prev_start = j;
+ }
+ r = best_val.f;
+ }
+
+ if( start+i == 0 )
+ result = r;
+
+ if( _results )
+ _results->data.fl[(start + i)*rstep] = r;
+ }
+
+ if( _neighbor_responses )
+ {
+ dst = (float*)(_neighbor_responses->data.ptr +
+ (start + i)*_neighbor_responses->step);
+ for( j = 0; j < k1; j++ )
+ dst[j] = nr[j].f;
+ for( ; j < k; j++ )
+ dst[j] = 0.f;
+ }
+
+ if( _dist )
+ {
+ dst = (float*)(_dist->data.ptr + (start + i)*_dist->step);
+ for( j = 0; j < k1; j++ )
+ dst[j] = dist[j + i*k];
+ for( ; j < k; j++ )
+ dst[j] = 0.f;
+ }
+ }
+
+ return result;
+}
+
+
+
+float CvKNearest::find_nearest( const CvMat* _samples, int k, CvMat* _results,
+ const float** _neighbors, CvMat* _neighbor_responses, CvMat* _dist ) const
+{
+ float result = 0.f;
+ bool local_alloc = false;
+ float* buf = 0;
+ const int max_blk_count = 128, max_buf_sz = 1 << 12;
+
+ CV_FUNCNAME( "CvKNearest::find_nearest" );
+
+ __BEGIN__;
+
+ int i, count, count_scale, blk_count0, blk_count = 0, buf_sz, k1;
+
+ if( !samples )
+ CV_ERROR( CV_StsError, "The search tree must be constructed first using train method" );
+
+ if( !CV_IS_MAT(_samples) ||
+ CV_MAT_TYPE(_samples->type) != CV_32FC1 ||
+ _samples->cols != var_count )
+ CV_ERROR( CV_StsBadArg, "Input samples must be floating-point matrix (<num_samples>x<var_count>)" );
+
+ if( _results && (!CV_IS_MAT(_results) ||
+ _results->cols != 1 && _results->rows != 1 ||
+ _results->cols + _results->rows - 1 != _samples->rows) )
+ CV_ERROR( CV_StsBadArg,
+ "The results must be 1d vector containing as much elements as the number of samples" );
+
+ if( _results && CV_MAT_TYPE(_results->type) != CV_32FC1 &&
+ (CV_MAT_TYPE(_results->type) != CV_32SC1 || regression))
+ CV_ERROR( CV_StsUnsupportedFormat,
+ "The results must be floating-point or integer (in case of classification) vector" );
+
+ if( k < 1 || k > max_k )
+ CV_ERROR( CV_StsOutOfRange, "k must be within 1..max_k range" );
+
+ if( _neighbor_responses )
+ {
+ if( !CV_IS_MAT(_neighbor_responses) || CV_MAT_TYPE(_neighbor_responses->type) != CV_32FC1 ||
+ _neighbor_responses->rows != _samples->rows || _neighbor_responses->cols != k )
+ CV_ERROR( CV_StsBadArg,
+ "The neighbor responses (if present) must be floating-point matrix of <num_samples> x <k> size" );
+ }
+
+ if( _dist )
+ {
+ if( !CV_IS_MAT(_dist) || CV_MAT_TYPE(_dist->type) != CV_32FC1 ||
+ _dist->rows != _samples->rows || _dist->cols != k )
+ CV_ERROR( CV_StsBadArg,
+ "The distances from the neighbors (if present) must be floating-point matrix of <num_samples> x <k> size" );
+ }
+
+ count = _samples->rows;
+ count_scale = k*2*sizeof(float);
+ blk_count0 = MIN( count, max_blk_count );
+ buf_sz = MIN( blk_count0 * count_scale, max_buf_sz );
+ blk_count0 = MAX( buf_sz/count_scale, 1 );
+ blk_count0 += blk_count0 % 2;
+ blk_count0 = MIN( blk_count0, count );
+ buf_sz = blk_count0 * count_scale + k*sizeof(float);
+ k1 = get_sample_count();
+ k1 = MIN( k1, k );
+
+ if( buf_sz <= CV_MAX_LOCAL_SIZE )
+ {
+ buf = (float*)cvStackAlloc( buf_sz );
+ local_alloc = true;
+ }
+ else
+ CV_CALL( buf = (float*)cvAlloc( buf_sz ));
+
+ for( i = 0; i < count; i += blk_count )
+ {
+ blk_count = MIN( count - i, blk_count0 );
+ float* neighbor_responses = buf;
+ float* dist = buf + blk_count*k;
+ Cv32suf* sort_buf = (Cv32suf*)(dist + blk_count*k);
+
+ find_neighbors_direct( _samples, k, i, i + blk_count,
+ neighbor_responses, _neighbors, dist );
+
+ float r = write_results( k, k1, i, i + blk_count, neighbor_responses, dist,
+ _results, _neighbor_responses, _dist, sort_buf );
+ if( i == 0 )
+ result = r;
+ }
+
+ __END__;
+
+ if( !local_alloc )
+ cvFree( &buf );
+
+ return result;
+}
+
+/* End of file */
+
diff --git a/ml/src/mlnbayes.cpp b/ml/src/mlnbayes.cpp
new file mode 100644
index 0000000..090c5ee
--- /dev/null
+++ b/ml/src/mlnbayes.cpp
@@ -0,0 +1,569 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_ml.h"
+
+CvNormalBayesClassifier::CvNormalBayesClassifier()
+{
+ var_count = var_all = 0;
+ var_idx = 0;
+ cls_labels = 0;
+ count = 0;
+ sum = 0;
+ productsum = 0;
+ avg = 0;
+ inv_eigen_values = 0;
+ cov_rotate_mats = 0;
+ c = 0;
+ default_model_name = "my_nb";
+}
+
+
+void CvNormalBayesClassifier::clear()
+{
+ if( cls_labels )
+ {
+ for( int cls = 0; cls < cls_labels->cols; cls++ )
+ {
+ cvReleaseMat( &count[cls] );
+ cvReleaseMat( &sum[cls] );
+ cvReleaseMat( &productsum[cls] );
+ cvReleaseMat( &avg[cls] );
+ cvReleaseMat( &inv_eigen_values[cls] );
+ cvReleaseMat( &cov_rotate_mats[cls] );
+ }
+ }
+
+ cvReleaseMat( &cls_labels );
+ cvReleaseMat( &var_idx );
+ cvReleaseMat( &c );
+ cvFree( &count );
+}
+
+
+CvNormalBayesClassifier::~CvNormalBayesClassifier()
+{
+ clear();
+}
+
+
+CvNormalBayesClassifier::CvNormalBayesClassifier(
+ const CvMat* _train_data, const CvMat* _responses,
+ const CvMat* _var_idx, const CvMat* _sample_idx )
+{
+ var_count = var_all = 0;
+ var_idx = 0;
+ cls_labels = 0;
+ count = 0;
+ sum = 0;
+ productsum = 0;
+ avg = 0;
+ inv_eigen_values = 0;
+ cov_rotate_mats = 0;
+ c = 0;
+ default_model_name = "my_nb";
+
+ train( _train_data, _responses, _var_idx, _sample_idx );
+}
+
+
+bool CvNormalBayesClassifier::train( const CvMat* _train_data, const CvMat* _responses,
+ const CvMat* _var_idx, const CvMat* _sample_idx, bool update )
+{
+ const float min_variation = FLT_EPSILON;
+ bool result = false;
+ CvMat* responses = 0;
+ const float** train_data = 0;
+ CvMat* __cls_labels = 0;
+ CvMat* __var_idx = 0;
+ CvMat* cov = 0;
+
+ CV_FUNCNAME( "CvNormalBayesClassifier::train" );
+
+ __BEGIN__;
+
+ int cls, nsamples = 0, _var_count = 0, _var_all = 0, nclasses = 0;
+ int s, c1, c2;
+ const int* responses_data;
+
+ CV_CALL( cvPrepareTrainData( 0,
+ _train_data, CV_ROW_SAMPLE, _responses, CV_VAR_CATEGORICAL,
+ _var_idx, _sample_idx, false, &train_data,
+ &nsamples, &_var_count, &_var_all, &responses,
+ &__cls_labels, &__var_idx ));
+
+ if( !update )
+ {
+ const size_t mat_size = sizeof(CvMat*);
+ size_t data_size;
+
+ clear();
+
+ var_idx = __var_idx;
+ cls_labels = __cls_labels;
+ __var_idx = __cls_labels = 0;
+ var_count = _var_count;
+ var_all = _var_all;
+
+ nclasses = cls_labels->cols;
+ data_size = nclasses*6*mat_size;
+
+ CV_CALL( count = (CvMat**)cvAlloc( data_size ));
+ memset( count, 0, data_size );
+
+ sum = count + nclasses;
+ productsum = sum + nclasses;
+ avg = productsum + nclasses;
+ inv_eigen_values= avg + nclasses;
+ cov_rotate_mats = inv_eigen_values + nclasses;
+
+ CV_CALL( c = cvCreateMat( 1, nclasses, CV_64FC1 ));
+
+ for( cls = 0; cls < nclasses; cls++ )
+ {
+ CV_CALL(count[cls] = cvCreateMat( 1, var_count, CV_32SC1 ));
+ CV_CALL(sum[cls] = cvCreateMat( 1, var_count, CV_64FC1 ));
+ CV_CALL(productsum[cls] = cvCreateMat( var_count, var_count, CV_64FC1 ));
+ CV_CALL(avg[cls] = cvCreateMat( 1, var_count, CV_64FC1 ));
+ CV_CALL(inv_eigen_values[cls] = cvCreateMat( 1, var_count, CV_64FC1 ));
+ CV_CALL(cov_rotate_mats[cls] = cvCreateMat( var_count, var_count, CV_64FC1 ));
+ CV_CALL(cvZero( count[cls] ));
+ CV_CALL(cvZero( sum[cls] ));
+ CV_CALL(cvZero( productsum[cls] ));
+ CV_CALL(cvZero( avg[cls] ));
+ CV_CALL(cvZero( inv_eigen_values[cls] ));
+ CV_CALL(cvZero( cov_rotate_mats[cls] ));
+ }
+ }
+ else
+ {
+ // check that the new training data has the same dimensionality etc.
+ if( _var_count != var_count || _var_all != var_all || !(!_var_idx && !var_idx ||
+ _var_idx && var_idx && cvNorm(_var_idx,var_idx,CV_C) < DBL_EPSILON) )
+ CV_ERROR( CV_StsBadArg,
+ "The new training data is inconsistent with the original training data" );
+
+ if( cls_labels->cols != __cls_labels->cols ||
+ cvNorm(cls_labels, __cls_labels, CV_C) > DBL_EPSILON )
+ CV_ERROR( CV_StsNotImplemented,
+ "In the current implementation the new training data must have absolutely "
+ "the same set of class labels as used in the original training data" );
+
+ nclasses = cls_labels->cols;
+ }
+
+ responses_data = responses->data.i;
+ CV_CALL( cov = cvCreateMat( _var_count, _var_count, CV_64FC1 ));
+
+ /* process train data (count, sum , productsum) */
+ for( s = 0; s < nsamples; s++ )
+ {
+ cls = responses_data[s];
+ int* count_data = count[cls]->data.i;
+ double* sum_data = sum[cls]->data.db;
+ double* prod_data = productsum[cls]->data.db;
+ const float* train_vec = train_data[s];
+
+ for( c1 = 0; c1 < _var_count; c1++, prod_data += _var_count )
+ {
+ double val1 = train_vec[c1];
+ sum_data[c1] += val1;
+ count_data[c1]++;
+ for( c2 = c1; c2 < _var_count; c2++ )
+ prod_data[c2] += train_vec[c2]*val1;
+ }
+ }
+
+ /* calculate avg, covariance matrix, c */
+ for( cls = 0; cls < nclasses; cls++ )
+ {
+ double det = 1;
+ int i, j;
+ CvMat* w = inv_eigen_values[cls];
+ int* count_data = count[cls]->data.i;
+ double* avg_data = avg[cls]->data.db;
+ double* sum1 = sum[cls]->data.db;
+
+ cvCompleteSymm( productsum[cls], 0 );
+
+ for( j = 0; j < _var_count; j++ )
+ {
+ int n = count_data[j];
+ avg_data[j] = n ? sum1[j] / n : 0.;
+ }
+
+ count_data = count[cls]->data.i;
+ avg_data = avg[cls]->data.db;
+ sum1 = sum[cls]->data.db;
+
+ for( i = 0; i < _var_count; i++ )
+ {
+ double* avg2_data = avg[cls]->data.db;
+ double* sum2 = sum[cls]->data.db;
+ double* prod_data = productsum[cls]->data.db + i*_var_count;
+ double* cov_data = cov->data.db + i*_var_count;
+ double s1val = sum1[j];
+ double avg1 = avg_data[i];
+ int count = count_data[i];
+
+ for( j = 0; j <= i; j++ )
+ {
+ double avg2 = avg2_data[j];
+ double cov_val = prod_data[j] - avg1 * sum2[j] - avg2 * s1val + avg1 * avg2 * count;
+ cov_val = (count > 1) ? cov_val / (count - 1) : cov_val;
+ cov_data[j] = cov_val;
+ }
+ }
+
+ CV_CALL( cvCompleteSymm( cov, 1 ));
+ CV_CALL( cvSVD( cov, w, cov_rotate_mats[cls], 0, CV_SVD_U_T ));
+ CV_CALL( cvMaxS( w, min_variation, w ));
+ for( j = 0; j < _var_count; j++ )
+ det *= w->data.db[j];
+
+ CV_CALL( cvDiv( NULL, w, w ));
+ c->data.db[cls] = log( det );
+ }
+
+ result = true;
+
+ __END__;
+
+ if( !result || cvGetErrStatus() < 0 )
+ clear();
+
+ cvReleaseMat( &cov );
+ cvReleaseMat( &__cls_labels );
+ cvReleaseMat( &__var_idx );
+ cvFree( &train_data );
+
+ return result;
+}
+
+
+float CvNormalBayesClassifier::predict( const CvMat* samples, CvMat* results ) const
+{
+ float value = 0;
+ void* buffer = 0;
+ int allocated_buffer = 0;
+
+ CV_FUNCNAME( "CvNormalBayesClassifier::predict" );
+
+ __BEGIN__;
+
+ int i, j, k, cls = -1, _var_count, nclasses;
+ double opt = FLT_MAX;
+ CvMat diff;
+ int rtype = 0, rstep = 0, size;
+ const int* vidx = 0;
+
+ nclasses = cls_labels->cols;
+ _var_count = avg[0]->cols;
+
+ if( !CV_IS_MAT(samples) || CV_MAT_TYPE(samples->type) != CV_32FC1 || samples->cols != var_all )
+ CV_ERROR( CV_StsBadArg,
+ "The input samples must be 32f matrix with the number of columns = var_all" );
+
+ if( samples->rows > 1 && !results )
+ CV_ERROR( CV_StsNullPtr,
+ "When the number of input samples is >1, the output vector of results must be passed" );
+
+ if( results )
+ {
+ if( !CV_IS_MAT(results) || CV_MAT_TYPE(results->type) != CV_32FC1 &&
+ CV_MAT_TYPE(results->type) != CV_32SC1 ||
+ results->cols != 1 && results->rows != 1 ||
+ results->cols + results->rows - 1 != samples->rows )
+ CV_ERROR( CV_StsBadArg, "The output array must be integer or floating-point vector "
+ "with the number of elements = number of rows in the input matrix" );
+
+ rtype = CV_MAT_TYPE(results->type);
+ rstep = CV_IS_MAT_CONT(results->type) ? 1 : results->step/CV_ELEM_SIZE(rtype);
+ }
+
+ if( var_idx )
+ vidx = var_idx->data.i;
+
+// allocate memory and initializing headers for calculating
+ size = sizeof(double) * (nclasses + var_count);
+ if( size <= CV_MAX_LOCAL_SIZE )
+ buffer = cvStackAlloc( size );
+ else
+ {
+ CV_CALL( buffer = cvAlloc( size ));
+ allocated_buffer = 1;
+ }
+
+ diff = cvMat( 1, var_count, CV_64FC1, buffer );
+
+ for( k = 0; k < samples->rows; k++ )
+ {
+ int ival;
+
+ for( i = 0; i < nclasses; i++ )
+ {
+ double cur = c->data.db[i];
+ CvMat* u = cov_rotate_mats[i];
+ CvMat* w = inv_eigen_values[i];
+ const double* avg_data = avg[i]->data.db;
+ const float* x = (const float*)(samples->data.ptr + samples->step*k);
+
+ // cov = u w u' --> cov^(-1) = u w^(-1) u'
+ for( j = 0; j < _var_count; j++ )
+ diff.data.db[j] = avg_data[j] - x[vidx ? vidx[j] : j];
+
+ CV_CALL(cvGEMM( &diff, u, 1, 0, 0, &diff, CV_GEMM_B_T ));
+ for( j = 0; j < _var_count; j++ )
+ {
+ double d = diff.data.db[j];
+ cur += d*d*w->data.db[j];
+ }
+
+ if( cur < opt )
+ {
+ cls = i;
+ opt = cur;
+ }
+ /* probability = exp( -0.5 * cur ) */
+ }
+
+ ival = cls_labels->data.i[cls];
+ if( results )
+ {
+ if( rtype == CV_32SC1 )
+ results->data.i[k*rstep] = ival;
+ else
+ results->data.fl[k*rstep] = (float)ival;
+ }
+ if( k == 0 )
+ value = (float)ival;
+
+ /*if( _probs )
+ {
+ CV_CALL( cvConvertScale( &expo, &expo, -0.5 ));
+ CV_CALL( cvExp( &expo, &expo ));
+ if( _probs->cols == 1 )
+ CV_CALL( cvReshape( &expo, &expo, 1, nclasses ));
+ CV_CALL( cvConvertScale( &expo, _probs, 1./cvSum( &expo ).val[0] ));
+ }*/
+ }
+
+ __END__;
+
+ if( allocated_buffer )
+ cvFree( &buffer );
+
+ return value;
+}
+
+
+void CvNormalBayesClassifier::write( CvFileStorage* fs, const char* name )
+{
+ CV_FUNCNAME( "CvNormalBayesClassifier::write" );
+
+ __BEGIN__;
+
+ int nclasses, i;
+
+ nclasses = cls_labels->cols;
+
+ cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_ML_NBAYES );
+
+ CV_CALL( cvWriteInt( fs, "var_count", var_count ));
+ CV_CALL( cvWriteInt( fs, "var_all", var_all ));
+
+ if( var_idx )
+ CV_CALL( cvWrite( fs, "var_idx", var_idx ));
+ CV_CALL( cvWrite( fs, "cls_labels", cls_labels ));
+
+ CV_CALL( cvStartWriteStruct( fs, "count", CV_NODE_SEQ ));
+ for( i = 0; i < nclasses; i++ )
+ CV_CALL( cvWrite( fs, NULL, count[i] ));
+ CV_CALL( cvEndWriteStruct( fs ));
+
+ CV_CALL( cvStartWriteStruct( fs, "sum", CV_NODE_SEQ ));
+ for( i = 0; i < nclasses; i++ )
+ CV_CALL( cvWrite( fs, NULL, sum[i] ));
+ CV_CALL( cvEndWriteStruct( fs ));
+
+ CV_CALL( cvStartWriteStruct( fs, "productsum", CV_NODE_SEQ ));
+ for( i = 0; i < nclasses; i++ )
+ CV_CALL( cvWrite( fs, NULL, productsum[i] ));
+ CV_CALL( cvEndWriteStruct( fs ));
+
+ CV_CALL( cvStartWriteStruct( fs, "avg", CV_NODE_SEQ ));
+ for( i = 0; i < nclasses; i++ )
+ CV_CALL( cvWrite( fs, NULL, avg[i] ));
+ CV_CALL( cvEndWriteStruct( fs ));
+
+ CV_CALL( cvStartWriteStruct( fs, "inv_eigen_values", CV_NODE_SEQ ));
+ for( i = 0; i < nclasses; i++ )
+ CV_CALL( cvWrite( fs, NULL, inv_eigen_values[i] ));
+ CV_CALL( cvEndWriteStruct( fs ));
+
+ CV_CALL( cvStartWriteStruct( fs, "cov_rotate_mats", CV_NODE_SEQ ));
+ for( i = 0; i < nclasses; i++ )
+ CV_CALL( cvWrite( fs, NULL, cov_rotate_mats[i] ));
+ CV_CALL( cvEndWriteStruct( fs ));
+
+ CV_CALL( cvWrite( fs, "c", c ));
+
+ cvEndWriteStruct( fs );
+
+ __END__;
+}
+
+
+void CvNormalBayesClassifier::read( CvFileStorage* fs, CvFileNode* root_node )
+{
+ bool ok = false;
+ CV_FUNCNAME( "CvNormalBayesClassifier::read" );
+
+ __BEGIN__;
+
+ int nclasses, i;
+ size_t data_size;
+ CvFileNode* node;
+ CvSeq* seq;
+ CvSeqReader reader;
+
+ clear();
+
+ CV_CALL( var_count = cvReadIntByName( fs, root_node, "var_count", -1 ));
+ CV_CALL( var_all = cvReadIntByName( fs, root_node, "var_all", -1 ));
+ CV_CALL( var_idx = (CvMat*)cvReadByName( fs, root_node, "var_idx" ));
+ CV_CALL( cls_labels = (CvMat*)cvReadByName( fs, root_node, "cls_labels" ));
+ if( !cls_labels )
+ CV_ERROR( CV_StsParseError, "No \"cls_labels\" in NBayes classifier" );
+ if( cls_labels->cols < 1 )
+ CV_ERROR( CV_StsBadArg, "Number of classes is less 1" );
+ if( var_count <= 0 )
+ CV_ERROR( CV_StsParseError,
+ "The field \"var_count\" of NBayes classifier is missing" );
+ nclasses = cls_labels->cols;
+
+ data_size = nclasses*6*sizeof(CvMat*);
+ CV_CALL( count = (CvMat**)cvAlloc( data_size ));
+ memset( count, 0, data_size );
+
+ sum = count + nclasses;
+ productsum = sum + nclasses;
+ avg = productsum + nclasses;
+ inv_eigen_values = avg + nclasses;
+ cov_rotate_mats = inv_eigen_values + nclasses;
+
+ CV_CALL( node = cvGetFileNodeByName( fs, root_node, "count" ));
+ seq = node->data.seq;
+ if( !CV_NODE_IS_SEQ(node->tag) || seq->total != nclasses)
+ CV_ERROR( CV_StsBadArg, "" );
+ CV_CALL( cvStartReadSeq( seq, &reader, 0 ));
+ for( i = 0; i < nclasses; i++ )
+ {
+ CV_CALL( count[i] = (CvMat*)cvRead( fs, (CvFileNode*)reader.ptr ));
+ CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
+ }
+
+ CV_CALL( node = cvGetFileNodeByName( fs, root_node, "sum" ));
+ seq = node->data.seq;
+ if( !CV_NODE_IS_SEQ(node->tag) || seq->total != nclasses)
+ CV_ERROR( CV_StsBadArg, "" );
+ CV_CALL( cvStartReadSeq( seq, &reader, 0 ));
+ for( i = 0; i < nclasses; i++ )
+ {
+ CV_CALL( sum[i] = (CvMat*)cvRead( fs, (CvFileNode*)reader.ptr ));
+ CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
+ }
+
+ CV_CALL( node = cvGetFileNodeByName( fs, root_node, "productsum" ));
+ seq = node->data.seq;
+ if( !CV_NODE_IS_SEQ(node->tag) || seq->total != nclasses)
+ CV_ERROR( CV_StsBadArg, "" );
+ CV_CALL( cvStartReadSeq( seq, &reader, 0 ));
+ for( i = 0; i < nclasses; i++ )
+ {
+ CV_CALL( productsum[i] = (CvMat*)cvRead( fs, (CvFileNode*)reader.ptr ));
+ CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
+ }
+
+ CV_CALL( node = cvGetFileNodeByName( fs, root_node, "avg" ));
+ seq = node->data.seq;
+ if( !CV_NODE_IS_SEQ(node->tag) || seq->total != nclasses)
+ CV_ERROR( CV_StsBadArg, "" );
+ CV_CALL( cvStartReadSeq( seq, &reader, 0 ));
+ for( i = 0; i < nclasses; i++ )
+ {
+ CV_CALL( avg[i] = (CvMat*)cvRead( fs, (CvFileNode*)reader.ptr ));
+ CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
+ }
+
+ CV_CALL( node = cvGetFileNodeByName( fs, root_node, "inv_eigen_values" ));
+ seq = node->data.seq;
+ if( !CV_NODE_IS_SEQ(node->tag) || seq->total != nclasses)
+ CV_ERROR( CV_StsBadArg, "" );
+ CV_CALL( cvStartReadSeq( seq, &reader, 0 ));
+ for( i = 0; i < nclasses; i++ )
+ {
+ CV_CALL( inv_eigen_values[i] = (CvMat*)cvRead( fs, (CvFileNode*)reader.ptr ));
+ CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
+ }
+
+ CV_CALL( node = cvGetFileNodeByName( fs, root_node, "cov_rotate_mats" ));
+ seq = node->data.seq;
+ if( !CV_NODE_IS_SEQ(node->tag) || seq->total != nclasses)
+ CV_ERROR( CV_StsBadArg, "" );
+ CV_CALL( cvStartReadSeq( seq, &reader, 0 ));
+ for( i = 0; i < nclasses; i++ )
+ {
+ CV_CALL( cov_rotate_mats[i] = (CvMat*)cvRead( fs, (CvFileNode*)reader.ptr ));
+ CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
+ }
+
+ CV_CALL( c = (CvMat*)cvReadByName( fs, root_node, "c" ));
+
+ ok = true;
+
+ __END__;
+
+ if( !ok )
+ clear();
+}
+
+/* End of file. */
+
diff --git a/ml/src/mlrtrees.cpp b/ml/src/mlrtrees.cpp
new file mode 100644
index 0000000..4e6117f
--- /dev/null
+++ b/ml/src/mlrtrees.cpp
@@ -0,0 +1,693 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_ml.h"
+
+CvForestTree::CvForestTree()
+{
+ forest = NULL;
+}
+
+
+CvForestTree::~CvForestTree()
+{
+ clear();
+}
+
+
+bool CvForestTree::train( CvDTreeTrainData* _data,
+ const CvMat* _subsample_idx,
+ CvRTrees* _forest )
+{
+ bool result = false;
+
+ CV_FUNCNAME( "CvForestTree::train" );
+
+ __BEGIN__;
+
+
+ clear();
+ forest = _forest;
+
+ data = _data;
+ data->shared = true;
+ CV_CALL(result = do_train(_subsample_idx));
+
+ __END__;
+
+ return result;
+}
+
+
+bool
+CvForestTree::train( const CvMat*, int, const CvMat*, const CvMat*,
+ const CvMat*, const CvMat*, const CvMat*, CvDTreeParams )
+{
+ assert(0);
+ return false;
+}
+
+
+bool
+CvForestTree::train( CvDTreeTrainData*, const CvMat* )
+{
+ assert(0);
+ return false;
+}
+
+
+CvDTreeSplit* CvForestTree::find_best_split( CvDTreeNode* node )
+{
+ int vi;
+ CvDTreeSplit *best_split = 0, *split = 0, *t;
+
+ CV_FUNCNAME("CvForestTree::find_best_split");
+ __BEGIN__;
+
+ CvMat* active_var_mask = 0;
+ if( forest )
+ {
+ int var_count;
+ CvRNG* rng = forest->get_rng();
+
+ active_var_mask = forest->get_active_var_mask();
+ var_count = active_var_mask->cols;
+
+ CV_ASSERT( var_count == data->var_count );
+
+ for( vi = 0; vi < var_count; vi++ )
+ {
+ uchar temp;
+ int i1 = cvRandInt(rng) % var_count;
+ int i2 = cvRandInt(rng) % var_count;
+ CV_SWAP( active_var_mask->data.ptr[i1],
+ active_var_mask->data.ptr[i2], temp );
+ }
+ }
+ for( vi = 0; vi < data->var_count; vi++ )
+ {
+ int ci = data->var_type->data.i[vi];
+ if( node->num_valid[vi] <= 1
+ || (active_var_mask && !active_var_mask->data.ptr[vi]) )
+ continue;
+
+ if( data->is_classifier )
+ {
+ if( ci >= 0 )
+ split = find_split_cat_class( node, vi );
+ else
+ split = find_split_ord_class( node, vi );
+ }
+ else
+ {
+ if( ci >= 0 )
+ split = find_split_cat_reg( node, vi );
+ else
+ split = find_split_ord_reg( node, vi );
+ }
+
+ if( split )
+ {
+ if( !best_split || best_split->quality < split->quality )
+ CV_SWAP( best_split, split, t );
+ if( split )
+ cvSetRemoveByPtr( data->split_heap, split );
+ }
+ }
+
+ __END__;
+
+ return best_split;
+}
+
+
+void CvForestTree::read( CvFileStorage* fs, CvFileNode* fnode, CvRTrees* _forest, CvDTreeTrainData* _data )
+{
+ CvDTree::read( fs, fnode, _data );
+ forest = _forest;
+}
+
+
+void CvForestTree::read( CvFileStorage*, CvFileNode* )
+{
+ assert(0);
+}
+
+void CvForestTree::read( CvFileStorage* _fs, CvFileNode* _node,
+ CvDTreeTrainData* _data )
+{
+ CvDTree::read( _fs, _node, _data );
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Random trees //
+//////////////////////////////////////////////////////////////////////////////////////////
+
+CvRTrees::CvRTrees()
+{
+ nclasses = 0;
+ oob_error = 0;
+ ntrees = 0;
+ trees = NULL;
+ data = NULL;
+ active_var_mask = NULL;
+ var_importance = NULL;
+ rng = cvRNG(0xffffffff);
+ default_model_name = "my_random_trees";
+}
+
+
+void CvRTrees::clear()
+{
+ int k;
+ for( k = 0; k < ntrees; k++ )
+ delete trees[k];
+ cvFree( &trees );
+
+ delete data;
+ data = 0;
+
+ cvReleaseMat( &active_var_mask );
+ cvReleaseMat( &var_importance );
+ ntrees = 0;
+}
+
+
+CvRTrees::~CvRTrees()
+{
+ clear();
+}
+
+
+CvMat* CvRTrees::get_active_var_mask()
+{
+ return active_var_mask;
+}
+
+
+CvRNG* CvRTrees::get_rng()
+{
+ return &rng;
+}
+
+bool CvRTrees::train( const CvMat* _train_data, int _tflag,
+ const CvMat* _responses, const CvMat* _var_idx,
+ const CvMat* _sample_idx, const CvMat* _var_type,
+ const CvMat* _missing_mask, CvRTParams params )
+{
+ bool result = false;
+
+ CV_FUNCNAME("CvRTrees::train");
+ __BEGIN__;
+
+ int var_count = 0;
+
+ clear();
+
+ CvDTreeParams tree_params( params.max_depth, params.min_sample_count,
+ params.regression_accuracy, params.use_surrogates, params.max_categories,
+ params.cv_folds, params.use_1se_rule, false, params.priors );
+
+ data = new CvDTreeTrainData();
+ CV_CALL(data->set_data( _train_data, _tflag, _responses, _var_idx,
+ _sample_idx, _var_type, _missing_mask, tree_params, true));
+
+ var_count = data->var_count;
+ if( params.nactive_vars > var_count )
+ params.nactive_vars = var_count;
+ else if( params.nactive_vars == 0 )
+ params.nactive_vars = (int)sqrt((double)var_count);
+ else if( params.nactive_vars < 0 )
+ CV_ERROR( CV_StsBadArg, "<nactive_vars> must be non-negative" );
+ params.term_crit = cvCheckTermCriteria( params.term_crit, 0.1, 1000 );
+
+ // Create mask of active variables at the tree nodes
+ CV_CALL(active_var_mask = cvCreateMat( 1, var_count, CV_8UC1 ));
+ if( params.calc_var_importance )
+ {
+ CV_CALL(var_importance = cvCreateMat( 1, var_count, CV_32FC1 ));
+ cvZero(var_importance);
+ }
+ { // initialize active variables mask
+ CvMat submask1, submask2;
+ cvGetCols( active_var_mask, &submask1, 0, params.nactive_vars );
+ cvGetCols( active_var_mask, &submask2, params.nactive_vars, var_count );
+ cvSet( &submask1, cvScalar(1) );
+ cvZero( &submask2 );
+ }
+
+ CV_CALL(result = grow_forest( params.term_crit ));
+
+ result = true;
+
+ __END__;
+
+ return result;
+}
+
+
+bool CvRTrees::grow_forest( const CvTermCriteria term_crit )
+{
+ bool result = false;
+
+ CvMat* sample_idx_mask_for_tree = 0;
+ CvMat* sample_idx_for_tree = 0;
+
+ CvMat* oob_sample_votes = 0;
+ CvMat* oob_responses = 0;
+
+ float* oob_samples_perm_ptr= 0;
+
+ float* samples_ptr = 0;
+ uchar* missing_ptr = 0;
+ float* true_resp_ptr = 0;
+
+ CV_FUNCNAME("CvRTrees::grow_forest");
+ __BEGIN__;
+
+ const int max_ntrees = term_crit.max_iter;
+ const double max_oob_err = term_crit.epsilon;
+
+ const int dims = data->var_count;
+ float maximal_response = 0;
+
+ // oob_predictions_sum[i] = sum of predicted values for the i-th sample
+ // oob_num_of_predictions[i] = number of summands
+ // (number of predictions for the i-th sample)
+ // initialize these variable to avoid warning C4701
+ CvMat oob_predictions_sum = cvMat( 1, 1, CV_32FC1 );
+ CvMat oob_num_of_predictions = cvMat( 1, 1, CV_32FC1 );
+
+ nsamples = data->sample_count;
+ nclasses = data->get_num_classes();
+
+ trees = (CvForestTree**)cvAlloc( sizeof(trees[0])*max_ntrees );
+ memset( trees, 0, sizeof(trees[0])*max_ntrees );
+
+ if( data->is_classifier )
+ {
+ CV_CALL(oob_sample_votes = cvCreateMat( nsamples, nclasses, CV_32SC1 ));
+ cvZero(oob_sample_votes);
+ }
+ else
+ {
+ // oob_responses[0,i] = oob_predictions_sum[i]
+ // = sum of predicted values for the i-th sample
+ // oob_responses[1,i] = oob_num_of_predictions[i]
+ // = number of summands (number of predictions for the i-th sample)
+ CV_CALL(oob_responses = cvCreateMat( 2, nsamples, CV_32FC1 ));
+ cvZero(oob_responses);
+ cvGetRow( oob_responses, &oob_predictions_sum, 0 );
+ cvGetRow( oob_responses, &oob_num_of_predictions, 1 );
+ }
+ CV_CALL(sample_idx_mask_for_tree = cvCreateMat( 1, nsamples, CV_8UC1 ));
+ CV_CALL(sample_idx_for_tree = cvCreateMat( 1, nsamples, CV_32SC1 ));
+ CV_CALL(oob_samples_perm_ptr = (float*)cvAlloc( sizeof(float)*nsamples*dims ));
+ CV_CALL(samples_ptr = (float*)cvAlloc( sizeof(float)*nsamples*dims ));
+ CV_CALL(missing_ptr = (uchar*)cvAlloc( sizeof(uchar)*nsamples*dims ));
+ CV_CALL(true_resp_ptr = (float*)cvAlloc( sizeof(float)*nsamples ));
+
+ CV_CALL(data->get_vectors( 0, samples_ptr, missing_ptr, true_resp_ptr ));
+ {
+ double minval, maxval;
+ CvMat responses = cvMat(1, nsamples, CV_32FC1, true_resp_ptr);
+ cvMinMaxLoc( &responses, &minval, &maxval );
+ maximal_response = (float)MAX( MAX( fabs(minval), fabs(maxval) ), 0 );
+ }
+
+ ntrees = 0;
+ while( ntrees < max_ntrees )
+ {
+ int i, oob_samples_count = 0;
+ double ncorrect_responses = 0; // used for estimation of variable importance
+ CvMat sample, missing;
+ CvForestTree* tree = 0;
+
+ cvZero( sample_idx_mask_for_tree );
+ for( i = 0; i < nsamples; i++ ) //form sample for creation one tree
+ {
+ int idx = cvRandInt( &rng ) % nsamples;
+ sample_idx_for_tree->data.i[i] = idx;
+ sample_idx_mask_for_tree->data.ptr[idx] = 0xFF;
+ }
+
+ trees[ntrees] = new CvForestTree();
+ tree = trees[ntrees];
+ CV_CALL(tree->train( data, sample_idx_for_tree, this ));
+
+ // form array of OOB samples indices and get these samples
+ sample = cvMat( 1, dims, CV_32FC1, samples_ptr );
+ missing = cvMat( 1, dims, CV_8UC1, missing_ptr );
+
+ oob_error = 0;
+ for( i = 0; i < nsamples; i++,
+ sample.data.fl += dims, missing.data.ptr += dims )
+ {
+ CvDTreeNode* predicted_node = 0;
+ // check if the sample is OOB
+ if( sample_idx_mask_for_tree->data.ptr[i] )
+ continue;
+
+ // predict oob samples
+ if( !predicted_node )
+ CV_CALL(predicted_node = tree->predict(&sample, &missing, true));
+
+ if( !data->is_classifier ) //regression
+ {
+ double avg_resp, resp = predicted_node->value;
+ oob_predictions_sum.data.fl[i] += (float)resp;
+ oob_num_of_predictions.data.fl[i] += 1;
+
+ // compute oob error
+ avg_resp = oob_predictions_sum.data.fl[i]/oob_num_of_predictions.data.fl[i];
+ avg_resp -= true_resp_ptr[i];
+ oob_error += avg_resp*avg_resp;
+ resp = (resp - true_resp_ptr[i])/maximal_response;
+ ncorrect_responses += exp( -resp*resp );
+ }
+ else //classification
+ {
+ double prdct_resp;
+ CvPoint max_loc;
+ CvMat votes;
+
+ cvGetRow(oob_sample_votes, &votes, i);
+ votes.data.i[predicted_node->class_idx]++;
+
+ // compute oob error
+ cvMinMaxLoc( &votes, 0, 0, 0, &max_loc );
+
+ prdct_resp = data->cat_map->data.i[max_loc.x];
+ oob_error += (fabs(prdct_resp - true_resp_ptr[i]) < FLT_EPSILON) ? 0 : 1;
+
+ ncorrect_responses += cvRound(predicted_node->value - true_resp_ptr[i]) == 0;
+ }
+ oob_samples_count++;
+ }
+ if( oob_samples_count > 0 )
+ oob_error /= (double)oob_samples_count;
+
+ // estimate variable importance
+ if( var_importance && oob_samples_count > 0 )
+ {
+ int m;
+
+ memcpy( oob_samples_perm_ptr, samples_ptr, dims*nsamples*sizeof(float));
+ for( m = 0; m < dims; m++ )
+ {
+ double ncorrect_responses_permuted = 0;
+ // randomly permute values of the m-th variable in the oob samples
+ float* mth_var_ptr = oob_samples_perm_ptr + m;
+
+ for( i = 0; i < nsamples; i++ )
+ {
+ int i1, i2;
+ float temp;
+
+ if( sample_idx_mask_for_tree->data.ptr[i] ) //the sample is not OOB
+ continue;
+ i1 = cvRandInt( &rng ) % nsamples;
+ i2 = cvRandInt( &rng ) % nsamples;
+ CV_SWAP( mth_var_ptr[i1*dims], mth_var_ptr[i2*dims], temp );
+
+ // turn values of (m-1)-th variable, that were permuted
+ // at the previous iteration, untouched
+ if( m > 1 )
+ oob_samples_perm_ptr[i*dims+m-1] = samples_ptr[i*dims+m-1];
+ }
+
+ // predict "permuted" cases and calculate the number of votes for the
+ // correct class in the variable-m-permuted oob data
+ sample = cvMat( 1, dims, CV_32FC1, oob_samples_perm_ptr );
+ missing = cvMat( 1, dims, CV_8UC1, missing_ptr );
+ for( i = 0; i < nsamples; i++,
+ sample.data.fl += dims, missing.data.ptr += dims )
+ {
+ double predct_resp, true_resp;
+
+ if( sample_idx_mask_for_tree->data.ptr[i] ) //the sample is not OOB
+ continue;
+
+ predct_resp = tree->predict(&sample, &missing, true)->value;
+ true_resp = true_resp_ptr[i];
+ if( data->is_classifier )
+ ncorrect_responses_permuted += cvRound(true_resp - predct_resp) == 0;
+ else
+ {
+ true_resp = (true_resp - predct_resp)/maximal_response;
+ ncorrect_responses_permuted += exp( -true_resp*true_resp );
+ }
+ }
+ var_importance->data.fl[m] += (float)(ncorrect_responses
+ - ncorrect_responses_permuted);
+ }
+ }
+ ntrees++;
+ if( term_crit.type != CV_TERMCRIT_ITER && oob_error < max_oob_err )
+ break;
+ }
+ if( var_importance )
+ CV_CALL(cvConvertScale( var_importance, var_importance, 1./ntrees/nsamples ));
+
+ result = true;
+
+ __END__;
+
+ cvReleaseMat( &sample_idx_mask_for_tree );
+ cvReleaseMat( &sample_idx_for_tree );
+ cvReleaseMat( &oob_sample_votes );
+ cvReleaseMat( &oob_responses );
+
+ cvFree( &oob_samples_perm_ptr );
+ cvFree( &samples_ptr );
+ cvFree( &missing_ptr );
+ cvFree( &true_resp_ptr );
+
+ return result;
+}
+
+
+const CvMat* CvRTrees::get_var_importance()
+{
+ return var_importance;
+}
+
+
+float CvRTrees::get_proximity( const CvMat* sample1, const CvMat* sample2,
+ const CvMat* missing1, const CvMat* missing2 ) const
+{
+ float result = 0;
+
+ CV_FUNCNAME( "CvRTrees::get_proximity" );
+
+ __BEGIN__;
+
+ int i;
+ for( i = 0; i < ntrees; i++ )
+ result += trees[i]->predict( sample1, missing1 ) ==
+ trees[i]->predict( sample2, missing2 ) ? 1 : 0;
+ result = result/(float)ntrees;
+
+ __END__;
+
+ return result;
+}
+
+
+float CvRTrees::predict( const CvMat* sample, const CvMat* missing ) const
+{
+ double result = -1;
+
+ CV_FUNCNAME("CvRTrees::predict");
+ __BEGIN__;
+
+ int k;
+
+ if( nclasses > 0 ) //classification
+ {
+ int max_nvotes = 0;
+ int* votes = (int*)alloca( sizeof(int)*nclasses );
+ memset( votes, 0, sizeof(*votes)*nclasses );
+ for( k = 0; k < ntrees; k++ )
+ {
+ CvDTreeNode* predicted_node = trees[k]->predict( sample, missing );
+ int nvotes;
+ int class_idx = predicted_node->class_idx;
+ CV_ASSERT( 0 <= class_idx && class_idx < nclasses );
+
+ nvotes = ++votes[class_idx];
+ if( nvotes > max_nvotes )
+ {
+ max_nvotes = nvotes;
+ result = predicted_node->value;
+ }
+ }
+ }
+ else // regression
+ {
+ result = 0;
+ for( k = 0; k < ntrees; k++ )
+ result += trees[k]->predict( sample, missing )->value;
+ result /= (double)ntrees;
+ }
+
+ __END__;
+
+ return (float)result;
+}
+
+
+void CvRTrees::write( CvFileStorage* fs, const char* name )
+{
+ CV_FUNCNAME( "CvRTrees::write" );
+
+ __BEGIN__;
+
+ int k;
+
+ if( ntrees < 1 || !trees || nsamples < 1 )
+ CV_ERROR( CV_StsBadArg, "Invalid CvRTrees object" );
+
+ cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_ML_RTREES );
+
+ cvWriteInt( fs, "nclasses", nclasses );
+ cvWriteInt( fs, "nsamples", nsamples );
+ cvWriteInt( fs, "nactive_vars", (int)cvSum(active_var_mask).val[0] );
+ cvWriteReal( fs, "oob_error", oob_error );
+
+ if( var_importance )
+ cvWrite( fs, "var_importance", var_importance );
+
+ cvWriteInt( fs, "ntrees", ntrees );
+
+ CV_CALL(data->write_params( fs ));
+
+ cvStartWriteStruct( fs, "trees", CV_NODE_SEQ );
+
+ for( k = 0; k < ntrees; k++ )
+ {
+ cvStartWriteStruct( fs, 0, CV_NODE_MAP );
+ CV_CALL( trees[k]->write( fs ));
+ cvEndWriteStruct( fs );
+ }
+
+ cvEndWriteStruct( fs ); //trees
+ cvEndWriteStruct( fs ); //CV_TYPE_NAME_ML_RTREES
+
+ __END__;
+}
+
+
+void CvRTrees::read( CvFileStorage* fs, CvFileNode* fnode )
+{
+ CV_FUNCNAME( "CvRTrees::read" );
+
+ __BEGIN__;
+
+ int nactive_vars, var_count, k;
+ CvSeqReader reader;
+ CvFileNode* trees_fnode = 0;
+
+ clear();
+
+ nclasses = cvReadIntByName( fs, fnode, "nclasses", -1 );
+ nsamples = cvReadIntByName( fs, fnode, "nsamples" );
+ nactive_vars = cvReadIntByName( fs, fnode, "nactive_vars", -1 );
+ oob_error = cvReadRealByName(fs, fnode, "oob_error", -1 );
+ ntrees = cvReadIntByName( fs, fnode, "ntrees", -1 );
+
+ var_importance = (CvMat*)cvReadByName( fs, fnode, "var_importance" );
+
+ if( nclasses < 0 || nsamples <= 0 || nactive_vars < 0 || oob_error < 0 || ntrees <= 0)
+ CV_ERROR( CV_StsParseError, "Some <nclasses>, <nsamples>, <var_count>, "
+ "<nactive_vars>, <oob_error>, <ntrees> of tags are missing" );
+
+ rng = CvRNG( -1 );
+
+ trees = (CvForestTree**)cvAlloc( sizeof(trees[0])*ntrees );
+ memset( trees, 0, sizeof(trees[0])*ntrees );
+
+ data = new CvDTreeTrainData();
+ data->read_params( fs, fnode );
+ data->shared = true;
+
+ trees_fnode = cvGetFileNodeByName( fs, fnode, "trees" );
+ if( !trees_fnode || !CV_NODE_IS_SEQ(trees_fnode->tag) )
+ CV_ERROR( CV_StsParseError, "<trees> tag is missing" );
+
+ cvStartReadSeq( trees_fnode->data.seq, &reader );
+ if( reader.seq->total != ntrees )
+ CV_ERROR( CV_StsParseError,
+ "<ntrees> is not equal to the number of trees saved in file" );
+
+ for( k = 0; k < ntrees; k++ )
+ {
+ trees[k] = new CvForestTree();
+ CV_CALL(trees[k]->read( fs, (CvFileNode*)reader.ptr, this, data ));
+ CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
+ }
+
+ var_count = data->var_count;
+ CV_CALL(active_var_mask = cvCreateMat( 1, var_count, CV_8UC1 ));
+ {
+ // initialize active variables mask
+ CvMat submask1, submask2;
+ cvGetCols( active_var_mask, &submask1, 0, nactive_vars );
+ cvGetCols( active_var_mask, &submask2, nactive_vars, var_count );
+ cvSet( &submask1, cvScalar(1) );
+ cvZero( &submask2 );
+ }
+
+ __END__;
+}
+
+
+int CvRTrees::get_tree_count() const
+{
+ return ntrees;
+}
+
+CvForestTree* CvRTrees::get_tree(int i) const
+{
+ return (unsigned)i < (unsigned)ntrees ? trees[i] : 0;
+}
+
+// End of file.
diff --git a/ml/src/mlsvm.cpp b/ml/src/mlsvm.cpp
new file mode 100644
index 0000000..fc1794f
--- /dev/null
+++ b/ml/src/mlsvm.cpp
@@ -0,0 +1,2689 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_ml.h"
+
+/****************************************************************************************\
+ COPYRIGHT NOTICE
+ ----------------
+
+ The code has been derived from libsvm library (version 2.6)
+ (http://www.csie.ntu.edu.tw/~cjlin/libsvm).
+
+ Here is the orignal copyright:
+------------------------------------------------------------------------------------------
+ Copyright (c) 2000-2003 Chih-Chung Chang and Chih-Jen Lin
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither name of copyright holders nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************************/
+
+#define CV_SVM_MIN_CACHE_SIZE (40 << 20) /* 40Mb */
+
+#include <stdarg.h>
+#include <ctype.h>
+
+#if _MSC_VER >= 1200
+#pragma warning( disable: 4514 ) /* unreferenced inline functions */
+#endif
+
+#if 1
+typedef float Qfloat;
+#define QFLOAT_TYPE CV_32F
+#else
+typedef double Qfloat;
+#define QFLOAT_TYPE CV_64F
+#endif
+
+// Param Grid
+bool CvParamGrid::check() const
+{
+ bool ok = false;
+
+ CV_FUNCNAME( "CvParamGrid::check" );
+ __BEGIN__;
+
+ if( min_val > max_val )
+ CV_ERROR( CV_StsBadArg, "Lower bound of the grid must be less then the upper one" );
+ if( min_val < DBL_EPSILON )
+ CV_ERROR( CV_StsBadArg, "Lower bound of the grid must be positive" );
+ if( step < 1. + FLT_EPSILON )
+ CV_ERROR( CV_StsBadArg, "Grid step must greater then 1" );
+
+ ok = true;
+
+ __END__;
+
+ return ok;
+}
+
+CvParamGrid CvSVM::get_default_grid( int param_id )
+{
+ CvParamGrid grid;
+ if( param_id == CvSVM::C )
+ {
+ grid.min_val = 0.1;
+ grid.max_val = 500;
+ grid.step = 5; // total iterations = 5
+ }
+ else if( param_id == CvSVM::GAMMA )
+ {
+ grid.min_val = 1e-5;
+ grid.max_val = 0.6;
+ grid.step = 15; // total iterations = 4
+ }
+ else if( param_id == CvSVM::P )
+ {
+ grid.min_val = 0.01;
+ grid.max_val = 100;
+ grid.step = 7; // total iterations = 4
+ }
+ else if( param_id == CvSVM::NU )
+ {
+ grid.min_val = 0.01;
+ grid.max_val = 0.2;
+ grid.step = 3; // total iterations = 3
+ }
+ else if( param_id == CvSVM::COEF )
+ {
+ grid.min_val = 0.1;
+ grid.max_val = 300;
+ grid.step = 14; // total iterations = 3
+ }
+ else if( param_id == CvSVM::DEGREE )
+ {
+ grid.min_val = 0.01;
+ grid.max_val = 4;
+ grid.step = 7; // total iterations = 3
+ }
+ else
+ cvError( CV_StsBadArg, "CvSVM::get_default_grid", "Invalid type of parameter "
+ "(use one of CvSVM::C, CvSVM::GAMMA et al.)", __FILE__, __LINE__ );
+ return grid;
+}
+
+// SVM training parameters
+CvSVMParams::CvSVMParams() :
+ svm_type(CvSVM::C_SVC), kernel_type(CvSVM::RBF), degree(0),
+ gamma(1), coef0(0), C(1), nu(0), p(0), class_weights(0)
+{
+ term_crit = cvTermCriteria( CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 1000, FLT_EPSILON );
+}
+
+
+CvSVMParams::CvSVMParams( int _svm_type, int _kernel_type,
+ double _degree, double _gamma, double _coef0,
+ double _Con, double _nu, double _p,
+ CvMat* _class_weights, CvTermCriteria _term_crit ) :
+ svm_type(_svm_type), kernel_type(_kernel_type),
+ degree(_degree), gamma(_gamma), coef0(_coef0),
+ C(_Con), nu(_nu), p(_p), class_weights(_class_weights), term_crit(_term_crit)
+{
+}
+
+
+/////////////////////////////////////// SVM kernel ///////////////////////////////////////
+
+CvSVMKernel::CvSVMKernel()
+{
+ clear();
+}
+
+
+void CvSVMKernel::clear()
+{
+ params = 0;
+ calc_func = 0;
+}
+
+
+CvSVMKernel::~CvSVMKernel()
+{
+}
+
+
+CvSVMKernel::CvSVMKernel( const CvSVMParams* _params, Calc _calc_func )
+{
+ clear();
+ create( _params, _calc_func );
+}
+
+
+bool CvSVMKernel::create( const CvSVMParams* _params, Calc _calc_func )
+{
+ clear();
+ params = _params;
+ calc_func = _calc_func;
+
+ if( !calc_func )
+ calc_func = params->kernel_type == CvSVM::RBF ? &CvSVMKernel::calc_rbf :
+ params->kernel_type == CvSVM::POLY ? &CvSVMKernel::calc_poly :
+ params->kernel_type == CvSVM::SIGMOID ? &CvSVMKernel::calc_sigmoid :
+ &CvSVMKernel::calc_linear;
+
+ return true;
+}
+
+
+void CvSVMKernel::calc_non_rbf_base( int vcount, int var_count, const float** vecs,
+ const float* another, Qfloat* results,
+ double alpha, double beta )
+{
+ int j, k;
+ for( j = 0; j < vcount; j++ )
+ {
+ const float* sample = vecs[j];
+ double s = 0;
+ for( k = 0; k <= var_count - 4; k += 4 )
+ s += sample[k]*another[k] + sample[k+1]*another[k+1] +
+ sample[k+2]*another[k+2] + sample[k+3]*another[k+3];
+ for( ; k < var_count; k++ )
+ s += sample[k]*another[k];
+ results[j] = (Qfloat)(s*alpha + beta);
+ }
+}
+
+
+void CvSVMKernel::calc_linear( int vcount, int var_count, const float** vecs,
+ const float* another, Qfloat* results )
+{
+ calc_non_rbf_base( vcount, var_count, vecs, another, results, 1, 0 );
+}
+
+
+void CvSVMKernel::calc_poly( int vcount, int var_count, const float** vecs,
+ const float* another, Qfloat* results )
+{
+ CvMat R = cvMat( 1, vcount, QFLOAT_TYPE, results );
+ calc_non_rbf_base( vcount, var_count, vecs, another, results, params->gamma, params->coef0 );
+ cvPow( &R, &R, params->degree );
+}
+
+
+void CvSVMKernel::calc_sigmoid( int vcount, int var_count, const float** vecs,
+ const float* another, Qfloat* results )
+{
+ int j;
+ calc_non_rbf_base( vcount, var_count, vecs, another, results,
+ -2*params->gamma, -2*params->coef0 );
+ // TODO: speedup this
+ for( j = 0; j < vcount; j++ )
+ {
+ Qfloat t = results[j];
+ double e = exp(-fabs(t));
+ if( t > 0 )
+ results[j] = (Qfloat)((1. - e)/(1. + e));
+ else
+ results[j] = (Qfloat)((e - 1.)/(e + 1.));
+ }
+}
+
+
+void CvSVMKernel::calc_rbf( int vcount, int var_count, const float** vecs,
+ const float* another, Qfloat* results )
+{
+ CvMat R = cvMat( 1, vcount, QFLOAT_TYPE, results );
+ double gamma = -params->gamma;
+ int j, k;
+
+ for( j = 0; j < vcount; j++ )
+ {
+ const float* sample = vecs[j];
+ double s = 0;
+
+ for( k = 0; k <= var_count - 4; k += 4 )
+ {
+ double t0 = sample[k] - another[k];
+ double t1 = sample[k+1] - another[k+1];
+
+ s += t0*t0 + t1*t1;
+
+ t0 = sample[k+2] - another[k+2];
+ t1 = sample[k+3] - another[k+3];
+
+ s += t0*t0 + t1*t1;
+ }
+
+ for( ; k < var_count; k++ )
+ {
+ double t0 = sample[k] - another[k];
+ s += t0*t0;
+ }
+ results[j] = (Qfloat)(s*gamma);
+ }
+
+ cvExp( &R, &R );
+}
+
+
+void CvSVMKernel::calc( int vcount, int var_count, const float** vecs,
+ const float* another, Qfloat* results )
+{
+ const Qfloat max_val = (Qfloat)(FLT_MAX*1e-3);
+ int j;
+ (this->*calc_func)( vcount, var_count, vecs, another, results );
+ for( j = 0; j < vcount; j++ )
+ {
+ if( results[j] > max_val )
+ results[j] = max_val;
+ }
+}
+
+
+// Generalized SMO+SVMlight algorithm
+// Solves:
+//
+// min [0.5(\alpha^T Q \alpha) + b^T \alpha]
+//
+// y^T \alpha = \delta
+// y_i = +1 or -1
+// 0 <= alpha_i <= Cp for y_i = 1
+// 0 <= alpha_i <= Cn for y_i = -1
+//
+// Given:
+//
+// Q, b, y, Cp, Cn, and an initial feasible point \alpha
+// l is the size of vectors and matrices
+// eps is the stopping criterion
+//
+// solution will be put in \alpha, objective value will be put in obj
+//
+
+void CvSVMSolver::clear()
+{
+ G = 0;
+ alpha = 0;
+ y = 0;
+ b = 0;
+ buf[0] = buf[1] = 0;
+ cvReleaseMemStorage( &storage );
+ kernel = 0;
+ select_working_set_func = 0;
+ calc_rho_func = 0;
+
+ rows = 0;
+ samples = 0;
+ get_row_func = 0;
+}
+
+
+CvSVMSolver::CvSVMSolver()
+{
+ storage = 0;
+ clear();
+}
+
+
+CvSVMSolver::~CvSVMSolver()
+{
+ clear();
+}
+
+
+CvSVMSolver::CvSVMSolver( int _sample_count, int _var_count, const float** _samples, schar* _y,
+ int _alpha_count, double* _alpha, double _Cp, double _Cn,
+ CvMemStorage* _storage, CvSVMKernel* _kernel, GetRow _get_row,
+ SelectWorkingSet _select_working_set, CalcRho _calc_rho )
+{
+ storage = 0;
+ create( _sample_count, _var_count, _samples, _y, _alpha_count, _alpha, _Cp, _Cn,
+ _storage, _kernel, _get_row, _select_working_set, _calc_rho );
+}
+
+
+bool CvSVMSolver::create( int _sample_count, int _var_count, const float** _samples, schar* _y,
+ int _alpha_count, double* _alpha, double _Cp, double _Cn,
+ CvMemStorage* _storage, CvSVMKernel* _kernel, GetRow _get_row,
+ SelectWorkingSet _select_working_set, CalcRho _calc_rho )
+{
+ bool ok = false;
+ int i, svm_type;
+
+ CV_FUNCNAME( "CvSVMSolver::create" );
+
+ __BEGIN__;
+
+ int rows_hdr_size;
+
+ clear();
+
+ sample_count = _sample_count;
+ var_count = _var_count;
+ samples = _samples;
+ y = _y;
+ alpha_count = _alpha_count;
+ alpha = _alpha;
+ kernel = _kernel;
+
+ C[0] = _Cn;
+ C[1] = _Cp;
+ eps = kernel->params->term_crit.epsilon;
+ max_iter = kernel->params->term_crit.max_iter;
+ storage = cvCreateChildMemStorage( _storage );
+
+ b = (double*)cvMemStorageAlloc( storage, alpha_count*sizeof(b[0]));
+ alpha_status = (schar*)cvMemStorageAlloc( storage, alpha_count*sizeof(alpha_status[0]));
+ G = (double*)cvMemStorageAlloc( storage, alpha_count*sizeof(G[0]));
+ for( i = 0; i < 2; i++ )
+ buf[i] = (Qfloat*)cvMemStorageAlloc( storage, sample_count*2*sizeof(buf[i][0]) );
+ svm_type = kernel->params->svm_type;
+
+ select_working_set_func = _select_working_set;
+ if( !select_working_set_func )
+ select_working_set_func = svm_type == CvSVM::NU_SVC || svm_type == CvSVM::NU_SVR ?
+ &CvSVMSolver::select_working_set_nu_svm : &CvSVMSolver::select_working_set;
+
+ calc_rho_func = _calc_rho;
+ if( !calc_rho_func )
+ calc_rho_func = svm_type == CvSVM::NU_SVC || svm_type == CvSVM::NU_SVR ?
+ &CvSVMSolver::calc_rho_nu_svm : &CvSVMSolver::calc_rho;
+
+ get_row_func = _get_row;
+ if( !get_row_func )
+ get_row_func = params->svm_type == CvSVM::EPS_SVR ||
+ params->svm_type == CvSVM::NU_SVR ? &CvSVMSolver::get_row_svr :
+ params->svm_type == CvSVM::C_SVC ||
+ params->svm_type == CvSVM::NU_SVC ? &CvSVMSolver::get_row_svc :
+ &CvSVMSolver::get_row_one_class;
+
+ cache_line_size = sample_count*sizeof(Qfloat);
+ // cache size = max(num_of_samples^2*sizeof(Qfloat)*0.25, 64Kb)
+ // (assuming that for large training sets ~25% of Q matrix is used)
+ cache_size = MAX( cache_line_size*sample_count/4, CV_SVM_MIN_CACHE_SIZE );
+
+ // the size of Q matrix row headers
+ rows_hdr_size = sample_count*sizeof(rows[0]);
+ if( rows_hdr_size > storage->block_size )
+ CV_ERROR( CV_StsOutOfRange, "Too small storage block size" );
+
+ lru_list.prev = lru_list.next = &lru_list;
+ rows = (CvSVMKernelRow*)cvMemStorageAlloc( storage, rows_hdr_size );
+ memset( rows, 0, rows_hdr_size );
+
+ ok = true;
+
+ __END__;
+
+ return ok;
+}
+
+
+float* CvSVMSolver::get_row_base( int i, bool* _existed )
+{
+ int i1 = i < sample_count ? i : i - sample_count;
+ CvSVMKernelRow* row = rows + i1;
+ bool existed = row->data != 0;
+ Qfloat* data;
+
+ if( existed || cache_size <= 0 )
+ {
+ CvSVMKernelRow* del_row = existed ? row : lru_list.prev;
+ data = del_row->data;
+ assert( data != 0 );
+
+ // delete row from the LRU list
+ del_row->data = 0;
+ del_row->prev->next = del_row->next;
+ del_row->next->prev = del_row->prev;
+ }
+ else
+ {
+ data = (Qfloat*)cvMemStorageAlloc( storage, cache_line_size );
+ cache_size -= cache_line_size;
+ }
+
+ // insert row into the LRU list
+ row->data = data;
+ row->prev = &lru_list;
+ row->next = lru_list.next;
+ row->prev->next = row->next->prev = row;
+
+ if( !existed )
+ {
+ kernel->calc( sample_count, var_count, samples, samples[i1], row->data );
+ }
+
+ if( _existed )
+ *_existed = existed;
+
+ return row->data;
+}
+
+
+float* CvSVMSolver::get_row_svc( int i, float* row, float*, bool existed )
+{
+ if( !existed )
+ {
+ const schar* _y = y;
+ int j, len = sample_count;
+ assert( _y && i < sample_count );
+
+ if( _y[i] > 0 )
+ {
+ for( j = 0; j < len; j++ )
+ row[j] = _y[j]*row[j];
+ }
+ else
+ {
+ for( j = 0; j < len; j++ )
+ row[j] = -_y[j]*row[j];
+ }
+ }
+ return row;
+}
+
+
+float* CvSVMSolver::get_row_one_class( int, float* row, float*, bool )
+{
+ return row;
+}
+
+
+float* CvSVMSolver::get_row_svr( int i, float* row, float* dst, bool )
+{
+ int j, len = sample_count;
+ Qfloat* dst_pos = dst;
+ Qfloat* dst_neg = dst + len;
+ if( i >= len )
+ {
+ Qfloat* temp;
+ CV_SWAP( dst_pos, dst_neg, temp );
+ }
+
+ for( j = 0; j < len; j++ )
+ {
+ Qfloat t = row[j];
+ dst_pos[j] = t;
+ dst_neg[j] = -t;
+ }
+ return dst;
+}
+
+
+
+float* CvSVMSolver::get_row( int i, float* dst )
+{
+ bool existed = false;
+ float* row = get_row_base( i, &existed );
+ return (this->*get_row_func)( i, row, dst, existed );
+}
+
+
+#undef is_upper_bound
+#define is_upper_bound(i) (alpha_status[i] > 0)
+
+#undef is_lower_bound
+#define is_lower_bound(i) (alpha_status[i] < 0)
+
+#undef is_free
+#define is_free(i) (alpha_status[i] == 0)
+
+#undef get_C
+#define get_C(i) (C[y[i]>0])
+
+#undef update_alpha_status
+#define update_alpha_status(i) \
+ alpha_status[i] = (schar)(alpha[i] >= get_C(i) ? 1 : alpha[i] <= 0 ? -1 : 0)
+
+#undef reconstruct_gradient
+#define reconstruct_gradient() /* empty for now */
+
+
+bool CvSVMSolver::solve_generic( CvSVMSolutionInfo& si )
+{
+ int iter = 0;
+ int i, j, k;
+
+ // 1. initialize gradient and alpha status
+ for( i = 0; i < alpha_count; i++ )
+ {
+ update_alpha_status(i);
+ G[i] = b[i];
+ if( fabs(G[i]) > 1e200 )
+ return false;
+ }
+
+ for( i = 0; i < alpha_count; i++ )
+ {
+ if( !is_lower_bound(i) )
+ {
+ const Qfloat *Q_i = get_row( i, buf[0] );
+ double alpha_i = alpha[i];
+
+ for( j = 0; j < alpha_count; j++ )
+ G[j] += alpha_i*Q_i[j];
+ }
+ }
+
+ // 2. optimization loop
+ for(;;)
+ {
+ const Qfloat *Q_i, *Q_j;
+ double C_i, C_j;
+ double old_alpha_i, old_alpha_j, alpha_i, alpha_j;
+ double delta_alpha_i, delta_alpha_j;
+
+#ifdef _DEBUG
+ for( i = 0; i < alpha_count; i++ )
+ {
+ if( fabs(G[i]) > 1e+300 )
+ return false;
+
+ if( fabs(alpha[i]) > 1e16 )
+ return false;
+ }
+#endif
+
+ if( (this->*select_working_set_func)( i, j ) != 0 || iter++ >= max_iter )
+ break;
+
+ Q_i = get_row( i, buf[0] );
+ Q_j = get_row( j, buf[1] );
+
+ C_i = get_C(i);
+ C_j = get_C(j);
+
+ alpha_i = old_alpha_i = alpha[i];
+ alpha_j = old_alpha_j = alpha[j];
+
+ if( y[i] != y[j] )
+ {
+ double denom = Q_i[i]+Q_j[j]+2*Q_i[j];
+ double delta = (-G[i]-G[j])/MAX(fabs(denom),FLT_EPSILON);
+ double diff = alpha_i - alpha_j;
+ alpha_i += delta;
+ alpha_j += delta;
+
+ if( diff > 0 && alpha_j < 0 )
+ {
+ alpha_j = 0;
+ alpha_i = diff;
+ }
+ else if( diff <= 0 && alpha_i < 0 )
+ {
+ alpha_i = 0;
+ alpha_j = -diff;
+ }
+
+ if( diff > C_i - C_j && alpha_i > C_i )
+ {
+ alpha_i = C_i;
+ alpha_j = C_i - diff;
+ }
+ else if( diff <= C_i - C_j && alpha_j > C_j )
+ {
+ alpha_j = C_j;
+ alpha_i = C_j + diff;
+ }
+ }
+ else
+ {
+ double denom = Q_i[i]+Q_j[j]-2*Q_i[j];
+ double delta = (G[i]-G[j])/MAX(fabs(denom),FLT_EPSILON);
+ double sum = alpha_i + alpha_j;
+ alpha_i -= delta;
+ alpha_j += delta;
+
+ if( sum > C_i && alpha_i > C_i )
+ {
+ alpha_i = C_i;
+ alpha_j = sum - C_i;
+ }
+ else if( sum <= C_i && alpha_j < 0)
+ {
+ alpha_j = 0;
+ alpha_i = sum;
+ }
+
+ if( sum > C_j && alpha_j > C_j )
+ {
+ alpha_j = C_j;
+ alpha_i = sum - C_j;
+ }
+ else if( sum <= C_j && alpha_i < 0 )
+ {
+ alpha_i = 0;
+ alpha_j = sum;
+ }
+ }
+
+ // update alpha
+ alpha[i] = alpha_i;
+ alpha[j] = alpha_j;
+ update_alpha_status(i);
+ update_alpha_status(j);
+
+ // update G
+ delta_alpha_i = alpha_i - old_alpha_i;
+ delta_alpha_j = alpha_j - old_alpha_j;
+
+ for( k = 0; k < alpha_count; k++ )
+ G[k] += Q_i[k]*delta_alpha_i + Q_j[k]*delta_alpha_j;
+ }
+
+ // calculate rho
+ (this->*calc_rho_func)( si.rho, si.r );
+
+ // calculate objective value
+ for( i = 0, si.obj = 0; i < alpha_count; i++ )
+ si.obj += alpha[i] * (G[i] + b[i]);
+
+ si.obj *= 0.5;
+
+ si.upper_bound_p = C[1];
+ si.upper_bound_n = C[0];
+
+ return true;
+}
+
+
+// return 1 if already optimal, return 0 otherwise
+bool
+CvSVMSolver::select_working_set( int& out_i, int& out_j )
+{
+ // return i,j which maximize -grad(f)^T d , under constraint
+ // if alpha_i == C, d != +1
+ // if alpha_i == 0, d != -1
+ double Gmax1 = -DBL_MAX; // max { -grad(f)_i * d | y_i*d = +1 }
+ int Gmax1_idx = -1;
+
+ double Gmax2 = -DBL_MAX; // max { -grad(f)_i * d | y_i*d = -1 }
+ int Gmax2_idx = -1;
+
+ int i;
+
+ for( i = 0; i < alpha_count; i++ )
+ {
+ double t;
+
+ if( y[i] > 0 ) // y = +1
+ {
+ if( !is_upper_bound(i) && (t = -G[i]) > Gmax1 ) // d = +1
+ {
+ Gmax1 = t;
+ Gmax1_idx = i;
+ }
+ if( !is_lower_bound(i) && (t = G[i]) > Gmax2 ) // d = -1
+ {
+ Gmax2 = t;
+ Gmax2_idx = i;
+ }
+ }
+ else // y = -1
+ {
+ if( !is_upper_bound(i) && (t = -G[i]) > Gmax2 ) // d = +1
+ {
+ Gmax2 = t;
+ Gmax2_idx = i;
+ }
+ if( !is_lower_bound(i) && (t = G[i]) > Gmax1 ) // d = -1
+ {
+ Gmax1 = t;
+ Gmax1_idx = i;
+ }
+ }
+ }
+
+ out_i = Gmax1_idx;
+ out_j = Gmax2_idx;
+
+ return Gmax1 + Gmax2 < eps;
+}
+
+
+void
+CvSVMSolver::calc_rho( double& rho, double& r )
+{
+ int i, nr_free = 0;
+ double ub = DBL_MAX, lb = -DBL_MAX, sum_free = 0;
+
+ for( i = 0; i < alpha_count; i++ )
+ {
+ double yG = y[i]*G[i];
+
+ if( is_lower_bound(i) )
+ {
+ if( y[i] > 0 )
+ ub = MIN(ub,yG);
+ else
+ lb = MAX(lb,yG);
+ }
+ else if( is_upper_bound(i) )
+ {
+ if( y[i] < 0)
+ ub = MIN(ub,yG);
+ else
+ lb = MAX(lb,yG);
+ }
+ else
+ {
+ ++nr_free;
+ sum_free += yG;
+ }
+ }
+
+ rho = nr_free > 0 ? sum_free/nr_free : (ub + lb)*0.5;
+ r = 0;
+}
+
+
+bool
+CvSVMSolver::select_working_set_nu_svm( int& out_i, int& out_j )
+{
+ // return i,j which maximize -grad(f)^T d , under constraint
+ // if alpha_i == C, d != +1
+ // if alpha_i == 0, d != -1
+ double Gmax1 = -DBL_MAX; // max { -grad(f)_i * d | y_i = +1, d = +1 }
+ int Gmax1_idx = -1;
+
+ double Gmax2 = -DBL_MAX; // max { -grad(f)_i * d | y_i = +1, d = -1 }
+ int Gmax2_idx = -1;
+
+ double Gmax3 = -DBL_MAX; // max { -grad(f)_i * d | y_i = -1, d = +1 }
+ int Gmax3_idx = -1;
+
+ double Gmax4 = -DBL_MAX; // max { -grad(f)_i * d | y_i = -1, d = -1 }
+ int Gmax4_idx = -1;
+
+ int i;
+
+ for( i = 0; i < alpha_count; i++ )
+ {
+ double t;
+
+ if( y[i] > 0 ) // y == +1
+ {
+ if( !is_upper_bound(i) && (t = -G[i]) > Gmax1 ) // d = +1
+ {
+ Gmax1 = t;
+ Gmax1_idx = i;
+ }
+ if( !is_lower_bound(i) && (t = G[i]) > Gmax2 ) // d = -1
+ {
+ Gmax2 = t;
+ Gmax2_idx = i;
+ }
+ }
+ else // y == -1
+ {
+ if( !is_upper_bound(i) && (t = -G[i]) > Gmax3 ) // d = +1
+ {
+ Gmax3 = t;
+ Gmax3_idx = i;
+ }
+ if( !is_lower_bound(i) && (t = G[i]) > Gmax4 ) // d = -1
+ {
+ Gmax4 = t;
+ Gmax4_idx = i;
+ }
+ }
+ }
+
+ if( MAX(Gmax1 + Gmax2, Gmax3 + Gmax4) < eps )
+ return 1;
+
+ if( Gmax1 + Gmax2 > Gmax3 + Gmax4 )
+ {
+ out_i = Gmax1_idx;
+ out_j = Gmax2_idx;
+ }
+ else
+ {
+ out_i = Gmax3_idx;
+ out_j = Gmax4_idx;
+ }
+ return 0;
+}
+
+
+void
+CvSVMSolver::calc_rho_nu_svm( double& rho, double& r )
+{
+ int nr_free1 = 0, nr_free2 = 0;
+ double ub1 = DBL_MAX, ub2 = DBL_MAX;
+ double lb1 = -DBL_MAX, lb2 = -DBL_MAX;
+ double sum_free1 = 0, sum_free2 = 0;
+ double r1, r2;
+
+ int i;
+
+ for( i = 0; i < alpha_count; i++ )
+ {
+ double G_i = G[i];
+ if( y[i] > 0 )
+ {
+ if( is_lower_bound(i) )
+ ub1 = MIN( ub1, G_i );
+ else if( is_upper_bound(i) )
+ lb1 = MAX( lb1, G_i );
+ else
+ {
+ ++nr_free1;
+ sum_free1 += G_i;
+ }
+ }
+ else
+ {
+ if( is_lower_bound(i) )
+ ub2 = MIN( ub2, G_i );
+ else if( is_upper_bound(i) )
+ lb2 = MAX( lb2, G_i );
+ else
+ {
+ ++nr_free2;
+ sum_free2 += G_i;
+ }
+ }
+ }
+
+ r1 = nr_free1 > 0 ? sum_free1/nr_free1 : (ub1 + lb1)*0.5;
+ r2 = nr_free2 > 0 ? sum_free2/nr_free2 : (ub2 + lb2)*0.5;
+
+ rho = (r1 - r2)*0.5;
+ r = (r1 + r2)*0.5;
+}
+
+
+/*
+///////////////////////// construct and solve various formulations ///////////////////////
+*/
+
+bool CvSVMSolver::solve_c_svc( int _sample_count, int _var_count, const float** _samples, schar* _y,
+ double _Cp, double _Cn, CvMemStorage* _storage,
+ CvSVMKernel* _kernel, double* _alpha, CvSVMSolutionInfo& _si )
+{
+ int i;
+
+ if( !create( _sample_count, _var_count, _samples, _y, _sample_count,
+ _alpha, _Cp, _Cn, _storage, _kernel, &CvSVMSolver::get_row_svc,
+ &CvSVMSolver::select_working_set, &CvSVMSolver::calc_rho ))
+ return false;
+
+ for( i = 0; i < sample_count; i++ )
+ {
+ alpha[i] = 0;
+ b[i] = -1;
+ }
+
+ if( !solve_generic( _si ))
+ return false;
+
+ for( i = 0; i < sample_count; i++ )
+ alpha[i] *= y[i];
+
+ return true;
+}
+
+
+bool CvSVMSolver::solve_nu_svc( int _sample_count, int _var_count, const float** _samples, schar* _y,
+ CvMemStorage* _storage, CvSVMKernel* _kernel,
+ double* _alpha, CvSVMSolutionInfo& _si )
+{
+ int i;
+ double sum_pos, sum_neg, inv_r;
+
+ if( !create( _sample_count, _var_count, _samples, _y, _sample_count,
+ _alpha, 1., 1., _storage, _kernel, &CvSVMSolver::get_row_svc,
+ &CvSVMSolver::select_working_set_nu_svm, &CvSVMSolver::calc_rho_nu_svm ))
+ return false;
+
+ sum_pos = kernel->params->nu * sample_count * 0.5;
+ sum_neg = kernel->params->nu * sample_count * 0.5;
+
+ for( i = 0; i < sample_count; i++ )
+ {
+ if( y[i] > 0 )
+ {
+ alpha[i] = MIN(1.0, sum_pos);
+ sum_pos -= alpha[i];
+ }
+ else
+ {
+ alpha[i] = MIN(1.0, sum_neg);
+ sum_neg -= alpha[i];
+ }
+ b[i] = 0;
+ }
+
+ if( !solve_generic( _si ))
+ return false;
+
+ inv_r = 1./_si.r;
+
+ for( i = 0; i < sample_count; i++ )
+ alpha[i] *= y[i]*inv_r;
+
+ _si.rho *= inv_r;
+ _si.obj *= (inv_r*inv_r);
+ _si.upper_bound_p = inv_r;
+ _si.upper_bound_n = inv_r;
+
+ return true;
+}
+
+
+bool CvSVMSolver::solve_one_class( int _sample_count, int _var_count, const float** _samples,
+ CvMemStorage* _storage, CvSVMKernel* _kernel,
+ double* _alpha, CvSVMSolutionInfo& _si )
+{
+ int i, n;
+ double nu = _kernel->params->nu;
+
+ if( !create( _sample_count, _var_count, _samples, 0, _sample_count,
+ _alpha, 1., 1., _storage, _kernel, &CvSVMSolver::get_row_one_class,
+ &CvSVMSolver::select_working_set, &CvSVMSolver::calc_rho ))
+ return false;
+
+ y = (schar*)cvMemStorageAlloc( storage, sample_count*sizeof(y[0]) );
+ n = cvRound( nu*sample_count );
+
+ for( i = 0; i < sample_count; i++ )
+ {
+ y[i] = 1;
+ b[i] = 0;
+ alpha[i] = i < n ? 1 : 0;
+ }
+
+ if( n < sample_count )
+ alpha[n] = nu * sample_count - n;
+ else
+ alpha[n-1] = nu * sample_count - (n-1);
+
+ return solve_generic(_si);
+}
+
+
+bool CvSVMSolver::solve_eps_svr( int _sample_count, int _var_count, const float** _samples,
+ const float* _y, CvMemStorage* _storage,
+ CvSVMKernel* _kernel, double* _alpha, CvSVMSolutionInfo& _si )
+{
+ int i;
+ double p = _kernel->params->p, C = _kernel->params->C;
+
+ if( !create( _sample_count, _var_count, _samples, 0,
+ _sample_count*2, 0, C, C, _storage, _kernel, &CvSVMSolver::get_row_svr,
+ &CvSVMSolver::select_working_set, &CvSVMSolver::calc_rho ))
+ return false;
+
+ y = (schar*)cvMemStorageAlloc( storage, sample_count*2*sizeof(y[0]) );
+ alpha = (double*)cvMemStorageAlloc( storage, alpha_count*sizeof(alpha[0]) );
+
+ for( i = 0; i < sample_count; i++ )
+ {
+ alpha[i] = 0;
+ b[i] = p - _y[i];
+ y[i] = 1;
+
+ alpha[i+sample_count] = 0;
+ b[i+sample_count] = p + _y[i];
+ y[i+sample_count] = -1;
+ }
+
+ if( !solve_generic( _si ))
+ return false;
+
+ for( i = 0; i < sample_count; i++ )
+ _alpha[i] = alpha[i] - alpha[i+sample_count];
+
+ return true;
+}
+
+
+bool CvSVMSolver::solve_nu_svr( int _sample_count, int _var_count, const float** _samples,
+ const float* _y, CvMemStorage* _storage,
+ CvSVMKernel* _kernel, double* _alpha, CvSVMSolutionInfo& _si )
+{
+ int i;
+ double C = _kernel->params->C, sum;
+
+ if( !create( _sample_count, _var_count, _samples, 0,
+ _sample_count*2, 0, 1., 1., _storage, _kernel, &CvSVMSolver::get_row_svr,
+ &CvSVMSolver::select_working_set_nu_svm, &CvSVMSolver::calc_rho_nu_svm ))
+ return false;
+
+ y = (schar*)cvMemStorageAlloc( storage, sample_count*2*sizeof(y[0]) );
+ alpha = (double*)cvMemStorageAlloc( storage, alpha_count*sizeof(alpha[0]) );
+ sum = C * _kernel->params->nu * sample_count * 0.5;
+
+ for( i = 0; i < sample_count; i++ )
+ {
+ alpha[i] = alpha[i + sample_count] = MIN(sum, C);
+ sum -= alpha[i];
+
+ b[i] = -_y[i];
+ y[i] = 1;
+
+ b[i + sample_count] = _y[i];
+ y[i + sample_count] = -1;
+ }
+
+ if( !solve_generic( _si ))
+ return false;
+
+ for( i = 0; i < sample_count; i++ )
+ _alpha[i] = alpha[i] - alpha[i+sample_count];
+
+ return true;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+CvSVM::CvSVM()
+{
+ decision_func = 0;
+ class_labels = 0;
+ class_weights = 0;
+ storage = 0;
+ var_idx = 0;
+ kernel = 0;
+ solver = 0;
+ default_model_name = "my_svm";
+
+ clear();
+}
+
+
+CvSVM::~CvSVM()
+{
+ clear();
+}
+
+
+void CvSVM::clear()
+{
+ cvFree( &decision_func );
+ cvReleaseMat( &class_labels );
+ cvReleaseMat( &class_weights );
+ cvReleaseMemStorage( &storage );
+ cvReleaseMat( &var_idx );
+ delete kernel;
+ delete solver;
+ kernel = 0;
+ solver = 0;
+ var_all = 0;
+ sv = 0;
+ sv_total = 0;
+}
+
+
+CvSVM::CvSVM( const CvMat* _train_data, const CvMat* _responses,
+ const CvMat* _var_idx, const CvMat* _sample_idx, CvSVMParams _params )
+{
+ decision_func = 0;
+ class_labels = 0;
+ class_weights = 0;
+ storage = 0;
+ var_idx = 0;
+ kernel = 0;
+ solver = 0;
+ default_model_name = "my_svm";
+
+ train( _train_data, _responses, _var_idx, _sample_idx, _params );
+}
+
+
+int CvSVM::get_support_vector_count() const
+{
+ return sv_total;
+}
+
+
+const float* CvSVM::get_support_vector(int i) const
+{
+ return sv && (unsigned)i < (unsigned)sv_total ? sv[i] : 0;
+}
+
+
+bool CvSVM::set_params( const CvSVMParams& _params )
+{
+ bool ok = false;
+
+ CV_FUNCNAME( "CvSVM::set_params" );
+
+ __BEGIN__;
+
+ int kernel_type, svm_type;
+
+ params = _params;
+
+ kernel_type = params.kernel_type;
+ svm_type = params.svm_type;
+
+ if( kernel_type != LINEAR && kernel_type != POLY &&
+ kernel_type != SIGMOID && kernel_type != RBF )
+ CV_ERROR( CV_StsBadArg, "Unknown/unsupported kernel type" );
+
+ if( kernel_type == LINEAR )
+ params.gamma = 1;
+ else if( params.gamma <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "gamma parameter of the kernel must be positive" );
+
+ if( kernel_type != SIGMOID && kernel_type != POLY )
+ params.coef0 = 0;
+ else if( params.coef0 < 0 )
+ CV_ERROR( CV_StsOutOfRange, "The kernel parameter <coef0> must be positive or zero" );
+
+ if( kernel_type != POLY )
+ params.degree = 0;
+ else if( params.degree <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "The kernel parameter <degree> must be positive" );
+
+ if( svm_type != C_SVC && svm_type != NU_SVC &&
+ svm_type != ONE_CLASS && svm_type != EPS_SVR &&
+ svm_type != NU_SVR )
+ CV_ERROR( CV_StsBadArg, "Unknown/unsupported SVM type" );
+
+ if( svm_type == ONE_CLASS || svm_type == NU_SVC )
+ params.C = 0;
+ else if( params.C <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "The parameter C must be positive" );
+
+ if( svm_type == C_SVC || svm_type == EPS_SVR )
+ params.nu = 0;
+ else if( params.nu <= 0 || params.nu >= 1 )
+ CV_ERROR( CV_StsOutOfRange, "The parameter nu must be between 0 and 1" );
+
+ if( svm_type != EPS_SVR )
+ params.p = 0;
+ else if( params.p <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "The parameter p must be positive" );
+
+ if( svm_type != C_SVC )
+ params.class_weights = 0;
+
+ params.term_crit = cvCheckTermCriteria( params.term_crit, DBL_EPSILON, INT_MAX );
+ params.term_crit.epsilon = MAX( params.term_crit.epsilon, DBL_EPSILON );
+ ok = true;
+
+ __END__;
+
+ return ok;
+}
+
+
+
+void CvSVM::create_kernel()
+{
+ kernel = new CvSVMKernel(&params,0);
+}
+
+
+void CvSVM::create_solver( )
+{
+ solver = new CvSVMSolver;
+}
+
+
+// switching function
+bool CvSVM::train1( int sample_count, int var_count, const float** samples,
+ const void* _responses, double Cp, double Cn,
+ CvMemStorage* _storage, double* alpha, double& rho )
+{
+ bool ok = false;
+
+ //CV_FUNCNAME( "CvSVM::train1" );
+
+ __BEGIN__;
+
+ CvSVMSolutionInfo si;
+ int svm_type = params.svm_type;
+
+ si.rho = 0;
+
+ ok = svm_type == C_SVC ? solver->solve_c_svc( sample_count, var_count, samples, (schar*)_responses,
+ Cp, Cn, _storage, kernel, alpha, si ) :
+ svm_type == NU_SVC ? solver->solve_nu_svc( sample_count, var_count, samples, (schar*)_responses,
+ _storage, kernel, alpha, si ) :
+ svm_type == ONE_CLASS ? solver->solve_one_class( sample_count, var_count, samples,
+ _storage, kernel, alpha, si ) :
+ svm_type == EPS_SVR ? solver->solve_eps_svr( sample_count, var_count, samples, (float*)_responses,
+ _storage, kernel, alpha, si ) :
+ svm_type == NU_SVR ? solver->solve_nu_svr( sample_count, var_count, samples, (float*)_responses,
+ _storage, kernel, alpha, si ) : false;
+
+ rho = si.rho;
+
+ __END__;
+
+ return ok;
+}
+
+
+bool CvSVM::do_train( int svm_type, int sample_count, int var_count, const float** samples,
+ const CvMat* responses, CvMemStorage* temp_storage, double* alpha )
+{
+ bool ok = false;
+
+ CV_FUNCNAME( "CvSVM::do_train" );
+
+ __BEGIN__;
+
+ CvSVMDecisionFunc* df = 0;
+ const int sample_size = var_count*sizeof(samples[0][0]);
+ int i, j, k;
+
+ if( svm_type == ONE_CLASS || svm_type == EPS_SVR || svm_type == NU_SVR )
+ {
+ int sv_count = 0;
+
+ CV_CALL( decision_func = df =
+ (CvSVMDecisionFunc*)cvAlloc( sizeof(df[0]) ));
+
+ df->rho = 0;
+ if( !train1( sample_count, var_count, samples, svm_type == ONE_CLASS ? 0 :
+ responses->data.i, 0, 0, temp_storage, alpha, df->rho ))
+ EXIT;
+
+ for( i = 0; i < sample_count; i++ )
+ sv_count += fabs(alpha[i]) > 0;
+
+ sv_total = df->sv_count = sv_count;
+ CV_CALL( df->alpha = (double*)cvMemStorageAlloc( storage, sv_count*sizeof(df->alpha[0])) );
+ CV_CALL( sv = (float**)cvMemStorageAlloc( storage, sv_count*sizeof(sv[0])));
+
+ for( i = k = 0; i < sample_count; i++ )
+ {
+ if( fabs(alpha[i]) > 0 )
+ {
+ CV_CALL( sv[k] = (float*)cvMemStorageAlloc( storage, sample_size ));
+ memcpy( sv[k], samples[i], sample_size );
+ df->alpha[k++] = alpha[i];
+ }
+ }
+ }
+ else
+ {
+ int class_count = class_labels->cols;
+ int* sv_tab = 0;
+ const float** temp_samples = 0;
+ int* class_ranges = 0;
+ schar* temp_y = 0;
+ assert( svm_type == CvSVM::C_SVC || svm_type == CvSVM::NU_SVC );
+
+ if( svm_type == CvSVM::C_SVC && params.class_weights )
+ {
+ const CvMat* cw = params.class_weights;
+
+ if( !CV_IS_MAT(cw) || cw->cols != 1 && cw->rows != 1 ||
+ cw->rows + cw->cols - 1 != class_count ||
+ CV_MAT_TYPE(cw->type) != CV_32FC1 && CV_MAT_TYPE(cw->type) != CV_64FC1 )
+ CV_ERROR( CV_StsBadArg, "params.class_weights must be 1d floating-point vector "
+ "containing as many elements as the number of classes" );
+
+ CV_CALL( class_weights = cvCreateMat( cw->rows, cw->cols, CV_64F ));
+ CV_CALL( cvConvert( cw, class_weights ));
+ CV_CALL( cvScale( class_weights, class_weights, params.C ));
+ }
+
+ CV_CALL( decision_func = df = (CvSVMDecisionFunc*)cvAlloc(
+ (class_count*(class_count-1)/2)*sizeof(df[0])));
+
+ CV_CALL( sv_tab = (int*)cvMemStorageAlloc( temp_storage, sample_count*sizeof(sv_tab[0]) ));
+ memset( sv_tab, 0, sample_count*sizeof(sv_tab[0]) );
+ CV_CALL( class_ranges = (int*)cvMemStorageAlloc( temp_storage,
+ (class_count + 1)*sizeof(class_ranges[0])));
+ CV_CALL( temp_samples = (const float**)cvMemStorageAlloc( temp_storage,
+ sample_count*sizeof(temp_samples[0])));
+ CV_CALL( temp_y = (schar*)cvMemStorageAlloc( temp_storage, sample_count));
+
+ class_ranges[class_count] = 0;
+ cvSortSamplesByClasses( samples, responses, class_ranges, 0 );
+ //check that while cross-validation there were the samples from all the classes
+ if( class_ranges[class_count] <= 0 )
+ CV_ERROR( CV_StsBadArg, "While cross-validation one or more of the classes have "
+ "been fell out of the sample. Try to enlarge <CvSVMParams::k_fold>" );
+
+ if( svm_type == NU_SVC )
+ {
+ // check if nu is feasible
+ for(i = 0; i < class_count; i++ )
+ {
+ int ci = class_ranges[i+1] - class_ranges[i];
+ for( j = i+1; j< class_count; j++ )
+ {
+ int cj = class_ranges[j+1] - class_ranges[j];
+ if( params.nu*(ci + cj)*0.5 > MIN( ci, cj ) )
+ {
+ // !!!TODO!!! add some diagnostic
+ EXIT; // exit immediately; will release the model and return NULL pointer
+ }
+ }
+ }
+ }
+
+ // train n*(n-1)/2 classifiers
+ for( i = 0; i < class_count; i++ )
+ {
+ for( j = i+1; j < class_count; j++, df++ )
+ {
+ int si = class_ranges[i], ci = class_ranges[i+1] - si;
+ int sj = class_ranges[j], cj = class_ranges[j+1] - sj;
+ double Cp = params.C, Cn = Cp;
+ int k1 = 0, sv_count = 0;
+
+ for( k = 0; k < ci; k++ )
+ {
+ temp_samples[k] = samples[si + k];
+ temp_y[k] = 1;
+ }
+
+ for( k = 0; k < cj; k++ )
+ {
+ temp_samples[ci + k] = samples[sj + k];
+ temp_y[ci + k] = -1;
+ }
+
+ if( class_weights )
+ {
+ Cp = class_weights->data.db[i];
+ Cn = class_weights->data.db[j];
+ }
+
+ if( !train1( ci + cj, var_count, temp_samples, temp_y,
+ Cp, Cn, temp_storage, alpha, df->rho ))
+ EXIT;
+
+ for( k = 0; k < ci + cj; k++ )
+ sv_count += fabs(alpha[k]) > 0;
+
+ df->sv_count = sv_count;
+
+ CV_CALL( df->alpha = (double*)cvMemStorageAlloc( temp_storage,
+ sv_count*sizeof(df->alpha[0])));
+ CV_CALL( df->sv_index = (int*)cvMemStorageAlloc( temp_storage,
+ sv_count*sizeof(df->sv_index[0])));
+
+ for( k = 0; k < ci; k++ )
+ {
+ if( fabs(alpha[k]) > 0 )
+ {
+ sv_tab[si + k] = 1;
+ df->sv_index[k1] = si + k;
+ df->alpha[k1++] = alpha[k];
+ }
+ }
+
+ for( k = 0; k < cj; k++ )
+ {
+ if( fabs(alpha[ci + k]) > 0 )
+ {
+ sv_tab[sj + k] = 1;
+ df->sv_index[k1] = sj + k;
+ df->alpha[k1++] = alpha[ci + k];
+ }
+ }
+ }
+ }
+
+ // allocate support vectors and initialize sv_tab
+ for( i = 0, k = 0; i < sample_count; i++ )
+ {
+ if( sv_tab[i] )
+ sv_tab[i] = ++k;
+ }
+
+ sv_total = k;
+ CV_CALL( sv = (float**)cvMemStorageAlloc( storage, sv_total*sizeof(sv[0])));
+
+ for( i = 0, k = 0; i < sample_count; i++ )
+ {
+ if( sv_tab[i] )
+ {
+ CV_CALL( sv[k] = (float*)cvMemStorageAlloc( storage, sample_size ));
+ memcpy( sv[k], samples[i], sample_size );
+ k++;
+ }
+ }
+
+ df = (CvSVMDecisionFunc*)decision_func;
+
+ // set sv pointers
+ for( i = 0; i < class_count; i++ )
+ {
+ for( j = i+1; j < class_count; j++, df++ )
+ {
+ for( k = 0; k < df->sv_count; k++ )
+ {
+ df->sv_index[k] = sv_tab[df->sv_index[k]]-1;
+ assert( (unsigned)df->sv_index[k] < (unsigned)sv_total );
+ }
+ }
+ }
+ }
+
+ ok = true;
+
+ __END__;
+
+ return ok;
+}
+
+bool CvSVM::train( const CvMat* _train_data, const CvMat* _responses,
+ const CvMat* _var_idx, const CvMat* _sample_idx, CvSVMParams _params )
+{
+ bool ok = false;
+ CvMat* responses = 0;
+ CvMemStorage* temp_storage = 0;
+ const float** samples = 0;
+
+ CV_FUNCNAME( "CvSVM::train" );
+
+ __BEGIN__;
+
+ int svm_type, sample_count, var_count, sample_size;
+ int block_size = 1 << 16;
+ double* alpha;
+
+ clear();
+ CV_CALL( set_params( _params ));
+
+ svm_type = _params.svm_type;
+
+ /* Prepare training data and related parameters */
+ CV_CALL( cvPrepareTrainData( "CvSVM::train", _train_data, CV_ROW_SAMPLE,
+ svm_type != CvSVM::ONE_CLASS ? _responses : 0,
+ svm_type == CvSVM::C_SVC ||
+ svm_type == CvSVM::NU_SVC ? CV_VAR_CATEGORICAL :
+ CV_VAR_ORDERED, _var_idx, _sample_idx,
+ false, &samples, &sample_count, &var_count, &var_all,
+ &responses, &class_labels, &var_idx ));
+
+
+ sample_size = var_count*sizeof(samples[0][0]);
+
+ // make the storage block size large enough to fit all
+ // the temporary vectors and output support vectors.
+ block_size = MAX( block_size, sample_count*(int)sizeof(CvSVMKernelRow));
+ block_size = MAX( block_size, sample_count*2*(int)sizeof(double) + 1024 );
+ block_size = MAX( block_size, sample_size*2 + 1024 );
+
+ CV_CALL( storage = cvCreateMemStorage(block_size));
+ CV_CALL( temp_storage = cvCreateChildMemStorage(storage));
+ CV_CALL( alpha = (double*)cvMemStorageAlloc(temp_storage, sample_count*sizeof(double)));
+
+ create_kernel();
+ create_solver();
+
+ if( !do_train( svm_type, sample_count, var_count, samples, responses, temp_storage, alpha ))
+ EXIT;
+
+ ok = true; // model has been trained succesfully
+
+ __END__;
+
+ delete solver;
+ solver = 0;
+ cvReleaseMemStorage( &temp_storage );
+ cvReleaseMat( &responses );
+ cvFree( &samples );
+
+ if( cvGetErrStatus() < 0 || !ok )
+ clear();
+
+ return ok;
+}
+
+bool CvSVM::train_auto( const CvMat* _train_data, const CvMat* _responses,
+ const CvMat* _var_idx, const CvMat* _sample_idx, CvSVMParams _params, int k_fold,
+ CvParamGrid C_grid, CvParamGrid gamma_grid, CvParamGrid p_grid,
+ CvParamGrid nu_grid, CvParamGrid coef_grid, CvParamGrid degree_grid )
+{
+ bool ok = false;
+ CvMat* responses = 0;
+ CvMat* responses_local = 0;
+ CvMemStorage* temp_storage = 0;
+ const float** samples = 0;
+ const float** samples_local = 0;
+
+ CV_FUNCNAME( "CvSVM::train_auto" );
+ __BEGIN__;
+
+ int svm_type, sample_count, var_count, sample_size;
+ int block_size = 1 << 16;
+ double* alpha;
+ int i, k;
+ CvRNG rng = cvRNG(-1);
+
+ // all steps are logarithmic and must be > 1
+ double degree_step = 10, g_step = 10, coef_step = 10, C_step = 10, nu_step = 10, p_step = 10;
+ double gamma = 0, C = 0, degree = 0, coef = 0, p = 0, nu = 0;
+ double best_degree = 0, best_gamma = 0, best_coef = 0, best_C = 0, best_nu = 0, best_p = 0;
+ float min_error = FLT_MAX, error;
+
+ if( _params.svm_type == CvSVM::ONE_CLASS )
+ {
+ if(!train( _train_data, _responses, _var_idx, _sample_idx, _params ))
+ EXIT;
+ return true;
+ }
+
+ clear();
+
+ if( k_fold < 2 )
+ CV_ERROR( CV_StsBadArg, "Parameter <k_fold> must be > 1" );
+
+ CV_CALL(set_params( _params ));
+ svm_type = _params.svm_type;
+
+ // All the parameters except, possibly, <coef0> are positive.
+ // <coef0> is nonnegative
+ if( C_grid.step <= 1 )
+ {
+ C_grid.min_val = C_grid.max_val = params.C;
+ C_grid.step = 10;
+ }
+ else
+ CV_CALL(C_grid.check());
+
+ if( gamma_grid.step <= 1 )
+ {
+ gamma_grid.min_val = gamma_grid.max_val = params.gamma;
+ gamma_grid.step = 10;
+ }
+ else
+ CV_CALL(gamma_grid.check());
+
+ if( p_grid.step <= 1 )
+ {
+ p_grid.min_val = p_grid.max_val = params.p;
+ p_grid.step = 10;
+ }
+ else
+ CV_CALL(p_grid.check());
+
+ if( nu_grid.step <= 1 )
+ {
+ nu_grid.min_val = nu_grid.max_val = params.nu;
+ nu_grid.step = 10;
+ }
+ else
+ CV_CALL(nu_grid.check());
+
+ if( coef_grid.step <= 1 )
+ {
+ coef_grid.min_val = coef_grid.max_val = params.coef0;
+ coef_grid.step = 10;
+ }
+ else
+ CV_CALL(coef_grid.check());
+
+ if( degree_grid.step <= 1 )
+ {
+ degree_grid.min_val = degree_grid.max_val = params.degree;
+ degree_grid.step = 10;
+ }
+ else
+ CV_CALL(degree_grid.check());
+
+ // these parameters are not used:
+ if( params.kernel_type != CvSVM::POLY )
+ degree_grid.min_val = degree_grid.max_val = params.degree;
+ if( params.kernel_type == CvSVM::LINEAR )
+ gamma_grid.min_val = gamma_grid.max_val = params.gamma;
+ if( params.kernel_type != CvSVM::POLY && params.kernel_type != CvSVM::SIGMOID )
+ coef_grid.min_val = coef_grid.max_val = params.coef0;
+ if( svm_type == CvSVM::NU_SVC || svm_type == CvSVM::ONE_CLASS )
+ C_grid.min_val = C_grid.max_val = params.C;
+ if( svm_type == CvSVM::C_SVC || svm_type == CvSVM::EPS_SVR )
+ nu_grid.min_val = nu_grid.max_val = params.nu;
+ if( svm_type != CvSVM::EPS_SVR )
+ p_grid.min_val = p_grid.max_val = params.p;
+
+ CV_ASSERT( g_step > 1 && degree_step > 1 && coef_step > 1);
+ CV_ASSERT( p_step > 1 && C_step > 1 && nu_step > 1 );
+
+ /* Prepare training data and related parameters */
+ CV_CALL(cvPrepareTrainData( "CvSVM::train_auto", _train_data, CV_ROW_SAMPLE,
+ svm_type != CvSVM::ONE_CLASS ? _responses : 0,
+ svm_type == CvSVM::C_SVC ||
+ svm_type == CvSVM::NU_SVC ? CV_VAR_CATEGORICAL :
+ CV_VAR_ORDERED, _var_idx, _sample_idx,
+ false, &samples, &sample_count, &var_count, &var_all,
+ &responses, &class_labels, &var_idx ));
+
+ sample_size = var_count*sizeof(samples[0][0]);
+
+ // make the storage block size large enough to fit all
+ // the temporary vectors and output support vectors.
+ block_size = MAX( block_size, sample_count*(int)sizeof(CvSVMKernelRow));
+ block_size = MAX( block_size, sample_count*2*(int)sizeof(double) + 1024 );
+ block_size = MAX( block_size, sample_size*2 + 1024 );
+
+ CV_CALL(storage = cvCreateMemStorage(block_size));
+ CV_CALL(temp_storage = cvCreateChildMemStorage(storage));
+ CV_CALL(alpha = (double*)cvMemStorageAlloc(temp_storage, sample_count*sizeof(double)));
+
+ create_kernel();
+ create_solver();
+
+ {
+ const int testset_size = sample_count/k_fold;
+ const int trainset_size = sample_count - testset_size;
+ const int last_testset_size = sample_count - testset_size*(k_fold-1);
+ const int last_trainset_size = sample_count - last_testset_size;
+ const bool is_regression = (svm_type == EPS_SVR) || (svm_type == NU_SVR);
+
+ size_t resp_elem_size = CV_ELEM_SIZE(responses->type);
+ size_t size = 2*last_trainset_size*sizeof(samples[0]);
+
+ samples_local = (const float**) cvAlloc( size );
+ memset( samples_local, 0, size );
+
+ responses_local = cvCreateMat( 1, trainset_size, CV_MAT_TYPE(responses->type) );
+ cvZero( responses_local );
+
+ // randomly permute samples and responses
+ for( i = 0; i < sample_count; i++ )
+ {
+ int i1 = cvRandInt( &rng ) % sample_count;
+ int i2 = cvRandInt( &rng ) % sample_count;
+ const float* temp;
+ float t;
+ int y;
+
+ CV_SWAP( samples[i1], samples[i2], temp );
+ if( is_regression )
+ CV_SWAP( responses->data.fl[i1], responses->data.fl[i2], t );
+ else
+ CV_SWAP( responses->data.i[i1], responses->data.i[i2], y );
+ }
+
+ C = C_grid.min_val;
+ do
+ {
+ params.C = C;
+ gamma = gamma_grid.min_val;
+ do
+ {
+ params.gamma = gamma;
+ p = p_grid.min_val;
+ do
+ {
+ params.p = p;
+ nu = nu_grid.min_val;
+ do
+ {
+ params.nu = nu;
+ coef = coef_grid.min_val;
+ do
+ {
+ params.coef0 = coef;
+ degree = degree_grid.min_val;
+ do
+ {
+ params.degree = degree;
+
+ float** test_samples_ptr = (float**)samples;
+ uchar* true_resp = responses->data.ptr;
+ int test_size = testset_size;
+ int train_size = trainset_size;
+
+ error = 0;
+ for( k = 0; k < k_fold; k++ )
+ {
+ memcpy( samples_local, samples, sizeof(samples[0])*test_size*k );
+ memcpy( samples_local + test_size*k, test_samples_ptr + test_size,
+ sizeof(samples[0])*(sample_count - testset_size*(k+1)) );
+
+ memcpy( responses_local->data.ptr, responses->data.ptr, resp_elem_size*test_size*k );
+ memcpy( responses_local->data.ptr + resp_elem_size*test_size*k,
+ true_resp + resp_elem_size*test_size,
+ sizeof(samples[0])*(sample_count - testset_size*(k+1)) );
+
+ if( k == k_fold - 1 )
+ {
+ test_size = last_testset_size;
+ train_size = last_trainset_size;
+ responses_local->cols = last_trainset_size;
+ }
+
+ // Train SVM on <train_size> samples
+ if( !do_train( svm_type, train_size, var_count,
+ (const float**)samples_local, responses_local, temp_storage, alpha ) )
+ EXIT;
+
+ // Compute test set error on <test_size> samples
+ CvMat s = cvMat( 1, var_count, CV_32FC1 );
+ for( i = 0; i < test_size; i++, true_resp += resp_elem_size, test_samples_ptr++ )
+ {
+ float resp;
+ s.data.fl = *test_samples_ptr;
+ resp = predict( &s );
+ error += is_regression ? powf( resp - *(float*)true_resp, 2 )
+ : ((int)resp != *(int*)true_resp);
+ }
+ }
+ if( min_error > error )
+ {
+ min_error = error;
+ best_degree = degree;
+ best_gamma = gamma;
+ best_coef = coef;
+ best_C = C;
+ best_nu = nu;
+ best_p = p;
+ }
+ degree *= degree_grid.step;
+ }
+ while( degree < degree_grid.max_val );
+ coef *= coef_grid.step;
+ }
+ while( coef < coef_grid.max_val );
+ nu *= nu_grid.step;
+ }
+ while( nu < nu_grid.max_val );
+ p *= p_grid.step;
+ }
+ while( p < p_grid.max_val );
+ gamma *= gamma_grid.step;
+ }
+ while( gamma < gamma_grid.max_val );
+ C *= C_grid.step;
+ }
+ while( C < C_grid.max_val );
+ }
+
+ min_error /= (float) sample_count;
+
+ params.C = best_C;
+ params.nu = best_nu;
+ params.p = best_p;
+ params.gamma = best_gamma;
+ params.degree = best_degree;
+ params.coef0 = best_coef;
+
+ CV_CALL(ok = do_train( svm_type, sample_count, var_count, samples, responses, temp_storage, alpha ));
+
+ __END__;
+
+ delete solver;
+ solver = 0;
+ cvReleaseMemStorage( &temp_storage );
+ cvReleaseMat( &responses );
+ cvReleaseMat( &responses_local );
+ cvFree( &samples );
+ cvFree( &samples_local );
+
+ if( cvGetErrStatus() < 0 || !ok )
+ clear();
+
+ return ok;
+}
+
+float CvSVM::predict( const CvMat* sample ) const
+{
+ bool local_alloc = 0;
+ float result = 0;
+ float* row_sample = 0;
+ Qfloat* buffer = 0;
+
+ CV_FUNCNAME( "CvSVM::predict" );
+
+ __BEGIN__;
+
+ int class_count;
+ int var_count, buf_sz;
+
+ if( !kernel )
+ CV_ERROR( CV_StsBadArg, "The SVM should be trained first" );
+
+ class_count = class_labels ? class_labels->cols :
+ params.svm_type == ONE_CLASS ? 1 : 0;
+
+ CV_CALL( cvPreparePredictData( sample, var_all, var_idx,
+ class_count, 0, &row_sample ));
+
+ var_count = get_var_count();
+
+ buf_sz = sv_total*sizeof(buffer[0]) + (class_count+1)*sizeof(int);
+ if( buf_sz <= CV_MAX_LOCAL_SIZE )
+ {
+ CV_CALL( buffer = (Qfloat*)cvStackAlloc( buf_sz ));
+ local_alloc = 1;
+ }
+ else
+ CV_CALL( buffer = (Qfloat*)cvAlloc( buf_sz ));
+
+ if( params.svm_type == EPS_SVR ||
+ params.svm_type == NU_SVR ||
+ params.svm_type == ONE_CLASS )
+ {
+ CvSVMDecisionFunc* df = (CvSVMDecisionFunc*)decision_func;
+ int i, sv_count = df->sv_count;
+ double sum = -df->rho;
+
+ kernel->calc( sv_count, var_count, (const float**)sv, row_sample, buffer );
+ for( i = 0; i < sv_count; i++ )
+ sum += buffer[i]*df->alpha[i];
+
+ result = params.svm_type == ONE_CLASS ? (float)(sum > 0) : (float)sum;
+ }
+ else if( params.svm_type == C_SVC ||
+ params.svm_type == NU_SVC )
+ {
+ CvSVMDecisionFunc* df = (CvSVMDecisionFunc*)decision_func;
+ int* vote = (int*)(buffer + sv_total);
+ int i, j, k;
+
+ memset( vote, 0, class_count*sizeof(vote[0]));
+ kernel->calc( sv_total, var_count, (const float**)sv, row_sample, buffer );
+
+ for( i = 0; i < class_count; i++ )
+ {
+ for( j = i+1; j < class_count; j++, df++ )
+ {
+ double sum = -df->rho;
+ int sv_count = df->sv_count;
+ for( k = 0; k < sv_count; k++ )
+ sum += df->alpha[k]*buffer[df->sv_index[k]];
+
+ vote[sum > 0 ? i : j]++;
+ }
+ }
+
+ for( i = 1, k = 0; i < class_count; i++ )
+ {
+ if( vote[i] > vote[k] )
+ k = i;
+ }
+
+ result = (float)(class_labels->data.i[k]);
+ }
+ else
+ CV_ERROR( CV_StsBadArg, "INTERNAL ERROR: Unknown SVM type, "
+ "the SVM structure is probably corrupted" );
+
+ __END__;
+
+ if( sample && (!CV_IS_MAT(sample) || sample->data.fl != row_sample) )
+ cvFree( &row_sample );
+
+ if( !local_alloc )
+ cvFree( &buffer );
+
+ return result;
+}
+
+
+void CvSVM::write_params( CvFileStorage* fs )
+{
+ //CV_FUNCNAME( "CvSVM::write_params" );
+
+ __BEGIN__;
+
+ int svm_type = params.svm_type;
+ int kernel_type = params.kernel_type;
+
+ const char* svm_type_str =
+ svm_type == CvSVM::C_SVC ? "C_SVC" :
+ svm_type == CvSVM::NU_SVC ? "NU_SVC" :
+ svm_type == CvSVM::ONE_CLASS ? "ONE_CLASS" :
+ svm_type == CvSVM::EPS_SVR ? "EPS_SVR" :
+ svm_type == CvSVM::NU_SVR ? "NU_SVR" : 0;
+ const char* kernel_type_str =
+ kernel_type == CvSVM::LINEAR ? "LINEAR" :
+ kernel_type == CvSVM::POLY ? "POLY" :
+ kernel_type == CvSVM::RBF ? "RBF" :
+ kernel_type == CvSVM::SIGMOID ? "SIGMOID" : 0;
+
+ if( svm_type_str )
+ cvWriteString( fs, "svm_type", svm_type_str );
+ else
+ cvWriteInt( fs, "svm_type", svm_type );
+
+ // save kernel
+ cvStartWriteStruct( fs, "kernel", CV_NODE_MAP + CV_NODE_FLOW );
+
+ if( kernel_type_str )
+ cvWriteString( fs, "type", kernel_type_str );
+ else
+ cvWriteInt( fs, "type", kernel_type );
+
+ if( kernel_type == CvSVM::POLY || !kernel_type_str )
+ cvWriteReal( fs, "degree", params.degree );
+
+ if( kernel_type != CvSVM::LINEAR || !kernel_type_str )
+ cvWriteReal( fs, "gamma", params.gamma );
+
+ if( kernel_type == CvSVM::POLY || kernel_type == CvSVM::SIGMOID || !kernel_type_str )
+ cvWriteReal( fs, "coef0", params.coef0 );
+
+ cvEndWriteStruct(fs);
+
+ if( svm_type == CvSVM::C_SVC || svm_type == CvSVM::EPS_SVR ||
+ svm_type == CvSVM::NU_SVR || !svm_type_str )
+ cvWriteReal( fs, "C", params.C );
+
+ if( svm_type == CvSVM::NU_SVC || svm_type == CvSVM::ONE_CLASS ||
+ svm_type == CvSVM::NU_SVR || !svm_type_str )
+ cvWriteReal( fs, "nu", params.nu );
+
+ if( svm_type == CvSVM::EPS_SVR || !svm_type_str )
+ cvWriteReal( fs, "p", params.p );
+
+ cvStartWriteStruct( fs, "term_criteria", CV_NODE_MAP + CV_NODE_FLOW );
+ if( params.term_crit.type & CV_TERMCRIT_EPS )
+ cvWriteReal( fs, "epsilon", params.term_crit.epsilon );
+ if( params.term_crit.type & CV_TERMCRIT_ITER )
+ cvWriteInt( fs, "iterations", params.term_crit.max_iter );
+ cvEndWriteStruct( fs );
+
+ __END__;
+}
+
+
+void CvSVM::write( CvFileStorage* fs, const char* name )
+{
+ CV_FUNCNAME( "CvSVM::write" );
+
+ __BEGIN__;
+
+ int i, var_count = get_var_count(), df_count, class_count;
+ const CvSVMDecisionFunc* df = decision_func;
+
+ cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_ML_SVM );
+
+ write_params( fs );
+
+ cvWriteInt( fs, "var_all", var_all );
+ cvWriteInt( fs, "var_count", var_count );
+
+ class_count = class_labels ? class_labels->cols :
+ params.svm_type == CvSVM::ONE_CLASS ? 1 : 0;
+
+ if( class_count )
+ {
+ cvWriteInt( fs, "class_count", class_count );
+
+ if( class_labels )
+ cvWrite( fs, "class_labels", class_labels );
+
+ if( class_weights )
+ cvWrite( fs, "class_weights", class_weights );
+ }
+
+ if( var_idx )
+ cvWrite( fs, "var_idx", var_idx );
+
+ // write the joint collection of support vectors
+ cvWriteInt( fs, "sv_total", sv_total );
+ cvStartWriteStruct( fs, "support_vectors", CV_NODE_SEQ );
+ for( i = 0; i < sv_total; i++ )
+ {
+ cvStartWriteStruct( fs, 0, CV_NODE_SEQ + CV_NODE_FLOW );
+ cvWriteRawData( fs, sv[i], var_count, "f" );
+ cvEndWriteStruct( fs );
+ }
+
+ cvEndWriteStruct( fs );
+
+ // write decision functions
+ df_count = class_count > 1 ? class_count*(class_count-1)/2 : 1;
+ df = decision_func;
+
+ cvStartWriteStruct( fs, "decision_functions", CV_NODE_SEQ );
+ for( i = 0; i < df_count; i++ )
+ {
+ int sv_count = df[i].sv_count;
+ cvStartWriteStruct( fs, 0, CV_NODE_MAP );
+ cvWriteInt( fs, "sv_count", sv_count );
+ cvWriteReal( fs, "rho", df[i].rho );
+ cvStartWriteStruct( fs, "alpha", CV_NODE_SEQ+CV_NODE_FLOW );
+ cvWriteRawData( fs, df[i].alpha, df[i].sv_count, "d" );
+ cvEndWriteStruct( fs );
+ if( class_count > 1 )
+ {
+ cvStartWriteStruct( fs, "index", CV_NODE_SEQ+CV_NODE_FLOW );
+ cvWriteRawData( fs, df[i].sv_index, df[i].sv_count, "i" );
+ cvEndWriteStruct( fs );
+ }
+ else
+ CV_ASSERT( sv_count == sv_total );
+ cvEndWriteStruct( fs );
+ }
+ cvEndWriteStruct( fs );
+ cvEndWriteStruct( fs );
+
+ __END__;
+}
+
+
+void CvSVM::read_params( CvFileStorage* fs, CvFileNode* svm_node )
+{
+ CV_FUNCNAME( "CvSVM::read_params" );
+
+ __BEGIN__;
+
+ int svm_type, kernel_type;
+ CvSVMParams _params;
+
+ CvFileNode* tmp_node = cvGetFileNodeByName( fs, svm_node, "svm_type" );
+ CvFileNode* kernel_node;
+ if( !tmp_node )
+ CV_ERROR( CV_StsBadArg, "svm_type tag is not found" );
+
+ if( CV_NODE_TYPE(tmp_node->tag) == CV_NODE_INT )
+ svm_type = cvReadInt( tmp_node, -1 );
+ else
+ {
+ const char* svm_type_str = cvReadString( tmp_node, "" );
+ svm_type =
+ strcmp( svm_type_str, "C_SVC" ) == 0 ? CvSVM::C_SVC :
+ strcmp( svm_type_str, "NU_SVC" ) == 0 ? CvSVM::NU_SVC :
+ strcmp( svm_type_str, "ONE_CLASS" ) == 0 ? CvSVM::ONE_CLASS :
+ strcmp( svm_type_str, "EPS_SVR" ) == 0 ? CvSVM::EPS_SVR :
+ strcmp( svm_type_str, "NU_SVR" ) == 0 ? CvSVM::NU_SVR : -1;
+
+ if( svm_type < 0 )
+ CV_ERROR( CV_StsParseError, "Missing of invalid SVM type" );
+ }
+
+ kernel_node = cvGetFileNodeByName( fs, svm_node, "kernel" );
+ if( !kernel_node )
+ CV_ERROR( CV_StsParseError, "SVM kernel tag is not found" );
+
+ tmp_node = cvGetFileNodeByName( fs, kernel_node, "type" );
+ if( !tmp_node )
+ CV_ERROR( CV_StsParseError, "SVM kernel type tag is not found" );
+
+ if( CV_NODE_TYPE(tmp_node->tag) == CV_NODE_INT )
+ kernel_type = cvReadInt( tmp_node, -1 );
+ else
+ {
+ const char* kernel_type_str = cvReadString( tmp_node, "" );
+ kernel_type =
+ strcmp( kernel_type_str, "LINEAR" ) == 0 ? CvSVM::LINEAR :
+ strcmp( kernel_type_str, "POLY" ) == 0 ? CvSVM::POLY :
+ strcmp( kernel_type_str, "RBF" ) == 0 ? CvSVM::RBF :
+ strcmp( kernel_type_str, "SIGMOID" ) == 0 ? CvSVM::SIGMOID : -1;
+
+ if( kernel_type < 0 )
+ CV_ERROR( CV_StsParseError, "Missing of invalid SVM kernel type" );
+ }
+
+ _params.svm_type = svm_type;
+ _params.kernel_type = kernel_type;
+ _params.degree = cvReadRealByName( fs, kernel_node, "degree", 0 );
+ _params.gamma = cvReadRealByName( fs, kernel_node, "gamma", 0 );
+ _params.coef0 = cvReadRealByName( fs, kernel_node, "coef0", 0 );
+
+ _params.C = cvReadRealByName( fs, svm_node, "C", 0 );
+ _params.nu = cvReadRealByName( fs, svm_node, "nu", 0 );
+ _params.p = cvReadRealByName( fs, svm_node, "p", 0 );
+ _params.class_weights = 0;
+
+ tmp_node = cvGetFileNodeByName( fs, svm_node, "term_criteria" );
+ if( tmp_node )
+ {
+ _params.term_crit.epsilon = cvReadRealByName( fs, tmp_node, "epsilon", -1. );
+ _params.term_crit.max_iter = cvReadIntByName( fs, tmp_node, "iterations", -1 );
+ _params.term_crit.type = (_params.term_crit.epsilon >= 0 ? CV_TERMCRIT_EPS : 0) +
+ (_params.term_crit.max_iter >= 0 ? CV_TERMCRIT_ITER : 0);
+ }
+ else
+ _params.term_crit = cvTermCriteria( CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 1000, FLT_EPSILON );
+
+ set_params( _params );
+
+ __END__;
+}
+
+
+void CvSVM::read( CvFileStorage* fs, CvFileNode* svm_node )
+{
+ const double not_found_dbl = DBL_MAX;
+
+ CV_FUNCNAME( "CvSVM::read" );
+
+ __BEGIN__;
+
+ int i, var_count, df_count, class_count;
+ int block_size = 1 << 16, sv_size;
+ CvFileNode *sv_node, *df_node;
+ CvSVMDecisionFunc* df;
+ CvSeqReader reader;
+
+ if( !svm_node )
+ CV_ERROR( CV_StsParseError, "The requested element is not found" );
+
+ clear();
+
+ // read SVM parameters
+ read_params( fs, svm_node );
+
+ // and top-level data
+ sv_total = cvReadIntByName( fs, svm_node, "sv_total", -1 );
+ var_all = cvReadIntByName( fs, svm_node, "var_all", -1 );
+ var_count = cvReadIntByName( fs, svm_node, "var_count", var_all );
+ class_count = cvReadIntByName( fs, svm_node, "class_count", 0 );
+
+ if( sv_total <= 0 || var_all <= 0 || var_count <= 0 || var_count > var_all || class_count < 0 )
+ CV_ERROR( CV_StsParseError, "SVM model data is invalid, check sv_count, var_* and class_count tags" );
+
+ CV_CALL( class_labels = (CvMat*)cvReadByName( fs, svm_node, "class_labels" ));
+ CV_CALL( class_weights = (CvMat*)cvReadByName( fs, svm_node, "class_weights" ));
+ CV_CALL( var_idx = (CvMat*)cvReadByName( fs, svm_node, "comp_idx" ));
+
+ if( class_count > 1 && (!class_labels ||
+ !CV_IS_MAT(class_labels) || class_labels->cols != class_count))
+ CV_ERROR( CV_StsParseError, "Array of class labels is missing or invalid" );
+
+ if( var_count < var_all && (!var_idx || !CV_IS_MAT(var_idx) || var_idx->cols != var_count) )
+ CV_ERROR( CV_StsParseError, "var_idx array is missing or invalid" );
+
+ // read support vectors
+ sv_node = cvGetFileNodeByName( fs, svm_node, "support_vectors" );
+ if( !sv_node || !CV_NODE_IS_SEQ(sv_node->tag))
+ CV_ERROR( CV_StsParseError, "Missing or invalid sequence of support vectors" );
+
+ block_size = MAX( block_size, sv_total*(int)sizeof(CvSVMKernelRow));
+ block_size = MAX( block_size, sv_total*2*(int)sizeof(double));
+ block_size = MAX( block_size, var_all*(int)sizeof(double));
+ CV_CALL( storage = cvCreateMemStorage( block_size ));
+ CV_CALL( sv = (float**)cvMemStorageAlloc( storage,
+ sv_total*sizeof(sv[0]) ));
+
+ CV_CALL( cvStartReadSeq( sv_node->data.seq, &reader, 0 ));
+ sv_size = var_count*sizeof(sv[0][0]);
+
+ for( i = 0; i < sv_total; i++ )
+ {
+ CvFileNode* sv_elem = (CvFileNode*)reader.ptr;
+ CV_ASSERT( var_count == 1 || (CV_NODE_IS_SEQ(sv_elem->tag) &&
+ sv_elem->data.seq->total == var_count) );
+
+ CV_CALL( sv[i] = (float*)cvMemStorageAlloc( storage, sv_size ));
+ CV_CALL( cvReadRawData( fs, sv_elem, sv[i], "f" ));
+ CV_NEXT_SEQ_ELEM( sv_node->data.seq->elem_size, reader );
+ }
+
+ // read decision functions
+ df_count = class_count > 1 ? class_count*(class_count-1)/2 : 1;
+ df_node = cvGetFileNodeByName( fs, svm_node, "decision_functions" );
+ if( !df_node || !CV_NODE_IS_SEQ(df_node->tag) ||
+ df_node->data.seq->total != df_count )
+ CV_ERROR( CV_StsParseError, "decision_functions is missing or is not a collection "
+ "or has a wrong number of elements" );
+
+ CV_CALL( df = decision_func = (CvSVMDecisionFunc*)cvAlloc( df_count*sizeof(df[0]) ));
+ cvStartReadSeq( df_node->data.seq, &reader, 0 );
+
+ for( i = 0; i < df_count; i++ )
+ {
+ CvFileNode* df_elem = (CvFileNode*)reader.ptr;
+ CvFileNode* alpha_node = cvGetFileNodeByName( fs, df_elem, "alpha" );
+
+ int sv_count = cvReadIntByName( fs, df_elem, "sv_count", -1 );
+ if( sv_count <= 0 )
+ CV_ERROR( CV_StsParseError, "sv_count is missing or non-positive" );
+ df[i].sv_count = sv_count;
+
+ df[i].rho = cvReadRealByName( fs, df_elem, "rho", not_found_dbl );
+ if( fabs(df[i].rho - not_found_dbl) < DBL_EPSILON )
+ CV_ERROR( CV_StsParseError, "rho is missing" );
+
+ if( !alpha_node )
+ CV_ERROR( CV_StsParseError, "alpha is missing in the decision function" );
+
+ CV_CALL( df[i].alpha = (double*)cvMemStorageAlloc( storage,
+ sv_count*sizeof(df[i].alpha[0])));
+ CV_ASSERT( sv_count == 1 || CV_NODE_IS_SEQ(alpha_node->tag) &&
+ alpha_node->data.seq->total == sv_count );
+ CV_CALL( cvReadRawData( fs, alpha_node, df[i].alpha, "d" ));
+
+ if( class_count > 1 )
+ {
+ CvFileNode* index_node = cvGetFileNodeByName( fs, df_elem, "index" );
+ if( !index_node )
+ CV_ERROR( CV_StsParseError, "index is missing in the decision function" );
+ CV_CALL( df[i].sv_index = (int*)cvMemStorageAlloc( storage,
+ sv_count*sizeof(df[i].sv_index[0])));
+ CV_ASSERT( sv_count == 1 || CV_NODE_IS_SEQ(index_node->tag) &&
+ index_node->data.seq->total == sv_count );
+ CV_CALL( cvReadRawData( fs, index_node, df[i].sv_index, "i" ));
+ }
+ else
+ df[i].sv_index = 0;
+
+ CV_NEXT_SEQ_ELEM( df_node->data.seq->elem_size, reader );
+ }
+
+ create_kernel();
+
+ __END__;
+}
+
+#if 0
+
+static void*
+icvCloneSVM( const void* _src )
+{
+ CvSVMModel* dst = 0;
+
+ CV_FUNCNAME( "icvCloneSVM" );
+
+ __BEGIN__;
+
+ const CvSVMModel* src = (const CvSVMModel*)_src;
+ int var_count, class_count;
+ int i, sv_total, df_count;
+ int sv_size;
+
+ if( !CV_IS_SVM(src) )
+ CV_ERROR( !src ? CV_StsNullPtr : CV_StsBadArg, "Input pointer is NULL or invalid" );
+
+ // 0. create initial CvSVMModel structure
+ CV_CALL( dst = icvCreateSVM() );
+ dst->params = src->params;
+ dst->params.weight_labels = 0;
+ dst->params.weights = 0;
+
+ dst->var_all = src->var_all;
+ if( src->class_labels )
+ dst->class_labels = cvCloneMat( src->class_labels );
+ if( src->class_weights )
+ dst->class_weights = cvCloneMat( src->class_weights );
+ if( src->comp_idx )
+ dst->comp_idx = cvCloneMat( src->comp_idx );
+
+ var_count = src->comp_idx ? src->comp_idx->cols : src->var_all;
+ class_count = src->class_labels ? src->class_labels->cols :
+ src->params.svm_type == CvSVM::ONE_CLASS ? 1 : 0;
+ sv_total = dst->sv_total = src->sv_total;
+ CV_CALL( dst->storage = cvCreateMemStorage( src->storage->block_size ));
+ CV_CALL( dst->sv = (float**)cvMemStorageAlloc( dst->storage,
+ sv_total*sizeof(dst->sv[0]) ));
+
+ sv_size = var_count*sizeof(dst->sv[0][0]);
+
+ for( i = 0; i < sv_total; i++ )
+ {
+ CV_CALL( dst->sv[i] = (float*)cvMemStorageAlloc( dst->storage, sv_size ));
+ memcpy( dst->sv[i], src->sv[i], sv_size );
+ }
+
+ df_count = class_count > 1 ? class_count*(class_count-1)/2 : 1;
+
+ CV_CALL( dst->decision_func = cvAlloc( df_count*sizeof(CvSVMDecisionFunc) ));
+
+ for( i = 0; i < df_count; i++ )
+ {
+ const CvSVMDecisionFunc *sdf =
+ (const CvSVMDecisionFunc*)src->decision_func+i;
+ CvSVMDecisionFunc *ddf =
+ (CvSVMDecisionFunc*)dst->decision_func+i;
+ int sv_count = sdf->sv_count;
+ ddf->sv_count = sv_count;
+ ddf->rho = sdf->rho;
+ CV_CALL( ddf->alpha = (double*)cvMemStorageAlloc( dst->storage,
+ sv_count*sizeof(ddf->alpha[0])));
+ memcpy( ddf->alpha, sdf->alpha, sv_count*sizeof(ddf->alpha[0]));
+
+ if( class_count > 1 )
+ {
+ CV_CALL( ddf->sv_index = (int*)cvMemStorageAlloc( dst->storage,
+ sv_count*sizeof(ddf->sv_index[0])));
+ memcpy( ddf->sv_index, sdf->sv_index, sv_count*sizeof(ddf->sv_index[0]));
+ }
+ else
+ ddf->sv_index = 0;
+ }
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 && dst )
+ icvReleaseSVM( &dst );
+
+ return dst;
+}
+
+static int icvRegisterSVMType()
+{
+ CvTypeInfo info;
+ memset( &info, 0, sizeof(info) );
+
+ info.flags = 0;
+ info.header_size = sizeof( info );
+ info.is_instance = icvIsSVM;
+ info.release = (CvReleaseFunc)icvReleaseSVM;
+ info.read = icvReadSVM;
+ info.write = icvWriteSVM;
+ info.clone = icvCloneSVM;
+ info.type_name = CV_TYPE_NAME_ML_SVM;
+ cvRegisterType( &info );
+
+ return 1;
+}
+
+
+static int svm = icvRegisterSVMType();
+
+/* The function trains SVM model with optimal parameters, obtained by using cross-validation.
+The parameters to be estimated should be indicated by setting theirs values to FLT_MAX.
+The optimal parameters are saved in <model_params> */
+CV_IMPL CvStatModel*
+cvTrainSVM_CrossValidation( const CvMat* train_data, int tflag,
+ const CvMat* responses,
+ CvStatModelParams* model_params,
+ const CvStatModelParams* cross_valid_params,
+ const CvMat* comp_idx,
+ const CvMat* sample_idx,
+ const CvParamGrid* degree_grid,
+ const CvParamGrid* gamma_grid,
+ const CvParamGrid* coef_grid,
+ const CvParamGrid* C_grid,
+ const CvParamGrid* nu_grid,
+ const CvParamGrid* p_grid )
+{
+ CvStatModel* svm = 0;
+
+ CV_FUNCNAME("cvTainSVMCrossValidation");
+ __BEGIN__;
+
+ double degree_step = 7,
+ g_step = 15,
+ coef_step = 14,
+ C_step = 20,
+ nu_step = 5,
+ p_step = 7; // all steps must be > 1
+ double degree_begin = 0.01, degree_end = 2;
+ double g_begin = 1e-5, g_end = 0.5;
+ double coef_begin = 0.1, coef_end = 300;
+ double C_begin = 0.1, C_end = 6000;
+ double nu_begin = 0.01, nu_end = 0.4;
+ double p_begin = 0.01, p_end = 100;
+
+ double rate = 0, gamma = 0, C = 0, degree = 0, coef = 0, p = 0, nu = 0;
+
+ double best_rate = 0;
+ double best_degree = degree_begin;
+ double best_gamma = g_begin;
+ double best_coef = coef_begin;
+ double best_C = C_begin;
+ double best_nu = nu_begin;
+ double best_p = p_begin;
+
+ CvSVMModelParams svm_params, *psvm_params;
+ CvCrossValidationParams* cv_params = (CvCrossValidationParams*)cross_valid_params;
+ int svm_type, kernel;
+ int is_regression;
+
+ if( !model_params )
+ CV_ERROR( CV_StsBadArg, "" );
+ if( !cv_params )
+ CV_ERROR( CV_StsBadArg, "" );
+
+ svm_params = *(CvSVMModelParams*)model_params;
+ psvm_params = (CvSVMModelParams*)model_params;
+ svm_type = svm_params.svm_type;
+ kernel = svm_params.kernel_type;
+
+ svm_params.degree = svm_params.degree > 0 ? svm_params.degree : 1;
+ svm_params.gamma = svm_params.gamma > 0 ? svm_params.gamma : 1;
+ svm_params.coef0 = svm_params.coef0 > 0 ? svm_params.coef0 : 1e-6;
+ svm_params.C = svm_params.C > 0 ? svm_params.C : 1;
+ svm_params.nu = svm_params.nu > 0 ? svm_params.nu : 1;
+ svm_params.p = svm_params.p > 0 ? svm_params.p : 1;
+
+ if( degree_grid )
+ {
+ if( !(degree_grid->max_val == 0 && degree_grid->min_val == 0 &&
+ degree_grid->step == 0) )
+ {
+ if( degree_grid->min_val > degree_grid->max_val )
+ CV_ERROR( CV_StsBadArg,
+ "low bound of grid should be less then the upper one");
+ if( degree_grid->step <= 1 )
+ CV_ERROR( CV_StsBadArg, "grid step should be greater 1" );
+ degree_begin = degree_grid->min_val;
+ degree_end = degree_grid->max_val;
+ degree_step = degree_grid->step;
+ }
+ }
+ else
+ degree_begin = degree_end = svm_params.degree;
+
+ if( gamma_grid )
+ {
+ if( !(gamma_grid->max_val == 0 && gamma_grid->min_val == 0 &&
+ gamma_grid->step == 0) )
+ {
+ if( gamma_grid->min_val > gamma_grid->max_val )
+ CV_ERROR( CV_StsBadArg,
+ "low bound of grid should be less then the upper one");
+ if( gamma_grid->step <= 1 )
+ CV_ERROR( CV_StsBadArg, "grid step should be greater 1" );
+ g_begin = gamma_grid->min_val;
+ g_end = gamma_grid->max_val;
+ g_step = gamma_grid->step;
+ }
+ }
+ else
+ g_begin = g_end = svm_params.gamma;
+
+ if( coef_grid )
+ {
+ if( !(coef_grid->max_val == 0 && coef_grid->min_val == 0 &&
+ coef_grid->step == 0) )
+ {
+ if( coef_grid->min_val > coef_grid->max_val )
+ CV_ERROR( CV_StsBadArg,
+ "low bound of grid should be less then the upper one");
+ if( coef_grid->step <= 1 )
+ CV_ERROR( CV_StsBadArg, "grid step should be greater 1" );
+ coef_begin = coef_grid->min_val;
+ coef_end = coef_grid->max_val;
+ coef_step = coef_grid->step;
+ }
+ }
+ else
+ coef_begin = coef_end = svm_params.coef0;
+
+ if( C_grid )
+ {
+ if( !(C_grid->max_val == 0 && C_grid->min_val == 0 && C_grid->step == 0))
+ {
+ if( C_grid->min_val > C_grid->max_val )
+ CV_ERROR( CV_StsBadArg,
+ "low bound of grid should be less then the upper one");
+ if( C_grid->step <= 1 )
+ CV_ERROR( CV_StsBadArg, "grid step should be greater 1" );
+ C_begin = C_grid->min_val;
+ C_end = C_grid->max_val;
+ C_step = C_grid->step;
+ }
+ }
+ else
+ C_begin = C_end = svm_params.C;
+
+ if( nu_grid )
+ {
+ if(!(nu_grid->max_val == 0 && nu_grid->min_val == 0 && nu_grid->step==0))
+ {
+ if( nu_grid->min_val > nu_grid->max_val )
+ CV_ERROR( CV_StsBadArg,
+ "low bound of grid should be less then the upper one");
+ if( nu_grid->step <= 1 )
+ CV_ERROR( CV_StsBadArg, "grid step should be greater 1" );
+ nu_begin = nu_grid->min_val;
+ nu_end = nu_grid->max_val;
+ nu_step = nu_grid->step;
+ }
+ }
+ else
+ nu_begin = nu_end = svm_params.nu;
+
+ if( p_grid )
+ {
+ if( !(p_grid->max_val == 0 && p_grid->min_val == 0 && p_grid->step == 0))
+ {
+ if( p_grid->min_val > p_grid->max_val )
+ CV_ERROR( CV_StsBadArg,
+ "low bound of grid should be less then the upper one");
+ if( p_grid->step <= 1 )
+ CV_ERROR( CV_StsBadArg, "grid step should be greater 1" );
+ p_begin = p_grid->min_val;
+ p_end = p_grid->max_val;
+ p_step = p_grid->step;
+ }
+ }
+ else
+ p_begin = p_end = svm_params.p;
+
+ // these parameters are not used:
+ if( kernel != CvSVM::POLY )
+ degree_begin = degree_end = svm_params.degree;
+
+ if( kernel == CvSVM::LINEAR )
+ g_begin = g_end = svm_params.gamma;
+
+ if( kernel != CvSVM::POLY && kernel != CvSVM::SIGMOID )
+ coef_begin = coef_end = svm_params.coef0;
+
+ if( svm_type == CvSVM::NU_SVC || svm_type == CvSVM::ONE_CLASS )
+ C_begin = C_end = svm_params.C;
+
+ if( svm_type == CvSVM::C_SVC || svm_type == CvSVM::EPS_SVR )
+ nu_begin = nu_end = svm_params.nu;
+
+ if( svm_type != CvSVM::EPS_SVR )
+ p_begin = p_end = svm_params.p;
+
+ is_regression = cv_params->is_regression;
+ best_rate = is_regression ? FLT_MAX : 0;
+
+ assert( g_step > 1 && degree_step > 1 && coef_step > 1);
+ assert( p_step > 1 && C_step > 1 && nu_step > 1 );
+
+ for( degree = degree_begin; degree <= degree_end; degree *= degree_step )
+ {
+ svm_params.degree = degree;
+ //printf("degree = %.3f\n", degree );
+ for( gamma= g_begin; gamma <= g_end; gamma *= g_step )
+ {
+ svm_params.gamma = gamma;
+ //printf(" gamma = %.3f\n", gamma );
+ for( coef = coef_begin; coef <= coef_end; coef *= coef_step )
+ {
+ svm_params.coef0 = coef;
+ //printf(" coef = %.3f\n", coef );
+ for( C = C_begin; C <= C_end; C *= C_step )
+ {
+ svm_params.C = C;
+ //printf(" C = %.3f\n", C );
+ for( nu = nu_begin; nu <= nu_end; nu *= nu_step )
+ {
+ svm_params.nu = nu;
+ //printf(" nu = %.3f\n", nu );
+ for( p = p_begin; p <= p_end; p *= p_step )
+ {
+ int well;
+ svm_params.p = p;
+ //printf(" p = %.3f\n", p );
+
+ CV_CALL(rate = cvCrossValidation( train_data, tflag, responses, &cvTrainSVM,
+ cross_valid_params, (CvStatModelParams*)&svm_params, comp_idx, sample_idx ));
+
+ well = rate > best_rate && !is_regression || rate < best_rate && is_regression;
+ if( well || (rate == best_rate && C < best_C) )
+ {
+ best_rate = rate;
+ best_degree = degree;
+ best_gamma = gamma;
+ best_coef = coef;
+ best_C = C;
+ best_nu = nu;
+ best_p = p;
+ }
+ //printf(" rate = %.2f\n", rate );
+ }
+ }
+ }
+ }
+ }
+ }
+ //printf("The best:\nrate = %.2f%% degree = %f gamma = %f coef = %f c = %f nu = %f p = %f\n",
+ // best_rate, best_degree, best_gamma, best_coef, best_C, best_nu, best_p );
+
+ psvm_params->C = best_C;
+ psvm_params->nu = best_nu;
+ psvm_params->p = best_p;
+ psvm_params->gamma = best_gamma;
+ psvm_params->degree = best_degree;
+ psvm_params->coef0 = best_coef;
+
+ CV_CALL(svm = cvTrainSVM( train_data, tflag, responses, model_params, comp_idx, sample_idx ));
+
+ __END__;
+
+ return svm;
+}
+
+#endif
+
+/* End of file. */
+
diff --git a/ml/src/mltestset.cpp b/ml/src/mltestset.cpp
new file mode 100644
index 0000000..d9810d4
--- /dev/null
+++ b/ml/src/mltestset.cpp
@@ -0,0 +1,170 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_ml.h"
+
+typedef struct CvDI
+{
+ double d;
+ int i;
+} CvDI;
+
+int CV_CDECL
+icvCmpDI( const void* a, const void* b, void* )
+{
+ const CvDI* e1 = (const CvDI*) a;
+ const CvDI* e2 = (const CvDI*) b;
+
+ return (e1->d < e2->d) ? -1 : (e1->d > e2->d);
+}
+
+CV_IMPL void
+cvCreateTestSet( int type, CvMat** samples,
+ int num_samples,
+ int num_features,
+ CvMat** responses,
+ int num_classes, ... )
+{
+ CvMat* mean = NULL;
+ CvMat* cov = NULL;
+ CvMemStorage* storage = NULL;
+
+ CV_FUNCNAME( "cvCreateTestSet" );
+
+ __BEGIN__;
+
+ if( samples )
+ *samples = NULL;
+ if( responses )
+ *responses = NULL;
+
+ if( type != CV_TS_CONCENTRIC_SPHERES )
+ CV_ERROR( CV_StsBadArg, "Invalid type parameter" );
+
+ if( !samples )
+ CV_ERROR( CV_StsNullPtr, "samples parameter must be not NULL" );
+
+ if( !responses )
+ CV_ERROR( CV_StsNullPtr, "responses parameter must be not NULL" );
+
+ if( num_samples < 1 )
+ CV_ERROR( CV_StsBadArg, "num_samples parameter must be positive" );
+
+ if( num_features < 1 )
+ CV_ERROR( CV_StsBadArg, "num_features parameter must be positive" );
+
+ if( num_classes < 1 )
+ CV_ERROR( CV_StsBadArg, "num_classes parameter must be positive" );
+
+ if( type == CV_TS_CONCENTRIC_SPHERES )
+ {
+ CvSeqWriter writer;
+ CvSeqReader reader;
+ CvMat sample;
+ CvDI elem;
+ CvSeq* seq = NULL;
+ int i, cur_class;
+
+ CV_CALL( *samples = cvCreateMat( num_samples, num_features, CV_32FC1 ) );
+ CV_CALL( *responses = cvCreateMat( 1, num_samples, CV_32SC1 ) );
+ CV_CALL( mean = cvCreateMat( 1, num_features, CV_32FC1 ) );
+ CV_CALL( cvSetZero( mean ) );
+ CV_CALL( cov = cvCreateMat( num_features, num_features, CV_32FC1 ) );
+ CV_CALL( cvSetIdentity( cov ) );
+
+ /* fill the feature values matrix with random numbers drawn from standard
+ normal distribution */
+ CV_CALL( cvRandMVNormal( mean, cov, *samples ) );
+
+ /* calculate distances from the origin to the samples and put them
+ into the sequence along with indices */
+ CV_CALL( storage = cvCreateMemStorage() );
+ CV_CALL( cvStartWriteSeq( 0, sizeof( CvSeq ), sizeof( CvDI ), storage, &writer ));
+ for( i = 0; i < (*samples)->rows; ++i )
+ {
+ CV_CALL( cvGetRow( *samples, &sample, i ));
+ elem.i = i;
+ CV_CALL( elem.d = cvNorm( &sample, NULL, CV_L2 ));
+ CV_WRITE_SEQ_ELEM( elem, writer );
+ }
+ CV_CALL( seq = cvEndWriteSeq( &writer ) );
+
+ /* sort the sequence in a distance ascending order */
+ CV_CALL( cvSeqSort( seq, icvCmpDI, NULL ) );
+
+ /* assign class labels */
+ num_classes = MIN( num_samples, num_classes );
+ CV_CALL( cvStartReadSeq( seq, &reader ) );
+ CV_READ_SEQ_ELEM( elem, reader );
+ for( i = 0, cur_class = 0; i < num_samples; ++cur_class )
+ {
+ int last_idx;
+ double max_dst;
+
+ last_idx = num_samples * (cur_class + 1) / num_classes - 1;
+ CV_CALL( max_dst = (*((CvDI*) cvGetSeqElem( seq, last_idx ))).d );
+ max_dst = MAX( max_dst, elem.d );
+
+ for( ; elem.d <= max_dst && i < num_samples; ++i )
+ {
+ CV_MAT_ELEM( **responses, int, 0, elem.i ) = cur_class;
+ if( i < num_samples - 1 )
+ {
+ CV_READ_SEQ_ELEM( elem, reader );
+ }
+ }
+ }
+ }
+
+ __END__;
+
+ if( cvGetErrStatus() < 0 )
+ {
+ if( samples )
+ cvReleaseMat( samples );
+ if( responses )
+ cvReleaseMat( responses );
+ }
+ cvReleaseMat( &mean );
+ cvReleaseMat( &cov );
+ cvReleaseMemStorage( &storage );
+}
+
+/* End of file. */
diff --git a/ml/src/mltree.cpp b/ml/src/mltree.cpp
new file mode 100644
index 0000000..8567890
--- /dev/null
+++ b/ml/src/mltree.cpp
@@ -0,0 +1,3412 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_ml.h"
+
+static const float ord_nan = FLT_MAX*0.5f;
+static const int min_block_size = 1 << 16;
+static const int block_size_delta = 1 << 10;
+
+CvDTreeTrainData::CvDTreeTrainData()
+{
+ var_idx = var_type = cat_count = cat_ofs = cat_map =
+ priors = priors_mult = counts = buf = direction = split_buf = 0;
+ tree_storage = temp_storage = 0;
+
+ clear();
+}
+
+
+CvDTreeTrainData::CvDTreeTrainData( const CvMat* _train_data, int _tflag,
+ const CvMat* _responses, const CvMat* _var_idx,
+ const CvMat* _sample_idx, const CvMat* _var_type,
+ const CvMat* _missing_mask, const CvDTreeParams& _params,
+ bool _shared, bool _add_labels )
+{
+ var_idx = var_type = cat_count = cat_ofs = cat_map =
+ priors = priors_mult = counts = buf = direction = split_buf = 0;
+ tree_storage = temp_storage = 0;
+
+ set_data( _train_data, _tflag, _responses, _var_idx, _sample_idx,
+ _var_type, _missing_mask, _params, _shared, _add_labels );
+}
+
+
+CvDTreeTrainData::~CvDTreeTrainData()
+{
+ clear();
+}
+
+
+bool CvDTreeTrainData::set_params( const CvDTreeParams& _params )
+{
+ bool ok = false;
+
+ CV_FUNCNAME( "CvDTreeTrainData::set_params" );
+
+ __BEGIN__;
+
+ // set parameters
+ params = _params;
+
+ if( params.max_categories < 2 )
+ CV_ERROR( CV_StsOutOfRange, "params.max_categories should be >= 2" );
+ params.max_categories = MIN( params.max_categories, 15 );
+
+ if( params.max_depth < 0 )
+ CV_ERROR( CV_StsOutOfRange, "params.max_depth should be >= 0" );
+ params.max_depth = MIN( params.max_depth, 25 );
+
+ params.min_sample_count = MAX(params.min_sample_count,1);
+
+ if( params.cv_folds < 0 )
+ CV_ERROR( CV_StsOutOfRange,
+ "params.cv_folds should be =0 (the tree is not pruned) "
+ "or n>0 (tree is pruned using n-fold cross-validation)" );
+
+ if( params.cv_folds == 1 )
+ params.cv_folds = 0;
+
+ if( params.regression_accuracy < 0 )
+ CV_ERROR( CV_StsOutOfRange, "params.regression_accuracy should be >= 0" );
+
+ ok = true;
+
+ __END__;
+
+ return ok;
+}
+
+
+#define CV_CMP_NUM_PTR(a,b) (*(a) < *(b))
+static CV_IMPLEMENT_QSORT_EX( icvSortIntPtr, int*, CV_CMP_NUM_PTR, int )
+static CV_IMPLEMENT_QSORT_EX( icvSortDblPtr, double*, CV_CMP_NUM_PTR, int )
+
+#define CV_CMP_PAIRS(a,b) ((a).val < (b).val)
+static CV_IMPLEMENT_QSORT_EX( icvSortPairs, CvPair32s32f, CV_CMP_PAIRS, int )
+
+void CvDTreeTrainData::set_data( const CvMat* _train_data, int _tflag,
+ const CvMat* _responses, const CvMat* _var_idx, const CvMat* _sample_idx,
+ const CvMat* _var_type, const CvMat* _missing_mask, const CvDTreeParams& _params,
+ bool _shared, bool _add_labels, bool _update_data )
+{
+ CvMat* sample_idx = 0;
+ CvMat* var_type0 = 0;
+ CvMat* tmp_map = 0;
+ int** int_ptr = 0;
+ CvDTreeTrainData* data = 0;
+
+ CV_FUNCNAME( "CvDTreeTrainData::set_data" );
+
+ __BEGIN__;
+
+ int sample_all = 0, r_type = 0, cv_n;
+ int total_c_count = 0;
+ int tree_block_size, temp_block_size, max_split_size, nv_size, cv_size = 0;
+ int ds_step, dv_step, ms_step = 0, mv_step = 0; // {data|mask}{sample|var}_step
+ int vi, i;
+ char err[100];
+ const int *sidx = 0, *vidx = 0;
+
+ if( _update_data && data_root )
+ {
+ data = new CvDTreeTrainData( _train_data, _tflag, _responses, _var_idx,
+ _sample_idx, _var_type, _missing_mask, _params, _shared, _add_labels );
+
+ // compare new and old train data
+ if( !(data->var_count == var_count &&
+ cvNorm( data->var_type, var_type, CV_C ) < FLT_EPSILON &&
+ cvNorm( data->cat_count, cat_count, CV_C ) < FLT_EPSILON &&
+ cvNorm( data->cat_map, cat_map, CV_C ) < FLT_EPSILON) )
+ CV_ERROR( CV_StsBadArg,
+ "The new training data must have the same types and the input and output variables "
+ "and the same categories for categorical variables" );
+
+ cvReleaseMat( &priors );
+ cvReleaseMat( &priors_mult );
+ cvReleaseMat( &buf );
+ cvReleaseMat( &direction );
+ cvReleaseMat( &split_buf );
+ cvReleaseMemStorage( &temp_storage );
+
+ priors = data->priors; data->priors = 0;
+ priors_mult = data->priors_mult; data->priors_mult = 0;
+ buf = data->buf; data->buf = 0;
+ buf_count = data->buf_count; buf_size = data->buf_size;
+ sample_count = data->sample_count;
+
+ direction = data->direction; data->direction = 0;
+ split_buf = data->split_buf; data->split_buf = 0;
+ temp_storage = data->temp_storage; data->temp_storage = 0;
+ nv_heap = data->nv_heap; cv_heap = data->cv_heap;
+
+ data_root = new_node( 0, sample_count, 0, 0 );
+ EXIT;
+ }
+
+ clear();
+
+ var_all = 0;
+ rng = cvRNG(-1);
+
+ CV_CALL( set_params( _params ));
+
+ // check parameter types and sizes
+ CV_CALL( cvCheckTrainData( _train_data, _tflag, _missing_mask, &var_all, &sample_all ));
+ if( _tflag == CV_ROW_SAMPLE )
+ {
+ ds_step = _train_data->step/CV_ELEM_SIZE(_train_data->type);
+ dv_step = 1;
+ if( _missing_mask )
+ ms_step = _missing_mask->step, mv_step = 1;
+ }
+ else
+ {
+ dv_step = _train_data->step/CV_ELEM_SIZE(_train_data->type);
+ ds_step = 1;
+ if( _missing_mask )
+ mv_step = _missing_mask->step, ms_step = 1;
+ }
+
+ sample_count = sample_all;
+ var_count = var_all;
+
+ if( _sample_idx )
+ {
+ CV_CALL( sample_idx = cvPreprocessIndexArray( _sample_idx, sample_all ));
+ sidx = sample_idx->data.i;
+ sample_count = sample_idx->rows + sample_idx->cols - 1;
+ }
+
+ if( _var_idx )
+ {
+ CV_CALL( var_idx = cvPreprocessIndexArray( _var_idx, var_all ));
+ vidx = var_idx->data.i;
+ var_count = var_idx->rows + var_idx->cols - 1;
+ }
+
+ if( !CV_IS_MAT(_responses) ||
+ (CV_MAT_TYPE(_responses->type) != CV_32SC1 &&
+ CV_MAT_TYPE(_responses->type) != CV_32FC1) ||
+ _responses->rows != 1 && _responses->cols != 1 ||
+ _responses->rows + _responses->cols - 1 != sample_all )
+ CV_ERROR( CV_StsBadArg, "The array of _responses must be an integer or "
+ "floating-point vector containing as many elements as "
+ "the total number of samples in the training data matrix" );
+
+ CV_CALL( var_type0 = cvPreprocessVarType( _var_type, var_idx, var_all, &r_type ));
+ CV_CALL( var_type = cvCreateMat( 1, var_count+2, CV_32SC1 ));
+
+ cat_var_count = 0;
+ ord_var_count = -1;
+
+ is_classifier = r_type == CV_VAR_CATEGORICAL;
+
+ // step 0. calc the number of categorical vars
+ for( vi = 0; vi < var_count; vi++ )
+ {
+ var_type->data.i[vi] = var_type0->data.ptr[vi] == CV_VAR_CATEGORICAL ?
+ cat_var_count++ : ord_var_count--;
+ }
+
+ ord_var_count = ~ord_var_count;
+ cv_n = params.cv_folds;
+ // set the two last elements of var_type array to be able
+ // to locate responses and cross-validation labels using
+ // the corresponding get_* functions.
+ var_type->data.i[var_count] = cat_var_count;
+ var_type->data.i[var_count+1] = cat_var_count+1;
+
+ // in case of single ordered predictor we need dummy cv_labels
+ // for safe split_node_data() operation
+ have_labels = cv_n > 0 || ord_var_count == 1 && cat_var_count == 0 || _add_labels;
+
+ buf_size = (ord_var_count + get_work_var_count())*sample_count + 2;
+ shared = _shared;
+ buf_count = shared ? 3 : 2;
+ CV_CALL( buf = cvCreateMat( buf_count, buf_size, CV_32SC1 ));
+ CV_CALL( cat_count = cvCreateMat( 1, cat_var_count+1, CV_32SC1 ));
+ CV_CALL( cat_ofs = cvCreateMat( 1, cat_count->cols+1, CV_32SC1 ));
+ CV_CALL( cat_map = cvCreateMat( 1, cat_count->cols*10 + 128, CV_32SC1 ));
+
+ // now calculate the maximum size of split,
+ // create memory storage that will keep nodes and splits of the decision tree
+ // allocate root node and the buffer for the whole training data
+ max_split_size = cvAlign(sizeof(CvDTreeSplit) +
+ (MAX(0,sample_count - 33)/32)*sizeof(int),sizeof(void*));
+ tree_block_size = MAX((int)sizeof(CvDTreeNode)*8, max_split_size);
+ tree_block_size = MAX(tree_block_size + block_size_delta, min_block_size);
+ CV_CALL( tree_storage = cvCreateMemStorage( tree_block_size ));
+ CV_CALL( node_heap = cvCreateSet( 0, sizeof(*node_heap), sizeof(CvDTreeNode), tree_storage ));
+
+ nv_size = var_count*sizeof(int);
+ nv_size = MAX( nv_size, (int)sizeof(CvSetElem) );
+
+ temp_block_size = nv_size;
+
+ if( cv_n )
+ {
+ if( sample_count < cv_n*MAX(params.min_sample_count,10) )
+ CV_ERROR( CV_StsOutOfRange,
+ "The many folds in cross-validation for such a small dataset" );
+
+ cv_size = cvAlign( cv_n*(sizeof(int) + sizeof(double)*2), sizeof(double) );
+ temp_block_size = MAX(temp_block_size, cv_size);
+ }
+
+ temp_block_size = MAX( temp_block_size + block_size_delta, min_block_size );
+ CV_CALL( temp_storage = cvCreateMemStorage( temp_block_size ));
+ CV_CALL( nv_heap = cvCreateSet( 0, sizeof(*nv_heap), nv_size, temp_storage ));
+ if( cv_size )
+ CV_CALL( cv_heap = cvCreateSet( 0, sizeof(*cv_heap), cv_size, temp_storage ));
+
+ CV_CALL( data_root = new_node( 0, sample_count, 0, 0 ));
+ CV_CALL( int_ptr = (int**)cvAlloc( sample_count*sizeof(int_ptr[0]) ));
+
+ max_c_count = 1;
+
+ // transform the training data to convenient representation
+ for( vi = 0; vi <= var_count; vi++ )
+ {
+ int ci;
+ const uchar* mask = 0;
+ int m_step = 0, step;
+ const int* idata = 0;
+ const float* fdata = 0;
+ int num_valid = 0;
+
+ if( vi < var_count ) // analyze i-th input variable
+ {
+ int vi0 = vidx ? vidx[vi] : vi;
+ ci = get_var_type(vi);
+ step = ds_step; m_step = ms_step;
+ if( CV_MAT_TYPE(_train_data->type) == CV_32SC1 )
+ idata = _train_data->data.i + vi0*dv_step;
+ else
+ fdata = _train_data->data.fl + vi0*dv_step;
+ if( _missing_mask )
+ mask = _missing_mask->data.ptr + vi0*mv_step;
+ }
+ else // analyze _responses
+ {
+ ci = cat_var_count;
+ step = CV_IS_MAT_CONT(_responses->type) ?
+ 1 : _responses->step / CV_ELEM_SIZE(_responses->type);
+ if( CV_MAT_TYPE(_responses->type) == CV_32SC1 )
+ idata = _responses->data.i;
+ else
+ fdata = _responses->data.fl;
+ }
+
+ if( vi < var_count && ci >= 0 ||
+ vi == var_count && is_classifier ) // process categorical variable or response
+ {
+ int c_count, prev_label;
+ int* c_map, *dst = get_cat_var_data( data_root, vi );
+
+ // copy data
+ for( i = 0; i < sample_count; i++ )
+ {
+ int val = INT_MAX, si = sidx ? sidx[i] : i;
+ if( !mask || !mask[si*m_step] )
+ {
+ if( idata )
+ val = idata[si*step];
+ else
+ {
+ float t = fdata[si*step];
+ val = cvRound(t);
+ if( val != t )
+ {
+ sprintf( err, "%d-th value of %d-th (categorical) "
+ "variable is not an integer", i, vi );
+ CV_ERROR( CV_StsBadArg, err );
+ }
+ }
+
+ if( val == INT_MAX )
+ {
+ sprintf( err, "%d-th value of %d-th (categorical) "
+ "variable is too large", i, vi );
+ CV_ERROR( CV_StsBadArg, err );
+ }
+ num_valid++;
+ }
+ dst[i] = val;
+ int_ptr[i] = dst + i;
+ }
+
+ // sort all the values, including the missing measurements
+ // that should all move to the end
+ icvSortIntPtr( int_ptr, sample_count, 0 );
+ //qsort( int_ptr, sample_count, sizeof(int_ptr[0]), icvCmpIntPtr );
+
+ c_count = num_valid > 0;
+
+ // count the categories
+ for( i = 1; i < num_valid; i++ )
+ c_count += *int_ptr[i] != *int_ptr[i-1];
+
+ if( vi > 0 )
+ max_c_count = MAX( max_c_count, c_count );
+ cat_count->data.i[ci] = c_count;
+ cat_ofs->data.i[ci] = total_c_count;
+
+ // resize cat_map, if need
+ if( cat_map->cols < total_c_count + c_count )
+ {
+ tmp_map = cat_map;
+ CV_CALL( cat_map = cvCreateMat( 1,
+ MAX(cat_map->cols*3/2,total_c_count+c_count), CV_32SC1 ));
+ for( i = 0; i < total_c_count; i++ )
+ cat_map->data.i[i] = tmp_map->data.i[i];
+ cvReleaseMat( &tmp_map );
+ }
+
+ c_map = cat_map->data.i + total_c_count;
+ total_c_count += c_count;
+
+ // compact the class indices and build the map
+ prev_label = ~*int_ptr[0];
+ c_count = -1;
+
+ for( i = 0; i < num_valid; i++ )
+ {
+ int cur_label = *int_ptr[i];
+ if( cur_label != prev_label )
+ c_map[++c_count] = prev_label = cur_label;
+ *int_ptr[i] = c_count;
+ }
+
+ // replace labels for missing values with -1
+ for( ; i < sample_count; i++ )
+ *int_ptr[i] = -1;
+ }
+ else if( ci < 0 ) // process ordered variable
+ {
+ CvPair32s32f* dst = get_ord_var_data( data_root, vi );
+
+ for( i = 0; i < sample_count; i++ )
+ {
+ float val = ord_nan;
+ int si = sidx ? sidx[i] : i;
+ if( !mask || !mask[si*m_step] )
+ {
+ if( idata )
+ val = (float)idata[si*step];
+ else
+ val = fdata[si*step];
+
+ if( fabs(val) >= ord_nan )
+ {
+ sprintf( err, "%d-th value of %d-th (ordered) "
+ "variable (=%g) is too large", i, vi, val );
+ CV_ERROR( CV_StsBadArg, err );
+ }
+ num_valid++;
+ }
+ dst[i].i = i;
+ dst[i].val = val;
+ }
+
+ icvSortPairs( dst, sample_count, 0 );
+ }
+ else // special case: process ordered response,
+ // it will be stored similarly to categorical vars (i.e. no pairs)
+ {
+ float* dst = get_ord_responses( data_root );
+
+ for( i = 0; i < sample_count; i++ )
+ {
+ float val = ord_nan;
+ int si = sidx ? sidx[i] : i;
+ if( idata )
+ val = (float)idata[si*step];
+ else
+ val = fdata[si*step];
+
+ if( fabs(val) >= ord_nan )
+ {
+ sprintf( err, "%d-th value of %d-th (ordered) "
+ "variable (=%g) is out of range", i, vi, val );
+ CV_ERROR( CV_StsBadArg, err );
+ }
+ dst[i] = val;
+ }
+
+ cat_count->data.i[cat_var_count] = 0;
+ cat_ofs->data.i[cat_var_count] = total_c_count;
+ num_valid = sample_count;
+ }
+
+ if( vi < var_count )
+ data_root->set_num_valid(vi, num_valid);
+ }
+
+ if( cv_n )
+ {
+ int* dst = get_labels(data_root);
+ CvRNG* r = &rng;
+
+ for( i = vi = 0; i < sample_count; i++ )
+ {
+ dst[i] = vi++;
+ vi &= vi < cv_n ? -1 : 0;
+ }
+
+ for( i = 0; i < sample_count; i++ )
+ {
+ int a = cvRandInt(r) % sample_count;
+ int b = cvRandInt(r) % sample_count;
+ CV_SWAP( dst[a], dst[b], vi );
+ }
+ }
+
+ cat_map->cols = MAX( total_c_count, 1 );
+
+ max_split_size = cvAlign(sizeof(CvDTreeSplit) +
+ (MAX(0,max_c_count - 33)/32)*sizeof(int),sizeof(void*));
+ CV_CALL( split_heap = cvCreateSet( 0, sizeof(*split_heap), max_split_size, tree_storage ));
+
+ have_priors = is_classifier && params.priors;
+ if( is_classifier )
+ {
+ int m = get_num_classes();
+ double sum = 0;
+ CV_CALL( priors = cvCreateMat( 1, m, CV_64F ));
+ for( i = 0; i < m; i++ )
+ {
+ double val = have_priors ? params.priors[i] : 1.;
+ if( val <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "Every class weight should be positive" );
+ priors->data.db[i] = val;
+ sum += val;
+ }
+
+ // normalize weights
+ if( have_priors )
+ cvScale( priors, priors, 1./sum );
+
+ CV_CALL( priors_mult = cvCloneMat( priors ));
+ CV_CALL( counts = cvCreateMat( 1, m, CV_32SC1 ));
+ }
+
+ CV_CALL( direction = cvCreateMat( 1, sample_count, CV_8UC1 ));
+ CV_CALL( split_buf = cvCreateMat( 1, sample_count, CV_32SC1 ));
+
+ __END__;
+
+ if( data )
+ delete data;
+
+ cvFree( &int_ptr );
+ cvReleaseMat( &sample_idx );
+ cvReleaseMat( &var_type0 );
+ cvReleaseMat( &tmp_map );
+}
+
+
+CvDTreeNode* CvDTreeTrainData::subsample_data( const CvMat* _subsample_idx )
+{
+ CvDTreeNode* root = 0;
+ CvMat* isubsample_idx = 0;
+ CvMat* subsample_co = 0;
+
+ CV_FUNCNAME( "CvDTreeTrainData::subsample_data" );
+
+ __BEGIN__;
+
+ if( !data_root )
+ CV_ERROR( CV_StsError, "No training data has been set" );
+
+ if( _subsample_idx )
+ CV_CALL( isubsample_idx = cvPreprocessIndexArray( _subsample_idx, sample_count ));
+
+ if( !isubsample_idx )
+ {
+ // make a copy of the root node
+ CvDTreeNode temp;
+ int i;
+ root = new_node( 0, 1, 0, 0 );
+ temp = *root;
+ *root = *data_root;
+ root->num_valid = temp.num_valid;
+ if( root->num_valid )
+ {
+ for( i = 0; i < var_count; i++ )
+ root->num_valid[i] = data_root->num_valid[i];
+ }
+ root->cv_Tn = temp.cv_Tn;
+ root->cv_node_risk = temp.cv_node_risk;
+ root->cv_node_error = temp.cv_node_error;
+ }
+ else
+ {
+ int* sidx = isubsample_idx->data.i;
+ // co - array of count/offset pairs (to handle duplicated values in _subsample_idx)
+ int* co, cur_ofs = 0;
+ int vi, i, total = data_root->sample_count;
+ int count = isubsample_idx->rows + isubsample_idx->cols - 1;
+ int work_var_count = get_work_var_count();
+ root = new_node( 0, count, 1, 0 );
+
+ CV_CALL( subsample_co = cvCreateMat( 1, total*2, CV_32SC1 ));
+ cvZero( subsample_co );
+ co = subsample_co->data.i;
+ for( i = 0; i < count; i++ )
+ co[sidx[i]*2]++;
+ for( i = 0; i < total; i++ )
+ {
+ if( co[i*2] )
+ {
+ co[i*2+1] = cur_ofs;
+ cur_ofs += co[i*2];
+ }
+ else
+ co[i*2+1] = -1;
+ }
+
+ for( vi = 0; vi < work_var_count; vi++ )
+ {
+ int ci = get_var_type(vi);
+
+ if( ci >= 0 || vi >= var_count )
+ {
+ const int* src = get_cat_var_data( data_root, vi );
+ int* dst = get_cat_var_data( root, vi );
+ int num_valid = 0;
+
+ for( i = 0; i < count; i++ )
+ {
+ int val = src[sidx[i]];
+ dst[i] = val;
+ num_valid += val >= 0;
+ }
+
+ if( vi < var_count )
+ root->set_num_valid(vi, num_valid);
+ }
+ else
+ {
+ const CvPair32s32f* src = get_ord_var_data( data_root, vi );
+ CvPair32s32f* dst = get_ord_var_data( root, vi );
+ int j = 0, idx, count_i;
+ int num_valid = data_root->get_num_valid(vi);
+
+ for( i = 0; i < num_valid; i++ )
+ {
+ idx = src[i].i;
+ count_i = co[idx*2];
+ if( count_i )
+ {
+ float val = src[i].val;
+ for( cur_ofs = co[idx*2+1]; count_i > 0; count_i--, j++, cur_ofs++ )
+ {
+ dst[j].val = val;
+ dst[j].i = cur_ofs;
+ }
+ }
+ }
+
+ root->set_num_valid(vi, j);
+
+ for( ; i < total; i++ )
+ {
+ idx = src[i].i;
+ count_i = co[idx*2];
+ if( count_i )
+ {
+ float val = src[i].val;
+ for( cur_ofs = co[idx*2+1]; count_i > 0; count_i--, j++, cur_ofs++ )
+ {
+ dst[j].val = val;
+ dst[j].i = cur_ofs;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &isubsample_idx );
+ cvReleaseMat( &subsample_co );
+
+ return root;
+}
+
+
+void CvDTreeTrainData::get_vectors( const CvMat* _subsample_idx,
+ float* values, uchar* missing,
+ float* responses, bool get_class_idx )
+{
+ CvMat* subsample_idx = 0;
+ CvMat* subsample_co = 0;
+
+ CV_FUNCNAME( "CvDTreeTrainData::get_vectors" );
+
+ __BEGIN__;
+
+ int i, vi, total = sample_count, count = total, cur_ofs = 0;
+ int* sidx = 0;
+ int* co = 0;
+
+ if( _subsample_idx )
+ {
+ CV_CALL( subsample_idx = cvPreprocessIndexArray( _subsample_idx, sample_count ));
+ sidx = subsample_idx->data.i;
+ CV_CALL( subsample_co = cvCreateMat( 1, sample_count*2, CV_32SC1 ));
+ co = subsample_co->data.i;
+ cvZero( subsample_co );
+ count = subsample_idx->cols + subsample_idx->rows - 1;
+ for( i = 0; i < count; i++ )
+ co[sidx[i]*2]++;
+ for( i = 0; i < total; i++ )
+ {
+ int count_i = co[i*2];
+ if( count_i )
+ {
+ co[i*2+1] = cur_ofs*var_count;
+ cur_ofs += count_i;
+ }
+ }
+ }
+
+ if( missing )
+ memset( missing, 1, count*var_count );
+
+ for( vi = 0; vi < var_count; vi++ )
+ {
+ int ci = get_var_type(vi);
+ if( ci >= 0 ) // categorical
+ {
+ float* dst = values + vi;
+ uchar* m = missing ? missing + vi : 0;
+ const int* src = get_cat_var_data(data_root, vi);
+
+ for( i = 0; i < count; i++, dst += var_count )
+ {
+ int idx = sidx ? sidx[i] : i;
+ int val = src[idx];
+ *dst = (float)val;
+ if( m )
+ {
+ *m = val < 0;
+ m += var_count;
+ }
+ }
+ }
+ else // ordered
+ {
+ float* dst = values + vi;
+ uchar* m = missing ? missing + vi : 0;
+ const CvPair32s32f* src = get_ord_var_data(data_root, vi);
+ int count1 = data_root->get_num_valid(vi);
+
+ for( i = 0; i < count1; i++ )
+ {
+ int idx = src[i].i;
+ int count_i = 1;
+ if( co )
+ {
+ count_i = co[idx*2];
+ cur_ofs = co[idx*2+1];
+ }
+ else
+ cur_ofs = idx*var_count;
+ if( count_i )
+ {
+ float val = src[i].val;
+ for( ; count_i > 0; count_i--, cur_ofs += var_count )
+ {
+ dst[cur_ofs] = val;
+ if( m )
+ m[cur_ofs] = 0;
+ }
+ }
+ }
+ }
+ }
+
+ // copy responses
+ if( responses )
+ {
+ if( is_classifier )
+ {
+ const int* src = get_class_labels(data_root);
+ for( i = 0; i < count; i++ )
+ {
+ int idx = sidx ? sidx[i] : i;
+ int val = get_class_idx ? src[idx] :
+ cat_map->data.i[cat_ofs->data.i[cat_var_count]+src[idx]];
+ responses[i] = (float)val;
+ }
+ }
+ else
+ {
+ const float* src = get_ord_responses(data_root);
+ for( i = 0; i < count; i++ )
+ {
+ int idx = sidx ? sidx[i] : i;
+ responses[i] = src[idx];
+ }
+ }
+ }
+
+ __END__;
+
+ cvReleaseMat( &subsample_idx );
+ cvReleaseMat( &subsample_co );
+}
+
+
+CvDTreeNode* CvDTreeTrainData::new_node( CvDTreeNode* parent, int count,
+ int storage_idx, int offset )
+{
+ CvDTreeNode* node = (CvDTreeNode*)cvSetNew( node_heap );
+
+ node->sample_count = count;
+ node->depth = parent ? parent->depth + 1 : 0;
+ node->parent = parent;
+ node->left = node->right = 0;
+ node->split = 0;
+ node->value = 0;
+ node->class_idx = 0;
+ node->maxlr = 0.;
+
+ node->buf_idx = storage_idx;
+ node->offset = offset;
+ if( nv_heap )
+ node->num_valid = (int*)cvSetNew( nv_heap );
+ else
+ node->num_valid = 0;
+ node->alpha = node->node_risk = node->tree_risk = node->tree_error = 0.;
+ node->complexity = 0;
+
+ if( params.cv_folds > 0 && cv_heap )
+ {
+ int cv_n = params.cv_folds;
+ node->Tn = INT_MAX;
+ node->cv_Tn = (int*)cvSetNew( cv_heap );
+ node->cv_node_risk = (double*)cvAlignPtr(node->cv_Tn + cv_n, sizeof(double));
+ node->cv_node_error = node->cv_node_risk + cv_n;
+ }
+ else
+ {
+ node->Tn = 0;
+ node->cv_Tn = 0;
+ node->cv_node_risk = 0;
+ node->cv_node_error = 0;
+ }
+
+ return node;
+}
+
+
+CvDTreeSplit* CvDTreeTrainData::new_split_ord( int vi, float cmp_val,
+ int split_point, int inversed, float quality )
+{
+ CvDTreeSplit* split = (CvDTreeSplit*)cvSetNew( split_heap );
+ split->var_idx = vi;
+ split->ord.c = cmp_val;
+ split->ord.split_point = split_point;
+ split->inversed = inversed;
+ split->quality = quality;
+ split->next = 0;
+
+ return split;
+}
+
+
+CvDTreeSplit* CvDTreeTrainData::new_split_cat( int vi, float quality )
+{
+ CvDTreeSplit* split = (CvDTreeSplit*)cvSetNew( split_heap );
+ int i, n = (max_c_count + 31)/32;
+
+ split->var_idx = vi;
+ split->inversed = 0;
+ split->quality = quality;
+ for( i = 0; i < n; i++ )
+ split->subset[i] = 0;
+ split->next = 0;
+
+ return split;
+}
+
+
+void CvDTreeTrainData::free_node( CvDTreeNode* node )
+{
+ CvDTreeSplit* split = node->split;
+ free_node_data( node );
+ while( split )
+ {
+ CvDTreeSplit* next = split->next;
+ cvSetRemoveByPtr( split_heap, split );
+ split = next;
+ }
+ node->split = 0;
+ cvSetRemoveByPtr( node_heap, node );
+}
+
+
+void CvDTreeTrainData::free_node_data( CvDTreeNode* node )
+{
+ if( node->num_valid )
+ {
+ cvSetRemoveByPtr( nv_heap, node->num_valid );
+ node->num_valid = 0;
+ }
+ // do not free cv_* fields, as all the cross-validation related data is released at once.
+}
+
+
+void CvDTreeTrainData::free_train_data()
+{
+ cvReleaseMat( &counts );
+ cvReleaseMat( &buf );
+ cvReleaseMat( &direction );
+ cvReleaseMat( &split_buf );
+ cvReleaseMemStorage( &temp_storage );
+ cv_heap = nv_heap = 0;
+}
+
+
+void CvDTreeTrainData::clear()
+{
+ free_train_data();
+
+ cvReleaseMemStorage( &tree_storage );
+
+ cvReleaseMat( &var_idx );
+ cvReleaseMat( &var_type );
+ cvReleaseMat( &cat_count );
+ cvReleaseMat( &cat_ofs );
+ cvReleaseMat( &cat_map );
+ cvReleaseMat( &priors );
+ cvReleaseMat( &priors_mult );
+
+ node_heap = split_heap = 0;
+
+ sample_count = var_all = var_count = max_c_count = ord_var_count = cat_var_count = 0;
+ have_labels = have_priors = is_classifier = false;
+
+ buf_count = buf_size = 0;
+ shared = false;
+
+ data_root = 0;
+
+ rng = cvRNG(-1);
+}
+
+
+int CvDTreeTrainData::get_num_classes() const
+{
+ return is_classifier ? cat_count->data.i[cat_var_count] : 0;
+}
+
+
+int CvDTreeTrainData::get_var_type(int vi) const
+{
+ return var_type->data.i[vi];
+}
+
+
+int CvDTreeTrainData::get_work_var_count() const
+{
+ return var_count + 1 + (have_labels ? 1 : 0);
+}
+
+CvPair32s32f* CvDTreeTrainData::get_ord_var_data( CvDTreeNode* n, int vi )
+{
+ int oi = ~get_var_type(vi);
+ assert( 0 <= oi && oi < ord_var_count );
+ return (CvPair32s32f*)(buf->data.i + n->buf_idx*buf->cols +
+ n->offset + oi*n->sample_count*2);
+}
+
+
+int* CvDTreeTrainData::get_class_labels( CvDTreeNode* n )
+{
+ return get_cat_var_data( n, var_count );
+}
+
+
+float* CvDTreeTrainData::get_ord_responses( CvDTreeNode* n )
+{
+ return (float*)get_cat_var_data( n, var_count );
+}
+
+
+int* CvDTreeTrainData::get_labels( CvDTreeNode* n )
+{
+ return have_labels ? get_cat_var_data( n, var_count + 1 ) : 0;
+}
+
+
+int* CvDTreeTrainData::get_cat_var_data( CvDTreeNode* n, int vi )
+{
+ int ci = get_var_type(vi);
+ assert( 0 <= ci && ci <= cat_var_count + 1 );
+ return buf->data.i + n->buf_idx*buf->cols + n->offset +
+ (ord_var_count*2 + ci)*n->sample_count;
+}
+
+
+int CvDTreeTrainData::get_child_buf_idx( CvDTreeNode* n )
+{
+ int idx = n->buf_idx + 1;
+ if( idx >= buf_count )
+ idx = shared ? 1 : 0;
+ return idx;
+}
+
+
+void CvDTreeTrainData::write_params( CvFileStorage* fs )
+{
+ CV_FUNCNAME( "CvDTreeTrainData::write_params" );
+
+ __BEGIN__;
+
+ int vi, vcount = var_count;
+
+ cvWriteInt( fs, "is_classifier", is_classifier ? 1 : 0 );
+ cvWriteInt( fs, "var_all", var_all );
+ cvWriteInt( fs, "var_count", var_count );
+ cvWriteInt( fs, "ord_var_count", ord_var_count );
+ cvWriteInt( fs, "cat_var_count", cat_var_count );
+
+ cvStartWriteStruct( fs, "training_params", CV_NODE_MAP );
+ cvWriteInt( fs, "use_surrogates", params.use_surrogates ? 1 : 0 );
+
+ if( is_classifier )
+ {
+ cvWriteInt( fs, "max_categories", params.max_categories );
+ }
+ else
+ {
+ cvWriteReal( fs, "regression_accuracy", params.regression_accuracy );
+ }
+
+ cvWriteInt( fs, "max_depth", params.max_depth );
+ cvWriteInt( fs, "min_sample_count", params.min_sample_count );
+ cvWriteInt( fs, "cross_validation_folds", params.cv_folds );
+
+ if( params.cv_folds > 1 )
+ {
+ cvWriteInt( fs, "use_1se_rule", params.use_1se_rule ? 1 : 0 );
+ cvWriteInt( fs, "truncate_pruned_tree", params.truncate_pruned_tree ? 1 : 0 );
+ }
+
+ if( priors )
+ cvWrite( fs, "priors", priors );
+
+ cvEndWriteStruct( fs );
+
+ if( var_idx )
+ cvWrite( fs, "var_idx", var_idx );
+
+ cvStartWriteStruct( fs, "var_type", CV_NODE_SEQ+CV_NODE_FLOW );
+
+ for( vi = 0; vi < vcount; vi++ )
+ cvWriteInt( fs, 0, var_type->data.i[vi] >= 0 );
+
+ cvEndWriteStruct( fs );
+
+ if( cat_count && (cat_var_count > 0 || is_classifier) )
+ {
+ CV_ASSERT( cat_count != 0 );
+ cvWrite( fs, "cat_count", cat_count );
+ cvWrite( fs, "cat_map", cat_map );
+ }
+
+ __END__;
+}
+
+
+void CvDTreeTrainData::read_params( CvFileStorage* fs, CvFileNode* node )
+{
+ CV_FUNCNAME( "CvDTreeTrainData::read_params" );
+
+ __BEGIN__;
+
+ CvFileNode *tparams_node, *vartype_node;
+ CvSeqReader reader;
+ int vi, max_split_size, tree_block_size;
+
+ is_classifier = (cvReadIntByName( fs, node, "is_classifier" ) != 0);
+ var_all = cvReadIntByName( fs, node, "var_all" );
+ var_count = cvReadIntByName( fs, node, "var_count", var_all );
+ cat_var_count = cvReadIntByName( fs, node, "cat_var_count" );
+ ord_var_count = cvReadIntByName( fs, node, "ord_var_count" );
+
+ tparams_node = cvGetFileNodeByName( fs, node, "training_params" );
+
+ if( tparams_node ) // training parameters are not necessary
+ {
+ params.use_surrogates = cvReadIntByName( fs, tparams_node, "use_surrogates", 1 ) != 0;
+
+ if( is_classifier )
+ {
+ params.max_categories = cvReadIntByName( fs, tparams_node, "max_categories" );
+ }
+ else
+ {
+ params.regression_accuracy =
+ (float)cvReadRealByName( fs, tparams_node, "regression_accuracy" );
+ }
+
+ params.max_depth = cvReadIntByName( fs, tparams_node, "max_depth" );
+ params.min_sample_count = cvReadIntByName( fs, tparams_node, "min_sample_count" );
+ params.cv_folds = cvReadIntByName( fs, tparams_node, "cross_validation_folds" );
+
+ if( params.cv_folds > 1 )
+ {
+ params.use_1se_rule = cvReadIntByName( fs, tparams_node, "use_1se_rule" ) != 0;
+ params.truncate_pruned_tree =
+ cvReadIntByName( fs, tparams_node, "truncate_pruned_tree" ) != 0;
+ }
+
+ priors = (CvMat*)cvReadByName( fs, tparams_node, "priors" );
+ if( priors )
+ {
+ if( !CV_IS_MAT(priors) )
+ CV_ERROR( CV_StsParseError, "priors must stored as a matrix" );
+ priors_mult = cvCloneMat( priors );
+ }
+ }
+
+ CV_CALL( var_idx = (CvMat*)cvReadByName( fs, node, "var_idx" ));
+ if( var_idx )
+ {
+ if( !CV_IS_MAT(var_idx) ||
+ var_idx->cols != 1 && var_idx->rows != 1 ||
+ var_idx->cols + var_idx->rows - 1 != var_count ||
+ CV_MAT_TYPE(var_idx->type) != CV_32SC1 )
+ CV_ERROR( CV_StsParseError,
+ "var_idx (if exist) must be valid 1d integer vector containing <var_count> elements" );
+
+ for( vi = 0; vi < var_count; vi++ )
+ if( (unsigned)var_idx->data.i[vi] >= (unsigned)var_all )
+ CV_ERROR( CV_StsOutOfRange, "some of var_idx elements are out of range" );
+ }
+
+ ////// read var type
+ CV_CALL( var_type = cvCreateMat( 1, var_count + 2, CV_32SC1 ));
+
+ cat_var_count = 0;
+ ord_var_count = -1;
+ vartype_node = cvGetFileNodeByName( fs, node, "var_type" );
+
+ if( vartype_node && CV_NODE_TYPE(vartype_node->tag) == CV_NODE_INT && var_count == 1 )
+ var_type->data.i[0] = vartype_node->data.i ? cat_var_count++ : ord_var_count--;
+ else
+ {
+ if( !vartype_node || CV_NODE_TYPE(vartype_node->tag) != CV_NODE_SEQ ||
+ vartype_node->data.seq->total != var_count )
+ CV_ERROR( CV_StsParseError, "var_type must exist and be a sequence of 0's and 1's" );
+
+ cvStartReadSeq( vartype_node->data.seq, &reader );
+
+ for( vi = 0; vi < var_count; vi++ )
+ {
+ CvFileNode* n = (CvFileNode*)reader.ptr;
+ if( CV_NODE_TYPE(n->tag) != CV_NODE_INT || (n->data.i & ~1) )
+ CV_ERROR( CV_StsParseError, "var_type must exist and be a sequence of 0's and 1's" );
+ var_type->data.i[vi] = n->data.i ? cat_var_count++ : ord_var_count--;
+ CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
+ }
+ }
+ var_type->data.i[var_count] = cat_var_count;
+
+ ord_var_count = ~ord_var_count;
+ if( cat_var_count != cat_var_count || ord_var_count != ord_var_count )
+ CV_ERROR( CV_StsParseError, "var_type is inconsistent with cat_var_count and ord_var_count" );
+ //////
+
+ if( cat_var_count > 0 || is_classifier )
+ {
+ int ccount, total_c_count = 0;
+ CV_CALL( cat_count = (CvMat*)cvReadByName( fs, node, "cat_count" ));
+ CV_CALL( cat_map = (CvMat*)cvReadByName( fs, node, "cat_map" ));
+
+ if( !CV_IS_MAT(cat_count) || !CV_IS_MAT(cat_map) ||
+ cat_count->cols != 1 && cat_count->rows != 1 ||
+ CV_MAT_TYPE(cat_count->type) != CV_32SC1 ||
+ cat_count->cols + cat_count->rows - 1 != cat_var_count + is_classifier ||
+ cat_map->cols != 1 && cat_map->rows != 1 ||
+ CV_MAT_TYPE(cat_map->type) != CV_32SC1 )
+ CV_ERROR( CV_StsParseError,
+ "Both cat_count and cat_map must exist and be valid 1d integer vectors of an appropriate size" );
+
+ ccount = cat_var_count + is_classifier;
+
+ CV_CALL( cat_ofs = cvCreateMat( 1, ccount + 1, CV_32SC1 ));
+ cat_ofs->data.i[0] = 0;
+ max_c_count = 1;
+
+ for( vi = 0; vi < ccount; vi++ )
+ {
+ int val = cat_count->data.i[vi];
+ if( val <= 0 )
+ CV_ERROR( CV_StsOutOfRange, "some of cat_count elements are out of range" );
+ max_c_count = MAX( max_c_count, val );
+ cat_ofs->data.i[vi+1] = total_c_count += val;
+ }
+
+ if( cat_map->cols + cat_map->rows - 1 != total_c_count )
+ CV_ERROR( CV_StsBadSize,
+ "cat_map vector length is not equal to the total number of categories in all categorical vars" );
+ }
+
+ max_split_size = cvAlign(sizeof(CvDTreeSplit) +
+ (MAX(0,max_c_count - 33)/32)*sizeof(int),sizeof(void*));
+
+ tree_block_size = MAX((int)sizeof(CvDTreeNode)*8, max_split_size);
+ tree_block_size = MAX(tree_block_size + block_size_delta, min_block_size);
+ CV_CALL( tree_storage = cvCreateMemStorage( tree_block_size ));
+ CV_CALL( node_heap = cvCreateSet( 0, sizeof(node_heap[0]),
+ sizeof(CvDTreeNode), tree_storage ));
+ CV_CALL( split_heap = cvCreateSet( 0, sizeof(split_heap[0]),
+ max_split_size, tree_storage ));
+
+ __END__;
+}
+
+
+/////////////////////// Decision Tree /////////////////////////
+
+CvDTree::CvDTree()
+{
+ data = 0;
+ var_importance = 0;
+ default_model_name = "my_tree";
+
+ clear();
+}
+
+
+void CvDTree::clear()
+{
+ cvReleaseMat( &var_importance );
+ if( data )
+ {
+ if( !data->shared )
+ delete data;
+ else
+ free_tree();
+ data = 0;
+ }
+ root = 0;
+ pruned_tree_idx = -1;
+}
+
+
+CvDTree::~CvDTree()
+{
+ clear();
+}
+
+
+const CvDTreeNode* CvDTree::get_root() const
+{
+ return root;
+}
+
+
+int CvDTree::get_pruned_tree_idx() const
+{
+ return pruned_tree_idx;
+}
+
+
+CvDTreeTrainData* CvDTree::get_data()
+{
+ return data;
+}
+
+
+bool CvDTree::train( const CvMat* _train_data, int _tflag,
+ const CvMat* _responses, const CvMat* _var_idx,
+ const CvMat* _sample_idx, const CvMat* _var_type,
+ const CvMat* _missing_mask, CvDTreeParams _params )
+{
+ bool result = false;
+
+ CV_FUNCNAME( "CvDTree::train" );
+
+ __BEGIN__;
+
+ clear();
+ data = new CvDTreeTrainData( _train_data, _tflag, _responses,
+ _var_idx, _sample_idx, _var_type,
+ _missing_mask, _params, false );
+ CV_CALL( result = do_train(0));
+
+ __END__;
+
+ return result;
+}
+
+
+bool CvDTree::train( CvDTreeTrainData* _data, const CvMat* _subsample_idx )
+{
+ bool result = false;
+
+ CV_FUNCNAME( "CvDTree::train" );
+
+ __BEGIN__;
+
+ clear();
+ data = _data;
+ data->shared = true;
+ CV_CALL( result = do_train(_subsample_idx));
+
+ __END__;
+
+ return result;
+}
+
+
+bool CvDTree::do_train( const CvMat* _subsample_idx )
+{
+ bool result = false;
+
+ CV_FUNCNAME( "CvDTree::do_train" );
+
+ __BEGIN__;
+
+ root = data->subsample_data( _subsample_idx );
+
+ CV_CALL( try_split_node(root));
+
+ if( data->params.cv_folds > 0 )
+ CV_CALL( prune_cv());
+
+ if( !data->shared )
+ data->free_train_data();
+
+ result = true;
+
+ __END__;
+
+ return result;
+}
+
+
+void CvDTree::try_split_node( CvDTreeNode* node )
+{
+ CvDTreeSplit* best_split = 0;
+ int i, n = node->sample_count, vi;
+ bool can_split = true;
+ double quality_scale;
+
+ calc_node_value( node );
+
+ if( node->sample_count <= data->params.min_sample_count ||
+ node->depth >= data->params.max_depth )
+ can_split = false;
+
+ if( can_split && data->is_classifier )
+ {
+ // check if we have a "pure" node,
+ // we assume that cls_count is filled by calc_node_value()
+ int* cls_count = data->counts->data.i;
+ int nz = 0, m = data->get_num_classes();
+ for( i = 0; i < m; i++ )
+ nz += cls_count[i] != 0;
+ if( nz == 1 ) // there is only one class
+ can_split = false;
+ }
+ else if( can_split )
+ {
+ if( sqrt(node->node_risk)/n < data->params.regression_accuracy )
+ can_split = false;
+ }
+
+ if( can_split )
+ {
+ best_split = find_best_split(node);
+ // TODO: check the split quality ...
+ node->split = best_split;
+ }
+
+ if( !can_split || !best_split )
+ {
+ data->free_node_data(node);
+ return;
+ }
+
+ quality_scale = calc_node_dir( node );
+
+ if( data->params.use_surrogates )
+ {
+ // find all the surrogate splits
+ // and sort them by their similarity to the primary one
+ for( vi = 0; vi < data->var_count; vi++ )
+ {
+ CvDTreeSplit* split;
+ int ci = data->get_var_type(vi);
+
+ if( vi == best_split->var_idx )
+ continue;
+
+ if( ci >= 0 )
+ split = find_surrogate_split_cat( node, vi );
+ else
+ split = find_surrogate_split_ord( node, vi );
+
+ if( split )
+ {
+ // insert the split
+ CvDTreeSplit* prev_split = node->split;
+ split->quality = (float)(split->quality*quality_scale);
+
+ while( prev_split->next &&
+ prev_split->next->quality > split->quality )
+ prev_split = prev_split->next;
+ split->next = prev_split->next;
+ prev_split->next = split;
+ }
+ }
+ }
+
+ split_node_data( node );
+ try_split_node( node->left );
+ try_split_node( node->right );
+}
+
+
+// calculate direction (left(-1),right(1),missing(0))
+// for each sample using the best split
+// the function returns scale coefficients for surrogate split quality factors.
+// the scale is applied to normalize surrogate split quality relatively to the
+// best (primary) split quality. That is, if a surrogate split is absolutely
+// identical to the primary split, its quality will be set to the maximum value =
+// quality of the primary split; otherwise, it will be lower.
+// besides, the function compute node->maxlr,
+// minimum possible quality (w/o considering the above mentioned scale)
+// for a surrogate split. Surrogate splits with quality less than node->maxlr
+// are not discarded.
+double CvDTree::calc_node_dir( CvDTreeNode* node )
+{
+ char* dir = (char*)data->direction->data.ptr;
+ int i, n = node->sample_count, vi = node->split->var_idx;
+ double L, R;
+
+ assert( !node->split->inversed );
+
+ if( data->get_var_type(vi) >= 0 ) // split on categorical var
+ {
+ const int* labels = data->get_cat_var_data(node,vi);
+ const int* subset = node->split->subset;
+
+ if( !data->have_priors )
+ {
+ int sum = 0, sum_abs = 0;
+
+ for( i = 0; i < n; i++ )
+ {
+ int idx = labels[i];
+ int d = idx >= 0 ? CV_DTREE_CAT_DIR(idx,subset) : 0;
+ sum += d; sum_abs += d & 1;
+ dir[i] = (char)d;
+ }
+
+ R = (sum_abs + sum) >> 1;
+ L = (sum_abs - sum) >> 1;
+ }
+ else
+ {
+ const int* responses = data->get_class_labels(node);
+ const double* priors = data->priors_mult->data.db;
+ double sum = 0, sum_abs = 0;
+
+ for( i = 0; i < n; i++ )
+ {
+ int idx = labels[i];
+ double w = priors[responses[i]];
+ int d = idx >= 0 ? CV_DTREE_CAT_DIR(idx,subset) : 0;
+ sum += d*w; sum_abs += (d & 1)*w;
+ dir[i] = (char)d;
+ }
+
+ R = (sum_abs + sum) * 0.5;
+ L = (sum_abs - sum) * 0.5;
+ }
+ }
+ else // split on ordered var
+ {
+ const CvPair32s32f* sorted = data->get_ord_var_data(node,vi);
+ int split_point = node->split->ord.split_point;
+ int n1 = node->get_num_valid(vi);
+
+ assert( 0 <= split_point && split_point < n1-1 );
+
+ if( !data->have_priors )
+ {
+ for( i = 0; i <= split_point; i++ )
+ dir[sorted[i].i] = (char)-1;
+ for( ; i < n1; i++ )
+ dir[sorted[i].i] = (char)1;
+ for( ; i < n; i++ )
+ dir[sorted[i].i] = (char)0;
+
+ L = split_point-1;
+ R = n1 - split_point + 1;
+ }
+ else
+ {
+ const int* responses = data->get_class_labels(node);
+ const double* priors = data->priors_mult->data.db;
+ L = R = 0;
+
+ for( i = 0; i <= split_point; i++ )
+ {
+ int idx = sorted[i].i;
+ double w = priors[responses[idx]];
+ dir[idx] = (char)-1;
+ L += w;
+ }
+
+ for( ; i < n1; i++ )
+ {
+ int idx = sorted[i].i;
+ double w = priors[responses[idx]];
+ dir[idx] = (char)1;
+ R += w;
+ }
+
+ for( ; i < n; i++ )
+ dir[sorted[i].i] = (char)0;
+ }
+ }
+
+ node->maxlr = MAX( L, R );
+ return node->split->quality/(L + R);
+}
+
+
+CvDTreeSplit* CvDTree::find_best_split( CvDTreeNode* node )
+{
+ int vi;
+ CvDTreeSplit *best_split = 0, *split = 0, *t;
+
+ for( vi = 0; vi < data->var_count; vi++ )
+ {
+ int ci = data->get_var_type(vi);
+ if( node->get_num_valid(vi) <= 1 )
+ continue;
+
+ if( data->is_classifier )
+ {
+ if( ci >= 0 )
+ split = find_split_cat_class( node, vi );
+ else
+ split = find_split_ord_class( node, vi );
+ }
+ else
+ {
+ if( ci >= 0 )
+ split = find_split_cat_reg( node, vi );
+ else
+ split = find_split_ord_reg( node, vi );
+ }
+
+ if( split )
+ {
+ if( !best_split || best_split->quality < split->quality )
+ CV_SWAP( best_split, split, t );
+ if( split )
+ cvSetRemoveByPtr( data->split_heap, split );
+ }
+ }
+
+ return best_split;
+}
+
+
+CvDTreeSplit* CvDTree::find_split_ord_class( CvDTreeNode* node, int vi )
+{
+ const float epsilon = FLT_EPSILON*2;
+ const CvPair32s32f* sorted = data->get_ord_var_data(node, vi);
+ const int* responses = data->get_class_labels(node);
+ int n = node->sample_count;
+ int n1 = node->get_num_valid(vi);
+ int m = data->get_num_classes();
+ const int* rc0 = data->counts->data.i;
+ int* lc = (int*)cvStackAlloc(m*sizeof(lc[0]));
+ int* rc = (int*)cvStackAlloc(m*sizeof(rc[0]));
+ int i, best_i = -1;
+ double lsum2 = 0, rsum2 = 0, best_val = 0;
+ const double* priors = data->have_priors ? data->priors_mult->data.db : 0;
+
+ // init arrays of class instance counters on both sides of the split
+ for( i = 0; i < m; i++ )
+ {
+ lc[i] = 0;
+ rc[i] = rc0[i];
+ }
+
+ // compensate for missing values
+ for( i = n1; i < n; i++ )
+ rc[responses[sorted[i].i]]--;
+
+ if( !priors )
+ {
+ int L = 0, R = n1;
+
+ for( i = 0; i < m; i++ )
+ rsum2 += (double)rc[i]*rc[i];
+
+ for( i = 0; i < n1 - 1; i++ )
+ {
+ int idx = responses[sorted[i].i];
+ int lv, rv;
+ L++; R--;
+ lv = lc[idx]; rv = rc[idx];
+ lsum2 += lv*2 + 1;
+ rsum2 -= rv*2 - 1;
+ lc[idx] = lv + 1; rc[idx] = rv - 1;
+
+ if( sorted[i].val + epsilon < sorted[i+1].val )
+ {
+ double val = (lsum2*R + rsum2*L)/((double)L*R);
+ if( best_val < val )
+ {
+ best_val = val;
+ best_i = i;
+ }
+ }
+ }
+ }
+ else
+ {
+ double L = 0, R = 0;
+ for( i = 0; i < m; i++ )
+ {
+ double wv = rc[i]*priors[i];
+ R += wv;
+ rsum2 += wv*wv;
+ }
+
+ for( i = 0; i < n1 - 1; i++ )
+ {
+ int idx = responses[sorted[i].i];
+ int lv, rv;
+ double p = priors[idx], p2 = p*p;
+ L += p; R -= p;
+ lv = lc[idx]; rv = rc[idx];
+ lsum2 += p2*(lv*2 + 1);
+ rsum2 -= p2*(rv*2 - 1);
+ lc[idx] = lv + 1; rc[idx] = rv - 1;
+
+ if( sorted[i].val + epsilon < sorted[i+1].val )
+ {
+ double val = (lsum2*R + rsum2*L)/((double)L*R);
+ if( best_val < val )
+ {
+ best_val = val;
+ best_i = i;
+ }
+ }
+ }
+ }
+
+ return best_i >= 0 ? data->new_split_ord( vi,
+ (sorted[best_i].val + sorted[best_i+1].val)*0.5f, best_i,
+ 0, (float)best_val ) : 0;
+}
+
+
+void CvDTree::cluster_categories( const int* vectors, int n, int m,
+ int* csums, int k, int* labels )
+{
+ // TODO: consider adding priors (class weights) and sample weights to the clustering algorithm
+ int iters = 0, max_iters = 100;
+ int i, j, idx;
+ double* buf = (double*)cvStackAlloc( (n + k)*sizeof(buf[0]) );
+ double *v_weights = buf, *c_weights = buf + k;
+ bool modified = true;
+ CvRNG* r = &data->rng;
+
+ // assign labels randomly
+ for( i = idx = 0; i < n; i++ )
+ {
+ int sum = 0;
+ const int* v = vectors + i*m;
+ labels[i] = idx++;
+ idx &= idx < k ? -1 : 0;
+
+ // compute weight of each vector
+ for( j = 0; j < m; j++ )
+ sum += v[j];
+ v_weights[i] = sum ? 1./sum : 0.;
+ }
+
+ for( i = 0; i < n; i++ )
+ {
+ int i1 = cvRandInt(r) % n;
+ int i2 = cvRandInt(r) % n;
+ CV_SWAP( labels[i1], labels[i2], j );
+ }
+
+ for( iters = 0; iters <= max_iters; iters++ )
+ {
+ // calculate csums
+ for( i = 0; i < k; i++ )
+ {
+ for( j = 0; j < m; j++ )
+ csums[i*m + j] = 0;
+ }
+
+ for( i = 0; i < n; i++ )
+ {
+ const int* v = vectors + i*m;
+ int* s = csums + labels[i]*m;
+ for( j = 0; j < m; j++ )
+ s[j] += v[j];
+ }
+
+ // exit the loop here, when we have up-to-date csums
+ if( iters == max_iters || !modified )
+ break;
+
+ modified = false;
+
+ // calculate weight of each cluster
+ for( i = 0; i < k; i++ )
+ {
+ const int* s = csums + i*m;
+ int sum = 0;
+ for( j = 0; j < m; j++ )
+ sum += s[j];
+ c_weights[i] = sum ? 1./sum : 0;
+ }
+
+ // now for each vector determine the closest cluster
+ for( i = 0; i < n; i++ )
+ {
+ const int* v = vectors + i*m;
+ double alpha = v_weights[i];
+ double min_dist2 = DBL_MAX;
+ int min_idx = -1;
+
+ for( idx = 0; idx < k; idx++ )
+ {
+ const int* s = csums + idx*m;
+ double dist2 = 0., beta = c_weights[idx];
+ for( j = 0; j < m; j++ )
+ {
+ double t = v[j]*alpha - s[j]*beta;
+ dist2 += t*t;
+ }
+ if( min_dist2 > dist2 )
+ {
+ min_dist2 = dist2;
+ min_idx = idx;
+ }
+ }
+
+ if( min_idx != labels[i] )
+ modified = true;
+ labels[i] = min_idx;
+ }
+ }
+}
+
+
+CvDTreeSplit* CvDTree::find_split_cat_class( CvDTreeNode* node, int vi )
+{
+ CvDTreeSplit* split;
+ const int* labels = data->get_cat_var_data(node, vi);
+ const int* responses = data->get_class_labels(node);
+ int ci = data->get_var_type(vi);
+ int n = node->sample_count;
+ int m = data->get_num_classes();
+ int _mi = data->cat_count->data.i[ci], mi = _mi;
+ int* lc = (int*)cvStackAlloc(m*sizeof(lc[0]));
+ int* rc = (int*)cvStackAlloc(m*sizeof(rc[0]));
+ int* _cjk = (int*)cvStackAlloc(m*(mi+1)*sizeof(_cjk[0]))+m, *cjk = _cjk;
+ double* c_weights = (double*)cvStackAlloc( mi*sizeof(c_weights[0]) );
+ int* cluster_labels = 0;
+ int** int_ptr = 0;
+ int i, j, k, idx;
+ double L = 0, R = 0;
+ double best_val = 0;
+ int prevcode = 0, best_subset = -1, subset_i, subset_n, subtract = 0;
+ const double* priors = data->priors_mult->data.db;
+
+ // init array of counters:
+ // c_{jk} - number of samples that have vi-th input variable = j and response = k.
+ for( j = -1; j < mi; j++ )
+ for( k = 0; k < m; k++ )
+ cjk[j*m + k] = 0;
+
+ for( i = 0; i < n; i++ )
+ {
+ j = labels[i];
+ k = responses[i];
+ cjk[j*m + k]++;
+ }
+
+ if( m > 2 )
+ {
+ if( mi > data->params.max_categories )
+ {
+ mi = MIN(data->params.max_categories, n);
+ cjk += _mi*m;
+ cluster_labels = (int*)cvStackAlloc(mi*sizeof(cluster_labels[0]));
+ cluster_categories( _cjk, _mi, m, cjk, mi, cluster_labels );
+ }
+ subset_i = 1;
+ subset_n = 1 << mi;
+ }
+ else
+ {
+ assert( m == 2 );
+ int_ptr = (int**)cvStackAlloc( mi*sizeof(int_ptr[0]) );
+ for( j = 0; j < mi; j++ )
+ int_ptr[j] = cjk + j*2 + 1;
+ icvSortIntPtr( int_ptr, mi, 0 );
+ subset_i = 0;
+ subset_n = mi;
+ }
+
+ for( k = 0; k < m; k++ )
+ {
+ int sum = 0;
+ for( j = 0; j < mi; j++ )
+ sum += cjk[j*m + k];
+ rc[k] = sum;
+ lc[k] = 0;
+ }
+
+ for( j = 0; j < mi; j++ )
+ {
+ double sum = 0;
+ for( k = 0; k < m; k++ )
+ sum += cjk[j*m + k]*priors[k];
+ c_weights[j] = sum;
+ R += c_weights[j];
+ }
+
+ for( ; subset_i < subset_n; subset_i++ )
+ {
+ double weight;
+ int* crow;
+ double lsum2 = 0, rsum2 = 0;
+
+ if( m == 2 )
+ idx = (int)(int_ptr[subset_i] - cjk)/2;
+ else
+ {
+ int graycode = (subset_i>>1)^subset_i;
+ int diff = graycode ^ prevcode;
+
+ // determine index of the changed bit.
+ Cv32suf u;
+ idx = diff >= (1 << 16) ? 16 : 0;
+ u.f = (float)(((diff >> 16) | diff) & 65535);
+ idx += (u.i >> 23) - 127;
+ subtract = graycode < prevcode;
+ prevcode = graycode;
+ }
+
+ crow = cjk + idx*m;
+ weight = c_weights[idx];
+ if( weight < FLT_EPSILON )
+ continue;
+
+ if( !subtract )
+ {
+ for( k = 0; k < m; k++ )
+ {
+ int t = crow[k];
+ int lval = lc[k] + t;
+ int rval = rc[k] - t;
+ double p = priors[k], p2 = p*p;
+ lsum2 += p2*lval*lval;
+ rsum2 += p2*rval*rval;
+ lc[k] = lval; rc[k] = rval;
+ }
+ L += weight;
+ R -= weight;
+ }
+ else
+ {
+ for( k = 0; k < m; k++ )
+ {
+ int t = crow[k];
+ int lval = lc[k] - t;
+ int rval = rc[k] + t;
+ double p = priors[k], p2 = p*p;
+ lsum2 += p2*lval*lval;
+ rsum2 += p2*rval*rval;
+ lc[k] = lval; rc[k] = rval;
+ }
+ L -= weight;
+ R += weight;
+ }
+
+ if( L > FLT_EPSILON && R > FLT_EPSILON )
+ {
+ double val = (lsum2*R + rsum2*L)/((double)L*R);
+ if( best_val < val )
+ {
+ best_val = val;
+ best_subset = subset_i;
+ }
+ }
+ }
+
+ if( best_subset < 0 )
+ return 0;
+
+ split = data->new_split_cat( vi, (float)best_val );
+
+ if( m == 2 )
+ {
+ for( i = 0; i <= best_subset; i++ )
+ {
+ idx = (int)(int_ptr[i] - cjk) >> 1;
+ split->subset[idx >> 5] |= 1 << (idx & 31);
+ }
+ }
+ else
+ {
+ for( i = 0; i < _mi; i++ )
+ {
+ idx = cluster_labels ? cluster_labels[i] : i;
+ if( best_subset & (1 << idx) )
+ split->subset[i >> 5] |= 1 << (i & 31);
+ }
+ }
+
+ return split;
+}
+
+
+CvDTreeSplit* CvDTree::find_split_ord_reg( CvDTreeNode* node, int vi )
+{
+ const float epsilon = FLT_EPSILON*2;
+ const CvPair32s32f* sorted = data->get_ord_var_data(node, vi);
+ const float* responses = data->get_ord_responses(node);
+ int n = node->sample_count;
+ int n1 = node->get_num_valid(vi);
+ int i, best_i = -1;
+ double best_val = 0, lsum = 0, rsum = node->value*n;
+ int L = 0, R = n1;
+
+ // compensate for missing values
+ for( i = n1; i < n; i++ )
+ rsum -= responses[sorted[i].i];
+
+ // find the optimal split
+ for( i = 0; i < n1 - 1; i++ )
+ {
+ float t = responses[sorted[i].i];
+ L++; R--;
+ lsum += t;
+ rsum -= t;
+
+ if( sorted[i].val + epsilon < sorted[i+1].val )
+ {
+ double val = (lsum*lsum*R + rsum*rsum*L)/((double)L*R);
+ if( best_val < val )
+ {
+ best_val = val;
+ best_i = i;
+ }
+ }
+ }
+
+ return best_i >= 0 ? data->new_split_ord( vi,
+ (sorted[best_i].val + sorted[best_i+1].val)*0.5f, best_i,
+ 0, (float)best_val ) : 0;
+}
+
+
+CvDTreeSplit* CvDTree::find_split_cat_reg( CvDTreeNode* node, int vi )
+{
+ CvDTreeSplit* split;
+ const int* labels = data->get_cat_var_data(node, vi);
+ const float* responses = data->get_ord_responses(node);
+ int ci = data->get_var_type(vi);
+ int n = node->sample_count;
+ int mi = data->cat_count->data.i[ci];
+ double* sum = (double*)cvStackAlloc( (mi+1)*sizeof(sum[0]) ) + 1;
+ int* counts = (int*)cvStackAlloc( (mi+1)*sizeof(counts[0]) ) + 1;
+ double** sum_ptr = 0;
+ int i, L = 0, R = 0;
+ double best_val = 0, lsum = 0, rsum = 0;
+ int best_subset = -1, subset_i;
+
+ for( i = -1; i < mi; i++ )
+ sum[i] = counts[i] = 0;
+
+ // calculate sum response and weight of each category of the input var
+ for( i = 0; i < n; i++ )
+ {
+ int idx = labels[i];
+ double s = sum[idx] + responses[i];
+ int nc = counts[idx] + 1;
+ sum[idx] = s;
+ counts[idx] = nc;
+ }
+
+ // calculate average response in each category
+ for( i = 0; i < mi; i++ )
+ {
+ R += counts[i];
+ rsum += sum[i];
+ sum[i] /= MAX(counts[i],1);
+ sum_ptr[i] = sum + i;
+ }
+
+ icvSortDblPtr( sum_ptr, mi, 0 );
+
+ // revert back to unnormalized sums
+ // (there should be a very little loss of accuracy)
+ for( i = 0; i < mi; i++ )
+ sum[i] *= counts[i];
+
+ for( subset_i = 0; subset_i < mi-1; subset_i++ )
+ {
+ int idx = (int)(sum_ptr[subset_i] - sum);
+ int ni = counts[idx];
+
+ if( ni )
+ {
+ double s = sum[idx];
+ lsum += s; L += ni;
+ rsum -= s; R -= ni;
+
+ if( L && R )
+ {
+ double val = (lsum*lsum*R + rsum*rsum*L)/((double)L*R);
+ if( best_val < val )
+ {
+ best_val = val;
+ best_subset = subset_i;
+ }
+ }
+ }
+ }
+
+ if( best_subset < 0 )
+ return 0;
+
+ split = data->new_split_cat( vi, (float)best_val );
+ for( i = 0; i <= best_subset; i++ )
+ {
+ int idx = (int)(sum_ptr[i] - sum);
+ split->subset[idx >> 5] |= 1 << (idx & 31);
+ }
+
+ return split;
+}
+
+
+CvDTreeSplit* CvDTree::find_surrogate_split_ord( CvDTreeNode* node, int vi )
+{
+ const float epsilon = FLT_EPSILON*2;
+ const CvPair32s32f* sorted = data->get_ord_var_data(node, vi);
+ const char* dir = (char*)data->direction->data.ptr;
+ int n1 = node->get_num_valid(vi);
+ // LL - number of samples that both the primary and the surrogate splits send to the left
+ // LR - ... primary split sends to the left and the surrogate split sends to the right
+ // RL - ... primary split sends to the right and the surrogate split sends to the left
+ // RR - ... both send to the right
+ int i, best_i = -1, best_inversed = 0;
+ double best_val;
+
+ if( !data->have_priors )
+ {
+ int LL = 0, RL = 0, LR, RR;
+ int worst_val = cvFloor(node->maxlr), _best_val = worst_val;
+ int sum = 0, sum_abs = 0;
+
+ for( i = 0; i < n1; i++ )
+ {
+ int d = dir[sorted[i].i];
+ sum += d; sum_abs += d & 1;
+ }
+
+ // sum_abs = R + L; sum = R - L
+ RR = (sum_abs + sum) >> 1;
+ LR = (sum_abs - sum) >> 1;
+
+ // initially all the samples are sent to the right by the surrogate split,
+ // LR of them are sent to the left by primary split, and RR - to the right.
+ // now iteratively compute LL, LR, RL and RR for every possible surrogate split value.
+ for( i = 0; i < n1 - 1; i++ )
+ {
+ int d = dir[sorted[i].i];
+
+ if( d < 0 )
+ {
+ LL++; LR--;
+ if( LL + RR > _best_val && sorted[i].val + epsilon < sorted[i+1].val )
+ {
+ best_val = LL + RR;
+ best_i = i; best_inversed = 0;
+ }
+ }
+ else if( d > 0 )
+ {
+ RL++; RR--;
+ if( RL + LR > _best_val && sorted[i].val + epsilon < sorted[i+1].val )
+ {
+ best_val = RL + LR;
+ best_i = i; best_inversed = 1;
+ }
+ }
+ }
+ best_val = _best_val;
+ }
+ else
+ {
+ double LL = 0, RL = 0, LR, RR;
+ double worst_val = node->maxlr;
+ double sum = 0, sum_abs = 0;
+ const double* priors = data->priors_mult->data.db;
+ const int* responses = data->get_class_labels(node);
+ best_val = worst_val;
+
+ for( i = 0; i < n1; i++ )
+ {
+ int idx = sorted[i].i;
+ double w = priors[responses[idx]];
+ int d = dir[idx];
+ sum += d*w; sum_abs += (d & 1)*w;
+ }
+
+ // sum_abs = R + L; sum = R - L
+ RR = (sum_abs + sum)*0.5;
+ LR = (sum_abs - sum)*0.5;
+
+ // initially all the samples are sent to the right by the surrogate split,
+ // LR of them are sent to the left by primary split, and RR - to the right.
+ // now iteratively compute LL, LR, RL and RR for every possible surrogate split value.
+ for( i = 0; i < n1 - 1; i++ )
+ {
+ int idx = sorted[i].i;
+ double w = priors[responses[idx]];
+ int d = dir[idx];
+
+ if( d < 0 )
+ {
+ LL += w; LR -= w;
+ if( LL + RR > best_val && sorted[i].val + epsilon < sorted[i+1].val )
+ {
+ best_val = LL + RR;
+ best_i = i; best_inversed = 0;
+ }
+ }
+ else if( d > 0 )
+ {
+ RL += w; RR -= w;
+ if( RL + LR > best_val && sorted[i].val + epsilon < sorted[i+1].val )
+ {
+ best_val = RL + LR;
+ best_i = i; best_inversed = 1;
+ }
+ }
+ }
+ }
+
+ return best_i >= 0 && best_val > node->maxlr ? data->new_split_ord( vi,
+ (sorted[best_i].val + sorted[best_i+1].val)*0.5f, best_i,
+ best_inversed, (float)best_val ) : 0;
+}
+
+
+CvDTreeSplit* CvDTree::find_surrogate_split_cat( CvDTreeNode* node, int vi )
+{
+ const int* labels = data->get_cat_var_data(node, vi);
+ const char* dir = (char*)data->direction->data.ptr;
+ int n = node->sample_count;
+ // LL - number of samples that both the primary and the surrogate splits send to the left
+ // LR - ... primary split sends to the left and the surrogate split sends to the right
+ // RL - ... primary split sends to the right and the surrogate split sends to the left
+ // RR - ... both send to the right
+ CvDTreeSplit* split = data->new_split_cat( vi, 0 );
+ int i, mi = data->cat_count->data.i[data->get_var_type(vi)], l_win = 0;
+ double best_val = 0;
+ double* lc = (double*)cvStackAlloc( (mi+1)*2*sizeof(lc[0]) ) + 1;
+ double* rc = lc + mi + 1;
+
+ for( i = -1; i < mi; i++ )
+ lc[i] = rc[i] = 0;
+
+ // for each category calculate the weight of samples
+ // sent to the left (lc) and to the right (rc) by the primary split
+ if( !data->have_priors )
+ {
+ int* _lc = (int*)cvStackAlloc((mi+2)*2*sizeof(_lc[0])) + 1;
+ int* _rc = _lc + mi + 1;
+
+ for( i = -1; i < mi; i++ )
+ _lc[i] = _rc[i] = 0;
+
+ for( i = 0; i < n; i++ )
+ {
+ int idx = labels[i];
+ int d = dir[i];
+ int sum = _lc[idx] + d;
+ int sum_abs = _rc[idx] + (d & 1);
+ _lc[idx] = sum; _rc[idx] = sum_abs;
+ }
+
+ for( i = 0; i < mi; i++ )
+ {
+ int sum = _lc[i];
+ int sum_abs = _rc[i];
+ lc[i] = (sum_abs - sum) >> 1;
+ rc[i] = (sum_abs + sum) >> 1;
+ }
+ }
+ else
+ {
+ const double* priors = data->priors_mult->data.db;
+ const int* responses = data->get_class_labels(node);
+
+ for( i = 0; i < n; i++ )
+ {
+ int idx = labels[i];
+ double w = priors[responses[i]];
+ int d = dir[i];
+ double sum = lc[idx] + d*w;
+ double sum_abs = rc[idx] + (d & 1)*w;
+ lc[idx] = sum; rc[idx] = sum_abs;
+ }
+
+ for( i = 0; i < mi; i++ )
+ {
+ double sum = lc[i];
+ double sum_abs = rc[i];
+ lc[i] = (sum_abs - sum) * 0.5;
+ rc[i] = (sum_abs + sum) * 0.5;
+ }
+ }
+
+ // 2. now form the split.
+ // in each category send all the samples to the same direction as majority
+ for( i = 0; i < mi; i++ )
+ {
+ double lval = lc[i], rval = rc[i];
+ if( lval > rval )
+ {
+ split->subset[i >> 5] |= 1 << (i & 31);
+ best_val += lval;
+ l_win++;
+ }
+ else
+ best_val += rval;
+ }
+
+ split->quality = (float)best_val;
+ if( split->quality <= node->maxlr || l_win == 0 || l_win == mi )
+ cvSetRemoveByPtr( data->split_heap, split ), split = 0;
+
+ return split;
+}
+
+
+void CvDTree::calc_node_value( CvDTreeNode* node )
+{
+ int i, j, k, n = node->sample_count, cv_n = data->params.cv_folds;
+ const int* cv_labels = data->get_labels(node);
+
+ if( data->is_classifier )
+ {
+ // in case of classification tree:
+ // * node value is the label of the class that has the largest weight in the node.
+ // * node risk is the weighted number of misclassified samples,
+ // * j-th cross-validation fold value and risk are calculated as above,
+ // but using the samples with cv_labels(*)!=j.
+ // * j-th cross-validation fold error is calculated as the weighted number of
+ // misclassified samples with cv_labels(*)==j.
+
+ // compute the number of instances of each class
+ int* cls_count = data->counts->data.i;
+ const int* responses = data->get_class_labels(node);
+ int m = data->get_num_classes();
+ int* cv_cls_count = (int*)cvStackAlloc(m*cv_n*sizeof(cv_cls_count[0]));
+ double max_val = -1, total_weight = 0;
+ int max_k = -1;
+ double* priors = data->priors_mult->data.db;
+
+ for( k = 0; k < m; k++ )
+ cls_count[k] = 0;
+
+ if( cv_n == 0 )
+ {
+ for( i = 0; i < n; i++ )
+ cls_count[responses[i]]++;
+ }
+ else
+ {
+ for( j = 0; j < cv_n; j++ )
+ for( k = 0; k < m; k++ )
+ cv_cls_count[j*m + k] = 0;
+
+ for( i = 0; i < n; i++ )
+ {
+ j = cv_labels[i]; k = responses[i];
+ cv_cls_count[j*m + k]++;
+ }
+
+ for( j = 0; j < cv_n; j++ )
+ for( k = 0; k < m; k++ )
+ cls_count[k] += cv_cls_count[j*m + k];
+ }
+
+ if( data->have_priors && node->parent == 0 )
+ {
+ // compute priors_mult from priors, take the sample ratio into account.
+ double sum = 0;
+ for( k = 0; k < m; k++ )
+ {
+ int n_k = cls_count[k];
+ priors[k] = data->priors->data.db[k]*(n_k ? 1./n_k : 0.);
+ sum += priors[k];
+ }
+ sum = 1./sum;
+ for( k = 0; k < m; k++ )
+ priors[k] *= sum;
+ }
+
+ for( k = 0; k < m; k++ )
+ {
+ double val = cls_count[k]*priors[k];
+ total_weight += val;
+ if( max_val < val )
+ {
+ max_val = val;
+ max_k = k;
+ }
+ }
+
+ node->class_idx = max_k;
+ node->value = data->cat_map->data.i[
+ data->cat_ofs->data.i[data->cat_var_count] + max_k];
+ node->node_risk = total_weight - max_val;
+
+ for( j = 0; j < cv_n; j++ )
+ {
+ double sum_k = 0, sum = 0, max_val_k = 0;
+ max_val = -1; max_k = -1;
+
+ for( k = 0; k < m; k++ )
+ {
+ double w = priors[k];
+ double val_k = cv_cls_count[j*m + k]*w;
+ double val = cls_count[k]*w - val_k;
+ sum_k += val_k;
+ sum += val;
+ if( max_val < val )
+ {
+ max_val = val;
+ max_val_k = val_k;
+ max_k = k;
+ }
+ }
+
+ node->cv_Tn[j] = INT_MAX;
+ node->cv_node_risk[j] = sum - max_val;
+ node->cv_node_error[j] = sum_k - max_val_k;
+ }
+ }
+ else
+ {
+ // in case of regression tree:
+ // * node value is 1/n*sum_i(Y_i), where Y_i is i-th response,
+ // n is the number of samples in the node.
+ // * node risk is the sum of squared errors: sum_i((Y_i - <node_value>)^2)
+ // * j-th cross-validation fold value and risk are calculated as above,
+ // but using the samples with cv_labels(*)!=j.
+ // * j-th cross-validation fold error is calculated
+ // using samples with cv_labels(*)==j as the test subset:
+ // error_j = sum_(i,cv_labels(i)==j)((Y_i - <node_value_j>)^2),
+ // where node_value_j is the node value calculated
+ // as described in the previous bullet, and summation is done
+ // over the samples with cv_labels(*)==j.
+
+ double sum = 0, sum2 = 0;
+ const float* values = data->get_ord_responses(node);
+ double *cv_sum = 0, *cv_sum2 = 0;
+ int* cv_count = 0;
+
+ if( cv_n == 0 )
+ {
+ for( i = 0; i < n; i++ )
+ {
+ double t = values[i];
+ sum += t;
+ sum2 += t*t;
+ }
+ }
+ else
+ {
+ cv_sum = (double*)cvStackAlloc( cv_n*sizeof(cv_sum[0]) );
+ cv_sum2 = (double*)cvStackAlloc( cv_n*sizeof(cv_sum2[0]) );
+ cv_count = (int*)cvStackAlloc( cv_n*sizeof(cv_count[0]) );
+
+ for( j = 0; j < cv_n; j++ )
+ {
+ cv_sum[j] = cv_sum2[j] = 0.;
+ cv_count[j] = 0;
+ }
+
+ for( i = 0; i < n; i++ )
+ {
+ j = cv_labels[i];
+ double t = values[i];
+ double s = cv_sum[j] + t;
+ double s2 = cv_sum2[j] + t*t;
+ int nc = cv_count[j] + 1;
+ cv_sum[j] = s;
+ cv_sum2[j] = s2;
+ cv_count[j] = nc;
+ }
+
+ for( j = 0; j < cv_n; j++ )
+ {
+ sum += cv_sum[j];
+ sum2 += cv_sum2[j];
+ }
+ }
+
+ node->node_risk = sum2 - (sum/n)*sum;
+ node->value = sum/n;
+
+ for( j = 0; j < cv_n; j++ )
+ {
+ double s = cv_sum[j], si = sum - s;
+ double s2 = cv_sum2[j], s2i = sum2 - s2;
+ int c = cv_count[j], ci = n - c;
+ double r = si/MAX(ci,1);
+ node->cv_node_risk[j] = s2i - r*r*ci;
+ node->cv_node_error[j] = s2 - 2*r*s + c*r*r;
+ node->cv_Tn[j] = INT_MAX;
+ }
+ }
+}
+
+
+void CvDTree::complete_node_dir( CvDTreeNode* node )
+{
+ int vi, i, n = node->sample_count, nl, nr, d0 = 0, d1 = -1;
+ int nz = n - node->get_num_valid(node->split->var_idx);
+ char* dir = (char*)data->direction->data.ptr;
+
+ // try to complete direction using surrogate splits
+ if( nz && data->params.use_surrogates )
+ {
+ CvDTreeSplit* split = node->split->next;
+ for( ; split != 0 && nz; split = split->next )
+ {
+ int inversed_mask = split->inversed ? -1 : 0;
+ vi = split->var_idx;
+
+ if( data->get_var_type(vi) >= 0 ) // split on categorical var
+ {
+ const int* labels = data->get_cat_var_data(node, vi);
+ const int* subset = split->subset;
+
+ for( i = 0; i < n; i++ )
+ {
+ int idx;
+ if( !dir[i] && (idx = labels[i]) >= 0 )
+ {
+ int d = CV_DTREE_CAT_DIR(idx,subset);
+ dir[i] = (char)((d ^ inversed_mask) - inversed_mask);
+ if( --nz )
+ break;
+ }
+ }
+ }
+ else // split on ordered var
+ {
+ const CvPair32s32f* sorted = data->get_ord_var_data(node, vi);
+ int split_point = split->ord.split_point;
+ int n1 = node->get_num_valid(vi);
+
+ assert( 0 <= split_point && split_point < n-1 );
+
+ for( i = 0; i < n1; i++ )
+ {
+ int idx = sorted[i].i;
+ if( !dir[idx] )
+ {
+ int d = i <= split_point ? -1 : 1;
+ dir[idx] = (char)((d ^ inversed_mask) - inversed_mask);
+ if( --nz )
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // find the default direction for the rest
+ if( nz )
+ {
+ for( i = nr = 0; i < n; i++ )
+ nr += dir[i] > 0;
+ nl = n - nr - nz;
+ d0 = nl > nr ? -1 : nr > nl;
+ }
+
+ // make sure that every sample is directed either to the left or to the right
+ for( i = 0; i < n; i++ )
+ {
+ int d = dir[i];
+ if( !d )
+ {
+ d = d0;
+ if( !d )
+ d = d1, d1 = -d1;
+ }
+ d = d > 0;
+ dir[i] = (char)d; // remap (-1,1) to (0,1)
+ }
+}
+
+
+void CvDTree::split_node_data( CvDTreeNode* node )
+{
+ int vi, i, n = node->sample_count, nl, nr;
+ char* dir = (char*)data->direction->data.ptr;
+ CvDTreeNode *left = 0, *right = 0;
+ int* new_idx = data->split_buf->data.i;
+ int new_buf_idx = data->get_child_buf_idx( node );
+ int work_var_count = data->get_work_var_count();
+
+ // speedup things a little, especially for tree ensembles with a lots of small trees:
+ // do not physically split the input data between the left and right child nodes
+ // when we are not going to split them further,
+ // as calc_node_value() does not requires input features anyway.
+ bool split_input_data;
+
+ complete_node_dir(node);
+
+ for( i = nl = nr = 0; i < n; i++ )
+ {
+ int d = dir[i];
+ // initialize new indices for splitting ordered variables
+ new_idx[i] = (nl & (d-1)) | (nr & -d); // d ? ri : li
+ nr += d;
+ nl += d^1;
+ }
+
+ node->left = left = data->new_node( node, nl, new_buf_idx, node->offset );
+ node->right = right = data->new_node( node, nr, new_buf_idx, node->offset +
+ (data->ord_var_count + work_var_count)*nl );
+
+ split_input_data = node->depth + 1 < data->params.max_depth &&
+ (node->left->sample_count > data->params.min_sample_count ||
+ node->right->sample_count > data->params.min_sample_count);
+
+ // split ordered variables, keep both halves sorted.
+ for( vi = 0; vi < data->var_count; vi++ )
+ {
+ int ci = data->get_var_type(vi);
+ int n1 = node->get_num_valid(vi);
+ CvPair32s32f *src, *ldst0, *rdst0, *ldst, *rdst;
+ CvPair32s32f tl, tr;
+
+ if( ci >= 0 || !split_input_data )
+ continue;
+
+ src = data->get_ord_var_data(node, vi);
+ ldst0 = ldst = data->get_ord_var_data(left, vi);
+ rdst0 = rdst = data->get_ord_var_data(right, vi);
+ tl = ldst0[nl]; tr = rdst0[nr];
+
+ // split sorted
+ for( i = 0; i < n1; i++ )
+ {
+ int idx = src[i].i;
+ float val = src[i].val;
+ int d = dir[idx];
+ idx = new_idx[idx];
+ ldst->i = rdst->i = idx;
+ ldst->val = rdst->val = val;
+ ldst += d^1;
+ rdst += d;
+ }
+
+ left->set_num_valid(vi, (int)(ldst - ldst0));
+ right->set_num_valid(vi, (int)(rdst - rdst0));
+
+ // split missing
+ for( ; i < n; i++ )
+ {
+ int idx = src[i].i;
+ int d = dir[idx];
+ idx = new_idx[idx];
+ ldst->i = rdst->i = idx;
+ ldst->val = rdst->val = ord_nan;
+ ldst += d^1;
+ rdst += d;
+ }
+
+ ldst0[nl] = tl; rdst0[nr] = tr;
+ }
+
+ // split categorical vars, responses and cv_labels using new_idx relocation table
+ for( vi = 0; vi < work_var_count; vi++ )
+ {
+ int ci = data->get_var_type(vi);
+ int n1 = node->get_num_valid(vi), nr1 = 0;
+ int *src, *ldst0, *rdst0, *ldst, *rdst;
+ int tl, tr;
+
+ if( ci < 0 || (vi < data->var_count && !split_input_data) )
+ continue;
+
+ src = data->get_cat_var_data(node, vi);
+ ldst0 = ldst = data->get_cat_var_data(left, vi);
+ rdst0 = rdst = data->get_cat_var_data(right, vi);
+ tl = ldst0[nl]; tr = rdst0[nr];
+
+ for( i = 0; i < n; i++ )
+ {
+ int d = dir[i];
+ int val = src[i];
+ *ldst = *rdst = val;
+ ldst += d^1;
+ rdst += d;
+ nr1 += (val >= 0)&d;
+ }
+
+ if( vi < data->var_count )
+ {
+ left->set_num_valid(vi, n1 - nr1);
+ right->set_num_valid(vi, nr1);
+ }
+
+ ldst0[nl] = tl; rdst0[nr] = tr;
+ }
+
+ // deallocate the parent node data that is not needed anymore
+ data->free_node_data(node);
+}
+
+
+void CvDTree::prune_cv()
+{
+ CvMat* ab = 0;
+ CvMat* temp = 0;
+ CvMat* err_jk = 0;
+
+ // 1. build tree sequence for each cv fold, calculate error_{Tj,beta_k}.
+ // 2. choose the best tree index (if need, apply 1SE rule).
+ // 3. store the best index and cut the branches.
+
+ CV_FUNCNAME( "CvDTree::prune_cv" );
+
+ __BEGIN__;
+
+ int ti, j, tree_count = 0, cv_n = data->params.cv_folds, n = root->sample_count;
+ // currently, 1SE for regression is not implemented
+ bool use_1se = data->params.use_1se_rule != 0 && data->is_classifier;
+ double* err;
+ double min_err = 0, min_err_se = 0;
+ int min_idx = -1;
+
+ CV_CALL( ab = cvCreateMat( 1, 256, CV_64F ));
+
+ // build the main tree sequence, calculate alpha's
+ for(;;tree_count++)
+ {
+ double min_alpha = update_tree_rnc(tree_count, -1);
+ if( cut_tree(tree_count, -1, min_alpha) )
+ break;
+
+ if( ab->cols <= tree_count )
+ {
+ CV_CALL( temp = cvCreateMat( 1, ab->cols*3/2, CV_64F ));
+ for( ti = 0; ti < ab->cols; ti++ )
+ temp->data.db[ti] = ab->data.db[ti];
+ cvReleaseMat( &ab );
+ ab = temp;
+ temp = 0;
+ }
+
+ ab->data.db[tree_count] = min_alpha;
+ }
+
+ ab->data.db[0] = 0.;
+
+ if( tree_count > 0 )
+ {
+ for( ti = 1; ti < tree_count-1; ti++ )
+ ab->data.db[ti] = sqrt(ab->data.db[ti]*ab->data.db[ti+1]);
+ ab->data.db[tree_count-1] = DBL_MAX*0.5;
+
+ CV_CALL( err_jk = cvCreateMat( cv_n, tree_count, CV_64F ));
+ err = err_jk->data.db;
+
+ for( j = 0; j < cv_n; j++ )
+ {
+ int tj = 0, tk = 0;
+ for( ; tk < tree_count; tj++ )
+ {
+ double min_alpha = update_tree_rnc(tj, j);
+ if( cut_tree(tj, j, min_alpha) )
+ min_alpha = DBL_MAX;
+
+ for( ; tk < tree_count; tk++ )
+ {
+ if( ab->data.db[tk] > min_alpha )
+ break;
+ err[j*tree_count + tk] = root->tree_error;
+ }
+ }
+ }
+
+ for( ti = 0; ti < tree_count; ti++ )
+ {
+ double sum_err = 0;
+ for( j = 0; j < cv_n; j++ )
+ sum_err += err[j*tree_count + ti];
+ if( ti == 0 || sum_err < min_err )
+ {
+ min_err = sum_err;
+ min_idx = ti;
+ if( use_1se )
+ min_err_se = sqrt( sum_err*(n - sum_err) );
+ }
+ else if( sum_err < min_err + min_err_se )
+ min_idx = ti;
+ }
+ }
+
+ pruned_tree_idx = min_idx;
+ free_prune_data(data->params.truncate_pruned_tree != 0);
+
+ __END__;
+
+ cvReleaseMat( &err_jk );
+ cvReleaseMat( &ab );
+ cvReleaseMat( &temp );
+}
+
+
+double CvDTree::update_tree_rnc( int T, int fold )
+{
+ CvDTreeNode* node = root;
+ double min_alpha = DBL_MAX;
+
+ for(;;)
+ {
+ CvDTreeNode* parent;
+ for(;;)
+ {
+ int t = fold >= 0 ? node->cv_Tn[fold] : node->Tn;
+ if( t <= T || !node->left )
+ {
+ node->complexity = 1;
+ node->tree_risk = node->node_risk;
+ node->tree_error = 0.;
+ if( fold >= 0 )
+ {
+ node->tree_risk = node->cv_node_risk[fold];
+ node->tree_error = node->cv_node_error[fold];
+ }
+ break;
+ }
+ node = node->left;
+ }
+
+ for( parent = node->parent; parent && parent->right == node;
+ node = parent, parent = parent->parent )
+ {
+ parent->complexity += node->complexity;
+ parent->tree_risk += node->tree_risk;
+ parent->tree_error += node->tree_error;
+
+ parent->alpha = ((fold >= 0 ? parent->cv_node_risk[fold] : parent->node_risk)
+ - parent->tree_risk)/(parent->complexity - 1);
+ min_alpha = MIN( min_alpha, parent->alpha );
+ }
+
+ if( !parent )
+ break;
+
+ parent->complexity = node->complexity;
+ parent->tree_risk = node->tree_risk;
+ parent->tree_error = node->tree_error;
+ node = parent->right;
+ }
+
+ return min_alpha;
+}
+
+
+int CvDTree::cut_tree( int T, int fold, double min_alpha )
+{
+ CvDTreeNode* node = root;
+ if( !node->left )
+ return 1;
+
+ for(;;)
+ {
+ CvDTreeNode* parent;
+ for(;;)
+ {
+ int t = fold >= 0 ? node->cv_Tn[fold] : node->Tn;
+ if( t <= T || !node->left )
+ break;
+ if( node->alpha <= min_alpha + FLT_EPSILON )
+ {
+ if( fold >= 0 )
+ node->cv_Tn[fold] = T;
+ else
+ node->Tn = T;
+ if( node == root )
+ return 1;
+ break;
+ }
+ node = node->left;
+ }
+
+ for( parent = node->parent; parent && parent->right == node;
+ node = parent, parent = parent->parent )
+ ;
+
+ if( !parent )
+ break;
+
+ node = parent->right;
+ }
+
+ return 0;
+}
+
+
+void CvDTree::free_prune_data(bool cut_tree)
+{
+ CvDTreeNode* node = root;
+
+ for(;;)
+ {
+ CvDTreeNode* parent;
+ for(;;)
+ {
+ // do not call cvSetRemoveByPtr( cv_heap, node->cv_Tn )
+ // as we will clear the whole cross-validation heap at the end
+ node->cv_Tn = 0;
+ node->cv_node_error = node->cv_node_risk = 0;
+ if( !node->left )
+ break;
+ node = node->left;
+ }
+
+ for( parent = node->parent; parent && parent->right == node;
+ node = parent, parent = parent->parent )
+ {
+ if( cut_tree && parent->Tn <= pruned_tree_idx )
+ {
+ data->free_node( parent->left );
+ data->free_node( parent->right );
+ parent->left = parent->right = 0;
+ }
+ }
+
+ if( !parent )
+ break;
+
+ node = parent->right;
+ }
+
+ if( data->cv_heap )
+ cvClearSet( data->cv_heap );
+}
+
+
+void CvDTree::free_tree()
+{
+ if( root && data && data->shared )
+ {
+ pruned_tree_idx = INT_MIN;
+ free_prune_data(true);
+ data->free_node(root);
+ root = 0;
+ }
+}
+
+
+CvDTreeNode* CvDTree::predict( const CvMat* _sample,
+ const CvMat* _missing, bool preprocessed_input ) const
+{
+ CvDTreeNode* result = 0;
+ int* catbuf = 0;
+
+ CV_FUNCNAME( "CvDTree::predict" );
+
+ __BEGIN__;
+
+ int i, step, mstep = 0;
+ const float* sample;
+ const uchar* m = 0;
+ CvDTreeNode* node = root;
+ const int* vtype;
+ const int* vidx;
+ const int* cmap;
+ const int* cofs;
+
+ if( !node )
+ CV_ERROR( CV_StsError, "The tree has not been trained yet" );
+
+ if( !CV_IS_MAT(_sample) || CV_MAT_TYPE(_sample->type) != CV_32FC1 ||
+ _sample->cols != 1 && _sample->rows != 1 ||
+ _sample->cols + _sample->rows - 1 != data->var_all && !preprocessed_input ||
+ _sample->cols + _sample->rows - 1 != data->var_count && preprocessed_input )
+ CV_ERROR( CV_StsBadArg,
+ "the input sample must be 1d floating-point vector with the same "
+ "number of elements as the total number of variables used for training" );
+
+ sample = _sample->data.fl;
+ step = CV_IS_MAT_CONT(_sample->type) ? 1 : _sample->step/sizeof(sample[0]);
+
+ if( data->cat_count && !preprocessed_input ) // cache for categorical variables
+ {
+ int n = data->cat_count->cols;
+ catbuf = (int*)cvStackAlloc(n*sizeof(catbuf[0]));
+ for( i = 0; i < n; i++ )
+ catbuf[i] = -1;
+ }
+
+ if( _missing )
+ {
+ if( !CV_IS_MAT(_missing) || !CV_IS_MASK_ARR(_missing) ||
+ !CV_ARE_SIZES_EQ(_missing, _sample) )
+ CV_ERROR( CV_StsBadArg,
+ "the missing data mask must be 8-bit vector of the same size as input sample" );
+ m = _missing->data.ptr;
+ mstep = CV_IS_MAT_CONT(_missing->type) ? 1 : _missing->step/sizeof(m[0]);
+ }
+
+ vtype = data->var_type->data.i;
+ vidx = data->var_idx && !preprocessed_input ? data->var_idx->data.i : 0;
+ cmap = data->cat_map ? data->cat_map->data.i : 0;
+ cofs = data->cat_ofs ? data->cat_ofs->data.i : 0;
+
+ while( node->Tn > pruned_tree_idx && node->left )
+ {
+ CvDTreeSplit* split = node->split;
+ int dir = 0;
+ for( ; !dir && split != 0; split = split->next )
+ {
+ int vi = split->var_idx;
+ int ci = vtype[vi];
+ i = vidx ? vidx[vi] : vi;
+ float val = sample[i*step];
+ if( m && m[i*mstep] )
+ continue;
+ if( ci < 0 ) // ordered
+ dir = val <= split->ord.c ? -1 : 1;
+ else // categorical
+ {
+ int c;
+ if( preprocessed_input )
+ c = cvRound(val);
+ else
+ {
+ c = catbuf[ci];
+ if( c < 0 )
+ {
+ int a = c = cofs[ci];
+ int b = cofs[ci+1];
+ int ival = cvRound(val);
+ if( ival != val )
+ CV_ERROR( CV_StsBadArg,
+ "one of input categorical variable is not an integer" );
+
+ while( a < b )
+ {
+ c = (a + b) >> 1;
+ if( ival < cmap[c] )
+ b = c;
+ else if( ival > cmap[c] )
+ a = c+1;
+ else
+ break;
+ }
+
+ if( c < 0 || ival != cmap[c] )
+ continue;
+
+ catbuf[ci] = c -= cofs[ci];
+ }
+ }
+ dir = CV_DTREE_CAT_DIR(c, split->subset);
+ }
+
+ if( split->inversed )
+ dir = -dir;
+ }
+
+ if( !dir )
+ {
+ double diff = node->right->sample_count - node->left->sample_count;
+ dir = diff < 0 ? -1 : 1;
+ }
+ node = dir < 0 ? node->left : node->right;
+ }
+
+ result = node;
+
+ __END__;
+
+ return result;
+}
+
+
+const CvMat* CvDTree::get_var_importance()
+{
+ if( !var_importance )
+ {
+ CvDTreeNode* node = root;
+ double* importance;
+ if( !node )
+ return 0;
+ var_importance = cvCreateMat( 1, data->var_count, CV_64F );
+ cvZero( var_importance );
+ importance = var_importance->data.db;
+
+ for(;;)
+ {
+ CvDTreeNode* parent;
+ for( ;; node = node->left )
+ {
+ CvDTreeSplit* split = node->split;
+
+ if( !node->left || node->Tn <= pruned_tree_idx )
+ break;
+
+ for( ; split != 0; split = split->next )
+ importance[split->var_idx] += split->quality;
+ }
+
+ for( parent = node->parent; parent && parent->right == node;
+ node = parent, parent = parent->parent )
+ ;
+
+ if( !parent )
+ break;
+
+ node = parent->right;
+ }
+
+ cvNormalize( var_importance, var_importance, 1., 0, CV_L1 );
+ }
+
+ return var_importance;
+}
+
+
+void CvDTree::write_split( CvFileStorage* fs, CvDTreeSplit* split )
+{
+ int ci;
+
+ cvStartWriteStruct( fs, 0, CV_NODE_MAP + CV_NODE_FLOW );
+ cvWriteInt( fs, "var", split->var_idx );
+ cvWriteReal( fs, "quality", split->quality );
+
+ ci = data->get_var_type(split->var_idx);
+ if( ci >= 0 ) // split on a categorical var
+ {
+ int i, n = data->cat_count->data.i[ci], to_right = 0, default_dir;
+ for( i = 0; i < n; i++ )
+ to_right += CV_DTREE_CAT_DIR(i,split->subset) > 0;
+
+ // ad-hoc rule when to use inverse categorical split notation
+ // to achieve more compact and clear representation
+ default_dir = to_right <= 1 || to_right <= MIN(3, n/2) || to_right <= n/3 ? -1 : 1;
+
+ cvStartWriteStruct( fs, default_dir*(split->inversed ? -1 : 1) > 0 ?
+ "in" : "not_in", CV_NODE_SEQ+CV_NODE_FLOW );
+
+ for( i = 0; i < n; i++ )
+ {
+ int dir = CV_DTREE_CAT_DIR(i,split->subset);
+ if( dir*default_dir < 0 )
+ cvWriteInt( fs, 0, i );
+ }
+ cvEndWriteStruct( fs );
+ }
+ else
+ cvWriteReal( fs, !split->inversed ? "le" : "gt", split->ord.c );
+
+ cvEndWriteStruct( fs );
+}
+
+
+void CvDTree::write_node( CvFileStorage* fs, CvDTreeNode* node )
+{
+ CvDTreeSplit* split;
+
+ cvStartWriteStruct( fs, 0, CV_NODE_MAP );
+
+ cvWriteInt( fs, "depth", node->depth );
+ cvWriteInt( fs, "sample_count", node->sample_count );
+ cvWriteReal( fs, "value", node->value );
+
+ if( data->is_classifier )
+ cvWriteInt( fs, "norm_class_idx", node->class_idx );
+
+ cvWriteInt( fs, "Tn", node->Tn );
+ cvWriteInt( fs, "complexity", node->complexity );
+ cvWriteReal( fs, "alpha", node->alpha );
+ cvWriteReal( fs, "node_risk", node->node_risk );
+ cvWriteReal( fs, "tree_risk", node->tree_risk );
+ cvWriteReal( fs, "tree_error", node->tree_error );
+
+ if( node->left )
+ {
+ cvStartWriteStruct( fs, "splits", CV_NODE_SEQ );
+
+ for( split = node->split; split != 0; split = split->next )
+ write_split( fs, split );
+
+ cvEndWriteStruct( fs );
+ }
+
+ cvEndWriteStruct( fs );
+}
+
+
+void CvDTree::write_tree_nodes( CvFileStorage* fs )
+{
+ //CV_FUNCNAME( "CvDTree::write_tree_nodes" );
+
+ __BEGIN__;
+
+ CvDTreeNode* node = root;
+
+ // traverse the tree and save all the nodes in depth-first order
+ for(;;)
+ {
+ CvDTreeNode* parent;
+ for(;;)
+ {
+ write_node( fs, node );
+ if( !node->left )
+ break;
+ node = node->left;
+ }
+
+ for( parent = node->parent; parent && parent->right == node;
+ node = parent, parent = parent->parent )
+ ;
+
+ if( !parent )
+ break;
+
+ node = parent->right;
+ }
+
+ __END__;
+}
+
+
+void CvDTree::write( CvFileStorage* fs, const char* name )
+{
+ //CV_FUNCNAME( "CvDTree::write" );
+
+ __BEGIN__;
+
+ cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_ML_TREE );
+
+ get_var_importance();
+ data->write_params( fs );
+ if( var_importance )
+ cvWrite( fs, "var_importance", var_importance );
+ write( fs );
+
+ cvEndWriteStruct( fs );
+
+ __END__;
+}
+
+
+void CvDTree::write( CvFileStorage* fs )
+{
+ //CV_FUNCNAME( "CvDTree::write" );
+
+ __BEGIN__;
+
+ cvWriteInt( fs, "best_tree_idx", pruned_tree_idx );
+
+ cvStartWriteStruct( fs, "nodes", CV_NODE_SEQ );
+ write_tree_nodes( fs );
+ cvEndWriteStruct( fs );
+
+ __END__;
+}
+
+
+CvDTreeSplit* CvDTree::read_split( CvFileStorage* fs, CvFileNode* fnode )
+{
+ CvDTreeSplit* split = 0;
+
+ CV_FUNCNAME( "CvDTree::read_split" );
+
+ __BEGIN__;
+
+ int vi, ci;
+
+ if( !fnode || CV_NODE_TYPE(fnode->tag) != CV_NODE_MAP )
+ CV_ERROR( CV_StsParseError, "some of the splits are not stored properly" );
+
+ vi = cvReadIntByName( fs, fnode, "var", -1 );
+ if( (unsigned)vi >= (unsigned)data->var_count )
+ CV_ERROR( CV_StsOutOfRange, "Split variable index is out of range" );
+
+ ci = data->get_var_type(vi);
+ if( ci >= 0 ) // split on categorical var
+ {
+ int i, n = data->cat_count->data.i[ci], inversed = 0, val;
+ CvSeqReader reader;
+ CvFileNode* inseq;
+ split = data->new_split_cat( vi, 0 );
+ inseq = cvGetFileNodeByName( fs, fnode, "in" );
+ if( !inseq )
+ {
+ inseq = cvGetFileNodeByName( fs, fnode, "not_in" );
+ inversed = 1;
+ }
+ if( !inseq ||
+ (CV_NODE_TYPE(inseq->tag) != CV_NODE_SEQ && CV_NODE_TYPE(inseq->tag) != CV_NODE_INT))
+ CV_ERROR( CV_StsParseError,
+ "Either 'in' or 'not_in' tags should be inside a categorical split data" );
+
+ if( CV_NODE_TYPE(inseq->tag) == CV_NODE_INT )
+ {
+ val = inseq->data.i;
+ if( (unsigned)val >= (unsigned)n )
+ CV_ERROR( CV_StsOutOfRange, "some of in/not_in elements are out of range" );
+
+ split->subset[val >> 5] |= 1 << (val & 31);
+ }
+ else
+ {
+ cvStartReadSeq( inseq->data.seq, &reader );
+
+ for( i = 0; i < reader.seq->total; i++ )
+ {
+ CvFileNode* inode = (CvFileNode*)reader.ptr;
+ val = inode->data.i;
+ if( CV_NODE_TYPE(inode->tag) != CV_NODE_INT || (unsigned)val >= (unsigned)n )
+ CV_ERROR( CV_StsOutOfRange, "some of in/not_in elements are out of range" );
+
+ split->subset[val >> 5] |= 1 << (val & 31);
+ CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
+ }
+ }
+
+ // for categorical splits we do not use inversed splits,
+ // instead we inverse the variable set in the split
+ if( inversed )
+ for( i = 0; i < (n + 31) >> 5; i++ )
+ split->subset[i] ^= -1;
+ }
+ else
+ {
+ CvFileNode* cmp_node;
+ split = data->new_split_ord( vi, 0, 0, 0, 0 );
+
+ cmp_node = cvGetFileNodeByName( fs, fnode, "le" );
+ if( !cmp_node )
+ {
+ cmp_node = cvGetFileNodeByName( fs, fnode, "gt" );
+ split->inversed = 1;
+ }
+
+ split->ord.c = (float)cvReadReal( cmp_node );
+ }
+
+ split->quality = (float)cvReadRealByName( fs, fnode, "quality" );
+
+ __END__;
+
+ return split;
+}
+
+
+CvDTreeNode* CvDTree::read_node( CvFileStorage* fs, CvFileNode* fnode, CvDTreeNode* parent )
+{
+ CvDTreeNode* node = 0;
+
+ CV_FUNCNAME( "CvDTree::read_node" );
+
+ __BEGIN__;
+
+ CvFileNode* splits;
+ int i, depth;
+
+ if( !fnode || CV_NODE_TYPE(fnode->tag) != CV_NODE_MAP )
+ CV_ERROR( CV_StsParseError, "some of the tree elements are not stored properly" );
+
+ CV_CALL( node = data->new_node( parent, 0, 0, 0 ));
+ depth = cvReadIntByName( fs, fnode, "depth", -1 );
+ if( depth != node->depth )
+ CV_ERROR( CV_StsParseError, "incorrect node depth" );
+
+ node->sample_count = cvReadIntByName( fs, fnode, "sample_count" );
+ node->value = cvReadRealByName( fs, fnode, "value" );
+ if( data->is_classifier )
+ node->class_idx = cvReadIntByName( fs, fnode, "norm_class_idx" );
+
+ node->Tn = cvReadIntByName( fs, fnode, "Tn" );
+ node->complexity = cvReadIntByName( fs, fnode, "complexity" );
+ node->alpha = cvReadRealByName( fs, fnode, "alpha" );
+ node->node_risk = cvReadRealByName( fs, fnode, "node_risk" );
+ node->tree_risk = cvReadRealByName( fs, fnode, "tree_risk" );
+ node->tree_error = cvReadRealByName( fs, fnode, "tree_error" );
+
+ splits = cvGetFileNodeByName( fs, fnode, "splits" );
+ if( splits )
+ {
+ CvSeqReader reader;
+ CvDTreeSplit* last_split = 0;
+
+ if( CV_NODE_TYPE(splits->tag) != CV_NODE_SEQ )
+ CV_ERROR( CV_StsParseError, "splits tag must stored as a sequence" );
+
+ cvStartReadSeq( splits->data.seq, &reader );
+ for( i = 0; i < reader.seq->total; i++ )
+ {
+ CvDTreeSplit* split;
+ CV_CALL( split = read_split( fs, (CvFileNode*)reader.ptr ));
+ if( !last_split )
+ node->split = last_split = split;
+ else
+ last_split = last_split->next = split;
+
+ CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
+ }
+ }
+
+ __END__;
+
+ return node;
+}
+
+
+void CvDTree::read_tree_nodes( CvFileStorage* fs, CvFileNode* fnode )
+{
+ CV_FUNCNAME( "CvDTree::read_tree_nodes" );
+
+ __BEGIN__;
+
+ CvSeqReader reader;
+ CvDTreeNode _root;
+ CvDTreeNode* parent = &_root;
+ int i;
+ parent->left = parent->right = parent->parent = 0;
+
+ cvStartReadSeq( fnode->data.seq, &reader );
+
+ for( i = 0; i < reader.seq->total; i++ )
+ {
+ CvDTreeNode* node;
+
+ CV_CALL( node = read_node( fs, (CvFileNode*)reader.ptr, parent != &_root ? parent : 0 ));
+ if( !parent->left )
+ parent->left = node;
+ else
+ parent->right = node;
+ if( node->split )
+ parent = node;
+ else
+ {
+ while( parent && parent->right )
+ parent = parent->parent;
+ }
+
+ CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
+ }
+
+ root = _root.left;
+
+ __END__;
+}
+
+
+void CvDTree::read( CvFileStorage* fs, CvFileNode* fnode )
+{
+ CvDTreeTrainData* _data = new CvDTreeTrainData();
+ _data->read_params( fs, fnode );
+
+ read( fs, fnode, _data );
+ get_var_importance();
+}
+
+
+// a special entry point for reading weak decision trees from the tree ensembles
+void CvDTree::read( CvFileStorage* fs, CvFileNode* node, CvDTreeTrainData* _data )
+{
+ CV_FUNCNAME( "CvDTree::read" );
+
+ __BEGIN__;
+
+ CvFileNode* tree_nodes;
+
+ clear();
+ data = _data;
+
+ tree_nodes = cvGetFileNodeByName( fs, node, "nodes" );
+ if( !tree_nodes || CV_NODE_TYPE(tree_nodes->tag) != CV_NODE_SEQ )
+ CV_ERROR( CV_StsParseError, "nodes tag is missing" );
+
+ pruned_tree_idx = cvReadIntByName( fs, node, "best_tree_idx", -1 );
+ read_tree_nodes( fs, tree_nodes );
+
+ __END__;
+}
+
+/* End of file. */
diff --git a/otherlibs/highgui/_highgui.h b/otherlibs/highgui/_highgui.h
new file mode 100644
index 0000000..60fbeb2
--- /dev/null
+++ b/otherlibs/highgui/_highgui.h
@@ -0,0 +1,85 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __HIGHGUI_H_
+#define __HIGHGUI_H_
+
+#include "highgui.h"
+#include "cxmisc.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+
+/* Errors */
+#define HG_OK 0 /* Don't bet on it! */
+#define HG_BADNAME -1 /* Bad window or file name */
+#define HG_INITFAILED -2 /* Can't initialize HigHGUI. Possibly, can't find vlgrfmts.dll */
+#define HG_WCFAILED -3 /* Can't create a window */
+#define HG_NULLPTR -4 /* The null pointer where it should not appear */
+#define HG_BADPARAM -5
+
+#define CV_WINDOW_MAGIC_VAL 0x00420042
+#define CV_TRACKBAR_MAGIC_VAL 0x00420043
+#define cvShowImage NULL
+
+/***************************** CvCapture structure ******************************/
+
+struct CvCapture
+{
+ virtual ~CvCapture() {}
+ virtual double getProperty(int) { return 0; }
+ virtual bool setProperty(int, double) { return 0; }
+ virtual bool grabFrame() { return true; }
+ virtual IplImage* retrieveFrame() { return 0; }
+ virtual IplImage* queryFrame() { return grabFrame() ? retrieveFrame() : 0; }
+};
+
+CvCapture* cvCreateCameraCapture_Socket( const char *address, const char* port, int width, int height );
+
+CVAPI(int) cvHaveImageReader(const char* filename);
+CVAPI(int) cvHaveImageWriter(const char* filename);
+
+
+#endif /* __HIGHGUI_H_ */
diff --git a/otherlibs/highgui/bitstrm.cpp b/otherlibs/highgui/bitstrm.cpp
new file mode 100644
index 0000000..3a3bb1a
--- /dev/null
+++ b/otherlibs/highgui/bitstrm.cpp
@@ -0,0 +1,1106 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_highgui.h"
+#include "bitstrm.h"
+
+#define BS_DEF_BLOCK_SIZE (1<<15)
+
+const ulong bs_bit_mask[] = {
+ 0,
+ 0x00000001, 0x00000003, 0x00000007, 0x0000000F,
+ 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
+ 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
+ 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
+ 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
+ 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
+ 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
+ 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
+};
+
+void bsBSwapBlock( uchar *start, uchar *end )
+{
+ ulong* data = (ulong*)start;
+ int i, size = (int)(end - start+3)/4;
+
+ for( i = 0; i < size; i++ )
+ {
+ ulong temp = data[i];
+ temp = BSWAP( temp );
+ data[i] = temp;
+ }
+}
+
+bool bsIsBigEndian( void )
+{
+ return (((const int*)"\0\x1\x2\x3\x4\x5\x6\x7")[0] & 255) != 0;
+}
+
+///////////////////////// RBaseStream ////////////////////////////
+
+bool RBaseStream::IsOpened()
+{
+ return m_is_opened;
+}
+
+void RBaseStream::Allocate()
+{
+ if( !m_start )
+ {
+ m_start = new uchar[m_block_size + m_unGetsize];
+ m_start+= m_unGetsize;
+ }
+ m_end = m_start + m_block_size;
+ m_current = m_end;
+}
+
+
+RBaseStream::RBaseStream()
+{
+ m_start = m_end = m_current = 0;
+ m_file = 0;
+ m_block_size = BS_DEF_BLOCK_SIZE;
+ m_unGetsize = 4; // 32 bits
+ m_is_opened = false;
+ m_jmp_set = false;
+}
+
+
+RBaseStream::~RBaseStream()
+{
+ Close(); // Close files
+ Release(); // free buffers
+}
+
+
+void RBaseStream::ReadBlock()
+{
+ size_t readed;
+ assert( m_file != 0 );
+
+ // copy unget buffer
+ if( m_start )
+ {
+ memcpy( m_start - m_unGetsize, m_end - m_unGetsize, m_unGetsize );
+ }
+
+ SetPos( GetPos() ); // normalize position
+
+ fseek( m_file, m_block_pos, SEEK_SET );
+ readed = fread( m_start, 1, m_block_size, m_file );
+ m_end = m_start + readed;
+ m_current -= m_block_size;
+ m_block_pos += m_block_size;
+
+ if( readed == 0 || m_current >= m_end )
+ {
+ if( m_jmp_set )
+ longjmp( m_jmp_buf, RBS_THROW_EOS );
+ }
+}
+
+
+bool RBaseStream::Open( const char* filename )
+{
+ Close();
+ Allocate();
+
+ m_file = fopen( filename, "rb" );
+
+ if( m_file )
+ {
+ m_is_opened = true;
+ SetPos(0);
+ }
+ return m_file != 0;
+}
+
+void RBaseStream::Close()
+{
+ if( m_file )
+ {
+ fclose( m_file );
+ m_file = 0;
+ }
+ m_is_opened = false;
+}
+
+
+void RBaseStream::Release()
+{
+ if( m_start )
+ {
+ delete[] (m_start - m_unGetsize);
+ }
+ m_start = m_end = m_current = 0;
+}
+
+
+void RBaseStream::SetBlockSize( int block_size, int unGetsize )
+{
+ assert( unGetsize >= 0 && block_size > 0 &&
+ (block_size & (block_size-1)) == 0 );
+
+ if( m_start && block_size == m_block_size && unGetsize == m_unGetsize ) return;
+ Release();
+ m_block_size = block_size;
+ m_unGetsize = unGetsize;
+ Allocate();
+}
+
+
+void RBaseStream::SetPos( int pos )
+{
+ int offset = pos & (m_block_size - 1);
+ int block_pos = pos - offset;
+
+ assert( IsOpened() && pos >= 0 );
+
+ if( m_current < m_end && block_pos == m_block_pos - m_block_size )
+ {
+ m_current = m_start + offset;
+ }
+ else
+ {
+ m_block_pos = block_pos;
+ m_current = m_start + m_block_size + offset;
+ }
+}
+
+
+int RBaseStream::GetPos()
+{
+ assert( IsOpened() );
+ return m_block_pos - m_block_size + (int)(m_current - m_start);
+}
+
+void RBaseStream::Skip( int bytes )
+{
+ assert( bytes >= 0 );
+ m_current += bytes;
+}
+
+jmp_buf& RBaseStream::JmpBuf()
+{
+ m_jmp_set = true;
+ return m_jmp_buf;
+}
+
+///////////////////////// RLByteStream ////////////////////////////
+
+RLByteStream::~RLByteStream()
+{
+}
+
+int RLByteStream::GetByte()
+{
+ uchar *current = m_current;
+ int val;
+
+ if( current >= m_end )
+ {
+ ReadBlock();
+ current = m_current;
+ }
+
+ val = *((uchar*)current);
+ m_current = current + 1;
+ return val;
+}
+
+
+void RLByteStream::GetBytes( void* buffer, int count, int* readed )
+{
+ uchar* data = (uchar*)buffer;
+ assert( count >= 0 );
+
+ if( readed) *readed = 0;
+
+ while( count > 0 )
+ {
+ int l;
+
+ for(;;)
+ {
+ l = (int)(m_end - m_current);
+ if( l > count ) l = count;
+ if( l > 0 ) break;
+ ReadBlock();
+ }
+ memcpy( data, m_current, l );
+ m_current += l;
+ data += l;
+ count -= l;
+ if( readed ) *readed += l;
+ }
+}
+
+
+//////////// RLByteStream & RMByteStream <Get[d]word>s ////////////////
+
+RMByteStream::~RMByteStream()
+{
+}
+
+
+int RLByteStream::GetWord()
+{
+ uchar *current = m_current;
+ int val;
+
+ if( current+1 < m_end )
+ {
+ val = current[0] + (current[1] << 8);
+ m_current = current + 2;
+ }
+ else
+ {
+ val = GetByte();
+ val|= GetByte() << 8;
+ }
+ return val;
+}
+
+
+int RLByteStream::GetDWord()
+{
+ uchar *current = m_current;
+ int val;
+
+ if( current+3 < m_end )
+ {
+ val = current[0] + (current[1] << 8) +
+ (current[2] << 16) + (current[3] << 24);
+ m_current = current + 4;
+ }
+ else
+ {
+ val = GetByte();
+ val |= GetByte() << 8;
+ val |= GetByte() << 16;
+ val |= GetByte() << 24;
+ }
+ return val;
+}
+
+
+int RMByteStream::GetWord()
+{
+ uchar *current = m_current;
+ int val;
+
+ if( current+1 < m_end )
+ {
+ val = (current[0] << 8) + current[1];
+ m_current = current + 2;
+ }
+ else
+ {
+ val = GetByte() << 8;
+ val|= GetByte();
+ }
+ return val;
+}
+
+
+int RMByteStream::GetDWord()
+{
+ uchar *current = m_current;
+ int val;
+
+ if( current+3 < m_end )
+ {
+ val = (current[0] << 24) + (current[1] << 16) +
+ (current[2] << 8) + current[3];
+ m_current = current + 4;
+ }
+ else
+ {
+ val = GetByte() << 24;
+ val |= GetByte() << 16;
+ val |= GetByte() << 8;
+ val |= GetByte();
+ }
+ return val;
+}
+
+
+///////////////////////// RLBitStream ////////////////////////////
+
+RLBitStream::~RLBitStream()
+{
+}
+
+
+void RLBitStream::ReadBlock()
+{
+ RBaseStream::ReadBlock();
+ if( bsIsBigEndian() )
+ bsBSwapBlock( m_start, m_end );
+}
+
+
+void RLBitStream::SetPos( int pos )
+{
+ RBaseStream::SetPos(pos);
+ int offset = (int)(m_current - m_end);
+ m_current = m_end + (offset & -4);
+ m_bit_idx = (offset&3)*8;
+}
+
+
+int RLBitStream::GetPos()
+{
+ return RBaseStream::GetPos() + (m_bit_idx >> 3);
+}
+
+
+int RLBitStream::Get( int bits )
+{
+ int bit_idx = m_bit_idx;
+ int new_bit_idx = bit_idx + bits;
+ int mask = new_bit_idx >= 32 ? -1 : 0;
+ ulong* current = (ulong*)m_current;
+
+ assert( (unsigned)bits < 32 );
+
+ if( (m_current = (uchar*)(current - mask)) >= m_end )
+ {
+ ReadBlock();
+ current = ((ulong*)m_current) + mask;
+ }
+ m_bit_idx = new_bit_idx & 31;
+ return ((current[0] >> bit_idx) |
+ ((current[1] <<-bit_idx) & mask)) & bs_bit_mask[bits];
+}
+
+int RLBitStream::Show( int bits )
+{
+ int bit_idx = m_bit_idx;
+ int new_bit_idx = bit_idx + bits;
+ int mask = new_bit_idx >= 32 ? -1 : 0;
+ ulong* current = (ulong*)m_current;
+
+ assert( (unsigned)bits < 32 );
+
+ if( (uchar*)(current - mask) >= m_end )
+ {
+ ReadBlock();
+ current = ((ulong*)m_current) + mask;
+ m_current = (uchar*)current;
+ }
+ return ((current[0] >> bit_idx) |
+ ((current[1] <<-bit_idx) & mask)) & bs_bit_mask[bits];
+}
+
+
+void RLBitStream::Move( int shift )
+{
+ int new_bit_idx = m_bit_idx + shift;
+ m_current += (new_bit_idx >> 5) << 2;
+ m_bit_idx = new_bit_idx & 31;
+}
+
+
+int RLBitStream::GetHuff( const short* table )
+{
+ int val;
+ int code_bits;
+
+ for(;;)
+ {
+ int table_bits = table[0];
+ val = table[Show(table_bits) + 2];
+ code_bits = val & 15;
+ val >>= 4;
+
+ if( code_bits != 0 ) break;
+ table += val*2;
+ Move( table_bits );
+ }
+
+ Move( code_bits );
+ if( val == RBS_HUFF_FORB )
+ {
+ if( m_jmp_set )
+ longjmp( m_jmp_buf, RBS_THROW_FORB );
+ }
+
+ return val;
+}
+
+void RLBitStream::Skip( int bytes )
+{
+ Move( bytes*8 );
+}
+
+///////////////////////// RMBitStream ////////////////////////////
+
+
+RMBitStream::~RMBitStream()
+{
+}
+
+
+void RMBitStream::ReadBlock()
+{
+ RBaseStream::ReadBlock();
+ if( !bsIsBigEndian() )
+ bsBSwapBlock( m_start, m_end );
+}
+
+
+void RMBitStream::SetPos( int pos )
+{
+ RBaseStream::SetPos(pos);
+ int offset = (int)(m_current - m_end);
+ m_current = m_end + ((offset - 1) & -4);
+ m_bit_idx = (32 - (offset&3)*8) & 31;
+}
+
+
+int RMBitStream::GetPos()
+{
+ return RBaseStream::GetPos() + ((32 - m_bit_idx) >> 3);
+}
+
+
+int RMBitStream::Get( int bits )
+{
+ int bit_idx = m_bit_idx - bits;
+ int mask = bit_idx >> 31;
+ ulong* current = ((ulong*)m_current) - mask;
+
+ assert( (unsigned)bits < 32 );
+
+ if( (m_current = (uchar*)current) >= m_end )
+ {
+ ReadBlock();
+ current = (ulong*)m_current;
+ }
+ m_bit_idx = bit_idx &= 31;
+ return (((current[-1] << -bit_idx) & mask)|
+ (current[0] >> bit_idx)) & bs_bit_mask[bits];
+}
+
+
+int RMBitStream::Show( int bits )
+{
+ int bit_idx = m_bit_idx - bits;
+ int mask = bit_idx >> 31;
+ ulong* current = ((ulong*)m_current) - mask;
+
+ assert( (unsigned)bits < 32 );
+
+ if( ((uchar*)current) >= m_end )
+ {
+ m_current = (uchar*)current;
+ ReadBlock();
+ current = (ulong*)m_current;
+ m_current -= 4;
+ }
+ return (((current[-1]<<-bit_idx) & mask)|
+ (current[0] >> bit_idx)) & bs_bit_mask[bits];
+}
+
+
+int RMBitStream::GetHuff( const short* table )
+{
+ int val;
+ int code_bits;
+
+ for(;;)
+ {
+ int table_bits = table[0];
+ val = table[Show(table_bits) + 1];
+ code_bits = val & 15;
+ val >>= 4;
+
+ if( code_bits != 0 ) break;
+ table += val;
+ Move( table_bits );
+ }
+
+ Move( code_bits );
+ if( val == RBS_HUFF_FORB )
+ {
+ if( m_jmp_set )
+ longjmp( m_jmp_buf, RBS_THROW_FORB );
+ }
+
+ return val;
+}
+
+
+void RMBitStream::Move( int shift )
+{
+ int new_bit_idx = m_bit_idx - shift;
+ m_current -= (new_bit_idx >> 5)<<2;
+ m_bit_idx = new_bit_idx & 31;
+}
+
+
+void RMBitStream::Skip( int bytes )
+{
+ Move( bytes*8 );
+}
+
+
+static const int huff_val_shift = 20, huff_code_mask = (1 << huff_val_shift) - 1;
+
+bool bsCreateDecodeHuffmanTable( const int* src, short* table, int max_size )
+{
+ const int forbidden_entry = (RBS_HUFF_FORB << 4)|1;
+ int first_bits = src[0];
+ struct
+ {
+ int bits;
+ int offset;
+ }
+ sub_tables[1 << 11];
+ int size = (1 << first_bits) + 1;
+ int i, k;
+
+ /* calc bit depths of sub tables */
+ memset( sub_tables, 0, ((size_t)1 << first_bits)*sizeof(sub_tables[0]) );
+ for( i = 1, k = 1; src[k] >= 0; i++ )
+ {
+ int code_count = src[k++];
+ int sb = i - first_bits;
+
+ if( sb <= 0 )
+ k += code_count;
+ else
+ for( code_count += k; k < code_count; k++ )
+ {
+ int code = src[k] & huff_code_mask;
+ sub_tables[code >> sb].bits = sb;
+ }
+ }
+
+ /* calc offsets of sub tables and whole size of table */
+ for( i = 0; i < (1 << first_bits); i++ )
+ {
+ int b = sub_tables[i].bits;
+ if( b > 0 )
+ {
+ b = 1 << b;
+ sub_tables[i].offset = size;
+ size += b + 1;
+ }
+ }
+
+ if( size > max_size )
+ {
+ assert(0);
+ return false;
+ }
+
+ /* fill first table and subtables with forbidden values */
+ for( i = 0; i < size; i++ )
+ {
+ table[i] = (short)forbidden_entry;
+ }
+
+ /* write header of first table */
+ table[0] = (short)first_bits;
+
+ /* fill first table and sub tables */
+ for( i = 1, k = 1; src[k] >= 0; i++ )
+ {
+ int code_count = src[k++];
+ for( code_count += k; k < code_count; k++ )
+ {
+ int table_bits= first_bits;
+ int code_bits = i;
+ int code = src[k] & huff_code_mask;
+ int val = src[k] >>huff_val_shift;
+ int j, offset = 0;
+
+ if( code_bits > table_bits )
+ {
+ int idx = code >> (code_bits -= table_bits);
+ code &= (1 << code_bits) - 1;
+ offset = sub_tables[idx].offset;
+ table_bits= sub_tables[idx].bits;
+ /* write header of subtable */
+ table[offset] = (short)table_bits;
+ /* write jump to subtable */
+ table[idx + 1]= (short)(offset << 4);
+ }
+
+ table_bits -= code_bits;
+ assert( table_bits >= 0 );
+ val = (val << 4) | code_bits;
+ offset += (code << table_bits) + 1;
+
+ for( j = 0; j < (1 << table_bits); j++ )
+ {
+ assert( table[offset + j] == forbidden_entry );
+ table[ offset + j ] = (short)val;
+ }
+ }
+ }
+ return true;
+}
+
+
+int* bsCreateSourceHuffmanTable( const uchar* src, int* dst,
+ int max_bits, int first_bits )
+{
+ int i, val_idx, code = 0;
+ int* table = dst;
+ *dst++ = first_bits;
+ for( i = 1, val_idx = max_bits; i <= max_bits; i++ )
+ {
+ int code_count = src[i - 1];
+ dst[0] = code_count;
+ code <<= 1;
+ for( int k = 0; k < code_count; k++ )
+ {
+ dst[k + 1] = (src[val_idx + k] << huff_val_shift)|(code + k);
+ }
+ code += code_count;
+ dst += code_count + 1;
+ val_idx += code_count;
+ }
+ dst[0] = -1;
+ return table;
+}
+
+
+/////////////////////////// WBaseStream /////////////////////////////////
+
+// WBaseStream - base class for output streams
+WBaseStream::WBaseStream()
+{
+ m_start = m_end = m_current = 0;
+ m_file = 0;
+ m_block_size = BS_DEF_BLOCK_SIZE;
+ m_is_opened = false;
+}
+
+
+WBaseStream::~WBaseStream()
+{
+ Close(); // Close files
+ Release(); // free buffers
+}
+
+
+bool WBaseStream::IsOpened()
+{
+ return m_is_opened;
+}
+
+
+void WBaseStream::Allocate()
+{
+ if( !m_start )
+ m_start = new uchar[m_block_size];
+
+ m_end = m_start + m_block_size;
+ m_current = m_start;
+}
+
+
+void WBaseStream::WriteBlock()
+{
+ int size = (int)(m_current - m_start);
+ assert( m_file != 0 );
+
+ //fseek( m_file, m_block_pos, SEEK_SET );
+ fwrite( m_start, 1, size, m_file );
+ m_current = m_start;
+
+ /*if( written < size ) throw RBS_THROW_EOS;*/
+
+ m_block_pos += size;
+}
+
+
+bool WBaseStream::Open( const char* filename )
+{
+ Close();
+ Allocate();
+
+ m_file = fopen( filename, "wb" );
+
+ if( m_file )
+ {
+ m_is_opened = true;
+ m_block_pos = 0;
+ m_current = m_start;
+ }
+ return m_file != 0;
+}
+
+
+void WBaseStream::Close()
+{
+ if( m_file )
+ {
+ WriteBlock();
+ fclose( m_file );
+ m_file = 0;
+ }
+ m_is_opened = false;
+}
+
+
+void WBaseStream::Release()
+{
+ if( m_start )
+ {
+ delete[] m_start;
+ }
+ m_start = m_end = m_current = 0;
+}
+
+
+void WBaseStream::SetBlockSize( int block_size )
+{
+ assert( block_size > 0 && (block_size & (block_size-1)) == 0 );
+
+ if( m_start && block_size == m_block_size ) return;
+ Release();
+ m_block_size = block_size;
+ Allocate();
+}
+
+
+int WBaseStream::GetPos()
+{
+ assert( IsOpened() );
+ return m_block_pos + (int)(m_current - m_start);
+}
+
+
+///////////////////////////// WLByteStream ///////////////////////////////////
+
+WLByteStream::~WLByteStream()
+{
+}
+
+void WLByteStream::PutByte( int val )
+{
+ *m_current++ = (uchar)val;
+ if( m_current >= m_end )
+ WriteBlock();
+}
+
+
+void WLByteStream::PutBytes( const void* buffer, int count )
+{
+ uchar* data = (uchar*)buffer;
+
+ assert( data && m_current && count >= 0 );
+
+ while( count )
+ {
+ int l = (int)(m_end - m_current);
+
+ if( l > count )
+ l = count;
+
+ if( l > 0 )
+ {
+ memcpy( m_current, data, l );
+ m_current += l;
+ data += l;
+ count -= l;
+ }
+ if( m_current == m_end )
+ WriteBlock();
+ }
+}
+
+
+void WLByteStream::PutWord( int val )
+{
+ uchar *current = m_current;
+
+ if( current+1 < m_end )
+ {
+ current[0] = (uchar)val;
+ current[1] = (uchar)(val >> 8);
+ m_current = current + 2;
+ if( m_current == m_end )
+ WriteBlock();
+ }
+ else
+ {
+ PutByte(val);
+ PutByte(val >> 8);
+ }
+}
+
+
+void WLByteStream::PutDWord( int val )
+{
+ uchar *current = m_current;
+
+ if( current+3 < m_end )
+ {
+ current[0] = (uchar)val;
+ current[1] = (uchar)(val >> 8);
+ current[2] = (uchar)(val >> 16);
+ current[3] = (uchar)(val >> 24);
+ m_current = current + 4;
+ if( m_current == m_end )
+ WriteBlock();
+ }
+ else
+ {
+ PutByte(val);
+ PutByte(val >> 8);
+ PutByte(val >> 16);
+ PutByte(val >> 24);
+ }
+}
+
+
+///////////////////////////// WMByteStream ///////////////////////////////////
+
+WMByteStream::~WMByteStream()
+{
+}
+
+
+void WMByteStream::PutWord( int val )
+{
+ uchar *current = m_current;
+
+ if( current+1 < m_end )
+ {
+ current[0] = (uchar)(val >> 8);
+ current[1] = (uchar)val;
+ m_current = current + 2;
+ if( m_current == m_end )
+ WriteBlock();
+ }
+ else
+ {
+ PutByte(val >> 8);
+ PutByte(val);
+ }
+}
+
+
+void WMByteStream::PutDWord( int val )
+{
+ uchar *current = m_current;
+
+ if( current+3 < m_end )
+ {
+ current[0] = (uchar)(val >> 24);
+ current[1] = (uchar)(val >> 16);
+ current[2] = (uchar)(val >> 8);
+ current[3] = (uchar)val;
+ m_current = current + 4;
+ if( m_current == m_end )
+ WriteBlock();
+ }
+ else
+ {
+ PutByte(val >> 24);
+ PutByte(val >> 16);
+ PutByte(val >> 8);
+ PutByte(val);
+ }
+}
+
+
+
+///////////////////////////// WMBitStream ///////////////////////////////////
+
+WMBitStream::WMBitStream()
+{
+ m_pad_val = 0;
+ ResetBuffer();
+}
+
+
+WMBitStream::~WMBitStream()
+{
+}
+
+
+bool WMBitStream::Open( const char* filename )
+{
+ ResetBuffer();
+ return WBaseStream::Open( filename );
+}
+
+
+void WMBitStream::ResetBuffer()
+{
+ m_val = 0;
+ m_bit_idx = 32;
+ m_current = m_start;
+}
+
+void WMBitStream::Flush()
+{
+ if( m_bit_idx < 32 )
+ {
+ Put( m_pad_val, m_bit_idx & 7 );
+ *((ulong*&)m_current)++ = m_val;
+ }
+}
+
+
+void WMBitStream::Close()
+{
+ if( m_is_opened )
+ {
+ Flush();
+ WBaseStream::Close();
+ }
+}
+
+
+void WMBitStream::WriteBlock()
+{
+ if( !bsIsBigEndian() )
+ bsBSwapBlock( m_start, m_current );
+ WBaseStream::WriteBlock();
+}
+
+
+int WMBitStream::GetPos()
+{
+ return WBaseStream::GetPos() + ((32 - m_bit_idx) >> 3);
+}
+
+
+void WMBitStream::Put( int val, int bits )
+{
+ int bit_idx = m_bit_idx - bits;
+ ulong curval = m_val;
+
+ assert( 0 <= bits && bits < 32 );
+
+ val &= bs_bit_mask[bits];
+
+ if( bit_idx >= 0 )
+ {
+ curval |= val << bit_idx;
+ }
+ else
+ {
+ *((ulong*&)m_current)++ = curval | ((unsigned)val >> -bit_idx);
+ if( m_current >= m_end )
+ {
+ WriteBlock();
+ }
+ bit_idx += 32;
+ curval = val << bit_idx;
+ }
+
+ m_val = curval;
+ m_bit_idx = bit_idx;
+}
+
+
+void WMBitStream::PutHuff( int val, const ulong* table )
+{
+ int min_val = (int)table[0];
+ val -= min_val;
+
+ assert( (unsigned)val < table[1] );
+
+ ulong code = table[val + 2];
+ assert( code != 0 );
+
+ Put( code >> 8, code & 255 );
+}
+
+
+bool bsCreateEncodeHuffmanTable( const int* src, ulong* table, int max_size )
+{
+ int i, k;
+ int min_val = INT_MAX, max_val = INT_MIN;
+ int size;
+
+ /* calc min and max values in the table */
+ for( i = 1, k = 1; src[k] >= 0; i++ )
+ {
+ int code_count = src[k++];
+
+ for( code_count += k; k < code_count; k++ )
+ {
+ int val = src[k] >> huff_val_shift;
+ if( val < min_val )
+ min_val = val;
+ if( val > max_val )
+ max_val = val;
+ }
+ }
+
+ size = max_val - min_val + 3;
+
+ if( size > max_size )
+ {
+ assert(0);
+ return false;
+ }
+
+ memset( table, 0, size*sizeof(table[0]));
+
+ table[0] = min_val;
+ table[1] = size - 2;
+
+ for( i = 1, k = 1; src[k] >= 0; i++ )
+ {
+ int code_count = src[k++];
+
+ for( code_count += k; k < code_count; k++ )
+ {
+ int val = src[k] >> huff_val_shift;
+ int code = src[k] & huff_code_mask;
+
+ table[val - min_val + 2] = (code << 8) | i;
+ }
+ }
+ return true;
+}
+
diff --git a/otherlibs/highgui/bitstrm.h b/otherlibs/highgui/bitstrm.h
new file mode 100644
index 0000000..8ddd759
--- /dev/null
+++ b/otherlibs/highgui/bitstrm.h
@@ -0,0 +1,272 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _BITSTRM_H_
+#define _BITSTRM_H_
+
+#include <stdio.h>
+#include <setjmp.h>
+
+#if _MSC_VER >= 1200
+ #pragma warning( disable: 4711 4324 )
+#endif
+
+#define RBS_THROW_EOS -123 /* <end of stream> exception code */
+#define RBS_THROW_FORB -124 /* <forrbidden huffman code> exception code */
+#define RBS_HUFF_FORB 2047 /* forrbidden huffman code "value" */
+
+typedef unsigned char uchar;
+typedef unsigned long ulong;
+
+// class RBaseStream - base class for other reading streams.
+class RBaseStream
+{
+public:
+ //methods
+ RBaseStream();
+ virtual ~RBaseStream();
+
+ virtual bool Open( const char* filename );
+ virtual void Close();
+ void SetBlockSize( int block_size, int unGetsize = 4 );
+ bool IsOpened();
+ void SetPos( int pos );
+ int GetPos();
+ void Skip( int bytes );
+ jmp_buf& JmpBuf();
+
+protected:
+
+ jmp_buf m_jmp_buf;
+ uchar* m_start;
+ uchar* m_end;
+ uchar* m_current;
+ FILE* m_file;
+ int m_unGetsize;
+ int m_block_size;
+ int m_block_pos;
+ bool m_jmp_set;
+ bool m_is_opened;
+
+ virtual void ReadBlock();
+ virtual void Release();
+ virtual void Allocate();
+};
+
+
+// class RLByteStream - uchar-oriented stream.
+// l in prefix means that the least significant uchar of a multi-uchar value goes first
+class RLByteStream : public RBaseStream
+{
+public:
+ virtual ~RLByteStream();
+
+ int GetByte();
+ void GetBytes( void* buffer, int count, int* readed = 0 );
+ int GetWord();
+ int GetDWord();
+};
+
+// class RMBitStream - uchar-oriented stream.
+// m in prefix means that the most significant uchar of a multi-uchar value go first
+class RMByteStream : public RLByteStream
+{
+public:
+ virtual ~RMByteStream();
+
+ int GetWord();
+ int GetDWord();
+};
+
+// class RLBitStream - bit-oriented stream.
+// l in prefix means that the least significant bit of a multi-bit value goes first
+class RLBitStream : public RBaseStream
+{
+public:
+ virtual ~RLBitStream();
+
+ void SetPos( int pos );
+ int GetPos();
+ int Get( int bits );
+ int Show( int bits );
+ int GetHuff( const short* table );
+ void Move( int shift );
+ void Skip( int bytes );
+
+protected:
+ int m_bit_idx;
+ virtual void ReadBlock();
+};
+
+// class RMBitStream - bit-oriented stream.
+// m in prefix means that the most significant bit of a multi-bit value goes first
+class RMBitStream : public RLBitStream
+{
+public:
+ virtual ~RMBitStream();
+
+ void SetPos( int pos );
+ int GetPos();
+ int Get( int bits );
+ int Show( int bits );
+ int GetHuff( const short* table );
+ void Move( int shift );
+ void Skip( int bytes );
+
+protected:
+ virtual void ReadBlock();
+};
+
+
+// WBaseStream - base class for output streams
+class WBaseStream
+{
+public:
+ //methods
+ WBaseStream();
+ virtual ~WBaseStream();
+
+ virtual bool Open( const char* filename );
+ virtual void Close();
+ void SetBlockSize( int block_size );
+ bool IsOpened();
+ int GetPos();
+
+protected:
+
+ uchar* m_start;
+ uchar* m_end;
+ uchar* m_current;
+ int m_block_size;
+ int m_block_pos;
+ FILE* m_file;
+ bool m_is_opened;
+
+ virtual void WriteBlock();
+ virtual void Release();
+ virtual void Allocate();
+};
+
+
+// class WLByteStream - uchar-oriented stream.
+// l in prefix means that the least significant uchar of a multi-byte value goes first
+class WLByteStream : public WBaseStream
+{
+public:
+ virtual ~WLByteStream();
+
+ void PutByte( int val );
+ void PutBytes( const void* buffer, int count );
+ void PutWord( int val );
+ void PutDWord( int val );
+};
+
+
+// class WLByteStream - uchar-oriented stream.
+// m in prefix means that the least significant uchar of a multi-byte value goes last
+class WMByteStream : public WLByteStream
+{
+public:
+ virtual ~WMByteStream();
+
+ void PutWord( int val );
+ void PutDWord( int val );
+};
+
+
+// class WLBitStream - bit-oriented stream.
+// l in prefix means that the least significant bit of a multi-bit value goes first
+class WLBitStream : public WBaseStream
+{
+public:
+ virtual ~WLBitStream();
+
+ int GetPos();
+ void Put( int val, int bits );
+ void PutHuff( int val, const int* table );
+
+protected:
+ int m_bit_idx;
+ int m_val;
+ virtual void WriteBlock();
+};
+
+
+// class WMBitStream - bit-oriented stream.
+// l in prefix means that the least significant bit of a multi-bit value goes first
+class WMBitStream : public WBaseStream
+{
+public:
+ WMBitStream();
+ virtual ~WMBitStream();
+
+ bool Open( const char* filename );
+ void Close();
+ virtual void Flush();
+
+ int GetPos();
+ void Put( int val, int bits );
+ void PutHuff( int val, const ulong* table );
+
+protected:
+ int m_bit_idx;
+ ulong m_pad_val;
+ ulong m_val;
+ virtual void WriteBlock();
+ void ResetBuffer();
+};
+
+
+
+#define BSWAP(v) (((v)<<24)|(((v)&0xff00)<<8)| \
+ (((v)>>8)&0xff00)|((unsigned)(v)>>24))
+
+int* bsCreateSourceHuffmanTable( const uchar* src, int* dst,
+ int max_bits, int first_bits );
+bool bsCreateDecodeHuffmanTable( const int* src, short* dst, int max_size );
+bool bsCreateEncodeHuffmanTable( const int* src, ulong* dst, int max_size );
+
+void bsBSwapBlock( uchar *start, uchar *end );
+bool bsIsBigEndian( void );
+
+extern const ulong bs_bit_mask[];
+
+#endif/*_BITSTRM_H_*/
diff --git a/otherlibs/highgui/cvcap.cpp b/otherlibs/highgui/cvcap.cpp
new file mode 100644
index 0000000..47b0588
--- /dev/null
+++ b/otherlibs/highgui/cvcap.cpp
@@ -0,0 +1,93 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_highgui.h"
+
+#if _MSC_VER >= 1200
+#pragma warning( disable: 4711 )
+#endif
+
+#if defined WIN64 && defined EM64T && defined _MSC_VER && !defined __ICL
+#pragma optimize("",off)
+#endif
+
+
+/************************* Reading AVIs & Camera data **************************/
+
+CV_IMPL void cvReleaseCapture( CvCapture** pcapture )
+{
+ if( pcapture && *pcapture )
+ {
+ delete *pcapture;
+ *pcapture = 0;
+ }
+}
+
+CV_IMPL IplImage* cvQueryFrame( CvCapture* capture )
+{
+ return capture ? capture->queryFrame() : 0;
+}
+
+
+CV_IMPL int cvGrabFrame( CvCapture* capture )
+{
+ return capture ? capture->grabFrame() : 0;
+}
+
+CV_IMPL IplImage* cvRetrieveFrame( CvCapture* capture )
+{
+ return capture ? capture->retrieveFrame() : 0;
+}
+
+CV_IMPL double cvGetCaptureProperty( CvCapture* capture, int id )
+{
+ return capture ? capture->getProperty(id) : 0;
+}
+
+CV_IMPL int cvSetCaptureProperty( CvCapture* capture, int id, double value )
+{
+ return capture ? capture->setProperty(id, value) : 0;
+}
+
+CV_IMPL CvCapture* cvCreateSocketCapture( const char *address, const char* port, int width, int height )
+{
+ return cvCreateCameraCapture_Socket(address, port, width, height);
+}
diff --git a/otherlibs/highgui/cvcap_socket.cpp b/otherlibs/highgui/cvcap_socket.cpp
new file mode 100644
index 0000000..6e2f01e
--- /dev/null
+++ b/otherlibs/highgui/cvcap_socket.cpp
@@ -0,0 +1,302 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2008, Nils Hasler, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+// Author: Bill McCord
+//
+// Intuitive Automata
+
+//
+// capture video from a socket connection
+//
+
+#include "_highgui.h"
+#include <android/log.h>
+#include <errno.h>
+#include <netdb.h>
+#include <unistd.h>
+
+#define LOGV(...) __android_log_print(ANDROID_LOG_SILENT, LOG_TAG, __VA_ARGS__)
+#define LOG_TAG "CVJNI"
+
+#ifdef NDEBUG
+#define CV_WARN(message)
+#else
+#define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__)
+#endif
+
+#define IMAGE( i, x, y, n ) *(( unsigned char * )(( i )->imageData \
+ + ( x ) * sizeof( unsigned char ) * 3 \
+ + ( y ) * ( i )->widthStep ) + ( n ))
+
+class CVCapture_Socket : public CvCapture
+{
+public:
+ CVCapture_Socket()
+ {
+ pAddrInfo = 0;
+ width = 0;
+ height = 0;
+ readBufSize = 0;
+ readBuf = 0;
+ frame = 0;
+ }
+
+ virtual ~CVCapture_Socket()
+ {
+ close();
+ }
+
+ virtual bool open(const char* _address, const char* _port, int _width, int _height);
+ virtual void close();
+ virtual double getProperty(int);
+ virtual bool setProperty(int, double);
+ virtual bool grabFrame();
+ virtual IplImage* retrieveFrame();
+
+protected:
+ struct addrinfo *pAddrInfo;
+ int width; // the width of the images received over the socket
+ int height; // the height of the images received over the socket
+ long readBufSize; // the length of the read buffer
+ char *readBuf; // the read buffer
+
+ IplImage* frame;
+};
+
+// The open method simply initializes some variables we will need later.
+bool CVCapture_Socket::open(const char* _address, const char* _port, int _width, int _height)
+{
+ // Free the addrinfo if it was allocated.
+ if (pAddrInfo)
+ {
+ freeaddrinfo(pAddrInfo);
+ pAddrInfo = 0;
+ }
+
+ // Check the easy stuff first.
+ width = _width;
+ height = _height;
+ if (width <= 0 || height <= 0)
+ {
+ LOGV("Invalid width or height!");
+ return false;
+ }
+
+ // Setup a new addrinfo to support a streaming socket at the given address and port.
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_NUMERICHOST;
+
+ int error = getaddrinfo(_address, _port, &hints, &pAddrInfo);
+ if (error)
+ {
+ char buffer[100];
+ sprintf(buffer, "getaddrinfo error: %s", gai_strerror(error));
+ LOGV("%s", buffer);
+ freeaddrinfo(pAddrInfo);
+ pAddrInfo = 0;
+ return false;
+ }
+
+ readBufSize = width * height * sizeof(int);
+ readBuf = (char*)malloc(readBufSize);
+ if (!readBuf)
+ {
+ LOGV("out of memory error");
+ freeaddrinfo(pAddrInfo);
+ pAddrInfo = 0;
+ return false;
+ }
+
+ return true;
+}
+
+// Close cleans up all of our state and cached data.
+void CVCapture_Socket::close()
+{
+ LOGV("Setting simple vars to 0");
+ width = 0;
+ height = 0;
+ readBufSize = 0;
+
+ LOGV("Freeing Addr Info");
+ if (pAddrInfo)
+ {
+ freeaddrinfo(pAddrInfo);
+ pAddrInfo = 0;
+ }
+
+ LOGV("Freeing Buffer");
+ if (readBuf)
+ {
+ free(readBuf);
+ readBuf = 0;
+ }
+
+ LOGV("Releasing Image");
+ if (frame)
+ {
+ cvReleaseImage( &frame );
+ frame = 0;
+ }
+
+ LOGV("Done closing Capture Socket");
+}
+
+// Helper to load pixels from a byte stream received over a socket.
+static IplImage* loadPixels(char* pixels, int width, int height) {
+
+ int x, y, pos, int_size = sizeof(int);
+ IplImage *img = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
+
+ for ( y = 0; y < height; y++ ) {
+ pos = y * width * int_size;
+ for ( x = 0; x < width; x++, pos += int_size ) {
+ // blue
+ IMAGE( img, x, y, 0 ) = pixels[pos + 3] & 0xFF;
+ // green
+ IMAGE( img, x, y, 1 ) = pixels[pos + 2] & 0xFF;
+ // red
+ IMAGE( img, x, y, 2 ) = pixels[pos + 1] & 0xFF;
+ }
+ }
+
+ return img;
+}
+
+// Grabs a frame (image) from a socket.
+bool CVCapture_Socket::grabFrame()
+{
+ // First ensure that our addrinfo and read buffer are allocated.
+ if (pAddrInfo == 0 || readBuf == 0)
+ {
+ LOGV("You haven't opened the socket capture yet!");
+ return false;
+ }
+
+ // Establish the socket.
+ int sockd = socket(pAddrInfo->ai_family, pAddrInfo->ai_socktype, pAddrInfo->ai_protocol);
+ if (sockd < 0 || errno != 0)
+ {
+ char buffer[100];
+ sprintf(buffer, "Failed to create socket, errno = %d", errno);
+ LOGV("%s", buffer);
+ ::close(sockd);
+ return false;
+ }
+
+ // Now connect to the socket.
+ if (connect(sockd, pAddrInfo->ai_addr, pAddrInfo->ai_addrlen) < 0 || errno != 0)
+ {
+ char buffer[100];
+ sprintf(buffer, "socket connection errorno = %d", errno);
+ LOGV("%s", buffer);
+ ::close(sockd);
+ return false;
+ }
+
+ // Release the image if it hasn't been already because we are going to overwrite it.
+ if (frame)
+ {
+ cvReleaseImage( &frame );
+ frame = 0;
+ }
+
+ // Read the socket until we have filled the data with the space allocated OR run
+ // out of data which we treat as an error.
+ long read_count, total_read = 0;
+ while (total_read < readBufSize)
+ {
+ read_count = read(sockd, &readBuf[total_read], readBufSize);
+ if (read_count <= 0 || errno != 0)
+ {
+ char buffer[100];
+ sprintf(buffer, "socket read errorno = %d", errno);
+ LOGV("%s", buffer);
+ break;
+ }
+ total_read += read_count;
+ }
+
+ // If we read all of the data we expected, we will load the frame from the pixels.
+ if (total_read == readBufSize)
+ {
+ frame = loadPixels(readBuf, width, height);
+ }
+ else
+ {
+ LOGV("full read of pixels failed");
+ }
+
+ // Close the socket and return the frame!
+ ::close(sockd);
+
+ return frame != 0;
+}
+
+IplImage* CVCapture_Socket::retrieveFrame()
+{
+ return frame;
+}
+
+double CVCapture_Socket::getProperty(int id)
+{
+ LOGV("unknown/unhandled property");
+ return 0;
+}
+
+bool CVCapture_Socket::setProperty(int id, double value)
+{
+ LOGV("unknown/unhandled property");
+ return false;
+}
+
+CvCapture* cvCreateCameraCapture_Socket( const char *address, const char *port, int width, int height )
+{
+ CVCapture_Socket* capture = new CVCapture_Socket;
+ if ( capture-> open(address, port, width, height) )
+ return capture;
+
+ delete capture;
+ return 0;
+}
diff --git a/otherlibs/highgui/dummy.cpp b/otherlibs/highgui/dummy.cpp
new file mode 100644
index 0000000..418b874
--- /dev/null
+++ b/otherlibs/highgui/dummy.cpp
@@ -0,0 +1 @@
+// this file is empty but needed for libtool
diff --git a/otherlibs/highgui/grfmt_base.cpp b/otherlibs/highgui/grfmt_base.cpp
new file mode 100644
index 0000000..06e33de
--- /dev/null
+++ b/otherlibs/highgui/grfmt_base.cpp
@@ -0,0 +1,305 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_highgui.h"
+
+#include "grfmt_base.h"
+#include "bitstrm.h"
+
+
+GrFmtReader::GrFmtReader( const char* filename )
+{
+ strncpy( m_filename, filename, sizeof(m_filename) - 1 );
+ m_filename[sizeof(m_filename)-1] = '\0';
+ m_width = m_height = 0;
+ m_iscolor = false;
+ m_bit_depth = 8;
+ m_native_depth = false;
+ m_isfloat = false;
+}
+
+
+GrFmtReader::~GrFmtReader()
+{
+ Close();
+}
+
+
+void GrFmtReader::Close()
+{
+ m_width = m_height = 0;
+ m_iscolor = false;
+}
+
+
+GrFmtWriter::GrFmtWriter( const char* filename )
+{
+ strncpy( m_filename, filename, sizeof(m_filename) - 1 );
+ m_filename[sizeof(m_filename)-1] = '\0';
+}
+
+
+bool GrFmtWriter::IsFormatSupported( int depth )
+{
+ return depth == IPL_DEPTH_8U;
+}
+
+
+GrFmtFilterFactory::GrFmtFilterFactory()
+{
+ m_description = m_signature = 0;
+ m_sign_len = 0;
+}
+
+
+bool GrFmtFilterFactory::CheckFile( const char* filename )
+{
+ FILE* f = 0;
+ char signature[4096];
+ int sign_len = 0;
+ int cur_sign_len = GetSignatureLength();
+
+ if( !filename ) return false;
+
+ assert( cur_sign_len <= (int)sizeof( signature ) );
+ f = fopen( filename, "rb" );
+
+ if( f )
+ {
+ sign_len = (int)fread( signature, 1, cur_sign_len, f );
+ fclose( f );
+
+ if( cur_sign_len <= sign_len && CheckSignature( signature ) )
+ return true;
+ }
+
+ return false;
+}
+
+
+bool GrFmtFilterFactory::CheckSignature( const char* signature )
+{
+ return m_sign_len > 0 && signature != 0 &&
+ memcmp( signature, m_signature, m_sign_len ) == 0;
+}
+
+
+static int GetExtensionLength( const char* buffer )
+{
+ int len = 0;
+
+ if( buffer )
+ {
+ const char* ext = strchr( buffer, '.');
+ if( ext++ )
+ while( isalnum(ext[len]) && len < _MAX_PATH )
+ len++;
+ }
+
+ return len;
+}
+
+
+bool GrFmtFilterFactory::CheckExtension( const char* format )
+{
+ const char* descr = 0;
+ int len = 0;
+
+ if( !format || !m_description )
+ return false;
+
+ // find the right-most extension of the passed format string
+ for(;;)
+ {
+ const char* ext = strchr( format + 1, '.' );
+ if( !ext ) break;
+ format = ext;
+ }
+
+ len = GetExtensionLength( format );
+
+ if( format[0] != '.' || len == 0 )
+ return false;
+
+ descr = strchr( m_description, '(' );
+
+ while( descr )
+ {
+ descr = strchr( descr + 1, '.' );
+ int i, len2 = GetExtensionLength( descr );
+
+ if( len2 == 0 )
+ break;
+
+ if( len2 == len )
+ {
+ for( i = 0; i < len; i++ )
+ {
+ int c1 = tolower(format[i+1]);
+ int c2 = tolower(descr[i+1]);
+
+ if( c1 != c2 )
+ break;
+ }
+ if( i == len )
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+
+///////////////////// GrFmtFilterList //////////////////////////
+
+GrFmtFactoriesList::GrFmtFactoriesList()
+{
+ m_factories = 0;
+ RemoveAll();
+}
+
+
+GrFmtFactoriesList::~GrFmtFactoriesList()
+{
+ RemoveAll();
+}
+
+
+void GrFmtFactoriesList::RemoveAll()
+{
+ if( m_factories )
+ {
+ for( int i = 0; i < m_curFactories; i++ ) delete m_factories[i];
+ delete[] m_factories;
+ }
+ m_factories = 0;
+ m_maxFactories = m_curFactories = 0;
+}
+
+
+bool GrFmtFactoriesList::AddFactory( GrFmtFilterFactory* factory )
+{
+ assert( factory != 0 );
+ if( m_curFactories == m_maxFactories )
+ {
+ // reallocate the factorys pointers storage
+ int newMaxFactories = 2*m_maxFactories;
+ if( newMaxFactories < 16 ) newMaxFactories = 16;
+
+ GrFmtFilterFactory** newFactories = new GrFmtFilterFactory*[newMaxFactories];
+
+ for( int i = 0; i < m_curFactories; i++ ) newFactories[i] = m_factories[i];
+
+ delete[] m_factories;
+ m_factories = newFactories;
+ m_maxFactories = newMaxFactories;
+ }
+
+ m_factories[m_curFactories++] = factory;
+ return true;
+}
+
+
+ListPosition GrFmtFactoriesList::GetFirstFactoryPos()
+{
+ return (ListPosition)m_factories;
+}
+
+
+GrFmtFilterFactory* GrFmtFactoriesList::GetNextFactory( ListPosition& pos )
+{
+ GrFmtFilterFactory* factory = 0;
+ GrFmtFilterFactory** temp = (GrFmtFilterFactory**)pos;
+
+ assert( temp == 0 || (m_factories <= temp && temp < m_factories + m_curFactories));
+ if( temp )
+ {
+ factory = *temp++;
+ pos = (ListPosition)(temp < m_factories + m_curFactories ? temp : 0);
+ }
+ return factory;
+}
+
+
+GrFmtReader* GrFmtFactoriesList::FindReader( const char* filename )
+{
+ if( !filename ) return 0;
+
+ GrFmtReader* reader = 0;
+ ListPosition pos = GetFirstFactoryPos();
+
+ while( pos )
+ {
+ GrFmtFilterFactory* tempFactory = GetNextFactory( pos );
+ if( tempFactory->CheckFile( filename ) )
+ {
+ reader = tempFactory->NewReader( filename );
+ break;
+ }
+ }
+
+ return reader;
+}
+
+
+GrFmtWriter* GrFmtFactoriesList::FindWriter( const char* filename )
+{
+ GrFmtWriter* writer = 0;
+ ListPosition pos = GetFirstFactoryPos();
+
+ if( !filename ) return 0;
+
+ while( pos )
+ {
+ GrFmtFilterFactory* tempFactory = GetNextFactory(pos);
+ if( tempFactory->CheckExtension( filename ))
+ {
+ writer = tempFactory->NewWriter( filename );
+ break;
+ }
+ }
+
+ return writer;
+}
+
+/* End of file. */
+
diff --git a/otherlibs/highgui/grfmt_base.h b/otherlibs/highgui/grfmt_base.h
new file mode 100644
index 0000000..fce1cc9
--- /dev/null
+++ b/otherlibs/highgui/grfmt_base.h
@@ -0,0 +1,163 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _GRFMT_BASE_H_
+#define _GRFMT_BASE_H_
+
+#if _MSC_VER >= 1200
+ #pragma warning( disable: 4514 )
+ #pragma warning( disable: 4711 )
+ #pragma warning( disable: 4611 )
+#endif
+
+#include "utils.h"
+#include "bitstrm.h"
+
+#define RBS_BAD_HEADER -125 /* invalid image header */
+#define BAD_HEADER_ERR() goto bad_header_exit
+
+#ifndef _MAX_PATH
+ #define _MAX_PATH 1024
+#endif
+
+
+///////////////////////////////// base class for readers ////////////////////////
+class GrFmtReader
+{
+public:
+
+ GrFmtReader( const char* filename );
+ virtual ~GrFmtReader();
+
+ int GetWidth() { return m_width; };
+ int GetHeight() { return m_height; };
+ bool IsColor() { return m_iscolor; };
+ int GetDepth() { return m_bit_depth; };
+ void UseNativeDepth( bool yes ) { m_native_depth = yes; };
+ bool IsFloat() { return m_isfloat; };
+
+ virtual bool ReadHeader() = 0;
+ virtual bool ReadData( uchar* data, int step, int color ) = 0;
+ virtual void Close();
+
+protected:
+
+ bool m_iscolor;
+ int m_width; // width of the image ( filled by ReadHeader )
+ int m_height; // height of the image ( filled by ReadHeader )
+ int m_bit_depth;// bit depth per channel (normally 8)
+ char m_filename[_MAX_PATH]; // filename
+ bool m_native_depth;// use the native bit depth of the image
+ bool m_isfloat; // is image saved as float or double?
+};
+
+
+///////////////////////////// base class for writers ////////////////////////////
+class GrFmtWriter
+{
+public:
+
+ GrFmtWriter( const char* filename );
+ virtual ~GrFmtWriter() {};
+ virtual bool IsFormatSupported( int depth );
+ virtual bool WriteImage( const uchar* data, int step,
+ int width, int height, int depth, int channels ) = 0;
+protected:
+ char m_filename[_MAX_PATH]; // filename
+};
+
+
+////////////////////////////// base class for filter factories //////////////////
+class GrFmtFilterFactory
+{
+public:
+
+ GrFmtFilterFactory();
+ virtual ~GrFmtFilterFactory() {};
+
+ const char* GetDescription() { return m_description; };
+ int GetSignatureLength() { return m_sign_len; };
+ virtual bool CheckFile( const char* filename );
+ virtual bool CheckSignature( const char* signature );
+ virtual bool CheckExtension( const char* filename );
+ virtual GrFmtReader* NewReader( const char* filename ) = 0;
+ virtual GrFmtWriter* NewWriter( const char* filename ) = 0;
+
+protected:
+ const char* m_description;
+ // graphic format description in form:
+ // <Some textual description>( *.<extension1> [; *.<extension2> ...]).
+ // the textual description can not contain symbols '(', ')'
+ // and may be, some others. It is safe to use letters, digits and spaces only.
+ // e.g. "Targa (*.tga)",
+ // or "Portable Graphic Format (*.pbm;*.pgm;*.ppm)"
+
+ int m_sign_len; // length of the signature of the format
+ const char* m_signature; // signature of the format
+};
+
+
+/////////////////////////// list of graphic format filters ///////////////////////////////
+
+typedef void* ListPosition;
+
+class GrFmtFactoriesList
+{
+public:
+
+ GrFmtFactoriesList();
+ virtual ~GrFmtFactoriesList();
+ void RemoveAll();
+ bool AddFactory( GrFmtFilterFactory* factory );
+ int FactoriesCount() { return m_curFactories; };
+ ListPosition GetFirstFactoryPos();
+ GrFmtFilterFactory* GetNextFactory( ListPosition& pos );
+ virtual GrFmtReader* FindReader( const char* filename );
+ virtual GrFmtWriter* FindWriter( const char* filename );
+
+protected:
+
+ GrFmtFilterFactory** m_factories;
+ int m_maxFactories;
+ int m_curFactories;
+};
+
+#endif/*_GRFMT_BASE_H_*/
diff --git a/otherlibs/highgui/grfmt_bmp.cpp b/otherlibs/highgui/grfmt_bmp.cpp
new file mode 100644
index 0000000..c67ed41
--- /dev/null
+++ b/otherlibs/highgui/grfmt_bmp.cpp
@@ -0,0 +1,551 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_highgui.h"
+#include "grfmt_bmp.h"
+
+static const char* fmtSignBmp = "BM";
+
+GrFmtBmp::GrFmtBmp()
+{
+ m_sign_len = 2;
+ m_signature = fmtSignBmp;
+ m_description = "Windows bitmap (*.bmp;*.dib)";
+}
+
+
+GrFmtBmp::~GrFmtBmp()
+{
+}
+
+
+GrFmtReader* GrFmtBmp::NewReader( const char* filename )
+{
+ return new GrFmtBmpReader( filename );
+}
+
+
+GrFmtWriter* GrFmtBmp::NewWriter( const char* filename )
+{
+ return new GrFmtBmpWriter( filename );
+}
+
+
+/************************ BMP reader *****************************/
+
+GrFmtBmpReader::GrFmtBmpReader( const char* filename ) : GrFmtReader( filename )
+{
+ m_offset = -1;
+}
+
+
+GrFmtBmpReader::~GrFmtBmpReader()
+{
+}
+
+
+void GrFmtBmpReader::Close()
+{
+ m_strm.Close();
+ GrFmtReader::Close();
+}
+
+
+bool GrFmtBmpReader::ReadHeader()
+{
+ bool result = false;
+
+ assert( strlen(m_filename) != 0 );
+ if( !m_strm.Open( m_filename )) return false;
+
+ if( setjmp( m_strm.JmpBuf()) == 0 )
+ {
+ m_strm.Skip( 10 );
+ m_offset = m_strm.GetDWord();
+
+ int size = m_strm.GetDWord();
+
+ if( size >= 36 )
+ {
+ m_width = m_strm.GetDWord();
+ m_height = m_strm.GetDWord();
+ m_bpp = m_strm.GetDWord() >> 16;
+ m_rle_code = (BmpCompression)m_strm.GetDWord();
+ m_strm.Skip(12);
+ int clrused = m_strm.GetDWord();
+ m_strm.Skip( size - 36 );
+
+ if( m_width > 0 && m_height > 0 &&
+ (((m_bpp == 1 || m_bpp == 4 || m_bpp == 8 ||
+ m_bpp == 24 || m_bpp == 32 ) && m_rle_code == BMP_RGB) ||
+ (m_bpp == 16 && (m_rle_code == BMP_RGB || m_rle_code == BMP_BITFIELDS)) ||
+ (m_bpp == 4 && m_rle_code == BMP_RLE4) ||
+ (m_bpp == 8 && m_rle_code == BMP_RLE8)))
+ {
+ m_iscolor = true;
+ result = true;
+
+ if( m_bpp <= 8 )
+ {
+ memset( m_palette, 0, sizeof(m_palette));
+ m_strm.GetBytes( m_palette, (clrused == 0? 1<<m_bpp : clrused)*4 );
+ m_iscolor = IsColorPalette( m_palette, m_bpp );
+ }
+ else if( m_bpp == 16 && m_rle_code == BMP_BITFIELDS )
+ {
+ int redmask = m_strm.GetDWord();
+ int greenmask = m_strm.GetDWord();
+ int bluemask = m_strm.GetDWord();
+
+ if( bluemask == 0x1f && greenmask == 0x3e0 && redmask == 0x7c00 )
+ m_bpp = 15;
+ else if( bluemask == 0x1f && greenmask == 0x7e0 && redmask == 0xf800 )
+ ;
+ else
+ result = false;
+ }
+ else if( m_bpp == 16 && m_rle_code == BMP_RGB )
+ m_bpp = 15;
+ }
+ }
+ else if( size == 12 )
+ {
+ m_width = m_strm.GetWord();
+ m_height = m_strm.GetWord();
+ m_bpp = m_strm.GetDWord() >> 16;
+ m_rle_code = BMP_RGB;
+
+ if( m_width > 0 && m_height > 0 &&
+ (m_bpp == 1 || m_bpp == 4 || m_bpp == 8 ||
+ m_bpp == 24 || m_bpp == 32 ))
+ {
+ if( m_bpp <= 8 )
+ {
+ uchar buffer[256*3];
+ int j, clrused = 1 << m_bpp;
+ m_strm.GetBytes( buffer, clrused*3 );
+ for( j = 0; j < clrused; j++ )
+ {
+ m_palette[j].b = buffer[3*j+0];
+ m_palette[j].g = buffer[3*j+1];
+ m_palette[j].r = buffer[3*j+2];
+ }
+ }
+ result = true;
+ }
+ }
+ }
+
+ if( !result )
+ {
+ m_offset = -1;
+ m_width = m_height = -1;
+ m_strm.Close();
+ }
+ return result;
+}
+
+
+bool GrFmtBmpReader::ReadData( uchar* data, int step, int color )
+{
+ const int buffer_size = 1 << 12;
+ uchar buffer[buffer_size];
+ uchar bgr_buffer[buffer_size];
+ uchar gray_palette[256];
+ bool result = false;
+ uchar* src = buffer;
+ uchar* bgr = bgr_buffer;
+ int src_pitch = ((m_width*(m_bpp != 15 ? m_bpp : 16) + 7)/8 + 3) & -4;
+ int nch = color ? 3 : 1;
+ int width3 = m_width*nch;
+ int y;
+
+ if( m_offset < 0 || !m_strm.IsOpened())
+ return false;
+
+ data += (m_height - 1)*step;
+ step = -step;
+
+ if( (m_bpp != 24 || !color) && src_pitch+32 > buffer_size )
+ src = new uchar[src_pitch+32];
+
+ if( !color )
+ {
+ if( m_bpp <= 8 )
+ {
+ CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp );
+ }
+ if( m_width*3 + 32 > buffer_size ) bgr = new uchar[m_width*3 + 32];
+ }
+
+ if( setjmp( m_strm.JmpBuf()) == 0 )
+ {
+ m_strm.SetPos( m_offset );
+
+ switch( m_bpp )
+ {
+ /************************* 1 BPP ************************/
+ case 1:
+ for( y = 0; y < m_height; y++, data += step )
+ {
+ m_strm.GetBytes( src, src_pitch );
+ FillColorRow1( color ? data : bgr, src, m_width, m_palette );
+ if( !color )
+ icvCvt_BGR2Gray_8u_C3C1R( bgr, 0, data, 0, cvSize(m_width,1) );
+ }
+ result = true;
+ break;
+
+ /************************* 4 BPP ************************/
+ case 4:
+ if( m_rle_code == BMP_RGB )
+ {
+ for( y = 0; y < m_height; y++, data += step )
+ {
+ m_strm.GetBytes( src, src_pitch );
+ if( color )
+ FillColorRow4( data, src, m_width, m_palette );
+ else
+ FillGrayRow4( data, src, m_width, gray_palette );
+ }
+ result = true;
+ }
+ else if( m_rle_code == BMP_RLE4 ) // rle4 compression
+ {
+ uchar* line_end = data + width3;
+ y = 0;
+
+ for(;;)
+ {
+ int code = m_strm.GetWord();
+ int len = code & 255;
+ code >>= 8;
+ if( len != 0 ) // encoded mode
+ {
+ PaletteEntry clr[2];
+ uchar gray_clr[2];
+ int t = 0;
+
+ clr[0] = m_palette[code >> 4];
+ clr[1] = m_palette[code & 15];
+ gray_clr[0] = gray_palette[code >> 4];
+ gray_clr[1] = gray_palette[code & 15];
+
+ uchar* end = data + len*nch;
+ if( end > line_end ) goto decode_rle4_bad;
+ do
+ {
+ if( color )
+ WRITE_PIX( data, clr[t] );
+ else
+ *data = gray_clr[t];
+ t ^= 1;
+ }
+ while( (data += nch) < end );
+ }
+ else if( code > 2 ) // absolute mode
+ {
+ if( data + code*nch > line_end ) goto decode_rle4_bad;
+ m_strm.GetBytes( src, (((code + 1)>>1) + 1) & -2 );
+ if( color )
+ data = FillColorRow4( data, src, code, m_palette );
+ else
+ data = FillGrayRow4( data, src, code, gray_palette );
+ }
+ else
+ {
+ int x_shift3 = (int)(line_end - data);
+ int y_shift = m_height - y;
+
+ if( code == 2 )
+ {
+ x_shift3 = m_strm.GetByte()*nch;
+ y_shift = m_strm.GetByte();
+ }
+
+ len = x_shift3 + (y_shift * width3) & ((code == 0) - 1);
+
+ if( color )
+ data = FillUniColor( data, line_end, step, width3,
+ y, m_height, x_shift3,
+ m_palette[0] );
+ else
+ data = FillUniGray( data, line_end, step, width3,
+ y, m_height, x_shift3,
+ gray_palette[0] );
+
+ if( y >= m_height )
+ break;
+ }
+ }
+
+ result = true;
+decode_rle4_bad: ;
+ }
+ break;
+
+ /************************* 8 BPP ************************/
+ case 8:
+ if( m_rle_code == BMP_RGB )
+ {
+ for( y = 0; y < m_height; y++, data += step )
+ {
+ m_strm.GetBytes( src, src_pitch );
+ if( color )
+ FillColorRow8( data, src, m_width, m_palette );
+ else
+ FillGrayRow8( data, src, m_width, gray_palette );
+ }
+ result = true;
+ }
+ else if( m_rle_code == BMP_RLE8 ) // rle8 compression
+ {
+ uchar* line_end = data + width3;
+ int line_end_flag = 0;
+ y = 0;
+
+ for(;;)
+ {
+ int code = m_strm.GetWord();
+ int len = code & 255;
+ code >>= 8;
+ if( len != 0 ) // encoded mode
+ {
+ int prev_y = y;
+ len *= nch;
+
+ if( data + len > line_end )
+ goto decode_rle8_bad;
+
+ if( color )
+ data = FillUniColor( data, line_end, step, width3,
+ y, m_height, len,
+ m_palette[code] );
+ else
+ data = FillUniGray( data, line_end, step, width3,
+ y, m_height, len,
+ gray_palette[code] );
+
+ line_end_flag = y - prev_y;
+ }
+ else if( code > 2 ) // absolute mode
+ {
+ int prev_y = y;
+ int code3 = code*nch;
+
+ if( data + code3 > line_end )
+ goto decode_rle8_bad;
+ m_strm.GetBytes( src, (code + 1) & -2 );
+ if( color )
+ data = FillColorRow8( data, src, code, m_palette );
+ else
+ data = FillGrayRow8( data, src, code, gray_palette );
+
+ line_end_flag = y - prev_y;
+ }
+ else
+ {
+ int x_shift3 = (int)(line_end - data);
+ int y_shift = m_height - y;
+
+ if( code || !line_end_flag || x_shift3 < width3 )
+ {
+ if( code == 2 )
+ {
+ x_shift3 = m_strm.GetByte()*nch;
+ y_shift = m_strm.GetByte();
+ }
+
+ x_shift3 += (y_shift * width3) & ((code == 0) - 1);
+
+ if( y >= m_height )
+ break;
+
+ if( color )
+ data = FillUniColor( data, line_end, step, width3,
+ y, m_height, x_shift3,
+ m_palette[0] );
+ else
+ data = FillUniGray( data, line_end, step, width3,
+ y, m_height, x_shift3,
+ gray_palette[0] );
+
+ if( y >= m_height )
+ break;
+ }
+
+ line_end_flag = 0;
+ }
+ }
+
+ result = true;
+decode_rle8_bad: ;
+ }
+ break;
+ /************************* 15 BPP ************************/
+ case 15:
+ for( y = 0; y < m_height; y++, data += step )
+ {
+ m_strm.GetBytes( src, src_pitch );
+ if( !color )
+ icvCvt_BGR5552Gray_8u_C2C1R( src, 0, data, 0, cvSize(m_width,1) );
+ else
+ icvCvt_BGR5552BGR_8u_C2C3R( src, 0, data, 0, cvSize(m_width,1) );
+ }
+ result = true;
+ break;
+ /************************* 16 BPP ************************/
+ case 16:
+ for( y = 0; y < m_height; y++, data += step )
+ {
+ m_strm.GetBytes( src, src_pitch );
+ if( !color )
+ icvCvt_BGR5652Gray_8u_C2C1R( src, 0, data, 0, cvSize(m_width,1) );
+ else
+ icvCvt_BGR5652BGR_8u_C2C3R( src, 0, data, 0, cvSize(m_width,1) );
+ }
+ result = true;
+ break;
+ /************************* 24 BPP ************************/
+ case 24:
+ for( y = 0; y < m_height; y++, data += step )
+ {
+ m_strm.GetBytes( color ? data : src, src_pitch );
+ if( !color )
+ icvCvt_BGR2Gray_8u_C3C1R( src, 0, data, 0, cvSize(m_width,1) );
+ }
+ result = true;
+ break;
+ /************************* 32 BPP ************************/
+ case 32:
+ for( y = 0; y < m_height; y++, data += step )
+ {
+ m_strm.GetBytes( src, src_pitch );
+
+ if( !color )
+ icvCvt_BGRA2Gray_8u_C4C1R( src, 0, data, 0, cvSize(m_width,1) );
+ else
+ icvCvt_BGRA2BGR_8u_C4C3R( src, 0, data, 0, cvSize(m_width,1) );
+ }
+ result = true;
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ if( src != buffer ) delete[] src;
+ if( bgr != bgr_buffer ) delete[] bgr;
+ return result;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+GrFmtBmpWriter::GrFmtBmpWriter( const char* filename ) : GrFmtWriter( filename )
+{
+}
+
+
+GrFmtBmpWriter::~GrFmtBmpWriter()
+{
+}
+
+
+bool GrFmtBmpWriter::WriteImage( const uchar* data, int step,
+ int width, int height, int /*depth*/, int channels )
+{
+ bool result = false;
+ int fileStep = (width*channels + 3) & -4;
+ uchar zeropad[] = "\0\0\0\0";
+
+ assert( data && width > 0 && height > 0 && step >= fileStep );
+
+ if( m_strm.Open( m_filename ) )
+ {
+ int bitmapHeaderSize = 40;
+ int paletteSize = channels > 1 ? 0 : 1024;
+ int headerSize = 14 /* fileheader */ + bitmapHeaderSize + paletteSize;
+ PaletteEntry palette[256];
+
+ // write signature 'BM'
+ m_strm.PutBytes( fmtSignBmp, (int)strlen(fmtSignBmp) );
+
+ // write file header
+ m_strm.PutDWord( fileStep*height + headerSize ); // file size
+ m_strm.PutDWord( 0 );
+ m_strm.PutDWord( headerSize );
+
+ // write bitmap header
+ m_strm.PutDWord( bitmapHeaderSize );
+ m_strm.PutDWord( width );
+ m_strm.PutDWord( height );
+ m_strm.PutWord( 1 );
+ m_strm.PutWord( channels << 3 );
+ m_strm.PutDWord( BMP_RGB );
+ m_strm.PutDWord( 0 );
+ m_strm.PutDWord( 0 );
+ m_strm.PutDWord( 0 );
+ m_strm.PutDWord( 0 );
+ m_strm.PutDWord( 0 );
+
+ if( channels == 1 )
+ {
+ FillGrayPalette( palette, 8 );
+ m_strm.PutBytes( palette, sizeof(palette));
+ }
+
+ width *= channels;
+ data += step*(height - 1);
+ for( ; height--; data -= step )
+ {
+ m_strm.PutBytes( data, width );
+ if( fileStep > width )
+ m_strm.PutBytes( zeropad, fileStep - width );
+ }
+
+ m_strm.Close();
+ result = true;
+ }
+ return result;
+}
+
+
diff --git a/otherlibs/highgui/grfmt_bmp.h b/otherlibs/highgui/grfmt_bmp.h
new file mode 100644
index 0000000..0bb154f
--- /dev/null
+++ b/otherlibs/highgui/grfmt_bmp.h
@@ -0,0 +1,107 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _GRFMT_BMP_H_
+#define _GRFMT_BMP_H_
+
+#include "grfmt_base.h"
+
+enum BmpCompression
+{
+ BMP_RGB = 0,
+ BMP_RLE8 = 1,
+ BMP_RLE4 = 2,
+ BMP_BITFIELDS = 3
+};
+
+
+// Windows Bitmap reader
+class GrFmtBmpReader : public GrFmtReader
+{
+public:
+
+ GrFmtBmpReader( const char* filename );
+ ~GrFmtBmpReader();
+
+ bool ReadData( uchar* data, int step, int color );
+ bool ReadHeader();
+ void Close();
+
+protected:
+
+ RLByteStream m_strm;
+ PaletteEntry m_palette[256];
+ int m_bpp;
+ int m_offset;
+ BmpCompression m_rle_code;
+};
+
+
+// ... writer
+class GrFmtBmpWriter : public GrFmtWriter
+{
+public:
+
+ GrFmtBmpWriter( const char* filename );
+ ~GrFmtBmpWriter();
+
+ bool WriteImage( const uchar* data, int step,
+ int width, int height, int depth, int channels );
+protected:
+
+ WLByteStream m_strm;
+};
+
+
+// ... and filter factory
+class GrFmtBmp : public GrFmtFilterFactory
+{
+public:
+
+ GrFmtBmp();
+ ~GrFmtBmp();
+
+ GrFmtReader* NewReader( const char* filename );
+ GrFmtWriter* NewWriter( const char* filename );
+
+};
+
+#endif/*_GRFMT_BMP_H_*/
diff --git a/otherlibs/highgui/grfmt_exr.cpp b/otherlibs/highgui/grfmt_exr.cpp
new file mode 100644
index 0000000..6d013d6
--- /dev/null
+++ b/otherlibs/highgui/grfmt_exr.cpp
@@ -0,0 +1,737 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_highgui.h"
+
+#ifdef HAVE_ILMIMF
+
+#include <OpenEXR/ImfHeader.h>
+#include <OpenEXR/ImfInputFile.h>
+#include <OpenEXR/ImfOutputFile.h>
+#include <OpenEXR/ImfChannelList.h>
+#include <OpenEXR/ImfStandardAttributes.h>
+#include <OpenEXR/half.h>
+#include "grfmt_exr.h"
+
+#if defined _MSC_VER && _MSC_VER >= 1200
+#pragma comment(lib, "Half.lib")
+#pragma comment(lib, "Iex.lib")
+#pragma comment(lib, "IlmImf.lib")
+#pragma comment(lib, "IlmThread.lib")
+#pragma comment(lib, "Imath.lib")
+
+#undef UINT
+#define UINT ((Imf::PixelType)0)
+#undef HALF
+#define HALF ((Imf::PixelType)1)
+#undef FLOAT
+#define FLOAT ((Imf::PixelType)2)
+#undef uint
+#define uint unsigned
+
+#endif
+
+// Exr Filter Factory
+GrFmtExr::GrFmtExr()
+{
+ m_sign_len = 4;
+ m_signature = "\x76\x2f\x31\x01";
+ m_description = "OpenEXR Image files (*.exr)";
+}
+
+
+GrFmtExr::~GrFmtExr()
+{
+}
+
+
+GrFmtReader* GrFmtExr::NewReader( const char* filename )
+{
+ return new GrFmtExrReader( filename );
+}
+
+
+GrFmtWriter* GrFmtExr::NewWriter( const char* filename )
+{
+ return new GrFmtExrWriter( filename );
+}
+
+
+/////////////////////// GrFmtExrReader ///////////////////
+
+GrFmtExrReader::GrFmtExrReader( const char* filename ) : GrFmtReader( filename )
+{
+ m_file = new InputFile( filename );
+ m_red = m_green = m_blue = 0;
+}
+
+
+GrFmtExrReader::~GrFmtExrReader()
+{
+ Close();
+}
+
+
+void GrFmtExrReader::Close()
+{
+ if( m_file )
+ {
+ delete m_file;
+ m_file = 0;
+ }
+
+ GrFmtReader::Close();
+}
+
+bool GrFmtExrReader::ReadHeader()
+{
+ bool result = false;
+
+ if( !m_file ) // probably paranoid
+ return false;
+
+ m_datawindow = m_file->header().dataWindow();
+ m_width = m_datawindow.max.x - m_datawindow.min.x + 1;
+ m_height = m_datawindow.max.y - m_datawindow.min.y + 1;
+
+ // the type HALF is converted to 32 bit float
+ // and the other types supported by OpenEXR are 32 bit anyway
+ m_bit_depth = 32;
+
+ if( hasChromaticities( m_file->header() ))
+ m_chroma = chromaticities( m_file->header() );
+
+ const ChannelList &channels = m_file->header().channels();
+ m_red = channels.findChannel( "R" );
+ m_green = channels.findChannel( "G" );
+ m_blue = channels.findChannel( "B" );
+ if( m_red || m_green || m_blue )
+ {
+ m_iscolor = true;
+ m_ischroma = false;
+ result = true;
+ }
+ else
+ {
+ m_green = channels.findChannel( "Y" );
+ if( m_green )
+ {
+ m_ischroma = true;
+ m_red = channels.findChannel( "RY" );
+ m_blue = channels.findChannel( "BY" );
+ m_iscolor = (m_blue || m_red);
+ result = true;
+ }
+ else
+ result = false;
+ }
+
+ if( result )
+ {
+ int uintcnt = 0;
+ int chcnt = 0;
+ if( m_red )
+ {
+ chcnt++;
+ uintcnt += ( m_red->type == UINT );
+ }
+ if( m_green )
+ {
+ chcnt++;
+ uintcnt += ( m_green->type == UINT );
+ }
+ if( m_blue )
+ {
+ chcnt++;
+ uintcnt += ( m_blue->type == UINT );
+ }
+ m_type = (chcnt == uintcnt) ? UINT : FLOAT;
+
+ m_isfloat = (m_type == FLOAT);
+ }
+
+ if( !result )
+ Close();
+
+ return result;
+}
+
+
+bool GrFmtExrReader::ReadData( uchar* data, int step, int color )
+{
+ bool justcopy = m_native_depth;
+ bool chromatorgb = false;
+ bool rgbtogray = false;
+ bool result = true;
+ FrameBuffer frame;
+ int xsample[3] = {1, 1, 1};
+ char *buffer;
+ int xstep;
+ int ystep;
+
+ xstep = m_native_depth ? 4 : 1;
+
+ if( !m_native_depth || (!color && m_iscolor ))
+ {
+ buffer = (char *)new float[ m_width * 3 ];
+ ystep = 0;
+ }
+ else
+ {
+ buffer = (char *)data;
+ ystep = step;
+ }
+
+ if( m_ischroma )
+ {
+ if( color )
+ {
+ if( m_iscolor )
+ {
+ if( m_blue )
+ {
+ frame.insert( "BY", Slice( m_type,
+ buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
+ 12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));
+ xsample[0] = m_blue->ySampling;
+ }
+ if( m_green )
+ {
+ frame.insert( "Y", Slice( m_type,
+ buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
+ 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
+ xsample[1] = m_green->ySampling;
+ }
+ if( m_red )
+ {
+ frame.insert( "RY", Slice( m_type,
+ buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
+ 12, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));
+ xsample[2] = m_red->ySampling;
+ }
+ chromatorgb = true;
+ }
+ else
+ {
+ frame.insert( "Y", Slice( m_type,
+ buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
+ 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
+ frame.insert( "Y", Slice( m_type,
+ buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
+ 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
+ frame.insert( "Y", Slice( m_type,
+ buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
+ 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
+ xsample[0] = m_green->ySampling;
+ xsample[1] = m_green->ySampling;
+ xsample[2] = m_green->ySampling;
+ }
+ }
+ else
+ {
+ frame.insert( "Y", Slice( m_type,
+ buffer - m_datawindow.min.x * 4 - m_datawindow.min.y * ystep,
+ 4, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
+ xsample[0] = m_green->ySampling;
+ }
+ }
+ else
+ {
+ if( m_blue )
+ {
+ frame.insert( "B", Slice( m_type,
+ buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep,
+ 12, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));
+ xsample[0] = m_blue->ySampling;
+ }
+ if( m_green )
+ {
+ frame.insert( "G", Slice( m_type,
+ buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 4,
+ 12, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
+ xsample[1] = m_green->ySampling;
+ }
+ if( m_red )
+ {
+ frame.insert( "R", Slice( m_type,
+ buffer - m_datawindow.min.x * 12 - m_datawindow.min.y * ystep + 8,
+ 12, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));
+ xsample[2] = m_red->ySampling;
+ }
+ if(color == 0)
+ {
+ rgbtogray = true;
+ justcopy = false;
+ }
+ }
+
+ m_file->setFrameBuffer( frame );
+ if( justcopy )
+ {
+ m_file->readPixels( m_datawindow.min.y, m_datawindow.max.y );
+
+ if( color )
+ {
+ if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
+ UpSample( data, 3, step / xstep, xsample[0], m_blue->ySampling );
+ if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
+ UpSample( data + xstep, 3, step / xstep, xsample[1], m_green->ySampling );
+ if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
+ UpSample( data + 2 * xstep, 3, step / xstep, xsample[2], m_red->ySampling );
+ }
+ else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
+ UpSample( data, 1, step / xstep, xsample[0], m_green->ySampling );
+ }
+ else
+ {
+ uchar *out = data;
+ int x, y;
+ for( y = m_datawindow.min.y; y <= m_datawindow.max.y; y++ )
+ {
+ m_file->readPixels( y, y );
+
+ if( rgbtogray )
+ {
+ if( xsample[0] != 1 )
+ UpSampleX( (float *)buffer, 3, xsample[0] );
+ if( xsample[1] != 1 )
+ UpSampleX( (float *)buffer + 4, 3, xsample[1] );
+ if( xsample[2] != 1 )
+ UpSampleX( (float *)buffer + 8, 3, xsample[2] );
+
+ RGBToGray( (float *)buffer, (float *)out );
+ }
+ else
+ {
+ if( xsample[0] != 1 )
+ UpSampleX( (float *)buffer, 3, xsample[0] );
+ if( xsample[1] != 1 )
+ UpSampleX( (float *)(buffer + 4), 3, xsample[1] );
+ if( xsample[2] != 1 )
+ UpSampleX( (float *)(buffer + 8), 3, xsample[2] );
+
+ if( chromatorgb )
+ ChromaToBGR( (float *)buffer, 1, step );
+
+ if( m_type == FLOAT )
+ {
+ float *fi = (float *)buffer;
+ for( x = 0; x < m_width * 3; x++)
+ {
+ int t = cvRound(fi[x]*5);
+ out[x] = CV_CAST_8U(t);
+ }
+ }
+ else
+ {
+ uint *ui = (uint *)buffer;
+ for( x = 0; x < m_width * 3; x++)
+ {
+ uint t = ui[x];
+ out[x] = CV_CAST_8U(t);
+ }
+ }
+ }
+
+ out += step;
+ }
+ if( color )
+ {
+ if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
+ UpSampleY( data, 3, step / xstep, m_blue->ySampling );
+ if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
+ UpSampleY( data + xstep, 3, step / xstep, m_green->ySampling );
+ if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
+ UpSampleY( data + 2 * xstep, 3, step / xstep, m_red->ySampling );
+ }
+ else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
+ UpSampleY( data, 1, step / xstep, m_green->ySampling );
+ }
+
+ if( chromatorgb )
+ ChromaToBGR( (float *)data, m_height, step / xstep );
+
+ Close();
+
+ return result;
+}
+
+/**
+// on entry pixel values are stored packed in the upper left corner of the image
+// this functions expands them by duplication to cover the whole image
+ */
+void GrFmtExrReader::UpSample( uchar *data, int xstep, int ystep, int xsample, int ysample )
+{
+ for( int y = (m_height - 1) / ysample, yre = m_height - ysample; y >= 0; y--, yre -= ysample )
+ {
+ for( int x = (m_width - 1) / xsample, xre = m_width - xsample; x >= 0; x--, xre -= xsample )
+ {
+ for( int i = 0; i < ysample; i++ )
+ {
+ for( int n = 0; n < xsample; n++ )
+ {
+ if( !m_native_depth )
+ data[(yre + i) * ystep + (xre + n) * xstep] = data[y * ystep + x * xstep];
+ else if( m_type == FLOAT )
+ ((float *)data)[(yre + i) * ystep + (xre + n) * xstep] = ((float *)data)[y * ystep + x * xstep];
+ else
+ ((uint *)data)[(yre + i) * ystep + (xre + n) * xstep] = ((uint *)data)[y * ystep + x * xstep];
+ }
+ }
+ }
+ }
+}
+
+/**
+// on entry pixel values are stored packed in the upper left corner of the image
+// this functions expands them by duplication to cover the whole image
+ */
+void GrFmtExrReader::UpSampleX( float *data, int xstep, int xsample )
+{
+ for( int x = (m_width - 1) / xsample, xre = m_width - xsample; x >= 0; x--, xre -= xsample )
+ {
+ for( int n = 0; n < xsample; n++ )
+ {
+ if( m_type == FLOAT )
+ ((float *)data)[(xre + n) * xstep] = ((float *)data)[x * xstep];
+ else
+ ((uint *)data)[(xre + n) * xstep] = ((uint *)data)[x * xstep];
+ }
+ }
+}
+
+/**
+// on entry pixel values are stored packed in the upper left corner of the image
+// this functions expands them by duplication to cover the whole image
+ */
+void GrFmtExrReader::UpSampleY( uchar *data, int xstep, int ystep, int ysample )
+{
+ for( int y = m_height - ysample, yre = m_height - ysample; y >= 0; y -= ysample, yre -= ysample )
+ {
+ for( int x = 0; x < m_width; x++ )
+ {
+ for( int i = 1; i < ysample; i++ )
+ {
+ if( !m_native_depth )
+ data[(yre + i) * ystep + x * xstep] = data[y * ystep + x * xstep];
+ else if( m_type == FLOAT )
+ ((float *)data)[(yre + i) * ystep + x * xstep] = ((float *)data)[y * ystep + x * xstep];
+ else
+ ((uint *)data)[(yre + i) * ystep + x * xstep] = ((uint *)data)[y * ystep + x * xstep];
+ }
+ }
+ }
+}
+
+/**
+// algorithm from ImfRgbaYca.cpp
+ */
+void GrFmtExrReader::ChromaToBGR( float *data, int numlines, int step )
+{
+ int x, y, t;
+
+ for( y = 0; y < numlines; y++ )
+ {
+ for( x = 0; x < m_width; x++ )
+ {
+ double b, Y, r;
+ if( !m_native_depth )
+ {
+ b = ((uchar *)data)[y * step + x * 3];
+ Y = ((uchar *)data)[y * step + x * 3 + 1];
+ r = ((uchar *)data)[y * step + x * 3 + 2];
+ }
+ else if( m_type == FLOAT )
+ {
+ b = data[y * step + x * 3];
+ Y = data[y * step + x * 3 + 1];
+ r = data[y * step + x * 3 + 2];
+ }
+ else
+ {
+ b = ((uint *)data)[y * step + x * 3];
+ Y = ((uint *)data)[y * step + x * 3 + 1];
+ r = ((uint *)data)[y * step + x * 3 + 2];
+ }
+ r = (r + 1) * Y;
+ b = (b + 1) * Y;
+ Y = (Y - b * m_chroma.blue[1] - r * m_chroma.red[1]) / m_chroma.green[1];
+
+ if( !m_native_depth )
+ {
+ int t = cvRound(b);
+ ((uchar *)data)[y * step + x * 3] = CV_CAST_8U(t);
+ t = cvRound(Y);
+ ((uchar *)data)[y * step + x * 3 + 1] = CV_CAST_8U(t);
+ t = cvRound(r);
+ ((uchar *)data)[y * step + x * 3 + 2] = CV_CAST_8U(t);
+ }
+ else if( m_type == FLOAT )
+ {
+ data[y * step + x * 3] = (float)b;
+ data[y * step + x * 3 + 1] = (float)Y;
+ data[y * step + x * 3 + 2] = (float)r;
+ }
+ else
+ {
+ int t = cvRound(b);
+ ((uint *)data)[y * step + x * 3] = (uint)MAX(t,0);
+ t = cvRound(Y);
+ ((uint *)data)[y * step + x * 3 + 1] = (uint)MAX(t,0);
+ t = cvRound(r);
+ ((uint *)data)[y * step + x * 3 + 2] = (uint)MAX(t,0);
+ }
+ }
+ }
+}
+
+
+/**
+// convert one row to gray
+*/
+void GrFmtExrReader::RGBToGray( float *in, float *out )
+{
+ if( m_type == FLOAT )
+ {
+ if( m_native_depth )
+ {
+ for( int i = 0, n = 0; i < m_width; i++, n += 3 )
+ out[i] = in[n] * m_chroma.blue[0] + in[n + 1] * m_chroma.green[0] + in[n + 2] * m_chroma.red[0];
+ }
+ else
+ {
+ uchar *o = (uchar *)out;
+ for( int i = 0, n = 0; i < m_width; i++, n += 3 )
+ o[i] = (uchar) (in[n] * m_chroma.blue[0] + in[n + 1] * m_chroma.green[0] + in[n + 2] * m_chroma.red[0]);
+ }
+ }
+ else // UINT
+ {
+ if( m_native_depth )
+ {
+ uint *ui = (uint *)in;
+ for( int i = 0; i < m_width * 3; i++ )
+ ui[i] -= 0x80000000;
+ int *si = (int *)in;
+ for( int i = 0, n = 0; i < m_width; i++, n += 3 )
+ ((int *)out)[i] = int(si[n] * m_chroma.blue[0] + si[n + 1] * m_chroma.green[0] + si[n + 2] * m_chroma.red[0]);
+ }
+ else // how to best convert float to uchar?
+ {
+ uint *ui = (uint *)in;
+ for( int i = 0, n = 0; i < m_width; i++, n += 3 )
+ ((uchar *)out)[i] = uchar((ui[n] * m_chroma.blue[0] + ui[n + 1] * m_chroma.green[0] + ui[n + 2] * m_chroma.red[0]) * (256.0 / 4294967296.0));
+ }
+ }
+}
+
+/////////////////////// GrFmtExrWriter ///////////////////
+
+
+GrFmtExrWriter::GrFmtExrWriter( const char* filename ) : GrFmtWriter( filename )
+{
+}
+
+
+GrFmtExrWriter::~GrFmtExrWriter()
+{
+}
+
+
+bool GrFmtExrWriter::IsFormatSupported( int depth )
+{
+ return depth == IPL_DEPTH_8U || depth == IPL_DEPTH_8S ||
+ depth == IPL_DEPTH_16U || depth == IPL_DEPTH_16S ||
+ depth == IPL_DEPTH_32S || depth == IPL_DEPTH_32F;
+ // TODO: do (or should) we support 64f?
+}
+
+
+// TODO scale appropriately
+bool GrFmtExrWriter::WriteImage( const uchar* data, int step,
+ int width, int height, int depth, int channels )
+{
+ bool result = false;
+
+ Header header( width, height );
+ PixelType type;
+ bool issigned = depth < 0;
+ bool isfloat = depth == IPL_DEPTH_32F || depth == IPL_DEPTH_64F;
+
+ if(depth == IPL_DEPTH_8U || depth == IPL_DEPTH_8S)
+ type = HALF;
+ else if(isfloat)
+ type = FLOAT;
+ else
+ type = UINT;
+
+ depth &= 255;
+
+ if( channels == 3 )
+ {
+ header.channels().insert( "R", Channel( type ));
+ header.channels().insert( "G", Channel( type ));
+ header.channels().insert( "B", Channel( type ));
+ //printf("bunt\n");
+ }
+ else
+ {
+ header.channels().insert( "Y", Channel( type ));
+ //printf("gray\n");
+ }
+
+ OutputFile file( m_filename, header );
+
+ FrameBuffer frame;
+
+ char *buffer;
+ int bufferstep;
+ int size;
+ if( type == FLOAT && depth == 32 )
+ {
+ buffer = (char *)const_cast<uchar *>(data);
+ bufferstep = step;
+ size = 4;
+ }
+ else if( depth > 16 || type == UINT )
+ {
+ buffer = (char *)new uint[width * channels];
+ bufferstep = 0;
+ size = 4;
+ }
+ else
+ {
+ buffer = (char *)new half[width * channels];
+ bufferstep = 0;
+ size = 2;
+ }
+
+ //printf("depth %d %s\n", depth, types[type]);
+
+ if( channels == 3 )
+ {
+ frame.insert( "B", Slice( type, buffer, size * 3, bufferstep ));
+ frame.insert( "G", Slice( type, buffer + size, size * 3, bufferstep ));
+ frame.insert( "R", Slice( type, buffer + size * 2, size * 3, bufferstep ));
+ }
+ else
+ frame.insert( "Y", Slice( type, buffer, size, bufferstep ));
+
+ file.setFrameBuffer( frame );
+
+ int offset = issigned ? 1 << (depth - 1) : 0;
+
+ result = true;
+ if( type == FLOAT && depth == 32 )
+ {
+ try
+ {
+ file.writePixels( height );
+ }
+ catch(...)
+ {
+ result = false;
+ }
+ }
+ else
+ {
+ // int scale = 1 << (32 - depth);
+ // printf("scale %d\n", scale);
+ for(int line = 0; line < height; line++)
+ {
+ if(type == UINT)
+ {
+ uint *buf = (uint *)buffer; // FIXME 64-bit problems
+
+ if( depth <= 8 )
+ {
+ for(int i = 0; i < width * channels; i++)
+ buf[i] = data[i] + offset;
+ }
+ else if( depth <= 16 )
+ {
+ unsigned short *sd = (unsigned short *)data;
+ for(int i = 0; i < width * channels; i++)
+ buf[i] = sd[i] + offset;
+ }
+ else
+ {
+ int *sd = (int *)data; // FIXME 64-bit problems
+ for(int i = 0; i < width * channels; i++)
+ buf[i] = (uint) sd[i] + offset;
+ }
+ }
+ else
+ {
+ half *buf = (half *)buffer;
+
+ if( depth <= 8 )
+ {
+ for(int i = 0; i < width * channels; i++)
+ buf[i] = data[i];
+ }
+ else if( depth <= 16 )
+ {
+ unsigned short *sd = (unsigned short *)data;
+ for(int i = 0; i < width * channels; i++)
+ buf[i] = sd[i];
+ }
+ }
+ try
+ {
+ file.writePixels( 1 );
+ }
+ catch(...)
+ {
+ result = false;
+ break;
+ }
+ data += step;
+ }
+ delete buffer;
+ }
+
+ return result;
+}
+
+#endif
+
+/* End of file. */
diff --git a/otherlibs/highgui/grfmt_exr.h b/otherlibs/highgui/grfmt_exr.h
new file mode 100644
index 0000000..f7ec773
--- /dev/null
+++ b/otherlibs/highgui/grfmt_exr.h
@@ -0,0 +1,116 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _GRFMT_EXR_H_
+#define _GRFMT_EXR_H_
+
+#ifdef HAVE_ILMIMF
+
+#include <ImfChromaticities.h>
+#include <ImfInputFile.h>
+#include <ImfChannelList.h>
+#include <ImathBox.h>
+#include "grfmt_base.h"
+
+using namespace Imf;
+using namespace Imath;
+
+/* libpng version only */
+
+class GrFmtExrReader : public GrFmtReader
+{
+public:
+
+ GrFmtExrReader( const char* filename );
+ ~GrFmtExrReader();
+
+ bool ReadData( uchar* data, int step, int color );
+ bool ReadHeader();
+ void Close();
+
+protected:
+ void UpSample( uchar *data, int xstep, int ystep, int xsample, int ysample );
+ void UpSampleX( float *data, int xstep, int xsample );
+ void UpSampleY( uchar *data, int xstep, int ystep, int ysample );
+ void ChromaToBGR( float *data, int numlines, int step );
+ void RGBToGray( float *in, float *out );
+
+ InputFile *m_file;
+ PixelType m_type;
+ Box2i m_datawindow;
+ bool m_ischroma;
+ const Channel *m_red;
+ const Channel *m_green;
+ const Channel *m_blue;
+ Chromaticities m_chroma;
+};
+
+
+class GrFmtExrWriter : public GrFmtWriter
+{
+public:
+
+ GrFmtExrWriter( const char* filename );
+ ~GrFmtExrWriter();
+
+ bool IsFormatSupported( int depth );
+ bool WriteImage( const uchar* data, int step,
+ int width, int height, int depth, int channels );
+protected:
+};
+
+
+// Exr filter factory
+class GrFmtExr : public GrFmtFilterFactory
+{
+public:
+
+ GrFmtExr();
+ ~GrFmtExr();
+
+ GrFmtReader* NewReader( const char* filename );
+ GrFmtWriter* NewWriter( const char* filename );
+// bool CheckSignature( const char* signature );
+};
+
+#endif
+
+#endif/*_GRFMT_EXR_H_*/
diff --git a/otherlibs/highgui/grfmt_imageio.cpp b/otherlibs/highgui/grfmt_imageio.cpp
new file mode 100644
index 0000000..92cd917
--- /dev/null
+++ b/otherlibs/highgui/grfmt_imageio.cpp
@@ -0,0 +1,396 @@
+/*
+ * grfmt_imageio.cpp
+ *
+ *
+ * Created by Morgan Conbere on 5/17/07.
+ *
+ */
+
+#include "_highgui.h"
+
+#ifdef HAVE_IMAGEIO
+
+#include "grfmt_imageio.h"
+#include <iostream>
+using namespace std;
+
+// ImageIO filter factory
+
+GrFmtImageIO::GrFmtImageIO()
+{
+ m_sign_len = 0;
+ m_signature = NULL;
+ m_description = "Apple ImageIO (*.bmp;*.dib;*.exr;*.jpeg;*.jpg;*.jpe;*.jp2;*.pdf;*.png;*.tiff;*.tif)";
+}
+
+
+GrFmtImageIO::~GrFmtImageIO()
+{
+}
+
+
+bool GrFmtImageIO::CheckFile( const char* filename )
+{
+ if( !filename ) return false;
+
+ // If a CFImageRef can be retrieved from an image file, it is
+ // readable by ImageIO. Effectively this is using ImageIO
+ // to check the signatures and determine the file format for us.
+ CFURLRef imageURLRef = CFURLCreateFromFileSystemRepresentation( NULL,
+ (const UInt8*)filename,
+ strlen( filename ),
+ false );
+ if( !imageURLRef ) return false;
+
+ CGImageSourceRef sourceRef = CGImageSourceCreateWithURL( imageURLRef, NULL );
+ CFRelease( imageURLRef );
+ if( !sourceRef ) return false;
+
+ CGImageRef imageRef = CGImageSourceCreateImageAtIndex( sourceRef, 0, NULL );
+ CFRelease( sourceRef );
+ if( !imageRef ) return false;
+
+ return true;
+}
+
+
+GrFmtReader* GrFmtImageIO::NewReader( const char* filename )
+{
+ return new GrFmtImageIOReader( filename );
+}
+
+
+GrFmtWriter* GrFmtImageIO::NewWriter( const char* filename )
+{
+ return new GrFmtImageIOWriter( filename );
+}
+
+
+/////////////////////// GrFmtImageIOReader ///////////////////
+
+GrFmtImageIOReader::GrFmtImageIOReader( const char* filename ) : GrFmtReader( filename )
+{
+ // Nothing to do here
+}
+
+
+GrFmtImageIOReader::~GrFmtImageIOReader()
+{
+ Close();
+}
+
+
+void GrFmtImageIOReader::Close()
+{
+ CGImageRelease( imageRef );
+
+ GrFmtReader::Close();
+}
+
+
+bool GrFmtImageIOReader::ReadHeader()
+{
+ CFURLRef imageURLRef;
+ CGImageSourceRef sourceRef;
+ imageRef = NULL;
+
+ imageURLRef = CFURLCreateFromFileSystemRepresentation( NULL,
+ (const UInt8*)m_filename,
+ strlen(m_filename),
+ false );
+
+ sourceRef = CGImageSourceCreateWithURL( imageURLRef, NULL );
+ CFRelease( imageURLRef );
+ if ( !sourceRef )
+ return false;
+
+ imageRef = CGImageSourceCreateImageAtIndex( sourceRef, 0, NULL );
+ CFRelease( sourceRef );
+ if( !imageRef )
+ return false;
+
+ m_width = CGImageGetWidth( imageRef );
+ m_height = CGImageGetHeight( imageRef );
+
+ CGColorSpaceRef colorSpace = CGImageGetColorSpace( imageRef );
+ if( !colorSpace )
+ return false;
+
+ m_iscolor = ( CGColorSpaceGetNumberOfComponents( colorSpace ) > 1 );
+
+ return true;
+}
+
+
+bool GrFmtImageIOReader::ReadData( uchar* data, int step, int color )
+{
+ int bpp; // Bytes per pixel
+
+ // Set color to either CV_IMAGE_LOAD_COLOR or CV_IMAGE_LOAD_GRAYSCALE if unchanged
+ color = color > 0 || ( m_iscolor && color < 0 );
+
+ // Get Height, Width, and color information
+ if( !ReadHeader() )
+ return false;
+
+ CGContextRef context = NULL; // The bitmap context
+ CGColorSpaceRef colorSpace = NULL;
+ uchar* bitmap = NULL;
+ CGImageAlphaInfo alphaInfo;
+
+ // CoreGraphics will take care of converting to grayscale and back as long as the
+ // appropriate colorspace is set
+ if( color == CV_LOAD_IMAGE_GRAYSCALE )
+ {
+ colorSpace = CGColorSpaceCreateDeviceGray();
+ bpp = 1;
+ alphaInfo = kCGImageAlphaNone;
+ }
+ else if( color == CV_LOAD_IMAGE_COLOR )
+ {
+ colorSpace = CGColorSpaceCreateDeviceRGB();
+ bpp = 4; /* CG only has 8 and 32 bit color spaces, so we waste a byte */
+ alphaInfo = kCGImageAlphaNoneSkipLast;
+ }
+ if( !colorSpace )
+ return false;
+
+ bitmap = (uchar*)malloc( bpp * m_height * m_width );
+ if( !bitmap )
+ {
+ CGColorSpaceRelease( colorSpace );
+ return false;
+ }
+
+ context = CGBitmapContextCreate( (void *)bitmap,
+ m_width, /* width */
+ m_height, /* height */
+ m_bit_depth, /* bit depth */
+ bpp * m_width, /* bytes per row */
+ colorSpace, /* color space */
+ alphaInfo);
+
+ CGColorSpaceRelease( colorSpace );
+ if( !context )
+ {
+ free( bitmap );
+ return false;
+ }
+
+ // Copy the image data into the bitmap region
+ CGRect rect = {{0,0},{m_width,m_height}};
+ CGContextDrawImage( context, rect, imageRef );
+
+ uchar* bitdata = (uchar*)CGBitmapContextGetData( context );
+ if( !bitdata )
+ {
+ free( bitmap);
+ CGContextRelease( context );
+ return false;
+ }
+
+ // Move the bitmap (in RGB) into data (in BGR)
+ int bitmapIndex = 0;
+
+ if( color == CV_LOAD_IMAGE_COLOR )
+ {
+ uchar * base = data;
+
+ for (int y = 0; y < m_height; y++)
+ {
+ uchar * line = base + y * step;
+
+ for (int x = 0; x < m_width; x++)
+ {
+ // Blue channel
+ line[0] = bitdata[bitmapIndex + 2];
+ // Green channel
+ line[1] = bitdata[bitmapIndex + 1];
+ // Red channel
+ line[2] = bitdata[bitmapIndex + 0];
+
+ line += 3;
+ bitmapIndex += bpp;
+ }
+ }
+ }
+ else if( color == CV_LOAD_IMAGE_GRAYSCALE )
+ {
+ for (int y = 0; y < m_height; y++)
+ memcpy (data + y * step, bitmap + y * m_width, m_width);
+ }
+
+ free( bitmap );
+ CGContextRelease( context );
+ return true;
+}
+
+
+/////////////////////// GrFmtImageIOWriter ///////////////////
+
+GrFmtImageIOWriter::GrFmtImageIOWriter( const char* filename ) : GrFmtWriter( filename )
+{
+ // Nothing to do here
+}
+
+
+GrFmtImageIOWriter::~GrFmtImageIOWriter()
+{
+ // Nothing to do here
+}
+
+
+static
+CFStringRef FilenameToUTI( const char* filename )
+{
+ const char* ext = filename;
+ for(;;)
+ {
+ const char* temp = strchr( ext + 1, '.' );
+ if( !temp ) break;
+ ext = temp;
+ }
+
+ CFStringRef imageUTI = NULL;
+
+ if( !strcmp(ext, ".bmp") || !strcmp(ext, ".dib") )
+ imageUTI = CFSTR( "com.microsoft.bmp" );
+ else if( !strcmp(ext, ".exr") )
+ imageUTI = CFSTR( "com.ilm.openexr-image" );
+ else if( !strcmp(ext, ".jpeg") || !strcmp(ext, ".jpg") || !strcmp(ext, ".jpe") )
+ imageUTI = CFSTR( "public.jpeg" );
+ else if( !strcmp(ext, ".jp2") )
+ imageUTI = CFSTR( "public.jpeg-2000" );
+ else if( !strcmp(ext, ".pdf") )
+ imageUTI = CFSTR( "com.adobe.pdf" );
+ else if( !strcmp(ext, ".png") )
+ imageUTI = CFSTR( "public.png" );
+ else if( !strcmp(ext, ".tiff") || !strcmp(ext, ".tif") )
+ imageUTI = CFSTR( "public.tiff" );
+
+ return imageUTI;
+}
+
+
+bool GrFmtImageIOWriter::WriteImage( const uchar* data, int step,
+ int width, int height, int /*depth*/, int _channels )
+{
+ // Determine the appropriate UTI based on the filename extension
+ CFStringRef imageUTI = FilenameToUTI( m_filename );
+
+ // Determine the Bytes Per Pixel
+ int bpp = (_channels == 1) ? 1 : 4;
+
+ // Write the data into a bitmap context
+ CGContextRef context;
+ CGColorSpaceRef colorSpace;
+ uchar* bitmapData = NULL;
+
+ if( bpp == 1 )
+ colorSpace = CGColorSpaceCreateWithName( kCGColorSpaceGenericGray );
+ else if( bpp == 4 )
+ colorSpace = CGColorSpaceCreateWithName( kCGColorSpaceGenericRGB );
+ if( !colorSpace )
+ return false;
+
+ bitmapData = (uchar*)malloc( bpp * height * width );
+ if( !bitmapData )
+ {
+ CGColorSpaceRelease( colorSpace );
+ return false;
+ }
+
+ context = CGBitmapContextCreate( bitmapData,
+ width,
+ height,
+ 8,
+ bpp * width,
+ colorSpace,
+ (bpp == 1) ? kCGImageAlphaNone :
+ kCGImageAlphaNoneSkipLast );
+ CGColorSpaceRelease( colorSpace );
+ if( !context )
+ {
+ free( bitmapData );
+ return false;
+ }
+
+ // Copy pixel information from data into bitmapData
+ if (bpp == 4)
+ {
+ int bitmapIndex = 0;
+ const uchar * base = data;
+
+ for (int y = 0; y < height; y++)
+ {
+ const uchar * line = base + y * step;
+
+ for (int x = 0; x < width; x++)
+ {
+ // Blue channel
+ bitmapData[bitmapIndex + 2] = line[0];
+ // Green channel
+ bitmapData[bitmapIndex + 1] = line[1];
+ // Red channel
+ bitmapData[bitmapIndex + 0] = line[2];
+
+ line += 3;
+ bitmapIndex += bpp;
+ }
+ }
+ }
+ else if (bpp == 1)
+ {
+ for (int y = 0; y < height; y++)
+ memcpy (bitmapData + y * width, data + y * step, width);
+ }
+
+ // Turn the bitmap context into an imageRef
+ CGImageRef imageRef = CGBitmapContextCreateImage( context );
+ CGContextRelease( context );
+ if( !imageRef )
+ {
+ free( bitmapData );
+ return false;
+ }
+
+ // Write the imageRef to a file based on the UTI
+ CFURLRef imageURLRef = CFURLCreateFromFileSystemRepresentation( NULL,
+ (const UInt8*)m_filename,
+ strlen(m_filename),
+ false );
+ if( !imageURLRef )
+ {
+ CGImageRelease( imageRef );
+ free( bitmapData );
+ return false;
+ }
+
+ CGImageDestinationRef destRef = CGImageDestinationCreateWithURL( imageURLRef,
+ imageUTI,
+ 1,
+ NULL);
+ CFRelease( imageURLRef );
+ if( !destRef )
+ {
+ CGImageRelease( imageRef );
+ free( bitmapData );
+ std::cerr << "!destRef" << std::endl << std::flush;
+ return false;
+ }
+
+ CGImageDestinationAddImage(destRef, imageRef, NULL);
+ if( !CGImageDestinationFinalize(destRef) )
+ {
+ std::cerr << "Finalize failed" << std::endl << std::flush;
+ return false;
+ }
+
+ CFRelease( destRef );
+ CGImageRelease( imageRef );
+ free( bitmapData );
+
+ return true;
+}
+
+#endif /* HAVE_IMAGEIO */
diff --git a/otherlibs/highgui/grfmt_imageio.h b/otherlibs/highgui/grfmt_imageio.h
new file mode 100644
index 0000000..4035af9
--- /dev/null
+++ b/otherlibs/highgui/grfmt_imageio.h
@@ -0,0 +1,60 @@
+/*
+ * grfmt_imageio.h
+ *
+ *
+ * Created by Morgan Conbere on 5/17/07.
+ *
+ */
+
+#ifndef _GRFMT_IMAGEIO_H_
+#define _GRFMT_IMAGEIO_H_
+
+#ifdef HAVE_IMAGEIO
+
+#include "grfmt_base.h"
+#include <ApplicationServices/ApplicationServices.h>
+
+class GrFmtImageIOReader : public GrFmtReader
+{
+public:
+
+ GrFmtImageIOReader( const char* filename );
+ ~GrFmtImageIOReader();
+
+ bool ReadData( uchar* data, int step, int color );
+ bool ReadHeader();
+ void Close();
+
+protected:
+
+ CGImageRef imageRef;
+};
+
+class GrFmtImageIOWriter : public GrFmtWriter
+{
+public:
+
+ GrFmtImageIOWriter( const char* filename );
+ ~GrFmtImageIOWriter();
+
+ bool WriteImage( const uchar* data, int step,
+ int width, int height, int depth, int channels );
+};
+
+// ImageIO filter factory
+class GrFmtImageIO :public GrFmtFilterFactory
+{
+public:
+
+ GrFmtImageIO();
+ ~GrFmtImageIO();
+
+ bool CheckFile( const char* filename );
+
+ GrFmtReader* NewReader( const char* filename );
+ GrFmtWriter* NewWriter( const char* filename );
+};
+
+#endif/*HAVE_IMAGEIO*/
+
+#endif/*_GRFMT_IMAGEIO_H_*/
diff --git a/otherlibs/highgui/grfmt_jpeg.cpp b/otherlibs/highgui/grfmt_jpeg.cpp
new file mode 100644
index 0000000..3235fe4
--- /dev/null
+++ b/otherlibs/highgui/grfmt_jpeg.cpp
@@ -0,0 +1,1866 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_highgui.h"
+#include "grfmt_jpeg.h"
+
+// JPEG filter factory
+
+GrFmtJpeg::GrFmtJpeg()
+{
+ m_sign_len = 3;
+ m_signature = "\xFF\xD8\xFF";
+ m_description = "JPEG files (*.jpeg;*.jpg;*.jpe)";
+}
+
+
+GrFmtJpeg::~GrFmtJpeg()
+{
+}
+
+
+GrFmtReader* GrFmtJpeg::NewReader( const char* filename )
+{
+ return new GrFmtJpegReader( filename );
+}
+
+
+GrFmtWriter* GrFmtJpeg::NewWriter( const char* filename )
+{
+ return new GrFmtJpegWriter( filename );
+}
+
+
+#ifdef HAVE_JPEG
+
+/****************************************************************************************\
+ This part of the file implements JPEG codec on base of IJG libjpeg library,
+ in particular, this is the modified example.doc from libjpeg package.
+ See otherlibs/_graphics/readme.txt for copyright notice.
+\****************************************************************************************/
+
+#include <stdio.h>
+#include <setjmp.h>
+
+#ifdef WIN32
+
+#define XMD_H // prevent redefinition of INT32
+#undef FAR // prevent FAR redefinition
+
+#endif
+
+#if defined WIN32 && defined __GNUC__
+typedef unsigned char boolean;
+#endif
+
+extern "C" {
+#include "jpeglib.h"
+}
+
+/////////////////////// Error processing /////////////////////
+
+typedef struct GrFmtJpegErrorMgr
+{
+ struct jpeg_error_mgr pub; /* "parent" structure */
+ jmp_buf setjmp_buffer; /* jump label */
+}
+GrFmtJpegErrorMgr;
+
+
+METHODDEF(void)
+error_exit( j_common_ptr cinfo )
+{
+ GrFmtJpegErrorMgr* err_mgr = (GrFmtJpegErrorMgr*)(cinfo->err);
+
+ /* Return control to the setjmp point */
+ longjmp( err_mgr->setjmp_buffer, 1 );
+}
+
+
+/////////////////////// GrFmtJpegReader ///////////////////
+
+
+GrFmtJpegReader::GrFmtJpegReader( const char* filename ) : GrFmtReader( filename )
+{
+ m_cinfo = 0;
+ m_f = 0;
+}
+
+
+GrFmtJpegReader::~GrFmtJpegReader()
+{
+}
+
+
+void GrFmtJpegReader::Close()
+{
+ if( m_f )
+ {
+ fclose( m_f );
+ m_f = 0;
+ }
+
+ if( m_cinfo )
+ {
+ jpeg_decompress_struct* cinfo = (jpeg_decompress_struct*)m_cinfo;
+ GrFmtJpegErrorMgr* jerr = (GrFmtJpegErrorMgr*)m_jerr;
+
+ jpeg_destroy_decompress( cinfo );
+ delete cinfo;
+ delete jerr;
+ m_cinfo = 0;
+ m_jerr = 0;
+ }
+ GrFmtReader::Close();
+}
+
+
+bool GrFmtJpegReader::ReadHeader()
+{
+ bool result = false;
+ Close();
+
+ jpeg_decompress_struct* cinfo = new jpeg_decompress_struct;
+ GrFmtJpegErrorMgr* jerr = new GrFmtJpegErrorMgr;
+
+ cinfo->err = jpeg_std_error(&jerr->pub);
+ jerr->pub.error_exit = error_exit;
+
+ m_cinfo = cinfo;
+ m_jerr = jerr;
+
+ if( setjmp( jerr->setjmp_buffer ) == 0 )
+ {
+ jpeg_create_decompress( cinfo );
+
+ m_f = fopen( m_filename, "rb" );
+ if( m_f )
+ {
+ jpeg_stdio_src( cinfo, m_f );
+ jpeg_read_header( cinfo, TRUE );
+
+ m_width = cinfo->image_width;
+ m_height = cinfo->image_height;
+ m_iscolor = cinfo->num_components > 1;
+
+ result = true;
+ }
+ }
+
+ if( !result )
+ Close();
+
+ return result;
+}
+
+/***************************************************************************
+ * following code is for supporting MJPEG image files
+ * based on a message of Laurent Pinchart on the video4linux mailing list
+ ***************************************************************************/
+
+/* JPEG DHT Segment for YCrCb omitted from MJPEG data */
+static
+unsigned char my_jpeg_odml_dht[0x1a4] = {
+ 0xff, 0xc4, 0x01, 0xa2,
+
+ 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+
+ 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+
+ 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
+ 0x04, 0x00, 0x00, 0x01, 0x7d,
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
+ 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1,
+ 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a,
+ 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
+ 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
+ 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85,
+ 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
+ 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
+ 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4,
+ 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa,
+
+ 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
+ 0x04, 0x00, 0x01, 0x02, 0x77,
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
+ 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09,
+ 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17,
+ 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,
+ 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
+ 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
+ 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,
+ 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
+ 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+ 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
+ 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+
+/*
+ * Parse the DHT table.
+ * This code comes from jpeg6b (jdmarker.c).
+ */
+static
+int my_jpeg_load_dht (struct jpeg_decompress_struct *info, unsigned char *dht,
+ JHUFF_TBL *ac_tables[], JHUFF_TBL *dc_tables[])
+{
+ unsigned int length = (dht[2] << 8) + dht[3] - 2;
+ unsigned int pos = 4;
+ unsigned int count, i;
+ int index;
+
+ JHUFF_TBL **hufftbl;
+ unsigned char bits[17];
+ unsigned char huffval[256];
+
+ while (length > 16)
+ {
+ bits[0] = 0;
+ index = dht[pos++];
+ count = 0;
+ for (i = 1; i <= 16; ++i)
+ {
+ bits[i] = dht[pos++];
+ count += bits[i];
+ }
+ length -= 17;
+
+ if (count > 256 || count > length)
+ return -1;
+
+ for (i = 0; i < count; ++i)
+ huffval[i] = dht[pos++];
+ length -= count;
+
+ if (index & 0x10)
+ {
+ index -= 0x10;
+ hufftbl = &ac_tables[index];
+ }
+ else
+ hufftbl = &dc_tables[index];
+
+ if (index < 0 || index >= NUM_HUFF_TBLS)
+ return -1;
+
+ if (*hufftbl == NULL)
+ *hufftbl = jpeg_alloc_huff_table ((j_common_ptr)info);
+ if (*hufftbl == NULL)
+ return -1;
+
+ memcpy ((*hufftbl)->bits, bits, sizeof (*hufftbl)->bits);
+ memcpy ((*hufftbl)->huffval, huffval, sizeof (*hufftbl)->huffval);
+ }
+
+ if (length != 0)
+ return -1;
+
+ return 0;
+}
+
+/***************************************************************************
+ * end of code for supportting MJPEG image files
+ * based on a message of Laurent Pinchart on the video4linux mailing list
+ ***************************************************************************/
+
+bool GrFmtJpegReader::ReadData( uchar* data, int step, int color )
+{
+ bool result = false;
+
+ color = color > 0 || (m_iscolor && color < 0);
+
+ if( m_cinfo && m_jerr && m_width && m_height )
+ {
+ jpeg_decompress_struct* cinfo = (jpeg_decompress_struct*)m_cinfo;
+ GrFmtJpegErrorMgr* jerr = (GrFmtJpegErrorMgr*)m_jerr;
+ JSAMPARRAY buffer = 0;
+
+ if( setjmp( jerr->setjmp_buffer ) == 0 )
+ {
+ /* check if this is a mjpeg image format */
+ if ( cinfo->ac_huff_tbl_ptrs[0] == NULL &&
+ cinfo->ac_huff_tbl_ptrs[1] == NULL &&
+ cinfo->dc_huff_tbl_ptrs[0] == NULL &&
+ cinfo->dc_huff_tbl_ptrs[1] == NULL )
+ {
+ /* yes, this is a mjpeg image format, so load the correct
+ huffman table */
+ my_jpeg_load_dht( cinfo,
+ my_jpeg_odml_dht,
+ cinfo->ac_huff_tbl_ptrs,
+ cinfo->dc_huff_tbl_ptrs );
+ }
+
+ if( color > 0 || (m_iscolor && color < 0) )
+ {
+ color = 1;
+ if( cinfo->num_components != 4 )
+ {
+ cinfo->out_color_space = JCS_RGB;
+ cinfo->out_color_components = 3;
+ }
+ else
+ {
+ cinfo->out_color_space = JCS_CMYK;
+ cinfo->out_color_components = 4;
+ }
+ }
+ else
+ {
+ color = 0;
+ if( cinfo->num_components != 4 )
+ {
+ cinfo->out_color_space = JCS_GRAYSCALE;
+ cinfo->out_color_components = 1;
+ }
+ else
+ {
+ cinfo->out_color_space = JCS_CMYK;
+ cinfo->out_color_components = 4;
+ }
+ }
+
+ jpeg_start_decompress( cinfo );
+
+ buffer = (*cinfo->mem->alloc_sarray)((j_common_ptr)cinfo,
+ JPOOL_IMAGE, m_width*4, 1 );
+
+ for( ; m_height--; data += step )
+ {
+ jpeg_read_scanlines( cinfo, buffer, 1 );
+ if( color )
+ {
+ if( cinfo->out_color_components == 3 )
+ icvCvt_RGB2BGR_8u_C3R( buffer[0], 0, data, 0, cvSize(m_width,1) );
+ else
+ icvCvt_CMYK2BGR_8u_C4C3R( buffer[0], 0, data, 0, cvSize(m_width,1) );
+ }
+ else
+ {
+ if( cinfo->out_color_components == 1 )
+ memcpy( data, buffer[0], m_width );
+ else
+ icvCvt_CMYK2Gray_8u_C4C1R( buffer[0], 0, data, 0, cvSize(m_width,1) );
+ }
+ }
+ result = true;
+ jpeg_finish_decompress( cinfo );
+ }
+ }
+
+ Close();
+ return result;
+}
+
+
+/////////////////////// GrFmtJpegWriter ///////////////////
+
+GrFmtJpegWriter::GrFmtJpegWriter( const char* filename ) : GrFmtWriter( filename )
+{
+}
+
+
+GrFmtJpegWriter::~GrFmtJpegWriter()
+{
+}
+
+
+bool GrFmtJpegWriter::WriteImage( const uchar* data, int step,
+ int width, int height, int /*depth*/, int _channels )
+{
+ const int default_quality = 95;
+ struct jpeg_compress_struct cinfo;
+ GrFmtJpegErrorMgr jerr;
+
+ bool result = false;
+ FILE* f = 0;
+ int channels = _channels > 1 ? 3 : 1;
+ uchar* buffer = 0; // temporary buffer for row flipping
+
+ cinfo.err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = error_exit;
+
+ if( setjmp( jerr.setjmp_buffer ) == 0 )
+ {
+ jpeg_create_compress(&cinfo);
+ f = fopen( m_filename, "wb" );
+
+ if( f )
+ {
+ jpeg_stdio_dest( &cinfo, f );
+
+ cinfo.image_width = width;
+ cinfo.image_height = height;
+ cinfo.input_components = channels;
+ cinfo.in_color_space = channels > 1 ? JCS_RGB : JCS_GRAYSCALE;
+
+ jpeg_set_defaults( &cinfo );
+ jpeg_set_quality( &cinfo, default_quality,
+ TRUE /* limit to baseline-JPEG values */ );
+ jpeg_start_compress( &cinfo, TRUE );
+
+ if( channels > 1 )
+ buffer = new uchar[width*channels];
+
+ for( ; height--; data += step )
+ {
+ uchar* ptr = (uchar*)data;
+
+ if( _channels == 3 )
+ {
+ icvCvt_BGR2RGB_8u_C3R( data, 0, buffer, 0, cvSize(width,1) );
+ ptr = buffer;
+ }
+ else if( _channels == 4 )
+ {
+ icvCvt_BGRA2BGR_8u_C4C3R( data, 0, buffer, 0, cvSize(width,1), 2 );
+ ptr = buffer;
+ }
+
+ jpeg_write_scanlines( &cinfo, &ptr, 1 );
+ }
+
+ jpeg_finish_compress( &cinfo );
+ result = true;
+ }
+ }
+
+ if(f) fclose(f);
+ jpeg_destroy_compress( &cinfo );
+
+ delete[] buffer;
+ return result;
+}
+
+#else
+
+////////////////////// JPEG-oriented two-level bitstream ////////////////////////
+
+RJpegBitStream::RJpegBitStream()
+{
+}
+
+RJpegBitStream::~RJpegBitStream()
+{
+ Close();
+}
+
+
+bool RJpegBitStream::Open( const char* filename )
+{
+ Close();
+ Allocate();
+
+ m_is_opened = m_low_strm.Open( filename );
+ if( m_is_opened ) SetPos(0);
+ return m_is_opened;
+}
+
+
+void RJpegBitStream::Close()
+{
+ m_low_strm.Close();
+ m_is_opened = false;
+}
+
+
+void RJpegBitStream::ReadBlock()
+{
+ uchar* end = m_start + m_block_size;
+ uchar* current = m_start;
+
+ if( setjmp( m_low_strm.JmpBuf()) == 0 )
+ {
+ int sz = m_unGetsize;
+ memmove( current - sz, m_end - sz, sz );
+ while( current < end )
+ {
+ int val = m_low_strm.GetByte();
+ if( val != 0xff )
+ {
+ *current++ = (uchar)val;
+ }
+ else
+ {
+ val = m_low_strm.GetByte();
+ if( val == 0 )
+ *current++ = 0xFF;
+ else if( !(0xD0 <= val && val <= 0xD7) )
+ {
+ m_low_strm.SetPos( m_low_strm.GetPos() - 2 );
+ goto fetch_end;
+ }
+ }
+ }
+fetch_end: ;
+ }
+ else
+ {
+ if( current == m_start && m_jmp_set )
+ longjmp( m_jmp_buf, RBS_THROW_EOS );
+ }
+ m_current = m_start;
+ m_end = m_start + (((current - m_start) + 3) & -4);
+ if( !bsIsBigEndian() )
+ bsBSwapBlock( m_start, m_end );
+}
+
+
+void RJpegBitStream::Flush()
+{
+ m_end = m_start + m_block_size;
+ m_current = m_end - 4;
+ m_bit_idx = 0;
+}
+
+void RJpegBitStream::AlignOnByte()
+{
+ m_bit_idx &= -8;
+}
+
+int RJpegBitStream::FindMarker()
+{
+ int code = m_low_strm.GetWord();
+ while( (code & 0xFF00) != 0xFF00 || (code == 0xFFFF || code == 0xFF00 ))
+ {
+ code = ((code&255) << 8) | m_low_strm.GetByte();
+ }
+ return code;
+}
+
+
+/****************************** JPEG (JFIF) reader ***************************/
+
+// zigzag & IDCT prescaling (AAN algorithm) tables
+static const uchar zigzag[] =
+{
+ 0, 8, 1, 2, 9, 16, 24, 17, 10, 3, 4, 11, 18, 25, 32, 40,
+ 33, 26, 19, 12, 5, 6, 13, 20, 27, 34, 41, 48, 56, 49, 42, 35,
+ 28, 21, 14, 7, 15, 22, 29, 36, 43, 50, 57, 58, 51, 44, 37, 30,
+ 23, 31, 38, 45, 52, 59, 60, 53, 46, 39, 47, 54, 61, 62, 55, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+
+static const int idct_prescale[] =
+{
+ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
+ 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270,
+ 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906,
+ 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
+ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
+ 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552,
+ 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446,
+ 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247
+};
+
+
+#define fixb 14
+#define fix(x, n) (int)((x)*(1 << (n)) + .5)
+#define fix1(x, n) (x)
+#define fixmul(x) (x)
+
+#define C0_707 fix( 0.707106781f, fixb )
+#define C0_924 fix( 0.923879533f, fixb )
+#define C0_541 fix( 0.541196100f, fixb )
+#define C0_382 fix( 0.382683432f, fixb )
+#define C1_306 fix( 1.306562965f, fixb )
+
+#define C1_082 fix( 1.082392200f, fixb )
+#define C1_414 fix( 1.414213562f, fixb )
+#define C1_847 fix( 1.847759065f, fixb )
+#define C2_613 fix( 2.613125930f, fixb )
+
+#define fixc 12
+#define b_cb fix( 1.772, fixc )
+#define g_cb -fix( 0.34414, fixc )
+#define g_cr -fix( 0.71414, fixc )
+#define r_cr fix( 1.402, fixc )
+
+#define y_r fix( 0.299, fixc )
+#define y_g fix( 0.587, fixc )
+#define y_b fix( 0.114, fixc )
+
+#define cb_r -fix( 0.1687, fixc )
+#define cb_g -fix( 0.3313, fixc )
+#define cb_b fix( 0.5, fixc )
+
+#define cr_r fix( 0.5, fixc )
+#define cr_g -fix( 0.4187, fixc )
+#define cr_b -fix( 0.0813, fixc )
+
+
+// IDCT without prescaling
+static void aan_idct8x8( int *src, int *dst, int step )
+{
+ int workspace[64], *work = workspace;
+ int i;
+
+ /* Pass 1: process rows */
+ for( i = 8; i > 0; i--, src += 8, work += 8 )
+ {
+ /* Odd part */
+ int x0 = src[5], x1 = src[3];
+ int x2 = src[1], x3 = src[7];
+
+ int x4 = x0 + x1; x0 -= x1;
+
+ x1 = x2 + x3; x2 -= x3;
+ x3 = x1 + x4; x1 -= x4;
+
+ x4 = (x0 + x2)*C1_847;
+ x0 = descale( x4 - x0*C2_613, fixb);
+ x2 = descale( x2*C1_082 - x4, fixb);
+ x1 = descale( x1*C1_414, fixb);
+
+ x0 -= x3;
+ x1 -= x0;
+ x2 += x1;
+
+ work[7] = x3; work[6] = x0;
+ work[5] = x1; work[4] = x2;
+
+ /* Even part */
+ x2 = src[2]; x3 = src[6];
+ x0 = src[0]; x1 = src[4];
+
+ x4 = x2 + x3;
+ x2 = descale((x2-x3)*C1_414, fixb) - x4;
+
+ x3 = x0 + x1; x0 -= x1;
+ x1 = x3 + x4; x3 -= x4;
+ x4 = x0 + x2; x0 -= x2;
+
+ x2 = work[7];
+ x1 -= x2; x2 = 2*x2 + x1;
+ work[7] = x1; work[0] = x2;
+
+ x2 = work[6];
+ x1 = x4 + x2; x4 -= x2;
+ work[1] = x1; work[6] = x4;
+
+ x1 = work[5]; x2 = work[4];
+ x4 = x0 + x1; x0 -= x1;
+ x1 = x3 + x2; x3 -= x2;
+
+ work[2] = x4; work[5] = x0;
+ work[3] = x3; work[4] = x1;
+ }
+
+ /* Pass 2: process columns */
+ work = workspace;
+ for( i = 8; i > 0; i--, dst += step, work++ )
+ {
+ /* Odd part */
+ int x0 = work[8*5], x1 = work[8*3];
+ int x2 = work[8*1], x3 = work[8*7];
+
+ int x4 = x0 + x1; x0 -= x1;
+ x1 = x2 + x3; x2 -= x3;
+ x3 = x1 + x4; x1 -= x4;
+
+ x4 = (x0 + x2)*C1_847;
+ x0 = descale( x4 - x0*C2_613, fixb);
+ x2 = descale( x2*C1_082 - x4, fixb);
+ x1 = descale( x1*C1_414, fixb);
+
+ x0 -= x3;
+ x1 -= x0;
+ x2 += x1;
+
+ dst[7] = x3; dst[6] = x0;
+ dst[5] = x1; dst[4] = x2;
+
+ /* Even part */
+ x2 = work[8*2]; x3 = work[8*6];
+ x0 = work[8*0]; x1 = work[8*4];
+
+ x4 = x2 + x3;
+ x2 = descale((x2-x3)*C1_414, fixb) - x4;
+
+ x3 = x0 + x1; x0 -= x1;
+ x1 = x3 + x4; x3 -= x4;
+ x4 = x0 + x2; x0 -= x2;
+
+ x2 = dst[7];
+ x1 -= x2; x2 = 2*x2 + x1;
+ x1 = descale(x1,3);
+ x2 = descale(x2,3);
+
+ dst[7] = x1; dst[0] = x2;
+
+ x2 = dst[6];
+ x1 = descale(x4 + x2,3);
+ x4 = descale(x4 - x2,3);
+ dst[1] = x1; dst[6] = x4;
+
+ x1 = dst[5]; x2 = dst[4];
+
+ x4 = descale(x0 + x1,3);
+ x0 = descale(x0 - x1,3);
+ x1 = descale(x3 + x2,3);
+ x3 = descale(x3 - x2,3);
+
+ dst[2] = x4; dst[5] = x0;
+ dst[3] = x3; dst[4] = x1;
+ }
+}
+
+
+static const int max_dec_htable_size = 1 << 12;
+static const int first_table_bits = 9;
+
+GrFmtJpegReader::GrFmtJpegReader( const char* filename ) : GrFmtReader( filename )
+{
+ m_planes= -1;
+ m_offset= -1;
+
+ int i;
+ for( i = 0; i < 4; i++ )
+ {
+ m_td[i] = new short[max_dec_htable_size];
+ m_ta[i] = new short[max_dec_htable_size];
+ }
+}
+
+
+GrFmtJpegReader::~GrFmtJpegReader()
+{
+ for( int i = 0; i < 4; i++ )
+ {
+ delete[] m_td[i];
+ m_td[i] = 0;
+ delete[] m_ta[i];
+ m_ta[i] = 0;
+ }
+}
+
+
+void GrFmtJpegReader::Close()
+{
+ m_strm.Close();
+ GrFmtReader::Close();
+}
+
+
+bool GrFmtJpegReader::ReadHeader()
+{
+ char buffer[16];
+ int i;
+ bool result = false, is_sof = false,
+ is_qt = false, is_ht = false, is_sos = false;
+
+ assert( strlen(m_filename) != 0 );
+ if( !m_strm.Open( m_filename )) return false;
+
+ memset( m_is_tq, 0, sizeof(m_is_tq));
+ memset( m_is_td, 0, sizeof(m_is_td));
+ memset( m_is_ta, 0, sizeof(m_is_ta));
+ m_MCUs = 0;
+
+ if( setjmp( m_strm.JmpBuf()) == 0 )
+ {
+ RMByteStream& lstrm = m_strm.m_low_strm;
+
+ lstrm.Skip( 2 ); // skip SOI marker
+
+ for(;;)
+ {
+ int marker = m_strm.FindMarker() & 255;
+
+ // check for standalone markers
+ if( marker != 0xD8 /* SOI */ && marker != 0xD9 /* EOI */ &&
+ marker != 0x01 /* TEM */ && !( 0xD0 <= marker && marker <= 0xD7 ))
+ {
+ int pos = lstrm.GetPos();
+ int length = lstrm.GetWord();
+
+ switch( marker )
+ {
+ case 0xE0: // APP0
+ lstrm.GetBytes( buffer, 5 );
+ if( strcmp(buffer, "JFIF") == 0 ) // JFIF identification
+ {
+ m_version = lstrm.GetWord();
+ //is_jfif = true;
+ }
+ break;
+
+ case 0xC0: // SOF0
+ m_precision = lstrm.GetByte();
+ m_height = lstrm.GetWord();
+ m_width = lstrm.GetWord();
+ m_planes = lstrm.GetByte();
+
+ if( m_width == 0 || m_height == 0 || // DNL not supported
+ (m_planes != 1 && m_planes != 3)) goto parsing_end;
+
+ m_iscolor = m_planes == 3;
+
+ memset( m_ci, -1, sizeof(m_ci));
+
+ for( i = 0; i < m_planes; i++ )
+ {
+ int idx = lstrm.GetByte();
+
+ if( idx < 1 || idx > m_planes ) // wrong index
+ {
+ idx = i+1; // hack
+ }
+ cmp_info& ci = m_ci[idx-1];
+
+ if( ci.tq > 0 /* duplicated description */) goto parsing_end;
+
+ ci.h = (char)lstrm.GetByte();
+ ci.v = (char)(ci.h & 15);
+ ci.h >>= 4;
+ ci.tq = (char)lstrm.GetByte();
+ if( !((ci.h == 1 || ci.h == 2 || ci.h == 4) &&
+ (ci.v == 1 || ci.v == 2 || ci.v == 4) &&
+ ci.tq < 3) ||
+ // chroma mcu-parts should have equal sizes and
+ // be non greater then luma sizes
+ !( i != 2 || (ci.h == m_ci[1].h && ci.v == m_ci[1].v &&
+ ci.h <= m_ci[0].h && ci.v <= m_ci[0].v)))
+ goto parsing_end;
+ }
+ is_sof = true;
+ m_type = marker - 0xC0;
+ break;
+
+ case 0xDB: // DQT
+ if( !LoadQuantTables( length )) goto parsing_end;
+ is_qt = true;
+ break;
+
+ case 0xC4: // DHT
+ if( !LoadHuffmanTables( length )) goto parsing_end;
+ is_ht = true;
+ break;
+
+ case 0xDA: // SOS
+ is_sos = true;
+ m_offset = pos - 2;
+ goto parsing_end;
+
+ case 0xDD: // DRI
+ m_MCUs = lstrm.GetWord();
+ break;
+ }
+ lstrm.SetPos( pos + length );
+ }
+ }
+parsing_end: ;
+ }
+
+ result = /*is_jfif &&*/ is_sof && is_qt && is_ht && is_sos;
+ if( !result )
+ {
+ m_width = m_height = -1;
+ m_offset = -1;
+ m_strm.Close();
+ }
+ return result;
+}
+
+
+bool GrFmtJpegReader::LoadQuantTables( int length )
+{
+ uchar buffer[128];
+ int i, tq_size;
+
+ RMByteStream& lstrm = m_strm.m_low_strm;
+ length -= 2;
+
+ while( length > 0 )
+ {
+ int tq = lstrm.GetByte();
+ int size = tq >> 4;
+ tq &= 15;
+
+ tq_size = (64<<size) + 1;
+ if( tq > 3 || size > 1 || length < tq_size ) return false;
+ length -= tq_size;
+
+ lstrm.GetBytes( buffer, tq_size - 1 );
+
+ if( size == 0 ) // 8 bit quant factors
+ {
+ for( i = 0; i < 64; i++ )
+ {
+ int idx = zigzag[i];
+ m_tq[tq][idx] = buffer[i] * 16 * idct_prescale[idx];
+ }
+ }
+ else // 16 bit quant factors
+ {
+ for( i = 0; i < 64; i++ )
+ {
+ int idx = zigzag[i];
+ m_tq[tq][idx] = ((unsigned short*)buffer)[i] * idct_prescale[idx];
+ }
+ }
+ m_is_tq[tq] = true;
+ }
+
+ return true;
+}
+
+
+bool GrFmtJpegReader::LoadHuffmanTables( int length )
+{
+ const int max_bits = 16;
+ uchar buffer[1024];
+ int buffer2[1024];
+
+ int i, ht_size;
+ RMByteStream& lstrm = m_strm.m_low_strm;
+ length -= 2;
+
+ while( length > 0 )
+ {
+ int t = lstrm.GetByte();
+ int hclass = t >> 4;
+ t &= 15;
+
+ if( t > 3 || hclass > 1 || length < 17 ) return false;
+ length -= 17;
+
+ lstrm.GetBytes( buffer, max_bits );
+ for( i = 0, ht_size = 0; i < max_bits; i++ ) ht_size += buffer[i];
+
+ if( length < ht_size ) return false;
+ length -= ht_size;
+
+ lstrm.GetBytes( buffer + max_bits, ht_size );
+
+ if( !::bsCreateDecodeHuffmanTable(
+ ::bsCreateSourceHuffmanTable(
+ buffer, buffer2, max_bits, first_table_bits ),
+ hclass == 0 ? m_td[t] : m_ta[t],
+ max_dec_htable_size )) return false;
+ if( hclass == 0 )
+ m_is_td[t] = true;
+ else
+ m_is_ta[t] = true;
+ }
+ return true;
+}
+
+
+bool GrFmtJpegReader::ReadData( uchar* data, int step, int color )
+{
+ if( m_offset < 0 || !m_strm.IsOpened())
+ return false;
+
+ if( setjmp( m_strm.JmpBuf()) == 0 )
+ {
+ RMByteStream& lstrm = m_strm.m_low_strm;
+ lstrm.SetPos( m_offset );
+
+ for(;;)
+ {
+ int marker = m_strm.FindMarker() & 255;
+
+ if( marker == 0xD8 /* SOI */ || marker == 0xD9 /* EOI */ )
+ goto decoding_end;
+
+ // check for standalone markers
+ if( marker != 0x01 /* TEM */ && !( 0xD0 <= marker && marker <= 0xD7 ))
+ {
+ int pos = lstrm.GetPos();
+ int length = lstrm.GetWord();
+
+ switch( marker )
+ {
+ case 0xC4: // DHT
+ if( !LoadHuffmanTables( length )) goto decoding_end;
+ break;
+
+ case 0xDA: // SOS
+ // read scan header
+ {
+ int idx[3] = { -1, -1, -1 };
+ int i, ns = lstrm.GetByte();
+ int sum = 0, a; // spectral selection & approximation
+
+ if( ns != m_planes ) goto decoding_end;
+ for( i = 0; i < ns; i++ )
+ {
+ int td, ta, c = lstrm.GetByte() - 1;
+ if( c < 0 || m_planes <= c )
+ {
+ c = i; // hack
+ }
+
+ if( idx[c] != -1 ) goto decoding_end;
+ idx[i] = c;
+ td = lstrm.GetByte();
+ ta = td & 15;
+ td >>= 4;
+ if( !(ta <= 3 && m_is_ta[ta] &&
+ td <= 3 && m_is_td[td] &&
+ m_is_tq[m_ci[c].tq]) )
+ goto decoding_end;
+
+ m_ci[c].td = (char)td;
+ m_ci[c].ta = (char)ta;
+
+ sum += m_ci[c].h*m_ci[c].v;
+ }
+
+ if( sum > 10 ) goto decoding_end;
+
+ m_ss = lstrm.GetByte();
+ m_se = lstrm.GetByte();
+
+ a = lstrm.GetByte();
+ m_al = a & 15;
+ m_ah = a >> 4;
+
+ ProcessScan( idx, ns, data, step, color );
+ goto decoding_end; // only single scan case is supported now
+ }
+
+ //m_offset = pos - 2;
+ //break;
+
+ case 0xDD: // DRI
+ m_MCUs = lstrm.GetWord();
+ break;
+ }
+
+ if( marker != 0xDA ) lstrm.SetPos( pos + length );
+ }
+ }
+decoding_end: ;
+ }
+
+ return true;
+}
+
+
+void GrFmtJpegReader::ResetDecoder()
+{
+ m_ci[0].dc_pred = m_ci[1].dc_pred = m_ci[2].dc_pred = 0;
+}
+
+void GrFmtJpegReader::ProcessScan( int* idx, int ns, uchar* data, int step, int color )
+{
+ int i, s = 0, mcu, x1 = 0, y1 = 0;
+ int temp[64];
+ int blocks[10][64];
+ int pos[3], h[3], v[3];
+ int x_shift = 0, y_shift = 0;
+ int nch = color ? 3 : 1;
+
+ assert( ns == m_planes && m_ss == 0 && m_se == 63 &&
+ m_al == 0 && m_ah == 0 ); // sequental & single scan
+
+ assert( idx[0] == 0 && (ns ==1 || (idx[1] == 1 && idx[2] == 2)));
+
+ for( i = 0; i < ns; i++ )
+ {
+ int c = idx[i];
+ h[c] = m_ci[c].h*8;
+ v[c] = m_ci[c].v*8;
+ pos[c] = s >> 6;
+ s += h[c]*v[c];
+ }
+
+ if( ns == 3 )
+ {
+ x_shift = h[0]/(h[1]*2);
+ y_shift = v[0]/(v[1]*2);
+ }
+
+ m_strm.Flush();
+ ResetDecoder();
+
+ for( mcu = 0;; mcu++ )
+ {
+ int x2, y2, x, y, xc;
+ int* cmp;
+ uchar* data1;
+
+ if( mcu == m_MCUs && m_MCUs != 0 )
+ {
+ ResetDecoder();
+ m_strm.AlignOnByte();
+ mcu = 0;
+ }
+
+ // Get mcu
+ for( i = 0; i < ns; i++ )
+ {
+ int c = idx[i];
+ cmp = blocks[pos[c]];
+ for( y = 0; y < v[c]; y += 8, cmp += h[c]*8 )
+ for( x = 0; x < h[c]; x += 8 )
+ {
+ GetBlock( temp, c );
+ if( i < (color ? 3 : 1))
+ {
+ aan_idct8x8( temp, cmp + x, h[c] );
+ }
+ }
+ }
+
+ y2 = v[0];
+ x2 = h[0];
+
+ if( y1 + y2 > m_height ) y2 = m_height - y1;
+ if( x1 + x2 > m_width ) x2 = m_width - x1;
+
+ cmp = blocks[0];
+ data1 = data + x1*nch;
+
+ if( ns == 1 )
+ for( y = 0; y < y2; y++, data1 += step, cmp += h[0] )
+ {
+ if( color )
+ {
+ for( x = 0; x < x2; x++ )
+ {
+ int val = descale( cmp[x] + 128*4, 2 );
+ data1[x*3] = data1[x*3 + 1] = data1[x*3 + 2] = saturate( val );
+ }
+ }
+ else
+ {
+ for( x = 0; x < x2; x++ )
+ {
+ int val = descale( cmp[x] + 128*4, 2 );
+ data1[x] = saturate( val );
+ }
+ }
+ }
+ else
+ {
+ for( y = 0; y < y2; y++, data1 += step, cmp += h[0] )
+ {
+ if( color )
+ {
+ int shift = h[1]*(y >> y_shift);
+ int* cmpCb = blocks[pos[1]] + shift;
+ int* cmpCr = blocks[pos[2]] + shift;
+ x = 0;
+ if( x_shift == 0 )
+ {
+ for( ; x < x2; x++ )
+ {
+ int Y = (cmp[x] + 128*4) << fixc;
+ int Cb = cmpCb[x];
+ int Cr = cmpCr[x];
+ int t = (Y + Cb*b_cb) >> (fixc + 2);
+ data1[x*3] = saturate(t);
+ t = (Y + Cb*g_cb + Cr*g_cr) >> (fixc + 2);
+ data1[x*3 + 1] = saturate(t);
+ t = (Y + Cr*r_cr) >> (fixc + 2);
+ data1[x*3 + 2] = saturate(t);
+ }
+ }
+ else if( x_shift == 1 )
+ {
+ for( xc = 0; x <= x2 - 2; x += 2, xc++ )
+ {
+ int Y = (cmp[x] + 128*4) << fixc;
+ int Cb = cmpCb[xc];
+ int Cr = cmpCr[xc];
+ int t = (Y + Cb*b_cb) >> (fixc + 2);
+ data1[x*3] = saturate(t);
+ t = (Y + Cb*g_cb + Cr*g_cr) >> (fixc + 2);
+ data1[x*3 + 1] = saturate(t);
+ t = (Y + Cr*r_cr) >> (fixc + 2);
+ data1[x*3 + 2] = saturate(t);
+ Y = (cmp[x+1] + 128*4) << fixc;
+ t = (Y + Cb*b_cb) >> (fixc + 2);
+ data1[x*3 + 3] = saturate(t);
+ t = (Y + Cb*g_cb + Cr*g_cr) >> (fixc + 2);
+ data1[x*3 + 4] = saturate(t);
+ t = (Y + Cr*r_cr) >> (fixc + 2);
+ data1[x*3 + 5] = saturate(t);
+ }
+ }
+ for( ; x < x2; x++ )
+ {
+ int Y = (cmp[x] + 128*4) << fixc;
+ int Cb = cmpCb[x >> x_shift];
+ int Cr = cmpCr[x >> x_shift];
+ int t = (Y + Cb*b_cb) >> (fixc + 2);
+ data1[x*3] = saturate(t);
+ t = (Y + Cb*g_cb + Cr*g_cr) >> (fixc + 2);
+ data1[x*3 + 1] = saturate(t);
+ t = (Y + Cr*r_cr) >> (fixc + 2);
+ data1[x*3 + 2] = saturate(t);
+ }
+ }
+ else
+ {
+ for( x = 0; x < x2; x++ )
+ {
+ int val = descale( cmp[x] + 128*4, 2 );
+ data1[x] = saturate(val);
+ }
+ }
+ }
+ }
+
+ x1 += h[0];
+ if( x1 >= m_width )
+ {
+ x1 = 0;
+ y1 += v[0];
+ data += v[0]*step;
+ if( y1 >= m_height ) break;
+ }
+ }
+}
+
+
+void GrFmtJpegReader::GetBlock( int* block, int c )
+{
+ memset( block, 0, 64*sizeof(block[0]) );
+
+ assert( 0 <= c && c < 3 );
+ const short* td = m_td[m_ci[c].td];
+ const short* ta = m_ta[m_ci[c].ta];
+ const int* tq = m_tq[m_ci[c].tq];
+
+ // Get DC coefficient
+ int i = 0, cat = m_strm.GetHuff( td );
+ int mask = bs_bit_mask[cat];
+ int val = m_strm.Get( cat );
+
+ val -= (val*2 <= mask ? mask : 0);
+ m_ci[c].dc_pred = val += m_ci[c].dc_pred;
+
+ block[0] = descale(val * tq[0],16);
+
+ // Get AC coeffs
+ for(;;)
+ {
+ cat = m_strm.GetHuff( ta );
+ if( cat == 0 ) break; // end of block
+
+ i += (cat >> 4) + 1;
+ cat &= 15;
+ mask = bs_bit_mask[cat];
+ val = m_strm.Get( cat );
+ cat = zigzag[i];
+ val -= (val*2 <= mask ? mask : 0);
+ block[cat] = descale(val * tq[cat], 16);
+ assert( i <= 63 );
+ if( i >= 63 ) break;
+ }
+}
+
+////////////////////// WJpegStream ///////////////////////
+
+WJpegBitStream::WJpegBitStream()
+{
+}
+
+
+WJpegBitStream::~WJpegBitStream()
+{
+ Close();
+ m_is_opened = false;
+}
+
+
+
+bool WJpegBitStream::Open( const char* filename )
+{
+ Close();
+ Allocate();
+
+ m_is_opened = m_low_strm.Open( filename );
+ if( m_is_opened )
+ {
+ m_block_pos = 0;
+ ResetBuffer();
+ }
+ return m_is_opened;
+}
+
+
+void WJpegBitStream::Close()
+{
+ if( m_is_opened )
+ {
+ Flush();
+ m_low_strm.Close();
+ m_is_opened = false;
+ }
+}
+
+
+void WJpegBitStream::Flush()
+{
+ Put( -1, m_bit_idx & 31 );
+ *((ulong*&)m_current)++ = m_val;
+ WriteBlock();
+ ResetBuffer();
+}
+
+
+void WJpegBitStream::WriteBlock()
+{
+ uchar* ptr = m_start;
+ if( !bsIsBigEndian() )
+ bsBSwapBlock( m_start, m_current );
+
+ while( ptr < m_current )
+ {
+ int val = *ptr++;
+ m_low_strm.PutByte( val );
+ if( val == 0xff )
+ {
+ m_low_strm.PutByte( 0 );
+ }
+ }
+
+ m_current = m_start;
+}
+
+
+/////////////////////// GrFmtJpegWriter ///////////////////
+
+GrFmtJpegWriter::GrFmtJpegWriter( const char* filename ) : GrFmtWriter( filename )
+{
+}
+
+GrFmtJpegWriter::~GrFmtJpegWriter()
+{
+}
+
+// Standard JPEG quantization tables
+static const uchar jpegTableK1_T[] =
+{
+ 16, 12, 14, 14, 18, 24, 49, 72,
+ 11, 12, 13, 17, 22, 35, 64, 92,
+ 10, 14, 16, 22, 37, 55, 78, 95,
+ 16, 19, 24, 29, 56, 64, 87, 98,
+ 24, 26, 40, 51, 68, 81, 103, 112,
+ 40, 58, 57, 87, 109, 104, 121, 100,
+ 51, 60, 69, 80, 103, 113, 120, 103,
+ 61, 55, 56, 62, 77, 92, 101, 99
+};
+
+
+static const uchar jpegTableK2_T[] =
+{
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+};
+
+
+// Standard Huffman tables
+
+// ... for luma DCs.
+static const uchar jpegTableK3[] =
+{
+ 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+
+// ... for chroma DCs.
+static const uchar jpegTableK4[] =
+{
+ 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+
+// ... for luma ACs.
+static const uchar jpegTableK5[] =
+{
+ 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125,
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+
+// ... for chroma ACs
+static const uchar jpegTableK6[] =
+{
+ 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119,
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+
+
+static const char jpegHeader[] =
+ "\xFF\xD8" // SOI - start of image
+ "\xFF\xE0" // APP0 - jfif extention
+ "\x00\x10" // 2 bytes: length of APP0 segment
+ "JFIF\x00" // JFIF signature
+ "\x01\x02" // version of JFIF
+ "\x00" // units = pixels ( 1 - inch, 2 - cm )
+ "\x00\x01\x00\x01" // 2 2-bytes values: x density & y density
+ "\x00\x00"; // width & height of thumbnail: ( 0x0 means no thumbnail)
+
+#define postshift 14
+
+// FDCT with postscaling
+static void aan_fdct8x8( int *src, int *dst,
+ int step, const int *postscale )
+{
+ int workspace[64], *work = workspace;
+ int i;
+
+ // Pass 1: process rows
+ for( i = 8; i > 0; i--, src += step, work += 8 )
+ {
+ int x0 = src[0], x1 = src[7];
+ int x2 = src[3], x3 = src[4];
+
+ int x4 = x0 + x1; x0 -= x1;
+ x1 = x2 + x3; x2 -= x3;
+
+ work[7] = x0; work[1] = x2;
+ x2 = x4 + x1; x4 -= x1;
+
+ x0 = src[1]; x3 = src[6];
+ x1 = x0 + x3; x0 -= x3;
+ work[5] = x0;
+
+ x0 = src[2]; x3 = src[5];
+ work[3] = x0 - x3; x0 += x3;
+
+ x3 = x0 + x1; x0 -= x1;
+ x1 = x2 + x3; x2 -= x3;
+
+ work[0] = x1; work[4] = x2;
+
+ x0 = descale((x0 - x4)*C0_707, fixb);
+ x1 = x4 + x0; x4 -= x0;
+ work[2] = x4; work[6] = x1;
+
+ x0 = work[1]; x1 = work[3];
+ x2 = work[5]; x3 = work[7];
+
+ x0 += x1; x1 += x2; x2 += x3;
+ x1 = descale(x1*C0_707, fixb);
+
+ x4 = x1 + x3; x3 -= x1;
+ x1 = (x0 - x2)*C0_382;
+ x0 = descale(x0*C0_541 + x1, fixb);
+ x2 = descale(x2*C1_306 + x1, fixb);
+
+ x1 = x0 + x3; x3 -= x0;
+ x0 = x4 + x2; x4 -= x2;
+
+ work[5] = x1; work[1] = x0;
+ work[7] = x4; work[3] = x3;
+ }
+
+ work = workspace;
+ // pass 2: process columns
+ for( i = 8; i > 0; i--, work++, postscale += 8, dst += 8 )
+ {
+ int x0 = work[8*0], x1 = work[8*7];
+ int x2 = work[8*3], x3 = work[8*4];
+
+ int x4 = x0 + x1; x0 -= x1;
+ x1 = x2 + x3; x2 -= x3;
+
+ work[8*7] = x0; work[8*0] = x2;
+ x2 = x4 + x1; x4 -= x1;
+
+ x0 = work[8*1]; x3 = work[8*6];
+ x1 = x0 + x3; x0 -= x3;
+ work[8*4] = x0;
+
+ x0 = work[8*2]; x3 = work[8*5];
+ work[8*3] = x0 - x3; x0 += x3;
+
+ x3 = x0 + x1; x0 -= x1;
+ x1 = x2 + x3; x2 -= x3;
+
+ dst[0] = descale(x1*postscale[0], postshift);
+ dst[4] = descale(x2*postscale[4], postshift);
+
+ x0 = descale((x0 - x4)*C0_707, fixb);
+ x1 = x4 + x0; x4 -= x0;
+
+ dst[2] = descale(x4*postscale[2], postshift);
+ dst[6] = descale(x1*postscale[6], postshift);
+
+ x0 = work[8*0]; x1 = work[8*3];
+ x2 = work[8*4]; x3 = work[8*7];
+
+ x0 += x1; x1 += x2; x2 += x3;
+ x1 = descale(x1*C0_707, fixb);
+
+ x4 = x1 + x3; x3 -= x1;
+ x1 = (x0 - x2)*C0_382;
+ x0 = descale(x0*C0_541 + x1, fixb);
+ x2 = descale(x2*C1_306 + x1, fixb);
+
+ x1 = x0 + x3; x3 -= x0;
+ x0 = x4 + x2; x4 -= x2;
+
+ dst[5] = descale(x1*postscale[5], postshift);
+ dst[1] = descale(x0*postscale[1], postshift);
+ dst[7] = descale(x4*postscale[7], postshift);
+ dst[3] = descale(x3*postscale[3], postshift);
+ }
+}
+
+
+bool GrFmtJpegWriter::WriteImage( const uchar* data, int step,
+ int width, int height, int /*depth*/, int _channels )
+{
+ assert( data && width > 0 && height > 0 );
+
+ if( !m_strm.Open( m_filename ) ) return false;
+
+ // encode the header and tables
+ // for each mcu:
+ // convert rgb to yuv with downsampling (if color).
+ // for every block:
+ // calc dct and quantize
+ // encode block.
+ int x, y;
+ int i, j;
+ const int max_quality = 12;
+ int quality = max_quality;
+ WMByteStream& lowstrm = m_strm.m_low_strm;
+ int fdct_qtab[2][64];
+ ulong huff_dc_tab[2][16];
+ ulong huff_ac_tab[2][256];
+ int channels = _channels > 1 ? 3 : 1;
+ int x_scale = channels > 1 ? 2 : 1, y_scale = x_scale;
+ int dc_pred[] = { 0, 0, 0 };
+ int x_step = x_scale * 8;
+ int y_step = y_scale * 8;
+ int block[6][64];
+ int buffer[1024];
+ int luma_count = x_scale*y_scale;
+ int block_count = luma_count + channels - 1;
+ int Y_step = x_scale*8;
+ const int UV_step = 16;
+ double inv_quality;
+
+ if( quality < 3 ) quality = 3;
+ if( quality > max_quality ) quality = max_quality;
+
+ inv_quality = 1./quality;
+
+ // Encode header
+ lowstrm.PutBytes( jpegHeader, sizeof(jpegHeader) - 1 );
+
+ // Encode quantization tables
+ for( i = 0; i < (channels > 1 ? 2 : 1); i++ )
+ {
+ const uchar* qtable = i == 0 ? jpegTableK1_T : jpegTableK2_T;
+ int chroma_scale = i > 0 ? luma_count : 1;
+
+ lowstrm.PutWord( 0xffdb ); // DQT marker
+ lowstrm.PutWord( 2 + 65*1 ); // put single qtable
+ lowstrm.PutByte( 0*16 + i ); // 8-bit table
+
+ // put coefficients
+ for( j = 0; j < 64; j++ )
+ {
+ int idx = zigzag[j];
+ int qval = cvRound(qtable[idx]*inv_quality);
+ if( qval < 1 )
+ qval = 1;
+ if( qval > 255 )
+ qval = 255;
+ fdct_qtab[i][idx] = cvRound((1 << (postshift + 9))/
+ (qval*chroma_scale*idct_prescale[idx]));
+ lowstrm.PutByte( qval );
+ }
+ }
+
+ // Encode huffman tables
+ for( i = 0; i < (channels > 1 ? 4 : 2); i++ )
+ {
+ const uchar* htable = i == 0 ? jpegTableK3 : i == 1 ? jpegTableK5 :
+ i == 2 ? jpegTableK4 : jpegTableK6;
+ int is_ac_tab = i & 1;
+ int idx = i >= 2;
+ int tableSize = 16 + (is_ac_tab ? 162 : 12);
+
+ lowstrm.PutWord( 0xFFC4 ); // DHT marker
+ lowstrm.PutWord( 3 + tableSize ); // define one huffman table
+ lowstrm.PutByte( is_ac_tab*16 + idx ); // put DC/AC flag and table index
+ lowstrm.PutBytes( htable, tableSize ); // put table
+
+ bsCreateEncodeHuffmanTable( bsCreateSourceHuffmanTable(
+ htable, buffer, 16, 9 ), is_ac_tab ? huff_ac_tab[idx] :
+ huff_dc_tab[idx], is_ac_tab ? 256 : 16 );
+ }
+
+ // put frame header
+ lowstrm.PutWord( 0xFFC0 ); // SOF0 marker
+ lowstrm.PutWord( 8 + 3*channels ); // length of frame header
+ lowstrm.PutByte( 8 ); // sample precision
+ lowstrm.PutWord( height );
+ lowstrm.PutWord( width );
+ lowstrm.PutByte( channels ); // number of components
+
+ for( i = 0; i < channels; i++ )
+ {
+ lowstrm.PutByte( i + 1 ); // (i+1)-th component id (Y,U or V)
+ if( i == 0 )
+ lowstrm.PutByte(x_scale*16 + y_scale); // chroma scale factors
+ else
+ lowstrm.PutByte(1*16 + 1);
+ lowstrm.PutByte( i > 0 ); // quantization table idx
+ }
+
+ // put scan header
+ lowstrm.PutWord( 0xFFDA ); // SOS marker
+ lowstrm.PutWord( 6 + 2*channels ); // length of scan header
+ lowstrm.PutByte( channels ); // number of components in the scan
+
+ for( i = 0; i < channels; i++ )
+ {
+ lowstrm.PutByte( i+1 ); // component id
+ lowstrm.PutByte( (i>0)*16 + (i>0) );// selection of DC & AC tables
+ }
+
+ lowstrm.PutWord(0*256 + 63);// start and end of spectral selection - for
+ // sequental DCT start is 0 and end is 63
+
+ lowstrm.PutByte( 0 ); // successive approximation bit position
+ // high & low - (0,0) for sequental DCT
+
+ // encode data
+ for( y = 0; y < height; y += y_step, data += y_step*step )
+ {
+ for( x = 0; x < width; x += x_step )
+ {
+ int x_limit = x_step;
+ int y_limit = y_step;
+ const uchar* rgb_data = data + x*_channels;
+ int* Y_data = block[0];
+
+ if( x + x_limit > width ) x_limit = width - x;
+ if( y + y_limit > height ) y_limit = height - y;
+
+ memset( block, 0, block_count*64*sizeof(block[0][0]));
+
+ if( channels > 1 )
+ {
+ int* UV_data = block[luma_count];
+
+ for( i = 0; i < y_limit; i++, rgb_data += step, Y_data += Y_step )
+ {
+ for( j = 0; j < x_limit; j++, rgb_data += _channels )
+ {
+ int r = rgb_data[2];
+ int g = rgb_data[1];
+ int b = rgb_data[0];
+
+ int Y = descale( r*y_r + g*y_g + b*y_b, fixc - 2) - 128*4;
+ int U = descale( r*cb_r + g*cb_g + b*cb_b, fixc - 2 );
+ int V = descale( r*cr_r + g*cr_g + b*cr_b, fixc - 2 );
+ int j2 = j >> (x_scale - 1);
+
+ Y_data[j] = Y;
+ UV_data[j2] += U;
+ UV_data[j2 + 8] += V;
+ }
+
+ rgb_data -= x_limit*_channels;
+ if( ((i+1) & (y_scale - 1)) == 0 )
+ {
+ UV_data += UV_step;
+ }
+ }
+ }
+ else
+ {
+ for( i = 0; i < y_limit; i++, rgb_data += step, Y_data += Y_step )
+ {
+ for( j = 0; j < x_limit; j++ )
+ Y_data[j] = rgb_data[j]*4 - 128*4;
+ }
+ }
+
+ for( i = 0; i < block_count; i++ )
+ {
+ int is_chroma = i >= luma_count;
+ int src_step = x_scale * 8;
+ int run = 0, val;
+ int* src_ptr = block[i & -2] + (i & 1)*8;
+ const ulong* htable = huff_ac_tab[is_chroma];
+
+ aan_fdct8x8( src_ptr, buffer, src_step, fdct_qtab[is_chroma] );
+
+ j = is_chroma + (i > luma_count);
+ val = buffer[0] - dc_pred[j];
+ dc_pred[j] = buffer[0];
+
+ {
+ float a = (float)val;
+ int cat = (((int&)a >> 23) & 255) - (126 & (val ? -1 : 0));
+
+ assert( cat <= 11 );
+ m_strm.PutHuff( cat, huff_dc_tab[is_chroma] );
+ m_strm.Put( val - (val < 0 ? 1 : 0), cat );
+ }
+
+ for( j = 1; j < 64; j++ )
+ {
+ val = buffer[zigzag[j]];
+
+ if( val == 0 )
+ {
+ run++;
+ }
+ else
+ {
+ while( run >= 16 )
+ {
+ m_strm.PutHuff( 0xF0, htable ); // encode 16 zeros
+ run -= 16;
+ }
+
+ {
+ float a = (float)val;
+ int cat = (((int&)a >> 23) & 255) - (126 & (val ? -1 : 0));
+
+ assert( cat <= 10 );
+ m_strm.PutHuff( cat + run*16, htable );
+ m_strm.Put( val - (val < 0 ? 1 : 0), cat );
+ }
+
+ run = 0;
+ }
+ }
+
+ if( run )
+ {
+ m_strm.PutHuff( 0x00, htable ); // encode EOB
+ }
+ }
+ }
+ }
+
+ // Flush
+ m_strm.Flush();
+
+ lowstrm.PutWord( 0xFFD9 ); // EOI marker
+ m_strm.Close();
+
+ return true;
+}
+
+#endif
+
+/* End of file. */
+
+
diff --git a/otherlibs/highgui/grfmt_jpeg.h b/otherlibs/highgui/grfmt_jpeg.h
new file mode 100644
index 0000000..9375717
--- /dev/null
+++ b/otherlibs/highgui/grfmt_jpeg.h
@@ -0,0 +1,214 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _GRFMT_JPEG_H_
+#define _GRFMT_JPEG_H_
+
+#include "grfmt_base.h"
+#include "bitstrm.h"
+
+#ifdef HAVE_JPEG
+
+/* IJG-based version */
+
+class GrFmtJpegReader : public GrFmtReader
+{
+public:
+
+ GrFmtJpegReader( const char* filename );
+ ~GrFmtJpegReader();
+
+ bool ReadData( uchar* data, int step, int color );
+ bool ReadHeader();
+ void Close();
+
+protected:
+
+ void* m_cinfo; // pointer to IJG JPEG codec structure
+ void* m_jerr; // pointer to error processing manager state
+ FILE* m_f;
+};
+
+
+class GrFmtJpegWriter : public GrFmtWriter
+{
+public:
+
+ GrFmtJpegWriter( const char* filename );
+ ~GrFmtJpegWriter();
+
+ bool WriteImage( const uchar* data, int step,
+ int width, int height, int depth, int channels );
+};
+
+#else
+
+/* hand-crafted implementation */
+
+class RJpegBitStream : public RMBitStream
+{
+public:
+ RMByteStream m_low_strm;
+
+ RJpegBitStream();
+ ~RJpegBitStream();
+
+ virtual bool Open( const char* filename );
+ virtual void Close();
+
+ void Flush(); // flushes high-level bit stream
+ void AlignOnByte();
+ int FindMarker();
+
+protected:
+ virtual void ReadBlock();
+};
+
+
+//////////////////// JPEG reader /////////////////////
+
+class GrFmtJpegReader : public GrFmtReader
+{
+public:
+
+ GrFmtJpegReader( const char* filename );
+ ~GrFmtJpegReader();
+
+ bool ReadData( uchar* data, int step, int color );
+ bool ReadHeader();
+ void Close();
+
+protected:
+
+ int m_offset; // offset of first scan
+ int m_version; // JFIF version
+ int m_planes; // 3 (YCrCb) or 1 (Gray)
+ int m_precision; // 8 or 12-bit per sample
+ int m_type; // SOF type
+ int m_MCUs; // MCUs in restart interval
+ int m_ss, m_se, m_ah, m_al; // progressive JPEG parameters
+
+ // information about each component
+ struct cmp_info
+ {
+ char h; // horizontal sampling factor
+ char v; // vertical sampling factor
+ char tq; // quantization table index
+ char td, ta; // DC & AC huffman tables
+ int dc_pred; // DC predictor
+ };
+
+ cmp_info m_ci[3];
+
+ int m_tq[4][64];
+ bool m_is_tq[4];
+
+ short* m_td[4];
+ bool m_is_td[4];
+
+ short* m_ta[4];
+ bool m_is_ta[4];
+
+ RJpegBitStream m_strm;
+
+protected:
+
+ bool LoadQuantTables( int length );
+ bool LoadHuffmanTables( int length );
+ void ProcessScan( int* idx, int ns, uchar* data, int step, int color );
+ void ResetDecoder();
+ void GetBlock( int* block, int c );
+};
+
+
+//////////////////// JPEG-specific output bitstream ///////////////////////
+
+class WJpegBitStream : public WMBitStream
+{
+public:
+ WMByteStream m_low_strm;
+
+ WJpegBitStream();
+ ~WJpegBitStream();
+
+ virtual void Flush();
+ virtual bool Open( const char* filename );
+ virtual void Close();
+
+protected:
+ virtual void WriteBlock();
+};
+
+
+//////////////////// JPEG reader /////////////////////
+
+class GrFmtJpegWriter : public GrFmtWriter
+{
+public:
+
+ GrFmtJpegWriter( const char* filename );
+ ~GrFmtJpegWriter();
+
+ bool WriteImage( const uchar* data, int step,
+ int width, int height, int depth, int channels );
+
+protected:
+
+ WJpegBitStream m_strm;
+};
+
+#endif /* HAVE_JPEG */
+
+
+// JPEG filter factory
+class GrFmtJpeg : public GrFmtFilterFactory
+{
+public:
+
+ GrFmtJpeg();
+ ~GrFmtJpeg();
+
+ GrFmtReader* NewReader( const char* filename );
+ GrFmtWriter* NewWriter( const char* filename );
+};
+
+
+#endif/*_GRFMT_JPEG_H_*/
diff --git a/otherlibs/highgui/grfmt_jpeg2000.cpp b/otherlibs/highgui/grfmt_jpeg2000.cpp
new file mode 100644
index 0000000..53067f2
--- /dev/null
+++ b/otherlibs/highgui/grfmt_jpeg2000.cpp
@@ -0,0 +1,502 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_highgui.h"
+
+#ifdef HAVE_JASPER
+
+#include "grfmt_jpeg2000.h"
+
+// JPEG-2000 Filter Factory
+GrFmtJpeg2000::GrFmtJpeg2000()
+{
+ m_sign_len = 12;
+ m_signature = "\x00\x00\x00\x0cjP \r\n\x87\n";
+ m_description = "JPEG-2000 files (*.jp2)";
+ jas_init();
+}
+
+
+GrFmtJpeg2000::~GrFmtJpeg2000()
+{
+ jas_cleanup();
+}
+
+
+GrFmtReader* GrFmtJpeg2000::NewReader( const char* filename )
+{
+ return new GrFmtJpeg2000Reader( filename );
+}
+
+
+GrFmtWriter* GrFmtJpeg2000::NewWriter( const char* filename )
+{
+ return new GrFmtJpeg2000Writer( filename );
+}
+
+
+/////////////////////// GrFmtJpeg2000Reader ///////////////////
+
+GrFmtJpeg2000Reader::GrFmtJpeg2000Reader( const char* filename ) : GrFmtReader( filename )
+{
+ m_stream = 0;
+ m_image = 0;
+}
+
+
+GrFmtJpeg2000Reader::~GrFmtJpeg2000Reader()
+{
+}
+
+
+void GrFmtJpeg2000Reader::Close()
+{
+ if( m_stream )
+ {
+ jas_stream_close( m_stream );
+ m_stream = 0;
+ }
+
+ if( m_image )
+ {
+ jas_image_destroy( m_image );
+ m_image = 0;
+ }
+ GrFmtReader::Close();
+}
+
+
+bool GrFmtJpeg2000Reader::ReadHeader()
+{
+ bool result = false;
+
+ Close();
+
+ m_stream = jas_stream_fopen( m_filename, "rb" );
+ if( m_stream )
+ {
+ m_image = jas_image_decode( m_stream, -1, 0 );
+ if( m_image ) {
+ m_width = jas_image_width( m_image );
+ m_height = jas_image_height( m_image );
+
+ int cntcmpts = 0; // count the known components
+ int numcmpts = jas_image_numcmpts( m_image );
+ for( int i = 0; i < numcmpts; i++ )
+ {
+ int depth = jas_image_cmptprec( m_image, i );
+ if( depth > m_bit_depth )
+ m_bit_depth = depth;
+ if( m_bit_depth > 8 )
+ m_bit_depth = 16;
+
+ if( jas_image_cmpttype( m_image, i ) > 2 )
+ continue;
+ cntcmpts++;
+ }
+
+ if( cntcmpts )
+ {
+ m_iscolor = (cntcmpts > 1);
+
+ result = true;
+ }
+ }
+ }
+
+ if( !result )
+ Close();
+
+ return result;
+}
+
+
+bool GrFmtJpeg2000Reader::ReadData( uchar* data, int step, int color )
+{
+ bool result = false;
+
+ color = color > 0 || ( m_iscolor && color < 0 );
+
+ if( m_stream && m_image )
+ {
+ bool convert;
+ int colorspace;
+ if( color )
+ {
+ convert = (jas_image_clrspc( m_image ) != JAS_CLRSPC_SRGB);
+ colorspace = JAS_CLRSPC_SRGB;
+ }
+ else
+ {
+ convert = (jas_clrspc_fam( jas_image_clrspc( m_image ) ) != JAS_CLRSPC_FAM_GRAY);
+ colorspace = JAS_CLRSPC_SGRAY; // TODO GENGRAY or SGRAY?
+ }
+
+ // convert to the desired colorspace
+ if( convert )
+ {
+ jas_cmprof_t *clrprof = jas_cmprof_createfromclrspc( colorspace );
+ if( clrprof )
+ {
+ jas_image_t *img = jas_image_chclrspc( m_image, clrprof, JAS_CMXFORM_INTENT_RELCLR );
+ if( img )
+ {
+ jas_image_destroy( m_image );
+ m_image = img;
+ result = true;
+ }
+ else
+ fprintf(stderr, "JPEG 2000 LOADER ERROR: cannot convert colorspace\n");
+ jas_cmprof_destroy( clrprof );
+ }
+ else
+ fprintf(stderr, "JPEG 2000 LOADER ERROR: unable to create colorspace\n");
+ }
+ else
+ result = true;
+
+ if( result )
+ {
+ int ncmpts;
+ int cmptlut[3];
+ if( color )
+ {
+ cmptlut[0] = jas_image_getcmptbytype( m_image, JAS_IMAGE_CT_RGB_B );
+ cmptlut[1] = jas_image_getcmptbytype( m_image, JAS_IMAGE_CT_RGB_G );
+ cmptlut[2] = jas_image_getcmptbytype( m_image, JAS_IMAGE_CT_RGB_R );
+ if( cmptlut[0] < 0 || cmptlut[1] < 0 || cmptlut[0] < 0 )
+ result = false;
+ ncmpts = 3;
+ }
+ else
+ {
+ cmptlut[0] = jas_image_getcmptbytype( m_image, JAS_IMAGE_CT_GRAY_Y );
+ if( cmptlut[0] < 0 )
+ result = false;
+ ncmpts = 1;
+ }
+
+ if( result )
+ {
+ for( int i = 0; i < ncmpts; i++ )
+ {
+ int maxval = 1 << jas_image_cmptprec( m_image, cmptlut[i] );
+ int offset = jas_image_cmptsgnd( m_image, cmptlut[i] ) ? maxval / 2 : 0;
+
+ int yend = jas_image_cmptbry( m_image, cmptlut[i] );
+ int ystep = jas_image_cmptvstep( m_image, cmptlut[i] );
+ int xend = jas_image_cmptbrx( m_image, cmptlut[i] );
+ int xstep = jas_image_cmpthstep( m_image, cmptlut[i] );
+
+ jas_matrix_t *buffer = jas_matrix_create( yend / ystep, xend / xstep );
+ if( buffer )
+ {
+ if( !jas_image_readcmpt( m_image, cmptlut[i], 0, 0, xend / xstep, yend / ystep, buffer ))
+ {
+ if( m_bit_depth == 8 || !m_native_depth )
+ result = ReadComponent8u( data + i, buffer, step, cmptlut[i], maxval, offset, ncmpts );
+ else
+ result = ReadComponent16u( ((unsigned short *)data) + i, buffer, step / 2, cmptlut[i], maxval, offset, ncmpts );
+ if( !result )
+ {
+ i = ncmpts;
+ result = false;
+ }
+ }
+ jas_matrix_destroy( buffer );
+ }
+ }
+ }
+ }
+ else
+ fprintf(stderr, "JPEG2000 LOADER ERROR: colorspace conversion failed\n" );
+ }
+
+ Close();
+
+ return result;
+}
+
+
+bool GrFmtJpeg2000Reader::ReadComponent8u( uchar *data, jas_matrix_t *buffer,
+ int step, int cmpt,
+ int maxval, int offset, int ncmpts )
+{
+ int xstart = jas_image_cmpttlx( m_image, cmpt );
+ int xend = jas_image_cmptbrx( m_image, cmpt );
+ int xstep = jas_image_cmpthstep( m_image, cmpt );
+ int xoffset = jas_image_tlx( m_image );
+ int ystart = jas_image_cmpttly( m_image, cmpt );
+ int yend = jas_image_cmptbry( m_image, cmpt );
+ int ystep = jas_image_cmptvstep( m_image, cmpt );
+ int yoffset = jas_image_tly( m_image );
+ int x, y, x1, y1, j;
+ int rshift = cvRound(log(maxval/256.)/log(2.));
+ int lshift = MAX(0, -rshift);
+ rshift = MAX(0, rshift);
+ int delta = (rshift > 0 ? 1 << (rshift - 1) : 0) + offset;
+
+ for( y = 0; y < yend - ystart; )
+ {
+ jas_seqent_t* pix_row = &jas_matrix_get( buffer, y / ystep, 0 );
+ uchar* dst = data + (y - yoffset) * step - xoffset;
+
+ if( xstep == 1 )
+ {
+ if( maxval == 256 && offset == 0 )
+ for( x = 0; x < xend - xstart; x++ )
+ {
+ int pix = pix_row[x];
+ dst[x*ncmpts] = CV_CAST_8U(pix);
+ }
+ else
+ for( x = 0; x < xend - xstart; x++ )
+ {
+ int pix = ((pix_row[x] + delta) >> rshift) << lshift;
+ dst[x*ncmpts] = CV_CAST_8U(pix);
+ }
+ }
+ else if( xstep == 2 && offset == 0 )
+ for( x = 0, j = 0; x < xend - xstart; x += 2, j++ )
+ {
+ int pix = ((pix_row[j] + delta) >> rshift) << lshift;
+ dst[x*ncmpts] = dst[(x+1)*ncmpts] = CV_CAST_8U(pix);
+ }
+ else
+ for( x = 0, j = 0; x < xend - xstart; j++ )
+ {
+ int pix = ((pix_row[j] + delta) >> rshift) << lshift;
+ pix = CV_CAST_8U(pix);
+ for( x1 = x + xstep; x < x1; x++ )
+ dst[x*ncmpts] = (uchar)pix;
+ }
+ y1 = y + ystep;
+ for( ++y; y < y1; y++, dst += step )
+ for( x = 0; x < xend - xstart; x++ )
+ dst[x*ncmpts + step] = dst[x*ncmpts];
+ }
+
+ return true;
+}
+
+
+bool GrFmtJpeg2000Reader::ReadComponent16u( unsigned short *data, jas_matrix_t *buffer,
+ int step, int cmpt,
+ int maxval, int offset, int ncmpts )
+{
+ int xstart = jas_image_cmpttlx( m_image, cmpt );
+ int xend = jas_image_cmptbrx( m_image, cmpt );
+ int xstep = jas_image_cmpthstep( m_image, cmpt );
+ int xoffset = jas_image_tlx( m_image );
+ int ystart = jas_image_cmpttly( m_image, cmpt );
+ int yend = jas_image_cmptbry( m_image, cmpt );
+ int ystep = jas_image_cmptvstep( m_image, cmpt );
+ int yoffset = jas_image_tly( m_image );
+ int x, y, x1, y1, j;
+ int rshift = cvRound(log(maxval/65536.)/log(2.));
+ int lshift = MAX(0, -rshift);
+ rshift = MAX(0, rshift);
+ int delta = (rshift > 0 ? 1 << (rshift - 1) : 0) + offset;
+
+ for( y = 0; y < yend - ystart; )
+ {
+ jas_seqent_t* pix_row = &jas_matrix_get( buffer, y / ystep, 0 );
+ ushort* dst = data + (y - yoffset) * step - xoffset;
+
+ if( xstep == 1 )
+ {
+ if( maxval == 65536 && offset == 0 )
+ for( x = 0; x < xend - xstart; x++ )
+ {
+ int pix = pix_row[x];
+ dst[x*ncmpts] = CV_CAST_16U(pix);
+ }
+ else
+ for( x = 0; x < xend - xstart; x++ )
+ {
+ int pix = ((pix_row[x] + delta) >> rshift) << lshift;
+ dst[x*ncmpts] = CV_CAST_16U(pix);
+ }
+ }
+ else if( xstep == 2 && offset == 0 )
+ for( x = 0, j = 0; x < xend - xstart; x += 2, j++ )
+ {
+ int pix = ((pix_row[j] + delta) >> rshift) << lshift;
+ dst[x*ncmpts] = dst[(x+1)*ncmpts] = CV_CAST_16U(pix);
+ }
+ else
+ for( x = 0, j = 0; x < xend - xstart; j++ )
+ {
+ int pix = ((pix_row[j] + delta) >> rshift) << lshift;
+ pix = CV_CAST_16U(pix);
+ for( x1 = x + xstep; x < x1; x++ )
+ dst[x*ncmpts] = (ushort)pix;
+ }
+ y1 = y + ystep;
+ for( ++y; y < y1; y++, dst += step )
+ for( x = 0; x < xend - xstart; x++ )
+ dst[x*ncmpts + step] = dst[x*ncmpts];
+ }
+
+ return true;
+}
+
+
+/////////////////////// GrFmtJpeg2000Writer ///////////////////
+
+
+GrFmtJpeg2000Writer::GrFmtJpeg2000Writer( const char* filename ) : GrFmtWriter( filename )
+{
+}
+
+
+GrFmtJpeg2000Writer::~GrFmtJpeg2000Writer()
+{
+}
+
+
+bool GrFmtJpeg2000Writer::IsFormatSupported( int depth )
+{
+ return depth == IPL_DEPTH_8U || depth == IPL_DEPTH_16U;
+}
+
+
+bool GrFmtJpeg2000Writer::WriteImage( const uchar* data, int step,
+ int width, int height, int depth, int channels )
+{
+ if( channels > 3 || channels < 1 )
+ return false;
+
+ jas_image_cmptparm_t component_info[3];
+ for( int i = 0; i < channels; i++ )
+ {
+ component_info[i].tlx = 0;
+ component_info[i].tly = 0;
+ component_info[i].hstep = 1;
+ component_info[i].vstep = 1;
+ component_info[i].width = width;
+ component_info[i].height = height;
+ component_info[i].prec = depth;
+ component_info[i].sgnd = 0;
+ }
+ jas_image_t *img = jas_image_create( channels, component_info, (channels == 1) ? JAS_CLRSPC_SGRAY : JAS_CLRSPC_SRGB );
+ if( !img )
+ return false;
+
+ if(channels == 1)
+ jas_image_setcmpttype( img, 0, JAS_IMAGE_CT_GRAY_Y );
+ else
+ {
+ jas_image_setcmpttype( img, 0, JAS_IMAGE_CT_RGB_B );
+ jas_image_setcmpttype( img, 1, JAS_IMAGE_CT_RGB_G );
+ jas_image_setcmpttype( img, 2, JAS_IMAGE_CT_RGB_R );
+ }
+
+ bool result;
+ if( depth == 8 )
+ result = WriteComponent8u( img, data, step, channels, width, height );
+ else
+ result = WriteComponent16u( img, (const unsigned short *)data, step / 2, channels, width, height );
+ if( result )
+ {
+ jas_stream_t *stream = jas_stream_fopen( m_filename, "wb" );
+ if( stream )
+ {
+ result = !jas_image_encode( img, stream, jas_image_strtofmt( "jp2" ), "" );
+
+ jas_stream_close( stream );
+ }
+
+ }
+ jas_image_destroy( img );
+
+ return result;
+}
+
+
+bool GrFmtJpeg2000Writer::WriteComponent8u( jas_image_t *img, const uchar *data,
+ int step, int ncmpts, int w, int h )
+{
+ jas_matrix_t *row = jas_matrix_create( 1, w );
+ if(!row)
+ return false;
+
+ for( int y = 0; y < h; y++, data += step )
+ {
+ for( int i = 0; i < ncmpts; i++ )
+ {
+ for( int x = 0; x < w; x++)
+ jas_matrix_setv( row, x, data[x * ncmpts + i] );
+ jas_image_writecmpt( img, i, 0, y, w, 1, row );
+ }
+ }
+
+ jas_matrix_destroy( row );
+
+ return true;
+}
+
+
+bool GrFmtJpeg2000Writer::WriteComponent16u( jas_image_t *img, const unsigned short *data,
+ int step, int ncmpts, int w, int h )
+{
+ jas_matrix_t *row = jas_matrix_create( 1, w );
+ if(!row)
+ return false;
+
+ for( int y = 0; y < h; y++, data += step )
+ {
+ for( int i = 0; i < ncmpts; i++ )
+ {
+ for( int x = 0; x < w; x++)
+ jas_matrix_setv( row, x, data[x * ncmpts + i] );
+ jas_image_writecmpt( img, i, 0, y, w, 1, row );
+ }
+ }
+
+ jas_matrix_destroy( row );
+
+ return true;
+}
+
+#endif
+
+/* End of file. */
diff --git a/otherlibs/highgui/grfmt_jpeg2000.h b/otherlibs/highgui/grfmt_jpeg2000.h
new file mode 100644
index 0000000..d9e4a13
--- /dev/null
+++ b/otherlibs/highgui/grfmt_jpeg2000.h
@@ -0,0 +1,115 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _GRFMT_JASPER_H_
+#define _GRFMT_JASPER_H_
+
+#ifdef HAVE_JASPER
+
+#ifdef WIN32
+#define JAS_WIN_MSVC_BUILD 1
+#endif
+
+#include <jasper/jasper.h>
+// FIXME bad hack
+#undef uchar
+#undef ulong
+#include "grfmt_base.h"
+
+
+/* libpng version only */
+
+class GrFmtJpeg2000Reader : public GrFmtReader
+{
+public:
+
+ GrFmtJpeg2000Reader( const char* filename );
+ ~GrFmtJpeg2000Reader();
+
+ bool CheckFormat( const char* signature );
+ bool ReadData( uchar* data, int step, int color );
+ bool ReadHeader();
+ void Close();
+
+protected:
+ bool ReadComponent8u( uchar *data, jas_matrix_t *buffer, int step, int cmpt,
+ int maxval, int offset, int ncmpts );
+ bool ReadComponent16u( unsigned short *data, jas_matrix_t *buffer, int step, int cmpt,
+ int maxval, int offset, int ncmpts );
+
+ jas_stream_t *m_stream;
+ jas_image_t *m_image;
+};
+
+
+class GrFmtJpeg2000Writer : public GrFmtWriter
+{
+public:
+
+ GrFmtJpeg2000Writer( const char* filename );
+ ~GrFmtJpeg2000Writer();
+
+ bool IsFormatSupported( int depth );
+ bool WriteImage( const uchar* data, int step,
+ int width, int height, int depth, int channels );
+protected:
+ bool WriteComponent8u( jas_image_t *img, const uchar *data,
+ int step, int ncmpts, int w, int h );
+ bool WriteComponent16u( jas_image_t *img, const unsigned short *data,
+ int step, int ncmpts, int w, int h );
+};
+
+
+// PNG filter factory
+class GrFmtJpeg2000 : public GrFmtFilterFactory
+{
+public:
+
+ GrFmtJpeg2000();
+ ~GrFmtJpeg2000();
+
+ GrFmtReader* NewReader( const char* filename );
+ GrFmtWriter* NewWriter( const char* filename );
+};
+
+#endif
+
+#endif/*_GRFMT_JASPER_H_*/
diff --git a/otherlibs/highgui/grfmt_png.cpp b/otherlibs/highgui/grfmt_png.cpp
new file mode 100644
index 0000000..b116ada
--- /dev/null
+++ b/otherlibs/highgui/grfmt_png.cpp
@@ -0,0 +1,333 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_highgui.h"
+
+#ifdef HAVE_PNG
+
+/****************************************************************************************\
+ This part of the file implements PNG codec on base of libpng library,
+ in particular, this code is based on example.c from libpng
+ (see otherlibs/_graphics/readme.txt for copyright notice)
+ and png2bmp sample from libpng distribution (Copyright (C) 1999-2001 MIYASAKA Masaru)
+\****************************************************************************************/
+
+#if defined WIN32 || defined HAVE_PNG_H
+#include <png.h>
+#else
+#include <libpng/png.h>
+#endif
+#include "grfmt_png.h"
+
+// PNG Filter Factory
+GrFmtPng::GrFmtPng()
+{
+ m_sign_len = 8;
+ m_signature = "\x89\x50\x4e\x47\xd\xa\x1a\xa";
+ m_description = "Portable Network Graphics files (*.png)";
+}
+
+
+GrFmtPng::~GrFmtPng()
+{
+}
+
+
+GrFmtReader* GrFmtPng::NewReader( const char* filename )
+{
+ return new GrFmtPngReader( filename );
+}
+
+
+GrFmtWriter* GrFmtPng::NewWriter( const char* filename )
+{
+ return new GrFmtPngWriter( filename );
+}
+
+
+bool GrFmtPng::CheckSignature( const char* signature )
+{
+ return png_check_sig( (uchar*)signature, m_sign_len ) != 0;
+}
+
+/////////////////////// GrFmtPngReader ///////////////////
+
+GrFmtPngReader::GrFmtPngReader( const char* filename ) : GrFmtReader( filename )
+{
+ m_color_type = m_bit_depth = 0;
+ m_png_ptr = 0;
+ m_info_ptr = m_end_info = 0;
+ m_f = 0;
+}
+
+
+GrFmtPngReader::~GrFmtPngReader()
+{
+}
+
+
+void GrFmtPngReader::Close()
+{
+ if( m_f )
+ {
+ fclose( m_f );
+ m_f = 0;
+ }
+
+ if( m_png_ptr )
+ {
+ png_structp png_ptr = (png_structp)m_png_ptr;
+ png_infop info_ptr = (png_infop)m_info_ptr;
+ png_infop end_info = (png_infop)m_end_info;
+ png_destroy_read_struct( &png_ptr, &info_ptr, &end_info );
+ m_png_ptr = m_info_ptr = m_end_info = 0;
+ }
+ GrFmtReader::Close();
+}
+
+
+bool GrFmtPngReader::ReadHeader()
+{
+ bool result = false;
+
+ Close();
+
+ png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
+
+ if( png_ptr )
+ {
+ png_infop info_ptr = png_create_info_struct( png_ptr );
+ png_infop end_info = png_create_info_struct( png_ptr );
+
+ m_png_ptr = png_ptr;
+ m_info_ptr = info_ptr;
+ m_end_info = end_info;
+
+ if( info_ptr && end_info )
+ {
+ if( setjmp( png_ptr->jmpbuf ) == 0 )
+ {
+ m_f = fopen( m_filename, "rb" );
+ if( m_f )
+ {
+ png_uint_32 width, height;
+ int bit_depth, color_type;
+
+ png_init_io( png_ptr, m_f );
+ png_read_info( png_ptr, info_ptr );
+
+ png_get_IHDR( png_ptr, info_ptr, &width, &height,
+ &bit_depth, &color_type, 0, 0, 0 );
+
+ m_iscolor = color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
+ color_type == PNG_COLOR_TYPE_PALETTE;
+
+ m_width = (int)width;
+ m_height = (int)height;
+ m_color_type = color_type;
+ m_bit_depth = bit_depth;
+
+ result = true;
+ }
+ }
+ }
+ }
+
+ if( !result )
+ Close();
+
+ return result;
+}
+
+
+bool GrFmtPngReader::ReadData( uchar* data, int step, int color )
+{
+ bool result = false;
+ uchar** buffer = 0;
+
+ color = color > 0 || ( m_iscolor && color < 0 );
+
+ if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height )
+ {
+ png_structp png_ptr = (png_structp)m_png_ptr;
+ png_infop info_ptr = (png_infop)m_info_ptr;
+ png_infop end_info = (png_infop)m_end_info;
+
+ if( setjmp(png_ptr->jmpbuf) == 0 )
+ {
+ int y;
+
+ if( m_bit_depth > 8 && !m_native_depth )
+ png_set_strip_16( png_ptr );
+ else if( !isBigEndian() )
+ png_set_swap( png_ptr );
+
+ /* observation: png_read_image() writes 400 bytes beyond
+ * end of data when reading a 400x118 color png
+ * "mpplus_sand.png". OpenCV crashes even with demo
+ * programs. Looking at the loaded image I'd say we get 4
+ * bytes per pixel instead of 3 bytes per pixel. Test
+ * indicate that it is a good idea to always ask for
+ * stripping alpha.. 18.11.2004 Axel Walthelm
+ */
+ png_set_strip_alpha( png_ptr );
+
+ if( m_color_type == PNG_COLOR_TYPE_PALETTE )
+ png_set_palette_to_rgb( png_ptr );
+
+ if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 )
+ png_set_gray_1_2_4_to_8( png_ptr );
+
+ if( m_iscolor && color )
+ png_set_bgr( png_ptr ); // convert RGB to BGR
+ else if( color )
+ png_set_gray_to_rgb( png_ptr ); // Gray->RGB
+ else
+ png_set_rgb_to_gray( png_ptr, 1, -1, -1 ); // RGB->Gray
+
+ png_read_update_info( png_ptr, info_ptr );
+
+ buffer = new uchar*[m_height];
+
+ for( y = 0; y < m_height; y++ )
+ buffer[y] = data + y*step;
+
+ png_read_image( png_ptr, buffer );
+ png_read_end( png_ptr, end_info );
+
+ result = true;
+ }
+ }
+
+ Close();
+ delete[] buffer;
+
+ return result;
+}
+
+
+/////////////////////// GrFmtPngWriter ///////////////////
+
+
+GrFmtPngWriter::GrFmtPngWriter( const char* filename ) : GrFmtWriter( filename )
+{
+}
+
+
+GrFmtPngWriter::~GrFmtPngWriter()
+{
+}
+
+
+bool GrFmtPngWriter::IsFormatSupported( int depth )
+{
+ return depth == IPL_DEPTH_8U || depth == IPL_DEPTH_16U;
+}
+
+bool GrFmtPngWriter::WriteImage( const uchar* data, int step,
+ int width, int height, int depth, int channels )
+{
+ png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
+ png_infop info_ptr = 0;
+ FILE* f = 0;
+ uchar** buffer = 0;
+ int y;
+ bool result = false;
+
+ if( depth != IPL_DEPTH_8U && depth != IPL_DEPTH_16U )
+ return false;
+
+ if( png_ptr )
+ {
+ info_ptr = png_create_info_struct( png_ptr );
+
+ if( info_ptr )
+ {
+ if( setjmp( png_ptr->jmpbuf ) == 0 )
+ {
+ f = fopen( m_filename, "wb" );
+
+ if( f )
+ {
+ png_init_io( png_ptr, f );
+
+ png_set_compression_mem_level( png_ptr, MAX_MEM_LEVEL );
+
+ png_set_IHDR( png_ptr, info_ptr, width, height, depth,
+ channels == 1 ? PNG_COLOR_TYPE_GRAY :
+ channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT );
+
+ png_write_info( png_ptr, info_ptr );
+
+ png_set_bgr( png_ptr );
+ if( !isBigEndian() )
+ png_set_swap( png_ptr );
+
+ buffer = new uchar*[height];
+ for( y = 0; y < height; y++ )
+ buffer[y] = (uchar*)(data + y*step);
+
+ png_write_image( png_ptr, buffer );
+ png_write_end( png_ptr, info_ptr );
+
+ delete[] buffer;
+
+ result = true;
+ }
+ }
+ }
+ }
+
+ png_destroy_write_struct( &png_ptr, &info_ptr );
+
+ if(f) fclose( f );
+
+ return result;
+}
+
+#endif
+
+/* End of file. */
+
+
diff --git a/otherlibs/highgui/grfmt_png.h b/otherlibs/highgui/grfmt_png.h
new file mode 100644
index 0000000..aef7347
--- /dev/null
+++ b/otherlibs/highgui/grfmt_png.h
@@ -0,0 +1,103 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _GRFMT_PNG_H_
+#define _GRFMT_PNG_H_
+
+#ifdef HAVE_PNG
+
+#include "grfmt_base.h"
+#include "bitstrm.h"
+
+/* libpng version only */
+
+class GrFmtPngReader : public GrFmtReader
+{
+public:
+
+ GrFmtPngReader( const char* filename );
+ ~GrFmtPngReader();
+
+ bool CheckFormat( const char* signature );
+ bool ReadData( uchar* data, int step, int color );
+ bool ReadHeader();
+ void Close();
+
+protected:
+
+ void* m_png_ptr; // pointer to decompression structure
+ void* m_info_ptr; // pointer to image information structure
+ void* m_end_info; // pointer to one more image information structure
+ FILE* m_f;
+ int m_color_type;
+};
+
+
+class GrFmtPngWriter : public GrFmtWriter
+{
+public:
+
+ GrFmtPngWriter( const char* filename );
+ ~GrFmtPngWriter();
+
+ bool IsFormatSupported( int depth );
+ bool WriteImage( const uchar* data, int step,
+ int width, int height, int depth, int channels );
+protected:
+};
+
+
+// PNG filter factory
+class GrFmtPng : public GrFmtFilterFactory
+{
+public:
+
+ GrFmtPng();
+ ~GrFmtPng();
+
+ GrFmtReader* NewReader( const char* filename );
+ GrFmtWriter* NewWriter( const char* filename );
+ bool CheckSignature( const char* signature );
+};
+
+#endif
+
+#endif/*_GRFMT_PNG_H_*/
diff --git a/otherlibs/highgui/grfmt_pxm.cpp b/otherlibs/highgui/grfmt_pxm.cpp
new file mode 100644
index 0000000..d917ea8
--- /dev/null
+++ b/otherlibs/highgui/grfmt_pxm.cpp
@@ -0,0 +1,510 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_highgui.h"
+#include "utils.h"
+#include "grfmt_pxm.h"
+
+// P?M filter factory
+
+GrFmtPxM::GrFmtPxM()
+{
+ m_sign_len = 3;
+ m_signature = "";
+ m_description = "Portable image format (*.pbm;*.pgm;*.ppm;*.pxm;*.pnm)";
+}
+
+
+GrFmtPxM::~GrFmtPxM()
+{
+}
+
+
+bool GrFmtPxM::CheckSignature( const char* signature )
+{
+ return signature[0] == 'P' &&
+ '1' <= signature[1] && signature[1] <= '6' &&
+ isspace(signature[2]);
+}
+
+
+GrFmtReader* GrFmtPxM::NewReader( const char* filename )
+{
+ return new GrFmtPxMReader( filename );
+}
+
+
+GrFmtWriter* GrFmtPxM::NewWriter( const char* filename )
+{
+ return new GrFmtPxMWriter( filename );
+}
+
+
+///////////////////////// P?M reader //////////////////////////////
+
+static int ReadNumber( RLByteStream& strm, int maxdigits )
+{
+ int code;
+ int val = 0;
+ int digits = 0;
+
+ code = strm.GetByte();
+
+ if( !isdigit(code))
+ {
+ do
+ {
+ if( code == '#' )
+ {
+ do
+ {
+ code = strm.GetByte();
+ }
+ while( code != '\n' && code != '\r' );
+ }
+
+ code = strm.GetByte();
+
+ while( isspace(code))
+ code = strm.GetByte();
+ }
+ while( !isdigit( code ));
+ }
+
+ do
+ {
+ val = val*10 + code - '0';
+ if( ++digits >= maxdigits ) break;
+ code = strm.GetByte();
+ }
+ while( isdigit(code));
+
+ return val;
+}
+
+
+GrFmtPxMReader::GrFmtPxMReader( const char* filename ) : GrFmtReader( filename )
+{
+ m_offset = -1;
+}
+
+
+GrFmtPxMReader::~GrFmtPxMReader()
+{
+}
+
+
+void GrFmtPxMReader::Close()
+{
+ m_strm.Close();
+}
+
+
+bool GrFmtPxMReader::ReadHeader()
+{
+ bool result = false;
+
+ assert( strlen(m_filename) != 0 );
+ if( !m_strm.Open( m_filename )) return false;
+
+ if( setjmp( m_strm.JmpBuf()) == 0 )
+ {
+ int code = m_strm.GetByte();
+ if( code != 'P' )
+ BAD_HEADER_ERR();
+
+ code = m_strm.GetByte();
+ switch( code )
+ {
+ case '1': case '4': m_bpp = 1; break;
+ case '2': case '5': m_bpp = 8; break;
+ case '3': case '6': m_bpp = 24; break;
+ default: BAD_HEADER_ERR();
+ }
+
+ m_binary = code >= '4';
+ m_iscolor = m_bpp > 8;
+
+ m_width = ReadNumber( m_strm, INT_MAX );
+ m_height = ReadNumber( m_strm, INT_MAX );
+
+ m_maxval = m_bpp == 1 ? 1 : ReadNumber( m_strm, INT_MAX );
+ if( m_maxval > 65535 )
+ BAD_HEADER_ERR();
+
+ //if( m_maxval > 255 ) m_binary = false; nonsense
+ if( m_maxval > 255 )
+ m_bit_depth = 16;
+
+ if( m_width > 0 && m_height > 0 && m_maxval > 0 && m_maxval < (1 << 16))
+ {
+ m_offset = m_strm.GetPos();
+ result = true;
+ }
+bad_header_exit:
+ ;
+ }
+
+ if( !result )
+ {
+ m_offset = -1;
+ m_width = m_height = -1;
+ m_strm.Close();
+ }
+ return result;
+}
+
+
+bool GrFmtPxMReader::ReadData( uchar* data, int step, int color )
+{
+ const int buffer_size = 1 << 12;
+ uchar buffer[buffer_size];
+ uchar pal_buffer[buffer_size];
+ PaletteEntry palette[256];
+ bool result = false;
+ uchar* src = buffer;
+ uchar* gray_palette = pal_buffer;
+ int src_pitch = (m_width*m_bpp*m_bit_depth/8 + 7)/8;
+ int nch = m_iscolor ? 3 : 1;
+ int width3 = m_width*nch;
+ int i, x, y;
+
+ if( m_offset < 0 || !m_strm.IsOpened())
+ return false;
+
+ if( src_pitch+32 > buffer_size )
+ src = new uchar[width3*m_bit_depth/8 + 32];
+
+ // create LUT for converting colors
+ if( m_bit_depth == 8 )
+ {
+ if( m_maxval + 1 > buffer_size )
+ gray_palette = new uchar[m_maxval + 1];
+
+ for( i = 0; i <= m_maxval; i++ )
+ {
+ gray_palette[i] = (uchar)((i*255/m_maxval)^(m_bpp == 1 ? 255 : 0));
+ }
+
+ FillGrayPalette( palette, m_bpp==1 ? 1 : 8 , m_bpp == 1 );
+ }
+
+ if( setjmp( m_strm.JmpBuf()) == 0 )
+ {
+ m_strm.SetPos( m_offset );
+
+ switch( m_bpp )
+ {
+ ////////////////////////// 1 BPP /////////////////////////
+ case 1:
+ if( !m_binary )
+ {
+ for( y = 0; y < m_height; y++, data += step )
+ {
+ for( x = 0; x < m_width; x++ )
+ src[x] = ReadNumber( m_strm, 1 ) != 0;
+
+ if( color )
+ FillColorRow8( data, src, m_width, palette );
+ else
+ FillGrayRow8( data, src, m_width, gray_palette );
+ }
+ }
+ else
+ {
+ for( y = 0; y < m_height; y++, data += step )
+ {
+ m_strm.GetBytes( src, src_pitch );
+
+ if( color )
+ FillColorRow1( data, src, m_width, palette );
+ else
+ FillGrayRow1( data, src, m_width, gray_palette );
+ }
+ }
+ result = true;
+ break;
+
+ ////////////////////////// 8 BPP /////////////////////////
+ case 8:
+ case 24:
+ for( y = 0; y < m_height; y++, data += step )
+ {
+ if( !m_binary )
+ {
+ for( x = 0; x < width3; x++ )
+ {
+ int code = ReadNumber( m_strm, INT_MAX );
+ if( (unsigned)code > (unsigned)m_maxval ) code = m_maxval;
+ if( m_bit_depth == 8 )
+ src[x] = gray_palette[code];
+ else
+ ((ushort *)src)[x] = (ushort)code;
+ }
+ }
+ else
+ {
+ m_strm.GetBytes( src, src_pitch );
+ if( m_bit_depth == 16 && !isBigEndian() )
+ {
+ for( x = 0; x < width3; x++ )
+ {
+ uchar v = src[x * 2];
+ src[x * 2] = src[x * 2 + 1];
+ src[x * 2 + 1] = v;
+ }
+ }
+ }
+
+ if( !m_native_depth && m_bit_depth == 16 )
+ {
+ for( x = 0; x < width3; x++ )
+ {
+ int v = ((ushort *)src)[x];
+ src[x] = (uchar)(v >> 8);
+ }
+ }
+
+ if( m_bpp == 8 ) // image has one channel
+ {
+ if( color )
+ {
+ if( m_bit_depth == 8 || !m_native_depth ) {
+ uchar *d = data, *s = src, *end = src + m_width;
+ for( ; s < end; d += 3, s++)
+ d[0] = d[1] = d[2] = *s;
+ } else {
+ ushort *d = (ushort *)data, *s = (ushort *)src, *end = ((ushort *)src) + m_width;
+ for( ; s < end; s++, d += 3)
+ d[0] = d[1] = d[2] = *s;
+ }
+ }
+ else if( m_native_depth )
+ memcpy( data, src, m_width*m_bit_depth/8 );
+ else
+ memcpy( data, src, m_width );
+ }
+ else
+ {
+ if( color )
+ {
+ if( m_bit_depth == 8 || !m_native_depth )
+ icvCvt_RGB2BGR_8u_C3R( src, 0, data, 0, cvSize(m_width,1) );
+ else
+ icvCvt_RGB2BGR_16u_C3R( (ushort *)src, 0, (ushort *)data, 0, cvSize(m_width,1) );
+ }
+ else if( m_bit_depth == 8 || !m_native_depth )
+ icvCvt_BGR2Gray_8u_C3C1R( src, 0, data, 0, cvSize(m_width,1), 2 );
+ else
+ icvCvt_BGR2Gray_16u_C3C1R( (ushort *)src, 0, (ushort *)data, 0, cvSize(m_width,1), 2 );
+ }
+ }
+ result = true;
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ if( src != buffer )
+ delete[] src;
+
+ if( gray_palette != pal_buffer )
+ delete[] gray_palette;
+
+ return result;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+GrFmtPxMWriter::GrFmtPxMWriter( const char* filename ) : GrFmtWriter( filename )
+{
+}
+
+
+GrFmtPxMWriter::~GrFmtPxMWriter()
+{
+}
+
+
+bool GrFmtPxMWriter::IsFormatSupported( int depth )
+{
+ return depth == IPL_DEPTH_8U || depth == IPL_DEPTH_16U;
+}
+
+
+bool GrFmtPxMWriter::WriteImage( const uchar* data, int step,
+ int width, int height, int depth, int _channels )
+{
+ bool isBinary = true;
+ bool result = false;
+
+ int channels = _channels > 1 ? 3 : 1;
+ int fileStep = width*channels*(depth/8);
+ int x, y;
+
+ assert( data && width > 0 && height > 0 && step >= fileStep );
+
+ if( m_strm.Open( m_filename ) )
+ {
+ int lineLength;
+ int bufferSize = 128; // buffer that should fit a header
+ char* buffer = 0;
+
+ if( isBinary )
+ lineLength = channels * width * depth / 8;
+ else
+ lineLength = (6 * channels + (channels > 1 ? 2 : 0)) * width + 32;
+
+ if( bufferSize < lineLength )
+ bufferSize = lineLength;
+
+ buffer = new char[bufferSize];
+ if( !buffer )
+ {
+ m_strm.Close();
+ return false;
+ }
+
+ // write header;
+ sprintf( buffer, "P%c\n%d %d\n%d\n",
+ '2' + (channels > 1 ? 1 : 0) + (isBinary ? 3 : 0),
+ width, height, (1 << depth) - 1 );
+
+ m_strm.PutBytes( buffer, (int)strlen(buffer) );
+
+ for( y = 0; y < height; y++, data += step )
+ {
+ if( isBinary )
+ {
+ if( _channels == 3 )
+ {
+ if( depth == 8 )
+ icvCvt_BGR2RGB_8u_C3R( (uchar*)data, 0,
+ (uchar*)buffer, 0, cvSize(width,1) );
+ else
+ icvCvt_BGR2RGB_16u_C3R( (ushort*)data, 0,
+ (ushort*)buffer, 0, cvSize(width,1) );
+ }
+
+ // swap endianness if necessary
+ if( depth == 16 && !isBigEndian() )
+ {
+ if( _channels == 1 )
+ memcpy( buffer, data, fileStep );
+ for( x = 0; x < width*channels*2; x += 2 )
+ {
+ uchar v = buffer[x];
+ buffer[x] = buffer[x + 1];
+ buffer[x + 1] = v;
+ }
+ }
+ m_strm.PutBytes( (channels > 1 || depth > 8) ? buffer : (char*)data, fileStep );
+ }
+ else
+ {
+ char* ptr = buffer;
+
+ if( channels > 1 )
+ {
+ if( depth == 8 )
+ {
+ for( x = 0; x < width*channels; x += channels )
+ {
+ sprintf( ptr, "% 4d", data[x + 2] );
+ ptr += 4;
+ sprintf( ptr, "% 4d", data[x + 1] );
+ ptr += 4;
+ sprintf( ptr, "% 4d", data[x] );
+ ptr += 4;
+ *ptr++ = ' ';
+ *ptr++ = ' ';
+ }
+ }
+ else
+ {
+ for( x = 0; x < width*channels; x += channels )
+ {
+ sprintf( ptr, "% 6d", ((ushort *)data)[x + 2] );
+ ptr += 6;
+ sprintf( ptr, "% 6d", ((ushort *)data)[x + 1] );
+ ptr += 6;
+ sprintf( ptr, "% 6d", ((ushort *)data)[x] );
+ ptr += 6;
+ *ptr++ = ' ';
+ *ptr++ = ' ';
+ }
+ }
+ }
+ else
+ {
+ if( depth == 8 )
+ {
+ for( x = 0; x < width; x++ )
+ {
+ sprintf( ptr, "% 4d", data[x] );
+ ptr += 4;
+ }
+ }
+ else
+ {
+ for( x = 0; x < width; x++ )
+ {
+ sprintf( ptr, "% 6d", ((ushort *)data)[x] );
+ ptr += 6;
+ }
+ }
+ }
+
+ *ptr++ = '\n';
+
+ m_strm.PutBytes( buffer, (int)(ptr - buffer) );
+ }
+ }
+ delete[] buffer;
+ m_strm.Close();
+ result = true;
+ }
+
+ return result;
+}
+
diff --git a/otherlibs/highgui/grfmt_pxm.h b/otherlibs/highgui/grfmt_pxm.h
new file mode 100644
index 0000000..96b98b0
--- /dev/null
+++ b/otherlibs/highgui/grfmt_pxm.h
@@ -0,0 +1,103 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _GRFMT_PxM_H_
+#define _GRFMT_PxM_H_
+
+#include "grfmt_base.h"
+#include "bitstrm.h"
+
+
+class GrFmtPxMReader : public GrFmtReader
+{
+public:
+
+ GrFmtPxMReader( const char* filename );
+ ~GrFmtPxMReader();
+
+ bool CheckFormat( const char* signature );
+ bool ReadData( uchar* data, int step, int color );
+ bool ReadHeader();
+ void Close();
+
+protected:
+
+ RLByteStream m_strm;
+ PaletteEntry m_palette[256];
+ int m_bpp;
+ int m_offset;
+ bool m_binary;
+ int m_maxval;
+};
+
+
+class GrFmtPxMWriter : public GrFmtWriter
+{
+public:
+
+ GrFmtPxMWriter( const char* filename );
+ ~GrFmtPxMWriter();
+
+ bool IsFormatSupported( int depth );
+
+ bool WriteImage( const uchar* data, int step,
+ int width, int height, int depth, int channels );
+protected:
+
+ WLByteStream m_strm;
+};
+
+
+// PxM filter factory
+class GrFmtPxM : public GrFmtFilterFactory
+{
+public:
+
+ GrFmtPxM();
+ ~GrFmtPxM();
+
+ GrFmtReader* NewReader( const char* filename );
+ GrFmtWriter* NewWriter( const char* filename );
+ bool CheckSignature( const char* signature );
+};
+
+
+#endif/*_GRFMT_PxM_H_*/
diff --git a/otherlibs/highgui/grfmt_sunras.cpp b/otherlibs/highgui/grfmt_sunras.cpp
new file mode 100644
index 0000000..5f5b02e
--- /dev/null
+++ b/otherlibs/highgui/grfmt_sunras.cpp
@@ -0,0 +1,442 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_highgui.h"
+#include "grfmt_sunras.h"
+
+static const char* fmtSignSunRas = "\x59\xA6\x6A\x95";
+
+// Sun Raster filter factory
+
+GrFmtSunRaster::GrFmtSunRaster()
+{
+ m_sign_len = 4;
+ m_signature = fmtSignSunRas;
+ m_description = "Sun raster files (*.sr;*.ras)";
+}
+
+
+GrFmtSunRaster::~GrFmtSunRaster()
+{
+}
+
+
+GrFmtReader* GrFmtSunRaster::NewReader( const char* filename )
+{
+ return new GrFmtSunRasterReader( filename );
+}
+
+
+GrFmtWriter* GrFmtSunRaster::NewWriter( const char* filename )
+{
+ return new GrFmtSunRasterWriter( filename );
+}
+
+
+/************************ Sun Raster reader *****************************/
+
+GrFmtSunRasterReader::GrFmtSunRasterReader( const char* filename ) : GrFmtReader( filename )
+{
+ m_offset = -1;
+}
+
+
+GrFmtSunRasterReader::~GrFmtSunRasterReader()
+{
+}
+
+
+void GrFmtSunRasterReader::Close()
+{
+ m_strm.Close();
+}
+
+
+bool GrFmtSunRasterReader::ReadHeader()
+{
+ bool result = false;
+
+ assert( strlen(m_filename) != 0 );
+ if( !m_strm.Open( m_filename )) return false;
+
+ if( setjmp( m_strm.JmpBuf()) == 0 )
+ {
+ m_strm.Skip( 4 );
+ m_width = m_strm.GetDWord();
+ m_height = m_strm.GetDWord();
+ m_bpp = m_strm.GetDWord();
+ int palSize = 3*(1 << m_bpp);
+
+ m_strm.Skip( 4 );
+ m_type = (SunRasType)m_strm.GetDWord();
+ m_maptype = (SunRasMapType)m_strm.GetDWord();
+ m_maplength = m_strm.GetDWord();
+
+ if( m_width > 0 && m_height > 0 &&
+ (m_bpp == 1 || m_bpp == 8 || m_bpp == 24 || m_bpp == 32) &&
+ (m_type == RAS_OLD || m_type == RAS_STANDARD ||
+ (m_type == RAS_BYTE_ENCODED && m_bpp == 8) || m_type == RAS_FORMAT_RGB) &&
+ (m_maptype == RMT_NONE && m_maplength == 0 ||
+ m_maptype == RMT_EQUAL_RGB && m_maplength <= palSize && m_bpp <= 8))
+ {
+ memset( m_palette, 0, sizeof(m_palette));
+
+ if( m_maplength != 0 )
+ {
+ int readed;
+ uchar buffer[256*3];
+
+ m_strm.GetBytes( buffer, m_maplength, &readed );
+ if( readed == m_maplength )
+ {
+ int i;
+ palSize = m_maplength/3;
+
+ for( i = 0; i < palSize; i++ )
+ {
+ m_palette[i].b = buffer[i + 2*palSize];
+ m_palette[i].g = buffer[i + palSize];
+ m_palette[i].r = buffer[i];
+ m_palette[i].a = 0;
+ }
+
+ m_iscolor = IsColorPalette( m_palette, m_bpp );
+ m_offset = m_strm.GetPos();
+
+ assert( m_offset == 32 + m_maplength );
+ result = true;
+ }
+ }
+ else
+ {
+ m_iscolor = m_bpp > 8;
+
+ if( !m_iscolor )
+ FillGrayPalette( m_palette, m_bpp );
+
+ m_offset = m_strm.GetPos();
+
+ assert( m_offset == 32 + m_maplength );
+ result = true;
+ }
+ }
+ }
+
+ if( !result )
+ {
+ m_offset = -1;
+ m_width = m_height = -1;
+ m_strm.Close();
+ }
+ return result;
+}
+
+
+bool GrFmtSunRasterReader::ReadData( uchar* data, int step, int color )
+{
+ const int buffer_size = 1 << 12;
+ uchar buffer[buffer_size];
+ uchar bgr_buffer[buffer_size];
+ uchar gray_palette[256];
+ bool result = false;
+ uchar* src = buffer;
+ uchar* bgr = bgr_buffer;
+ int src_pitch = ((m_width*m_bpp + 7)/8 + 1) & -2;
+ int nch = color ? 3 : 1;
+ int width3 = m_width*nch;
+ int y;
+
+ if( m_offset < 0 || !m_strm.IsOpened())
+ return false;
+
+ if( src_pitch+32 > buffer_size )
+ src = new uchar[src_pitch+32];
+
+ if( m_width*3 + 32 > buffer_size )
+ bgr = new uchar[m_width*3 + 32];
+
+ if( !color && m_maptype == RMT_EQUAL_RGB )
+ CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp );
+
+ if( setjmp( m_strm.JmpBuf()) == 0 )
+ {
+ m_strm.SetPos( m_offset );
+
+ switch( m_bpp )
+ {
+ /************************* 1 BPP ************************/
+ case 1:
+ if( m_type != RAS_BYTE_ENCODED )
+ {
+ for( y = 0; y < m_height; y++, data += step )
+ {
+ m_strm.GetBytes( src, src_pitch );
+ if( color )
+ FillColorRow1( data, src, m_width, m_palette );
+ else
+ FillGrayRow1( data, src, m_width, gray_palette );
+ }
+ result = true;
+ }
+ else
+ {
+ uchar* line_end = src + (m_width*m_bpp + 7)/8;
+ uchar* tsrc = src;
+ y = 0;
+
+ for(;;)
+ {
+ int max_count = (int)(line_end - tsrc);
+ int code = 0, len = 0, len1 = 0;
+
+ do
+ {
+ code = m_strm.GetByte();
+ if( code == 0x80 )
+ {
+ len = m_strm.GetByte();
+ if( len != 0 ) break;
+ }
+ tsrc[len1] = (uchar)code;
+ }
+ while( ++len1 < max_count );
+
+ tsrc += len1;
+
+ if( len > 0 ) // encoded mode
+ {
+ ++len;
+ code = m_strm.GetByte();
+ if( len > line_end - tsrc )
+ {
+ assert(0);
+ goto bad_decoding_1bpp;
+ }
+
+ memset( tsrc, code, len );
+ tsrc += len;
+ }
+
+ if( tsrc >= line_end )
+ {
+ tsrc = src;
+ if( color )
+ FillColorRow1( data, src, m_width, m_palette );
+ else
+ FillGrayRow1( data, src, m_width, gray_palette );
+ data += step;
+ if( ++y >= m_height ) break;
+ }
+ }
+ result = true;
+bad_decoding_1bpp:
+ ;
+ }
+ break;
+ /************************* 8 BPP ************************/
+ case 8:
+ if( m_type != RAS_BYTE_ENCODED )
+ {
+ for( y = 0; y < m_height; y++, data += step )
+ {
+ m_strm.GetBytes( src, src_pitch );
+ if( color )
+ FillColorRow8( data, src, m_width, m_palette );
+ else
+ FillGrayRow8( data, src, m_width, gray_palette );
+ }
+ result = true;
+ }
+ else // RLE-encoded
+ {
+ uchar* line_end = data + width3;
+ y = 0;
+
+ for(;;)
+ {
+ int max_count = (int)(line_end - data);
+ int code = 0, len = 0, len1;
+ uchar* tsrc = src;
+
+ do
+ {
+ code = m_strm.GetByte();
+ if( code == 0x80 )
+ {
+ len = m_strm.GetByte();
+ if( len != 0 ) break;
+ }
+ *tsrc++ = (uchar)code;
+ }
+ while( (max_count -= nch) > 0 );
+
+ len1 = (int)(tsrc - src);
+
+ if( len1 > 0 )
+ {
+ if( color )
+ FillColorRow8( data, src, len1, m_palette );
+ else
+ FillGrayRow8( data, src, len1, gray_palette );
+ data += len1*nch;
+ }
+
+ if( len > 0 ) // encoded mode
+ {
+ len = (len + 1)*nch;
+ code = m_strm.GetByte();
+
+ if( color )
+ data = FillUniColor( data, line_end, step, width3,
+ y, m_height, len,
+ m_palette[code] );
+ else
+ data = FillUniGray( data, line_end, step, width3,
+ y, m_height, len,
+ gray_palette[code] );
+ if( y >= m_height )
+ break;
+ }
+
+ if( data == line_end )
+ {
+ if( m_strm.GetByte() != 0 )
+ goto bad_decoding_end;
+ line_end += step;
+ data = line_end - width3;
+ if( ++y >= m_height ) break;
+ }
+ }
+
+ result = true;
+bad_decoding_end:
+ ;
+ }
+ break;
+ /************************* 24 BPP ************************/
+ case 24:
+ for( y = 0; y < m_height; y++, data += step )
+ {
+ m_strm.GetBytes( color ? data : bgr, src_pitch );
+
+ if( color )
+ {
+ if( m_type == RAS_FORMAT_RGB )
+ icvCvt_RGB2BGR_8u_C3R( data, 0, data, 0, cvSize(m_width,1) );
+ }
+ else
+ {
+ icvCvt_BGR2Gray_8u_C3C1R( bgr, 0, data, 0, cvSize(m_width,1),
+ m_type == RAS_FORMAT_RGB ? 2 : 0 );
+ }
+ }
+ result = true;
+ break;
+ /************************* 32 BPP ************************/
+ case 32:
+ for( y = 0; y < m_height; y++, data += step )
+ {
+ /* hack: a0 b0 g0 r0 a1 b1 g1 r1 ... are written to src + 3,
+ so when we look at src + 4, we see b0 g0 r0 x b1 g1 g1 x ... */
+ m_strm.GetBytes( src + 3, src_pitch );
+
+ if( color )
+ icvCvt_BGRA2BGR_8u_C4C3R( src + 4, 0, data, 0, cvSize(m_width,1),
+ m_type == RAS_FORMAT_RGB ? 2 : 0 );
+ else
+ icvCvt_BGRA2Gray_8u_C4C1R( src + 4, 0, data, 0, cvSize(m_width,1),
+ m_type == RAS_FORMAT_RGB ? 2 : 0 );
+ }
+ result = true;
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ if( src != buffer ) delete[] src;
+ if( bgr != bgr_buffer ) delete[] bgr;
+
+ return result;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+GrFmtSunRasterWriter::GrFmtSunRasterWriter( const char* filename ) : GrFmtWriter( filename )
+{
+}
+
+
+GrFmtSunRasterWriter::~GrFmtSunRasterWriter()
+{
+}
+
+
+bool GrFmtSunRasterWriter::WriteImage( const uchar* data, int step,
+ int width, int height, int /*depth*/, int channels )
+{
+ bool result = false;
+ int fileStep = (width*channels + 1) & -2;
+ int y;
+
+ assert( data && width > 0 && height > 0 && step >= fileStep);
+
+ if( m_strm.Open( m_filename ) )
+ {
+ m_strm.PutBytes( fmtSignSunRas, (int)strlen(fmtSignSunRas) );
+ m_strm.PutDWord( width );
+ m_strm.PutDWord( height );
+ m_strm.PutDWord( channels*8 );
+ m_strm.PutDWord( fileStep*height );
+ m_strm.PutDWord( RAS_STANDARD );
+ m_strm.PutDWord( RMT_NONE );
+ m_strm.PutDWord( 0 );
+
+ for( y = 0; y < height; y++, data += step )
+ m_strm.PutBytes( data, fileStep );
+
+ m_strm.Close();
+ result = true;
+ }
+ return result;
+}
+
diff --git a/otherlibs/highgui/grfmt_sunras.h b/otherlibs/highgui/grfmt_sunras.h
new file mode 100644
index 0000000..2460608
--- /dev/null
+++ b/otherlibs/highgui/grfmt_sunras.h
@@ -0,0 +1,113 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _GRFMT_SUNRAS_H_
+#define _GRFMT_SUNRAS_H_
+
+#include "grfmt_base.h"
+
+enum SunRasType
+{
+ RAS_OLD = 0,
+ RAS_STANDARD = 1,
+ RAS_BYTE_ENCODED = 2, /* RLE encoded */
+ RAS_FORMAT_RGB = 3 /* RGB instead of BGR */
+};
+
+enum SunRasMapType
+{
+ RMT_NONE = 0, /* direct color encoding */
+ RMT_EQUAL_RGB = 1 /* paletted image */
+};
+
+
+// Sun Raster Reader
+class GrFmtSunRasterReader : public GrFmtReader
+{
+public:
+
+ GrFmtSunRasterReader( const char* filename );
+ ~GrFmtSunRasterReader();
+
+ bool ReadData( uchar* data, int step, int color );
+ bool ReadHeader();
+ void Close();
+
+protected:
+
+ RMByteStream m_strm;
+ PaletteEntry m_palette[256];
+ int m_bpp;
+ int m_offset;
+ SunRasType m_type;
+ SunRasMapType m_maptype;
+ int m_maplength;
+};
+
+
+class GrFmtSunRasterWriter : public GrFmtWriter
+{
+public:
+
+ GrFmtSunRasterWriter( const char* filename );
+ ~GrFmtSunRasterWriter();
+
+ bool WriteImage( const uchar* data, int step,
+ int width, int height, int depth, int channels );
+protected:
+
+ WMByteStream m_strm;
+};
+
+
+// ... and filter factory
+class GrFmtSunRaster : public GrFmtFilterFactory
+{
+public:
+
+ GrFmtSunRaster();
+ ~GrFmtSunRaster();
+
+ GrFmtReader* NewReader( const char* filename );
+ GrFmtWriter* NewWriter( const char* filename );
+};
+
+#endif/*_GRFMT_SUNRAS_H_*/
diff --git a/otherlibs/highgui/grfmt_tiff.cpp b/otherlibs/highgui/grfmt_tiff.cpp
new file mode 100644
index 0000000..f69cc30
--- /dev/null
+++ b/otherlibs/highgui/grfmt_tiff.cpp
@@ -0,0 +1,826 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/****************************************************************************************\
+ A part of the file implements TIFF reader on base of libtiff library
+ (see otherlibs/_graphics/readme.txt for copyright notice)
+\****************************************************************************************/
+
+#include "_highgui.h"
+#include "grfmt_tiff.h"
+
+static const char fmtSignTiffII[] = "II\x2a\x00";
+static const char fmtSignTiffMM[] = "MM\x00\x2a";
+
+GrFmtTiff::GrFmtTiff()
+{
+ m_sign_len = 4;
+ m_signature = "";
+ m_description = "TIFF Files (*.tiff;*.tif)";
+}
+
+GrFmtTiff::~GrFmtTiff()
+{
+}
+
+bool GrFmtTiff::CheckSignature( const char* signature )
+{
+ return memcmp( signature, fmtSignTiffII, 4 ) == 0 ||
+ memcmp( signature, fmtSignTiffMM, 4 ) == 0;
+}
+
+
+GrFmtReader* GrFmtTiff::NewReader( const char* filename )
+{
+ return new GrFmtTiffReader( filename );
+}
+
+
+GrFmtWriter* GrFmtTiff::NewWriter( const char* filename )
+{
+ return new GrFmtTiffWriter( filename );
+}
+
+
+#ifdef HAVE_TIFF
+
+#include "tiff.h"
+#include "tiffio.h"
+
+static int grfmt_tiff_err_handler_init = 0;
+
+static void GrFmtSilentTIFFErrorHandler( const char*, const char*, va_list ) {}
+
+GrFmtTiffReader::GrFmtTiffReader( const char* filename ) : GrFmtReader( filename )
+{
+ m_tif = 0;
+
+ if( !grfmt_tiff_err_handler_init )
+ {
+ grfmt_tiff_err_handler_init = 1;
+
+ TIFFSetErrorHandler( GrFmtSilentTIFFErrorHandler );
+ TIFFSetWarningHandler( GrFmtSilentTIFFErrorHandler );
+ }
+}
+
+
+GrFmtTiffReader::~GrFmtTiffReader()
+{
+}
+
+
+void GrFmtTiffReader::Close()
+{
+ if( m_tif )
+ {
+ TIFF* tif = (TIFF*)m_tif;
+ TIFFClose( tif );
+ m_tif = 0;
+ }
+}
+
+
+bool GrFmtTiffReader::CheckFormat( const char* signature )
+{
+ return memcmp( signature, fmtSignTiffII, 4 ) == 0 ||
+ memcmp( signature, fmtSignTiffMM, 4 ) == 0;
+}
+
+
+bool GrFmtTiffReader::ReadHeader()
+{
+ char errmsg[1024];
+ bool result = false;
+
+ Close();
+ TIFF* tif = TIFFOpen( m_filename, "r" );
+
+ if( tif )
+ {
+ int width = 0, height = 0, photometric = 0, compression = 0;
+ m_tif = tif;
+
+ if( TIFFRGBAImageOK( tif, errmsg ) &&
+ TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &width ) &&
+ TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &height ) &&
+ TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ) &&
+ (!TIFFGetField( tif, TIFFTAG_COMPRESSION, &compression ) ||
+ (compression != COMPRESSION_LZW &&
+ compression != COMPRESSION_OJPEG)))
+ {
+ m_width = width;
+ m_height = height;
+ m_iscolor = photometric > 1;
+
+ result = true;
+ }
+ }
+
+ if( !result )
+ Close();
+
+ return result;
+}
+
+
+bool GrFmtTiffReader::ReadData( uchar* data, int step, int color )
+{
+ bool result = false;
+ uchar* buffer = 0;
+
+ color = color > 0 || (color < 0 && m_iscolor);
+
+ if( m_tif && m_width && m_height )
+ {
+ TIFF* tif = (TIFF*)m_tif;
+ int tile_width0 = m_width, tile_height0 = 0;
+ int x, y, i;
+ int is_tiled = TIFFIsTiled(tif);
+
+ if( !is_tiled &&
+ TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 ) ||
+ is_tiled &&
+ TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) &&
+ TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 ))
+ {
+ if( tile_width0 <= 0 )
+ tile_width0 = m_width;
+
+ if( tile_height0 <= 0 )
+ tile_height0 = m_height;
+
+ buffer = new uchar[tile_height0*tile_width0*4];
+
+ for( y = 0; y < m_height; y += tile_height0, data += step*tile_height0 )
+ {
+ int tile_height = tile_height0;
+
+ if( y + tile_height > m_height )
+ tile_height = m_height - y;
+
+ for( x = 0; x < m_width; x += tile_width0 )
+ {
+ int tile_width = tile_width0, ok;
+
+ if( x + tile_width > m_width )
+ tile_width = m_width - x;
+
+ if( !is_tiled )
+ ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer );
+ else
+ ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer );
+
+ if( !ok )
+ goto exit_func;
+
+ for( i = 0; i < tile_height; i++ )
+ if( color )
+ icvCvt_BGRA2BGR_8u_C4C3R( buffer + i*tile_width*4, 0,
+ data + x*3 + step*(tile_height - i - 1), 0,
+ cvSize(tile_width,1), 2 );
+ else
+ icvCvt_BGRA2Gray_8u_C4C1R( buffer + i*tile_width*4, 0,
+ data + x + step*(tile_height - i - 1), 0,
+ cvSize(tile_width,1), 2 );
+ }
+ }
+
+ result = true;
+ }
+ }
+
+exit_func:
+
+ Close();
+ delete[] buffer;
+
+ return result;
+}
+
+#else
+
+static const int tiffMask[] = { 0xff, 0xff, 0xffffffff, 0xffff, 0xffffffff };
+
+/************************ TIFF reader *****************************/
+
+GrFmtTiffReader::GrFmtTiffReader( const char* filename ) : GrFmtReader( filename )
+{
+ m_offsets = 0;
+ m_maxoffsets = 0;
+ m_strips = -1;
+ m_max_pal_length = 0;
+ m_temp_palette = 0;
+}
+
+
+GrFmtTiffReader::~GrFmtTiffReader()
+{
+ Close();
+
+ delete[] m_offsets;
+ delete[] m_temp_palette;
+}
+
+void GrFmtTiffReader::Close()
+{
+ m_strm.Close();
+}
+
+
+bool GrFmtTiffReader::CheckFormat( const char* signature )
+{
+ return memcmp( signature, fmtSignTiffII, 4 ) == 0 ||
+ memcmp( signature, fmtSignTiffMM, 4 ) == 0;
+}
+
+
+int GrFmtTiffReader::GetWordEx()
+{
+ int val = m_strm.GetWord();
+ if( m_byteorder == TIFF_ORDER_MM )
+ val = ((val)>>8)|(((val)&0xff)<<8);
+ return val;
+}
+
+
+int GrFmtTiffReader::GetDWordEx()
+{
+ int val = m_strm.GetDWord();
+ if( m_byteorder == TIFF_ORDER_MM )
+ val = BSWAP( val );
+ return val;
+}
+
+
+int GrFmtTiffReader::ReadTable( int offset, int count,
+ TiffFieldType fieldType,
+ int*& array, int& arraysize )
+{
+ int i;
+
+ if( count < 0 )
+ return RBS_BAD_HEADER;
+
+ if( fieldType != TIFF_TYPE_SHORT &&
+ fieldType != TIFF_TYPE_LONG &&
+ fieldType != TIFF_TYPE_BYTE )
+ return RBS_BAD_HEADER;
+
+ if( count > arraysize )
+ {
+ delete[] array;
+ arraysize = arraysize*3/2;
+ if( arraysize < count )
+ arraysize = count;
+ array = new int[arraysize];
+ }
+
+ if( count > 1 )
+ {
+ int pos = m_strm.GetPos();
+ m_strm.SetPos( offset );
+
+ if( fieldType == TIFF_TYPE_LONG )
+ {
+ if( m_byteorder == TIFF_ORDER_MM )
+ for( i = 0; i < count; i++ )
+ array[i] = ((RMByteStream&)m_strm).GetDWord();
+ else
+ for( i = 0; i < count; i++ )
+ array[i] = ((RLByteStream&)m_strm).GetDWord();
+ }
+ else if( fieldType == TIFF_TYPE_SHORT )
+ {
+ if( m_byteorder == TIFF_ORDER_MM )
+ for( i = 0; i < count; i++ )
+ array[i] = ((RMByteStream&)m_strm).GetWord();
+ else
+ for( i = 0; i < count; i++ )
+ array[i] = ((RLByteStream&)m_strm).GetWord();
+ }
+ else // fieldType == TIFF_TYPE_BYTE
+ for( i = 0; i < count; i++ )
+ array[i] = m_strm.GetByte();
+
+ m_strm.SetPos(pos);
+ }
+ else
+ {
+ assert( (offset & ~tiffMask[fieldType]) == 0 );
+ array[0] = offset;
+ }
+
+ return 0;
+}
+
+
+bool GrFmtTiffReader::ReadHeader()
+{
+ bool result = false;
+ int photometric = -1;
+ int channels = 1;
+ int pal_length = -1;
+
+ const int MAX_CHANNELS = 4;
+ int bpp_arr[MAX_CHANNELS];
+
+ assert( strlen(m_filename) != 0 );
+ if( !m_strm.Open( m_filename )) return false;
+
+ m_width = -1;
+ m_height = -1;
+ m_strips = -1;
+ m_bpp = 1;
+ m_compression = TIFF_UNCOMP;
+ m_rows_per_strip = -1;
+ m_iscolor = false;
+
+ if( setjmp( m_strm.JmpBuf()) == 0 )
+ {
+ m_byteorder = (TiffByteOrder)m_strm.GetWord();
+ m_strm.Skip( 2 );
+ int header_offset = GetDWordEx();
+
+ m_strm.SetPos( header_offset );
+
+ // read the first tag directory
+ int i, j, count = GetWordEx();
+
+ for( i = 0; i < count; i++ )
+ {
+ // read tag
+ TiffTag tag = (TiffTag)GetWordEx();
+ TiffFieldType fieldType = (TiffFieldType)GetWordEx();
+ int count = GetDWordEx();
+ int value = GetDWordEx();
+ if( count == 1 )
+ {
+ if( m_byteorder == TIFF_ORDER_MM )
+ {
+ if( fieldType == TIFF_TYPE_SHORT )
+ value = (unsigned)value >> 16;
+ else if( fieldType == TIFF_TYPE_BYTE )
+ value = (unsigned)value >> 24;
+ }
+
+ value &= tiffMask[fieldType];
+ }
+
+ switch( tag )
+ {
+ case TIFF_TAG_WIDTH:
+ m_width = value;
+ break;
+
+ case TIFF_TAG_HEIGHT:
+ m_height = value;
+ break;
+
+ case TIFF_TAG_BITS_PER_SAMPLE:
+ {
+ int* bpp_arr_ref = bpp_arr;
+
+ if( count > MAX_CHANNELS )
+ BAD_HEADER_ERR();
+
+ if( ReadTable( value, count, fieldType, bpp_arr_ref, count ) < 0 )
+ BAD_HEADER_ERR();
+
+ for( j = 1; j < count; j++ )
+ {
+ if( bpp_arr[j] != bpp_arr[0] )
+ BAD_HEADER_ERR();
+ }
+
+ m_bpp = bpp_arr[0];
+ }
+
+ break;
+
+ case TIFF_TAG_COMPRESSION:
+ m_compression = (TiffCompression)value;
+ if( m_compression != TIFF_UNCOMP &&
+ m_compression != TIFF_HUFFMAN &&
+ m_compression != TIFF_PACKBITS )
+ BAD_HEADER_ERR();
+ break;
+
+ case TIFF_TAG_PHOTOMETRIC:
+ photometric = value;
+ if( (unsigned)photometric > 3 )
+ BAD_HEADER_ERR();
+ break;
+
+ case TIFF_TAG_STRIP_OFFSETS:
+ m_strips = count;
+ if( ReadTable( value, count, fieldType, m_offsets, m_maxoffsets ) < 0 )
+ BAD_HEADER_ERR();
+ break;
+
+ case TIFF_TAG_SAMPLES_PER_PIXEL:
+ channels = value;
+ if( channels != 1 && channels != 3 && channels != 4 )
+ BAD_HEADER_ERR();
+ break;
+
+ case TIFF_TAG_ROWS_PER_STRIP:
+ m_rows_per_strip = value;
+ break;
+
+ case TIFF_TAG_PLANAR_CONFIG:
+ {
+ int planar_config = value;
+ if( planar_config != 1 )
+ BAD_HEADER_ERR();
+ }
+ break;
+
+ case TIFF_TAG_COLOR_MAP:
+ if( fieldType != TIFF_TYPE_SHORT || count < 2 )
+ BAD_HEADER_ERR();
+ if( ReadTable( value, count, fieldType,
+ m_temp_palette, m_max_pal_length ) < 0 )
+ BAD_HEADER_ERR();
+ pal_length = count / 3;
+ if( pal_length > 256 )
+ BAD_HEADER_ERR();
+ for( i = 0; i < pal_length; i++ )
+ {
+ m_palette[i].r = (uchar)(m_temp_palette[i] >> 8);
+ m_palette[i].g = (uchar)(m_temp_palette[i + pal_length] >> 8);
+ m_palette[i].b = (uchar)(m_temp_palette[i + pal_length*2] >> 8);
+ }
+ break;
+ case TIFF_TAG_STRIP_COUNTS:
+ break;
+ }
+ }
+
+ if( m_strips == 1 && m_rows_per_strip == -1 )
+ m_rows_per_strip = m_height;
+
+ if( m_width > 0 && m_height > 0 && m_strips > 0 &&
+ (m_height + m_rows_per_strip - 1)/m_rows_per_strip == m_strips )
+ {
+ switch( m_bpp )
+ {
+ case 1:
+ if( photometric == 0 || photometric == 1 && channels == 1 )
+ {
+ FillGrayPalette( m_palette, m_bpp, photometric == 0 );
+ result = true;
+ m_iscolor = false;
+ }
+ break;
+ case 4:
+ case 8:
+ if( (photometric == 0 || photometric == 1 ||
+ photometric == 3 && pal_length == (1 << m_bpp)) &&
+ m_compression != TIFF_HUFFMAN && channels == 1 )
+ {
+ if( pal_length < 0 )
+ {
+ FillGrayPalette( m_palette, m_bpp, photometric == 0 );
+ m_iscolor = false;
+ }
+ else
+ {
+ m_iscolor = IsColorPalette( m_palette, m_bpp );
+ }
+ result = true;
+ }
+ else if( photometric == 2 && pal_length < 0 &&
+ (channels == 3 || channels == 4) &&
+ m_compression == TIFF_UNCOMP )
+ {
+ m_bpp = 8*channels;
+ m_iscolor = true;
+ result = true;
+ }
+ break;
+ default:
+ BAD_HEADER_ERR();
+ }
+ }
+bad_header_exit:
+ ;
+ }
+
+ if( !result )
+ {
+ m_strips = -1;
+ m_width = m_height = -1;
+ m_strm.Close();
+ }
+
+ return result;
+}
+
+
+bool GrFmtTiffReader::ReadData( uchar* data, int step, int color )
+{
+ const int buffer_size = 1 << 12;
+ uchar buffer[buffer_size];
+ uchar gray_palette[256];
+ bool result = false;
+ uchar* src = buffer;
+ int src_pitch = (m_width*m_bpp + 7)/8;
+ int y = 0;
+
+ if( m_strips < 0 || !m_strm.IsOpened())
+ return false;
+
+ if( src_pitch+32 > buffer_size )
+ src = new uchar[src_pitch+32];
+
+ if( !color )
+ if( m_bpp <= 8 )
+ {
+ CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp );
+ }
+
+ if( setjmp( m_strm.JmpBuf()) == 0 )
+ {
+ for( int s = 0; s < m_strips; s++ )
+ {
+ int y_limit = m_rows_per_strip;
+
+ y_limit += y;
+ if( y_limit > m_height ) y_limit = m_height;
+
+ m_strm.SetPos( m_offsets[s] );
+
+ if( m_compression == TIFF_UNCOMP )
+ {
+ for( ; y < y_limit; y++, data += step )
+ {
+ m_strm.GetBytes( src, src_pitch );
+ if( color )
+ switch( m_bpp )
+ {
+ case 1:
+ FillColorRow1( data, src, m_width, m_palette );
+ break;
+ case 4:
+ FillColorRow4( data, src, m_width, m_palette );
+ break;
+ case 8:
+ FillColorRow8( data, src, m_width, m_palette );
+ break;
+ case 24:
+ icvCvt_RGB2BGR_8u_C3R( src, 0, data, 0, cvSize(m_width,1) );
+ break;
+ case 32:
+ icvCvt_BGRA2BGR_8u_C4C3R( src, 0, data, 0, cvSize(m_width,1), 2 );
+ break;
+ default:
+ assert(0);
+ goto bad_decoding_end;
+ }
+ else
+ switch( m_bpp )
+ {
+ case 1:
+ FillGrayRow1( data, src, m_width, gray_palette );
+ break;
+ case 4:
+ FillGrayRow4( data, src, m_width, gray_palette );
+ break;
+ case 8:
+ FillGrayRow8( data, src, m_width, gray_palette );
+ break;
+ case 24:
+ icvCvt_BGR2Gray_8u_C3C1R( src, 0, data, 0, cvSize(m_width,1), 2 );
+ break;
+ case 32:
+ icvCvt_BGRA2Gray_8u_C4C1R( src, 0, data, 0, cvSize(m_width,1), 2 );
+ break;
+ default:
+ assert(0);
+ goto bad_decoding_end;
+ }
+ }
+ }
+ else
+ {
+ }
+
+ result = true;
+
+bad_decoding_end:
+
+ ;
+ }
+ }
+
+ if( src != buffer ) delete[] src;
+ return result;
+}
+
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+GrFmtTiffWriter::GrFmtTiffWriter( const char* filename ) : GrFmtWriter( filename )
+{
+}
+
+GrFmtTiffWriter::~GrFmtTiffWriter()
+{
+}
+
+void GrFmtTiffWriter::WriteTag( TiffTag tag, TiffFieldType fieldType,
+ int count, int value )
+{
+ m_strm.PutWord( tag );
+ m_strm.PutWord( fieldType );
+ m_strm.PutDWord( count );
+ m_strm.PutDWord( value );
+}
+
+
+bool GrFmtTiffWriter::WriteImage( const uchar* data, int step,
+ int width, int height, int /*depth*/, int channels )
+{
+ bool result = false;
+ int fileStep = width*channels;
+
+ assert( data && width > 0 && height > 0 && step >= fileStep);
+
+ if( m_strm.Open( m_filename ) )
+ {
+ int rowsPerStrip = (1 << 13)/fileStep;
+
+ if( rowsPerStrip < 1 )
+ rowsPerStrip = 1;
+
+ if( rowsPerStrip > height )
+ rowsPerStrip = height;
+
+ int i, stripCount = (height + rowsPerStrip - 1) / rowsPerStrip;
+/*#if defined _DEBUG || !defined WIN32
+ int uncompressedRowSize = rowsPerStrip * fileStep;
+#endif*/
+ int directoryOffset = 0;
+
+ int* stripOffsets = new int[stripCount];
+ short* stripCounts = new short[stripCount];
+ uchar* buffer = new uchar[fileStep + 32];
+ int stripOffsetsOffset = 0;
+ int stripCountsOffset = 0;
+ int bitsPerSample = 8; // TODO support 16 bit
+ int y = 0;
+
+ m_strm.PutBytes( fmtSignTiffII, 4 );
+ m_strm.PutDWord( directoryOffset );
+
+ // write an image data first (the most reasonable way
+ // for compressed images)
+ for( i = 0; i < stripCount; i++ )
+ {
+ int limit = y + rowsPerStrip;
+
+ if( limit > height )
+ limit = height;
+
+ stripOffsets[i] = m_strm.GetPos();
+
+ for( ; y < limit; y++, data += step )
+ {
+ if( channels == 3 )
+ icvCvt_BGR2RGB_8u_C3R( data, 0, buffer, 0, cvSize(width,1) );
+ else if( channels == 4 )
+ icvCvt_BGRA2RGBA_8u_C4R( data, 0, buffer, 0, cvSize(width,1) );
+
+ m_strm.PutBytes( channels > 1 ? buffer : data, fileStep );
+ }
+
+ stripCounts[i] = (short)(m_strm.GetPos() - stripOffsets[i]);
+ /*assert( stripCounts[i] == uncompressedRowSize ||
+ stripCounts[i] < uncompressedRowSize &&
+ i == stripCount - 1);*/
+ }
+
+ if( stripCount > 2 )
+ {
+ stripOffsetsOffset = m_strm.GetPos();
+ for( i = 0; i < stripCount; i++ )
+ m_strm.PutDWord( stripOffsets[i] );
+
+ stripCountsOffset = m_strm.GetPos();
+ for( i = 0; i < stripCount; i++ )
+ m_strm.PutWord( stripCounts[i] );
+ }
+ else if(stripCount == 2)
+ {
+ stripOffsetsOffset = m_strm.GetPos();
+ for (i = 0; i < stripCount; i++)
+ {
+ m_strm.PutDWord (stripOffsets [i]);
+ }
+ stripCountsOffset = stripCounts [0] + (stripCounts [1] << 16);
+ }
+ else
+ {
+ stripOffsetsOffset = stripOffsets[0];
+ stripCountsOffset = stripCounts[0];
+ }
+
+ if( channels > 1 )
+ {
+ bitsPerSample = m_strm.GetPos();
+ m_strm.PutWord(8);
+ m_strm.PutWord(8);
+ m_strm.PutWord(8);
+ if( channels == 4 )
+ m_strm.PutWord(8);
+ }
+
+ directoryOffset = m_strm.GetPos();
+
+ // write header
+ m_strm.PutWord( 9 );
+
+ /* warning: specification 5.0 of Tiff want to have tags in
+ ascending order. This is a non-fatal error, but this cause
+ warning with some tools. So, keep this in ascending order */
+
+ WriteTag( TIFF_TAG_WIDTH, TIFF_TYPE_LONG, 1, width );
+ WriteTag( TIFF_TAG_HEIGHT, TIFF_TYPE_LONG, 1, height );
+ WriteTag( TIFF_TAG_BITS_PER_SAMPLE,
+ TIFF_TYPE_SHORT, channels, bitsPerSample );
+ WriteTag( TIFF_TAG_COMPRESSION, TIFF_TYPE_LONG, 1, TIFF_UNCOMP );
+ WriteTag( TIFF_TAG_PHOTOMETRIC, TIFF_TYPE_SHORT, 1, channels > 1 ? 2 : 1 );
+
+ WriteTag( TIFF_TAG_STRIP_OFFSETS, TIFF_TYPE_LONG,
+ stripCount, stripOffsetsOffset );
+
+ WriteTag( TIFF_TAG_SAMPLES_PER_PIXEL, TIFF_TYPE_SHORT, 1, channels );
+ WriteTag( TIFF_TAG_ROWS_PER_STRIP, TIFF_TYPE_LONG, 1, rowsPerStrip );
+
+ WriteTag( TIFF_TAG_STRIP_COUNTS,
+ stripCount > 1 ? TIFF_TYPE_SHORT : TIFF_TYPE_LONG,
+ stripCount, stripCountsOffset );
+
+ m_strm.PutDWord(0);
+ m_strm.Close();
+
+ // write directory offset
+ FILE* f = fopen( m_filename, "r+b" );
+ buffer[0] = (uchar)directoryOffset;
+ buffer[1] = (uchar)(directoryOffset >> 8);
+ buffer[2] = (uchar)(directoryOffset >> 16);
+ buffer[3] = (uchar)(directoryOffset >> 24);
+
+ fseek( f, 4, SEEK_SET );
+ fwrite( buffer, 1, 4, f );
+ fclose(f);
+
+ delete[] stripOffsets;
+ delete[] stripCounts;
+ delete[] buffer;
+
+ result = true;
+ }
+ return result;
+}
+
diff --git a/otherlibs/highgui/grfmt_tiff.h b/otherlibs/highgui/grfmt_tiff.h
new file mode 100644
index 0000000..6ae7042
--- /dev/null
+++ b/otherlibs/highgui/grfmt_tiff.h
@@ -0,0 +1,178 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _GRFMT_TIFF_H_
+#define _GRFMT_TIFF_H_
+
+#include "grfmt_base.h"
+
+
+// native simple TIFF codec
+enum TiffCompression
+{
+ TIFF_UNCOMP = 1,
+ TIFF_HUFFMAN = 2,
+ TIFF_PACKBITS = 32773
+};
+
+enum TiffByteOrder
+{
+ TIFF_ORDER_II = 0x4949,
+ TIFF_ORDER_MM = 0x4d4d
+};
+
+
+enum TiffTag
+{
+ TIFF_TAG_WIDTH = 256,
+ TIFF_TAG_HEIGHT = 257,
+ TIFF_TAG_BITS_PER_SAMPLE = 258,
+ TIFF_TAG_COMPRESSION = 259,
+ TIFF_TAG_PHOTOMETRIC = 262,
+ TIFF_TAG_STRIP_OFFSETS = 273,
+ TIFF_TAG_STRIP_COUNTS = 279,
+ TIFF_TAG_SAMPLES_PER_PIXEL = 277,
+ TIFF_TAG_ROWS_PER_STRIP = 278,
+ TIFF_TAG_PLANAR_CONFIG = 284,
+ TIFF_TAG_COLOR_MAP = 320
+};
+
+
+enum TiffFieldType
+{
+ TIFF_TYPE_BYTE = 1,
+ TIFF_TYPE_SHORT = 3,
+ TIFF_TYPE_LONG = 4
+};
+
+
+
+#ifdef HAVE_TIFF
+
+// libtiff based TIFF codec
+
+class GrFmtTiffReader : public GrFmtReader
+{
+public:
+
+ GrFmtTiffReader( const char* filename );
+ ~GrFmtTiffReader();
+
+ bool CheckFormat( const char* signature );
+ bool ReadData( uchar* data, int step, int color );
+ bool ReadHeader();
+ void Close();
+
+protected:
+
+ void* m_tif;
+};
+
+
+#else
+
+class GrFmtTiffReader : public GrFmtReader
+{
+public:
+
+ GrFmtTiffReader( const char* filename );
+ ~GrFmtTiffReader();
+
+ bool CheckFormat( const char* signature );
+ bool ReadData( uchar* data, int step, int color );
+ bool ReadHeader();
+ void Close();
+
+protected:
+
+ RLByteStream m_strm;
+ PaletteEntry m_palette[256];
+ int m_bpp;
+ int* m_temp_palette;
+ int m_max_pal_length;
+ int* m_offsets;
+ int m_maxoffsets;
+ int m_strips;
+ int m_rows_per_strip;
+ TiffCompression m_compression;
+ TiffByteOrder m_byteorder;
+
+ int GetWordEx();
+ int GetDWordEx();
+ int ReadTable( int offset, int count, TiffFieldType fieldtype,
+ int*& array, int& arraysize );
+};
+
+#endif
+
+// ... and writer
+class GrFmtTiffWriter : public GrFmtWriter
+{
+public:
+
+ GrFmtTiffWriter( const char* filename );
+ ~GrFmtTiffWriter();
+
+ bool WriteImage( const uchar* data, int step,
+ int width, int height, int depth, int channels );
+protected:
+
+ WLByteStream m_strm;
+
+ void WriteTag( TiffTag tag, TiffFieldType fieldType,
+ int count, int value );
+};
+
+
+// TIFF filter factory
+class GrFmtTiff : public GrFmtFilterFactory
+{
+public:
+
+ GrFmtTiff();
+ ~GrFmtTiff();
+
+ GrFmtReader* NewReader( const char* filename );
+ GrFmtWriter* NewWriter( const char* filename );
+ bool CheckSignature( const char* signature );
+};
+
+#endif/*_GRFMT_TIFF_H_*/
diff --git a/otherlibs/highgui/grfmts.h b/otherlibs/highgui/grfmts.h
new file mode 100644
index 0000000..6e183ea
--- /dev/null
+++ b/otherlibs/highgui/grfmts.h
@@ -0,0 +1,56 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _GRFMTS_H_
+#define _GRFMTS_H_
+
+#include "grfmt_base.h"
+#include "grfmt_imageio.h"
+#include "grfmt_bmp.h"
+#include "grfmt_sunras.h"
+#include "grfmt_jpeg.h"
+#include "grfmt_pxm.h"
+#include "grfmt_tiff.h"
+#include "grfmt_png.h"
+#include "grfmt_jpeg2000.h"
+#include "grfmt_exr.h"
+
+#endif/*_GRFMTS_H_*/
diff --git a/otherlibs/highgui/highgui.h b/otherlibs/highgui/highgui.h
new file mode 100644
index 0000000..1f35a1f
--- /dev/null
+++ b/otherlibs/highgui/highgui.h
@@ -0,0 +1,385 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _HIGH_GUI_
+#define _HIGH_GUI_
+
+#ifndef SKIP_INCLUDES
+
+ #include "cxcore.h"
+ #if defined WIN32 || defined WIN64
+ #include <windows.h>
+ #endif
+
+#else // SKIP_INCLUDES
+
+ #if defined WIN32 || defined WIN64
+ #define CV_CDECL __cdecl
+ #define CV_STDCALL __stdcall
+ #else
+ #define CV_CDECL
+ #define CV_STDCALL
+ #endif
+
+ #ifndef CV_EXTERN_C
+ #ifdef __cplusplus
+ #define CV_EXTERN_C extern "C"
+ #define CV_DEFAULT(val) = val
+ #else
+ #define CV_EXTERN_C
+ #define CV_DEFAULT(val)
+ #endif
+ #endif
+
+ #ifndef CV_EXTERN_C_FUNCPTR
+ #ifdef __cplusplus
+ #define CV_EXTERN_C_FUNCPTR(x) extern "C" { typedef x; }
+ #else
+ #define CV_EXTERN_C_FUNCPTR(x) typedef x
+ #endif
+ #endif
+
+ #ifndef CV_INLINE
+ #if defined __cplusplus
+ #define CV_INLINE inline
+ #elif (defined WIN32 || defined WIN64) && !defined __GNUC__
+ #define CV_INLINE __inline
+ #else
+ #define CV_INLINE static
+ #endif
+ #endif /* CV_INLINE */
+
+ #if (defined WIN32 || defined WIN64) && defined CVAPI_EXPORTS
+ #define CV_EXPORTS __declspec(dllexport)
+ #else
+ #define CV_EXPORTS
+ #endif
+
+ #ifndef CVAPI
+ #define CVAPI(rettype) CV_EXTERN_C CV_EXPORTS rettype CV_CDECL
+ #endif
+
+#endif // SKIP_INCLUDES
+
+#if defined(_CH_)
+ #pragma package <chopencv>
+ #include <chdl.h>
+ LOAD_CHDL(highgui)
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif /* __cplusplus */
+
+#define CV_EVENT_MOUSEMOVE 0
+#define CV_EVENT_LBUTTONDOWN 1
+#define CV_EVENT_RBUTTONDOWN 2
+#define CV_EVENT_MBUTTONDOWN 3
+#define CV_EVENT_LBUTTONUP 4
+#define CV_EVENT_RBUTTONUP 5
+#define CV_EVENT_MBUTTONUP 6
+#define CV_EVENT_LBUTTONDBLCLK 7
+#define CV_EVENT_RBUTTONDBLCLK 8
+#define CV_EVENT_MBUTTONDBLCLK 9
+
+#define CV_EVENT_FLAG_LBUTTON 1
+#define CV_EVENT_FLAG_RBUTTON 2
+#define CV_EVENT_FLAG_MBUTTON 4
+#define CV_EVENT_FLAG_CTRLKEY 8
+#define CV_EVENT_FLAG_SHIFTKEY 16
+#define CV_EVENT_FLAG_ALTKEY 32
+
+
+/* 8bit, color or not */
+#define CV_LOAD_IMAGE_UNCHANGED -1
+/* 8bit, gray */
+#define CV_LOAD_IMAGE_GRAYSCALE 0
+/* ?, color */
+#define CV_LOAD_IMAGE_COLOR 1
+/* any depth, ? */
+#define CV_LOAD_IMAGE_ANYDEPTH 2
+/* ?, any color */
+#define CV_LOAD_IMAGE_ANYCOLOR 4
+
+/* load image from file
+ iscolor can be a combination of above flags where CV_LOAD_IMAGE_UNCHANGED
+ overrides the other flags
+ using CV_LOAD_IMAGE_ANYCOLOR alone is equivalent to CV_LOAD_IMAGE_UNCHANGED
+ unless CV_LOAD_IMAGE_ANYDEPTH is specified images are converted to 8bit
+*/
+CVAPI(IplImage*) cvLoadImage( const char* filename, int iscolor CV_DEFAULT(CV_LOAD_IMAGE_COLOR));
+CVAPI(CvMat*) cvLoadImageM( const char* filename, int iscolor CV_DEFAULT(CV_LOAD_IMAGE_COLOR));
+
+/* save image to file */
+CVAPI(int) cvSaveImage( const char* filename, const CvArr* image );
+
+#define CV_CVTIMG_FLIP 1
+#define CV_CVTIMG_SWAP_RB 2
+/* utility function: convert one image to another with optional vertical flip */
+CVAPI(void) cvConvertImage( const CvArr* src, CvArr* dst, int flags CV_DEFAULT(0));
+
+/* wait for key event infinitely (delay<=0) or for "delay" milliseconds */
+CVAPI(int) cvWaitKey(int delay CV_DEFAULT(0));
+
+
+/****************************************************************************************\
+* Working with Video Files and Cameras *
+\****************************************************************************************/
+
+/* "black box" capture structure */
+typedef struct CvCapture CvCapture;
+
+/* start capturing frames from video file */
+CVAPI(CvCapture*) cvCreateSocketCapture( const char *address, const char* port, int width, int height );
+
+/* grab a frame, return 1 on success, 0 on fail.
+ this function is thought to be fast */
+CVAPI(int) cvGrabFrame( CvCapture* capture );
+
+/* get the frame grabbed with cvGrabFrame(..)
+ This function may apply some frame processing like
+ frame decompression, flipping etc.
+ !!!DO NOT RELEASE or MODIFY the retrieved frame!!! */
+CVAPI(IplImage*) cvRetrieveFrame( CvCapture* capture );
+
+/* Just a combination of cvGrabFrame and cvRetrieveFrame
+ !!!DO NOT RELEASE or MODIFY the retrieved frame!!! */
+CVAPI(IplImage*) cvQueryFrame( CvCapture* capture );
+
+/* stop capturing/reading and free resources */
+CVAPI(void) cvReleaseCapture( CvCapture** capture );
+
+#define CV_CAP_PROP_POS_MSEC 0
+#define CV_CAP_PROP_POS_FRAMES 1
+#define CV_CAP_PROP_POS_AVI_RATIO 2
+#define CV_CAP_PROP_FRAME_WIDTH 3
+#define CV_CAP_PROP_FRAME_HEIGHT 4
+#define CV_CAP_PROP_FPS 5
+#define CV_CAP_PROP_FOURCC 6
+#define CV_CAP_PROP_FRAME_COUNT 7
+#define CV_CAP_PROP_FORMAT 8
+#define CV_CAP_PROP_MODE 9
+#define CV_CAP_PROP_BRIGHTNESS 10
+#define CV_CAP_PROP_CONTRAST 11
+#define CV_CAP_PROP_SATURATION 12
+#define CV_CAP_PROP_HUE 13
+#define CV_CAP_PROP_GAIN 14
+#define CV_CAP_PROP_CONVERT_RGB 15
+
+
+/* retrieve or set capture properties */
+CVAPI(double) cvGetCaptureProperty( CvCapture* capture, int property_id );
+CVAPI(int) cvSetCaptureProperty( CvCapture* capture, int property_id, double value );
+
+/****************************************************************************************\
+* Obsolete functions/synonyms *
+\****************************************************************************************/
+
+#ifndef HIGHGUI_NO_BACKWARD_COMPATIBILITY
+ #define HIGHGUI_BACKWARD_COMPATIBILITY
+#endif
+
+#ifdef HIGHGUI_BACKWARD_COMPATIBILITY
+
+#define cvCaptureFromFile cvCreateFileCapture
+#define cvCaptureFromCAM cvCreateCameraCapture
+#define cvCaptureFromAVI cvCaptureFromFile
+#define cvCreateAVIWriter cvCreateVideoWriter
+#define cvWriteToAVI cvWriteFrame
+#define cvAddSearchPath(path)
+#define cvvInitSystem cvInitSystem
+#define cvvNamedWindow cvNamedWindow
+#define cvvResizeWindow cvResizeWindow
+#define cvvDestroyWindow cvDestroyWindow
+#define cvvCreateTrackbar cvCreateTrackbar
+#define cvvLoadImage(name) cvLoadImage((name),1)
+#define cvvSaveImage cvSaveImage
+#define cvvAddSearchPath cvAddSearchPath
+#define cvvWaitKey(name) cvWaitKey(0)
+#define cvvWaitKeyEx(name,delay) cvWaitKey(delay)
+#define cvvConvertImage cvConvertImage
+#define HG_AUTOSIZE CV_WINDOW_AUTOSIZE
+#define set_preprocess_func cvSetPreprocessFuncWin32
+#define set_postprocess_func cvSetPostprocessFuncWin32
+
+#ifdef WIN32
+
+typedef int (CV_CDECL * CvWin32WindowCallback)(HWND, UINT, WPARAM, LPARAM, int*);
+CVAPI(void) cvSetPreprocessFuncWin32( CvWin32WindowCallback on_preprocess );
+CVAPI(void) cvSetPostprocessFuncWin32( CvWin32WindowCallback on_postprocess );
+
+CV_INLINE int iplWidth( const IplImage* img );
+CV_INLINE int iplWidth( const IplImage* img )
+{
+ return !img ? 0 : !img->roi ? img->width : img->roi->width;
+}
+
+CV_INLINE int iplHeight( const IplImage* img );
+CV_INLINE int iplHeight( const IplImage* img )
+{
+ return !img ? 0 : !img->roi ? img->height : img->roi->height;
+}
+
+#endif
+
+#endif /* obsolete functions */
+
+/* For use with Win32 */
+#ifdef WIN32
+
+CV_INLINE RECT NormalizeRect( RECT r );
+CV_INLINE RECT NormalizeRect( RECT r )
+{
+ int t;
+
+ if( r.left > r.right )
+ {
+ t = r.left;
+ r.left = r.right;
+ r.right = t;
+ }
+
+ if( r.top > r.bottom )
+ {
+ t = r.top;
+ r.top = r.bottom;
+ r.bottom = t;
+ }
+
+ return r;
+}
+
+CV_INLINE CvRect RectToCvRect( RECT sr );
+CV_INLINE CvRect RectToCvRect( RECT sr )
+{
+ sr = NormalizeRect( sr );
+ return cvRect( sr.left, sr.top, sr.right - sr.left, sr.bottom - sr.top );
+}
+
+CV_INLINE RECT CvRectToRect( CvRect sr );
+CV_INLINE RECT CvRectToRect( CvRect sr )
+{
+ RECT dr;
+ dr.left = sr.x;
+ dr.top = sr.y;
+ dr.right = sr.x + sr.width;
+ dr.bottom = sr.y + sr.height;
+
+ return dr;
+}
+
+CV_INLINE IplROI RectToROI( RECT r );
+CV_INLINE IplROI RectToROI( RECT r )
+{
+ IplROI roi;
+ r = NormalizeRect( r );
+ roi.xOffset = r.left;
+ roi.yOffset = r.top;
+ roi.width = r.right - r.left;
+ roi.height = r.bottom - r.top;
+ roi.coi = 0;
+
+ return roi;
+}
+
+#endif /* WIN32 */
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif /* __cplusplus */
+
+
+#if defined __cplusplus && (!defined WIN32 || !defined (__GNUC__)) && !defined CV_NO_CVV_IMAGE
+
+#define CImage CvvImage
+
+/* CvvImage class definition */
+class CV_EXPORTS CvvImage
+{
+public:
+ CvvImage();
+ virtual ~CvvImage();
+
+ /* Create image (BGR or grayscale) */
+ virtual bool Create( int width, int height, int bits_per_pixel, int image_origin = 0 );
+
+ /* Load image from specified file */
+ virtual bool Load( const char* filename, int desired_color = 1 );
+
+ /* Load rectangle from the file */
+ virtual bool LoadRect( const char* filename,
+ int desired_color, CvRect r );
+
+#ifdef WIN32
+ virtual bool LoadRect( const char* filename,
+ int desired_color, RECT r )
+ {
+ return LoadRect( filename, desired_color,
+ cvRect( r.left, r.top, r.right - r.left, r.bottom - r.top ));
+ }
+#endif
+
+ /* Save entire image to specified file. */
+ virtual bool Save( const char* filename );
+
+ /* Get copy of input image ROI */
+ virtual void CopyOf( CvvImage& image, int desired_color = -1 );
+ virtual void CopyOf( IplImage* img, int desired_color = -1 );
+
+ IplImage* GetImage() { return m_img; };
+ virtual void Destroy(void);
+
+ /* width and height of ROI */
+ int Width() { return !m_img ? 0 : !m_img->roi ? m_img->width : m_img->roi->width; };
+ int Height() { return !m_img ? 0 : !m_img->roi ? m_img->height : m_img->roi->height;};
+ int Bpp() { return m_img ? (m_img->depth & 255)*m_img->nChannels : 0; };
+
+ virtual void Fill( int color );
+
+
+protected:
+
+ IplImage* m_img;
+};
+
+#endif /* __cplusplus */
+
+#endif /* _HIGH_GUI_ */
diff --git a/otherlibs/highgui/image.cpp b/otherlibs/highgui/image.cpp
new file mode 100644
index 0000000..082c1ca
--- /dev/null
+++ b/otherlibs/highgui/image.cpp
@@ -0,0 +1,255 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+//
+// Image.cpp: implementation of the CvvImage class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "_highgui.h"
+
+#if defined __cplusplus && (!defined WIN32 || !defined __GNUC__)
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CvvImage::CvvImage()
+{
+ m_img = 0;
+}
+
+void CvvImage::Destroy()
+{
+ cvReleaseImage( &m_img );
+}
+
+CvvImage::~CvvImage()
+{
+ Destroy();
+}
+
+bool CvvImage::Create( int w, int h, int bpp, int origin )
+{
+ const unsigned max_img_size = 10000;
+
+ if( (bpp != 8 && bpp != 24 && bpp != 32) ||
+ (unsigned)w >= max_img_size || (unsigned)h >= max_img_size ||
+ (origin != IPL_ORIGIN_TL && origin != IPL_ORIGIN_BL))
+ {
+ assert(0); // most probably, it is a programming error
+ return false;
+ }
+
+ if( !m_img || Bpp() != bpp || m_img->width != w || m_img->height != h )
+ {
+ if( m_img && m_img->nSize == sizeof(IplImage))
+ Destroy();
+
+ /* prepare IPL header */
+ m_img = cvCreateImage( cvSize( w, h ), IPL_DEPTH_8U, bpp/8 );
+ }
+
+ if( m_img )
+ m_img->origin = origin == 0 ? IPL_ORIGIN_TL : IPL_ORIGIN_BL;
+
+ return m_img != 0;
+}
+
+void CvvImage::CopyOf( CvvImage& image, int desired_color )
+{
+ IplImage* img = image.GetImage();
+ if( img )
+ {
+ CopyOf( img, desired_color );
+ }
+}
+
+
+#define HG_IS_IMAGE(img) \
+ ((img) != 0 && ((const IplImage*)(img))->nSize == sizeof(IplImage) && \
+ ((IplImage*)img)->imageData != 0)
+
+
+void CvvImage::CopyOf( IplImage* img, int desired_color )
+{
+ if( HG_IS_IMAGE(img) )
+ {
+ int color = desired_color;
+ CvSize size = cvGetSize( img );
+
+ if( color < 0 )
+ color = img->nChannels > 1;
+
+ if( Create( size.width, size.height,
+ (!color ? 1 : img->nChannels > 1 ? img->nChannels : 3)*8,
+ img->origin ))
+ {
+ cvConvertImage( img, m_img, 0 );
+ }
+ }
+}
+
+
+bool CvvImage::Load( const char* filename, int desired_color )
+{
+ IplImage* img = cvLoadImage( filename, desired_color );
+ if( !img )
+ return false;
+
+ CopyOf( img, desired_color );
+ cvReleaseImage( &img );
+
+ return true;
+}
+
+
+bool CvvImage::LoadRect( const char* filename,
+ int desired_color, CvRect r )
+{
+ if( r.width < 0 || r.height < 0 ) return false;
+
+ IplImage* img = cvLoadImage( filename, desired_color );
+ if( !img )
+ return false;
+
+ if( r.width == 0 || r.height == 0 )
+ {
+ r.width = img->width;
+ r.height = img->height;
+ r.x = r.y = 0;
+ }
+
+ if( r.x > img->width || r.y > img->height ||
+ r.x + r.width < 0 || r.y + r.height < 0 )
+ {
+ cvReleaseImage( &img );
+ return false;
+ }
+
+ /* truncate r to source image */
+ if( r.x < 0 )
+ {
+ r.width += r.x;
+ r.x = 0;
+ }
+ if( r.y < 0 )
+ {
+ r.height += r.y;
+ r.y = 0;
+ }
+
+ if( r.x + r.width > img->width )
+ r.width = img->width - r.x;
+
+ if( r.y + r.height > img->height )
+ r.height = img->height - r.y;
+
+ cvSetImageROI( img, r );
+ CopyOf( img, desired_color );
+
+ cvReleaseImage( &img );
+ return true;
+}
+
+
+bool CvvImage::Save( const char* filename )
+{
+ if( !m_img )
+ return false;
+ cvSaveImage( filename, m_img );
+ return true;
+}
+
+
+
+#ifdef WIN32
+
+void CImage::DrawToHDC( HDC hDCDst, RECT* pDstRect )
+{
+ if( pDstRect && m_img && m_img->depth == IPL_DEPTH_8U && m_img->imageData )
+ {
+ uchar buffer[sizeof(BITMAPINFOHEADER) + 1024];
+ BITMAPINFO* bmi = (BITMAPINFO*)buffer;
+ int bmp_w = m_img->width, bmp_h = m_img->height;
+
+ CvRect roi = cvGetImageROI( m_img );
+ CvRect dst = RectToCvRect( *pDstRect );
+
+ if( roi.width == dst.width && roi.height == dst.height )
+ {
+ Show( hDCDst, dst.x, dst.y, dst.width, dst.height, roi.x, roi.y );
+ return;
+ }
+
+ if( roi.width > dst.width )
+ {
+ SetStretchBltMode(
+ hDCDst, // handle to device context
+ HALFTONE );
+ }
+ else
+ {
+ SetStretchBltMode(
+ hDCDst, // handle to device context
+ COLORONCOLOR );
+ }
+
+ FillBitmapInfo( bmi, bmp_w, bmp_h, Bpp(), m_img->origin );
+
+ ::StretchDIBits(
+ hDCDst,
+ dst.x, dst.y, dst.width, dst.height,
+ roi.x, roi.y, roi.width, roi.height,
+ m_img->imageData, bmi, DIB_RGB_COLORS, SRCCOPY );
+ }
+}
+
+#endif
+
+void CvvImage::Fill( int color )
+{
+ cvSet( m_img, cvScalar(color&255,(color>>8)&255,(color>>16)&255,(color>>24)&255) );
+}
+
+#endif
+
+/* End of file. */
diff --git a/otherlibs/highgui/loadsave.cpp b/otherlibs/highgui/loadsave.cpp
new file mode 100644
index 0000000..97c0db9
--- /dev/null
+++ b/otherlibs/highgui/loadsave.cpp
@@ -0,0 +1,555 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+//
+// Loading and saving IPL images.
+//
+
+#include "_highgui.h"
+#include "grfmts.h"
+
+#if 0
+/****************************************************************************************\
+* Path class (list of search folders) *
+\****************************************************************************************/
+
+class CvFilePath
+{
+public:
+ CvFilePath();
+ ~CvFilePath();
+
+ // preprocess folder or file name - calculate its length,
+ // check for invalid symbols in the name and substitute
+ // all backslashes with simple slashes.
+ // the result is put into the specified buffer
+ static int Preprocess( const char* filename, char* buffer );
+
+ // add folder to the path
+ bool Add( const char* path );
+
+ // clear the path
+ void Clear();
+
+ // return the path - string, where folders are separated by ';'
+ const char* Get() const { return m_path; };
+
+ // find the file in the path
+ const char* Find( const char* filename, char* buffer ) const;
+
+ // return the first folder from the path
+ // the returned string is not terminated by '\0'!!!
+ // its length is returned via len parameter
+ const char* First( int& len ) const;
+
+ // return the folder, next in the path after the specified folder.
+ // see also note to First() method
+ const char* Next( const char* folder, int& len ) const;
+
+protected:
+
+ char* m_path;
+ int m_maxsize;
+ int m_len;
+};
+
+
+void CvFilePath::Clear()
+{
+ delete[] m_path;
+ m_maxsize = m_len = 0;
+}
+
+
+CvFilePath::CvFilePath()
+{
+ m_path = 0;
+ m_maxsize = m_len = 0;
+}
+
+
+CvFilePath::~CvFilePath()
+{
+ Clear();
+}
+
+
+bool CvFilePath::Add( const char* path )
+{
+ char buffer[_MAX_PATH + 1];
+ int len = Preprocess( path, buffer );
+
+ if( len < 0 )
+ return false;
+
+ if( m_len + len + 3 // +1 for one more ';',
+ // another +1 for possible additional '/',
+ // and the last +1 is for '\0'
+ > m_maxsize )
+ {
+ int new_size = (m_len + len + 3 + 1023) & -1024;
+ char* new_path = new char[new_size];
+
+ if( m_path )
+ {
+ memcpy( new_path, m_path, m_len );
+ delete[] m_path;
+ }
+
+ m_path = new_path;
+ m_maxsize = new_size;
+ }
+
+ m_path[m_len++] = ';';
+ memcpy( m_path + m_len, buffer, len );
+ m_len += len;
+
+ if( m_path[m_len] != '/' )
+ m_path[m_len++] = '/';
+
+ m_path[m_len] = '\0'; // '\0' is not counted in m_len.
+
+ return true;
+}
+
+
+const char* CvFilePath::First( int& len ) const
+{
+ const char* path = (const char*)(m_path ? m_path : "");
+ const char* path_end = path;
+
+ while( *path_end && *path_end != ';' )
+ path_end++;
+
+ len = path_end - path;
+ return path;
+}
+
+
+const char* CvFilePath::Next( const char* folder, int& len ) const
+{
+ if( !folder || folder < m_path || folder >= m_path + m_len )
+ return 0;
+
+ folder = strchr( folder, ';' );
+ if( folder )
+ {
+ const char* folder_end = ++folder;
+ while( *folder_end && *folder_end != ';' )
+ folder_end++;
+
+ len = folder_end - folder;
+ }
+
+ return folder;
+}
+
+
+const char* CvFilePath::Find( const char* filename, char* buffer ) const
+{
+ char path0[_MAX_PATH + 1];
+ int len = Preprocess( filename, path0 );
+ int folder_len = 0;
+ const char* folder = First( folder_len );
+ char* name_only = 0;
+ char* name = path0;
+ FILE* f = 0;
+
+ if( len < 0 )
+ return 0;
+
+ do
+ {
+ if( folder_len + len <= _MAX_PATH )
+ {
+ memcpy( buffer, folder, folder_len );
+ strcpy( buffer + folder_len, name );
+
+ f = fopen( buffer, "rb" );
+ if( f )
+ break;
+ }
+
+ if( name != name_only )
+ {
+ name_only = strrchr( path0, '/' );
+ if( !name_only )
+ name_only = path0;
+ else
+ name_only++;
+ len = strlen( name_only );
+ name = name_only;
+ }
+ }
+ while( (folder = Next( folder, folder_len )) != 0 );
+
+ filename = 0;
+
+ if( f )
+ {
+ filename = (const char*)buffer;
+ fclose(f);
+ }
+
+ return filename;
+}
+
+
+int CvFilePath::Preprocess( const char* str, char* buffer )
+{
+ int i;
+
+ if( !str || !buffer )
+ return -1;
+
+ for( i = 0; i <= _MAX_PATH; i++ )
+ {
+ buffer[i] = str[i];
+
+ if( isalnum(str[i])) // fast check to skip most of characters
+ continue;
+
+ if( str[i] == '\0' )
+ break;
+
+ if( str[i] == '\\' ) // convert back slashes to simple slashes
+ // (for Win32-*NIX compatibility)
+ buffer[i] = '/';
+
+ if (str[i] == '*' || str[i] == '?' || str[i] == '\"' ||
+ str[i] == '>' || str[i] == '<' ||
+ str[i] == ';' || /* used as a separator in the path */
+ #ifndef WIN32
+ str[i] == ',' || str[i] == '%' ||
+ #endif
+ str[i] == '|')
+ return -1;
+ }
+
+ return i <= _MAX_PATH ? i : -1;
+}
+#endif
+
+/****************************************************************************************\
+* Image Readers & Writers Class *
+\****************************************************************************************/
+
+class CvImageFilters
+{
+public:
+
+ CvImageFilters();
+ ~CvImageFilters();
+
+ GrFmtReader* FindReader( const char* filename ) const;
+ GrFmtWriter* FindWriter( const char* filename ) const;
+
+ //const CvFilePath& Path() const { return (const CvFilePath&)m_path; };
+ //CvFilePath& Path() { return m_path; };
+
+protected:
+
+ GrFmtFactoriesList* m_factories;
+};
+
+
+CvImageFilters::CvImageFilters()
+{
+ m_factories = new GrFmtFactoriesList;
+
+#ifdef HAVE_IMAGEIO
+ m_factories->AddFactory( new GrFmtImageIO() );
+#endif
+ m_factories->AddFactory( new GrFmtBmp() );
+ m_factories->AddFactory( new GrFmtJpeg() );
+ m_factories->AddFactory( new GrFmtSunRaster() );
+ m_factories->AddFactory( new GrFmtPxM() );
+ m_factories->AddFactory( new GrFmtTiff() );
+#ifdef HAVE_PNG
+ m_factories->AddFactory( new GrFmtPng() );
+#endif
+#ifdef HAVE_JASPER
+ m_factories->AddFactory( new GrFmtJpeg2000() );
+#endif
+#ifdef HAVE_ILMIMF
+ m_factories->AddFactory( new GrFmtExr() );
+#endif
+}
+
+
+CvImageFilters::~CvImageFilters()
+{
+ delete m_factories;
+}
+
+
+GrFmtReader* CvImageFilters::FindReader( const char* filename ) const
+{
+ return m_factories->FindReader( filename );
+}
+
+
+GrFmtWriter* CvImageFilters::FindWriter( const char* filename ) const
+{
+ return m_factories->FindWriter( filename );
+}
+
+/****************************************************************************************\
+* HighGUI loading & saving function implementation *
+\****************************************************************************************/
+
+static int icvSetCXCOREBindings(void)
+{
+ return CV_SET_IMAGE_IO_FUNCTIONS();
+}
+
+int cxcore_bindings_initialized = icvSetCXCOREBindings();
+
+// global image I/O filters
+static CvImageFilters g_Filters;
+
+#if 0
+CV_IMPL void
+cvAddSearchPath( const char* path )
+{
+ CV_FUNCNAME( "cvAddSearchPath" );
+
+ __BEGIN__;
+
+ if( !path || strlen(path) == 0 )
+ CV_ERROR( CV_StsNullPtr, "Null path" );
+
+ g_Filters.AddPath( path );
+
+ __END__;
+}
+#endif
+
+CV_IMPL int
+cvHaveImageReader( const char* filename )
+{
+ GrFmtReader* reader = g_Filters.FindReader( filename );
+ if( reader ) {
+ delete reader;
+ return 1;
+ }
+ return 0;
+}
+
+CV_IMPL int cvHaveImageWriter( const char* filename )
+{
+ GrFmtWriter* writer = g_Filters.FindWriter( filename );
+ if( writer ) {
+ delete writer;
+ return 1;
+ }
+ return 0;
+}
+
+static void*
+icvLoadImage( const char* filename, int flags, bool load_as_matrix )
+{
+ GrFmtReader* reader = 0;
+ IplImage* image = 0;
+ CvMat hdr, *matrix = 0;
+ int depth = 8;
+
+ CV_FUNCNAME( "cvLoadImage" );
+
+ __BEGIN__;
+
+ CvSize size;
+ int iscolor;
+ int cn;
+
+ if( !filename || strlen(filename) == 0 )
+ CV_ERROR( CV_StsNullPtr, "null filename" );
+
+ reader = g_Filters.FindReader( filename );
+ if( !reader )
+ EXIT;
+
+ if( !reader->ReadHeader() )
+ EXIT;
+
+ size.width = reader->GetWidth();
+ size.height = reader->GetHeight();
+
+ if( flags == -1 )
+ iscolor = reader->IsColor();
+ else
+ {
+ if( (flags & CV_LOAD_IMAGE_COLOR) != 0 ||
+ ((flags & CV_LOAD_IMAGE_ANYCOLOR) != 0 && reader->IsColor()) )
+ iscolor = 1;
+ else
+ iscolor = 0;
+
+ if( (flags & CV_LOAD_IMAGE_ANYDEPTH) != 0 )
+ {
+ reader->UseNativeDepth(true);
+ depth = reader->GetDepth();
+ }
+ }
+
+ cn = iscolor ? 3 : 1;
+
+ if( load_as_matrix )
+ {
+ int type;
+ if(reader->IsFloat() && depth != 8)
+ type = CV_32F;
+ else
+ type = ( depth <= 8 ) ? CV_8U : ( depth <= 16 ) ? CV_16U : CV_32S;
+ CV_CALL( matrix = cvCreateMat( size.height, size.width, CV_MAKETYPE(type, cn) ));
+ }
+ else
+ {
+ int type;
+ if(reader->IsFloat() && depth != 8)
+ type = IPL_DEPTH_32F;
+ else
+ type = ( depth <= 8 ) ? IPL_DEPTH_8U : ( depth <= 16 ) ? IPL_DEPTH_16U : IPL_DEPTH_32S;
+ CV_CALL( image = cvCreateImage( size, type, cn ));
+ matrix = cvGetMat( image, &hdr );
+ }
+
+ if( !reader->ReadData( matrix->data.ptr, matrix->step, iscolor ))
+ {
+ if( load_as_matrix )
+ cvReleaseMat( &matrix );
+ else
+ cvReleaseImage( &image );
+ EXIT;
+ }
+
+ __END__;
+
+ delete reader;
+
+ if( cvGetErrStatus() < 0 )
+ {
+ if( load_as_matrix )
+ cvReleaseMat( &matrix );
+ else
+ cvReleaseImage( &image );
+ }
+
+ return load_as_matrix ? (void*)matrix : (void*)image;
+}
+
+
+CV_IMPL IplImage*
+cvLoadImage( const char* filename, int iscolor )
+{
+ return (IplImage*)icvLoadImage( filename, iscolor, false );
+}
+
+CV_IMPL CvMat*
+cvLoadImageM( const char* filename, int iscolor )
+{
+ return (CvMat*)icvLoadImage( filename, iscolor, true );
+}
+
+
+CV_IMPL int
+cvSaveImage( const char* filename, const CvArr* arr )
+{
+ int origin = 0;
+ GrFmtWriter* writer = 0;
+ CvMat *temp = 0, *temp2 = 0;
+
+ CV_FUNCNAME( "cvSaveImage" );
+
+ __BEGIN__;
+
+ CvMat stub, *image;
+ int channels, ipl_depth;
+
+ if( !filename || strlen(filename) == 0 )
+ CV_ERROR( CV_StsNullPtr, "null filename" );
+
+ CV_CALL( image = cvGetMat( arr, &stub ));
+
+ if( CV_IS_IMAGE( arr ))
+ origin = ((IplImage*)arr)->origin;
+
+ channels = CV_MAT_CN( image->type );
+ if( channels != 1 && channels != 3 && channels != 4 )
+ CV_ERROR( CV_BadNumChannels, "" );
+
+ writer = g_Filters.FindWriter( filename );
+ if( !writer )
+ CV_ERROR( CV_StsError, "could not find a filter for the specified extension" );
+
+ if( origin )
+ {
+ CV_CALL( temp = cvCreateMat(image->rows, image->cols, image->type) );
+ CV_CALL( cvFlip( image, temp, 0 ));
+ image = temp;
+ }
+
+ ipl_depth = cvCvToIplDepth(image->type);
+
+ if( !writer->IsFormatSupported(ipl_depth) )
+ {
+ assert( writer->IsFormatSupported(IPL_DEPTH_8U) );
+ CV_CALL( temp2 = cvCreateMat(image->rows,
+ image->cols, CV_MAKETYPE(CV_8U,channels)) );
+ CV_CALL( cvConvertImage( image, temp2 ));
+ image = temp2;
+ ipl_depth = IPL_DEPTH_8U;
+ }
+
+ if( !writer->WriteImage( image->data.ptr, image->step, image->width,
+ image->height, ipl_depth, channels ))
+ CV_ERROR( CV_StsError, "could not save the image" );
+
+ __END__;
+
+ delete writer;
+ cvReleaseMat( &temp );
+ cvReleaseMat( &temp2 );
+
+ return cvGetErrStatus() >= 0;
+}
+
+/* End of file. */
diff --git a/otherlibs/highgui/precomp.cpp b/otherlibs/highgui/precomp.cpp
new file mode 100644
index 0000000..e70769d
--- /dev/null
+++ b/otherlibs/highgui/precomp.cpp
@@ -0,0 +1,43 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_highgui.h"
+
diff --git a/otherlibs/highgui/utils.cpp b/otherlibs/highgui/utils.cpp
new file mode 100644
index 0000000..c5b48ff
--- /dev/null
+++ b/otherlibs/highgui/utils.cpp
@@ -0,0 +1,668 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_highgui.h"
+#include "utils.h"
+
+#if defined WIN32 && defined _MSC_VER && _MSC_VER >= 1200
+#if defined WIN64 && defined EM64T
+ #ifdef _DEBUG
+ #pragma comment(lib, "libjasperd_64.lib")
+ #pragma comment(lib, "libjpegd_64.lib")
+ #pragma comment(lib, "libpngd_64.lib")
+ #pragma comment(lib, "libtiffd_64.lib")
+ #pragma comment(lib, "zlibd_64.lib")
+ #else
+ #pragma comment(lib, "libjasper_64.lib")
+ #pragma comment(lib, "libjpeg_64.lib")
+ #pragma comment(lib, "libpng_64.lib")
+ #pragma comment(lib, "libtiff_64.lib")
+ #pragma comment(lib, "zlib_64.lib")
+ #endif
+#elif !defined WIN64
+ #ifdef _DEBUG
+ #pragma comment(lib, "libjasperd.lib")
+ #pragma comment(lib, "libjpegd.lib")
+ #pragma comment(lib, "libpngd.lib")
+ #pragma comment(lib, "libtiffd.lib")
+ #pragma comment(lib, "zlibd.lib")
+ #else
+ #pragma comment(lib, "libjasper.lib")
+ #pragma comment(lib, "libjpeg.lib")
+ #pragma comment(lib, "libpng.lib")
+ #pragma comment(lib, "libtiff.lib")
+ #pragma comment(lib, "zlib.lib")
+ #endif
+#endif
+#endif
+
+#define SCALE 14
+#define cR (int)(0.299*(1 << SCALE) + 0.5)
+#define cG (int)(0.587*(1 << SCALE) + 0.5)
+#define cB ((1 << SCALE) - cR - cG)
+
+
+void icvCvt_BGR2Gray_8u_C3C1R( const uchar* rgb, int rgb_step,
+ uchar* gray, int gray_step,
+ CvSize size, int _swap_rb )
+{
+ int i;
+ int swap_rb = _swap_rb ? 2 : 0;
+ for( ; size.height--; gray += gray_step )
+ {
+ for( i = 0; i < size.width; i++, rgb += 3 )
+ {
+ int t = descale( rgb[swap_rb]*cB + rgb[1]*cG + rgb[swap_rb^2]*cR, SCALE );
+ gray[i] = (uchar)t;
+ }
+
+ rgb += rgb_step - size.width*3;
+ }
+}
+
+
+void icvCvt_BGR2Gray_16u_C3C1R( const ushort* rgb, int rgb_step,
+ ushort* gray, int gray_step,
+ CvSize size, int _swap_rb )
+{
+ int i;
+ int swap_rb = _swap_rb ? 2 : 0;
+ for( ; size.height--; gray += gray_step )
+ {
+ for( i = 0; i < size.width; i++, rgb += 3 )
+ {
+ int t = descale( rgb[swap_rb]*cB + rgb[1]*cG + rgb[swap_rb^2]*cR, SCALE );
+ gray[i] = (ushort)t;
+ }
+
+ rgb += rgb_step - size.width*3;
+ }
+}
+
+
+void icvCvt_BGRA2Gray_8u_C4C1R( const uchar* rgba, int rgba_step,
+ uchar* gray, int gray_step,
+ CvSize size, int _swap_rb )
+{
+ int i;
+ int swap_rb = _swap_rb ? 2 : 0;
+ for( ; size.height--; gray += gray_step )
+ {
+ for( i = 0; i < size.width; i++, rgba += 4 )
+ {
+ int t = descale( rgba[swap_rb]*cB + rgba[1]*cG + rgba[swap_rb^2]*cR, SCALE );
+ gray[i] = (uchar)t;
+ }
+
+ rgba += rgba_step - size.width*4;
+ }
+}
+
+
+void icvCvt_Gray2BGR_8u_C1C3R( const uchar* gray, int gray_step,
+ uchar* bgr, int bgr_step, CvSize size )
+{
+ int i;
+ for( ; size.height--; gray += gray_step )
+ {
+ for( i = 0; i < size.width; i++, bgr += 3 )
+ {
+ bgr[0] = bgr[1] = bgr[2] = gray[i];
+ }
+ bgr += bgr_step - size.width*3;
+ }
+}
+
+
+void icvCvt_BGRA2BGR_8u_C4C3R( const uchar* bgra, int bgra_step,
+ uchar* bgr, int bgr_step,
+ CvSize size, int _swap_rb )
+{
+ int i;
+ int swap_rb = _swap_rb ? 2 : 0;
+ for( ; size.height--; )
+ {
+ for( i = 0; i < size.width; i++, bgr += 3, bgra += 4 )
+ {
+ uchar t0 = bgra[swap_rb], t1 = bgra[1];
+ bgr[0] = t0; bgr[1] = t1;
+ t0 = bgra[swap_rb^2]; bgr[2] = t0;
+ }
+ bgr += bgr_step - size.width*3;
+ bgra += bgra_step - size.width*4;
+ }
+}
+
+
+void icvCvt_BGRA2RGBA_8u_C4R( const uchar* bgra, int bgra_step,
+ uchar* rgba, int rgba_step, CvSize size )
+{
+ int i;
+ for( ; size.height--; )
+ {
+ for( i = 0; i < size.width; i++, bgra += 4, rgba += 4 )
+ {
+ uchar t0 = bgra[0], t1 = bgra[1];
+ uchar t2 = bgra[2], t3 = bgra[3];
+ rgba[0] = t2; rgba[1] = t1;
+ rgba[2] = t0; rgba[3] = t3;
+ }
+ bgra += bgra_step - size.width*4;
+ rgba += rgba_step - size.width*4;
+ }
+}
+
+
+void icvCvt_BGR2RGB_8u_C3R( const uchar* bgr, int bgr_step,
+ uchar* rgb, int rgb_step, CvSize size )
+{
+ int i;
+ for( ; size.height--; )
+ {
+ for( i = 0; i < size.width; i++, bgr += 3, rgb += 3 )
+ {
+ uchar t0 = bgr[0], t1 = bgr[1], t2 = bgr[2];
+ rgb[2] = t0; rgb[1] = t1; rgb[0] = t2;
+ }
+ bgr += bgr_step - size.width*3;
+ rgb += rgb_step - size.width*3;
+ }
+}
+
+
+void icvCvt_BGR2RGB_16u_C3R( const ushort* bgr, int bgr_step,
+ ushort* rgb, int rgb_step, CvSize size )
+{
+ int i;
+ for( ; size.height--; )
+ {
+ for( i = 0; i < size.width; i++, bgr += 3, rgb += 3 )
+ {
+ ushort t0 = bgr[0], t1 = bgr[1], t2 = bgr[2];
+ rgb[2] = t0; rgb[1] = t1; rgb[0] = t2;
+ }
+ bgr += bgr_step - size.width*3;
+ rgb += rgb_step - size.width*3;
+ }
+}
+
+
+typedef unsigned short ushort;
+
+void icvCvt_BGR5552Gray_8u_C2C1R( const uchar* bgr555, int bgr555_step,
+ uchar* gray, int gray_step, CvSize size )
+{
+ int i;
+ for( ; size.height--; gray += gray_step, bgr555 += bgr555_step )
+ {
+ for( i = 0; i < size.width; i++ )
+ {
+ int t = descale( ((((ushort*)bgr555)[i] << 3) & 0xf8)*cB +
+ ((((ushort*)bgr555)[i] >> 2) & 0xf8)*cG +
+ ((((ushort*)bgr555)[i] >> 7) & 0xf8)*cR, SCALE );
+ gray[i] = (uchar)t;
+ }
+ }
+}
+
+
+void icvCvt_BGR5652Gray_8u_C2C1R( const uchar* bgr565, int bgr565_step,
+ uchar* gray, int gray_step, CvSize size )
+{
+ int i;
+ for( ; size.height--; gray += gray_step, bgr565 += bgr565_step )
+ {
+ for( i = 0; i < size.width; i++ )
+ {
+ int t = descale( ((((ushort*)bgr565)[i] << 3) & 0xf8)*cB +
+ ((((ushort*)bgr565)[i] >> 3) & 0xfc)*cG +
+ ((((ushort*)bgr565)[i] >> 8) & 0xf8)*cR, SCALE );
+ gray[i] = (uchar)t;
+ }
+ }
+}
+
+
+void icvCvt_BGR5552BGR_8u_C2C3R( const uchar* bgr555, int bgr555_step,
+ uchar* bgr, int bgr_step, CvSize size )
+{
+ int i;
+ for( ; size.height--; bgr555 += bgr555_step )
+ {
+ for( i = 0; i < size.width; i++, bgr += 3 )
+ {
+ int t0 = (((ushort*)bgr555)[i] << 3) & 0xf8;
+ int t1 = (((ushort*)bgr555)[i] >> 2) & 0xf8;
+ int t2 = (((ushort*)bgr555)[i] >> 7) & 0xf8;
+ bgr[0] = (uchar)t0; bgr[1] = (uchar)t1; bgr[2] = (uchar)t2;
+ }
+ bgr += bgr_step - size.width*3;
+ }
+}
+
+
+void icvCvt_BGR5652BGR_8u_C2C3R( const uchar* bgr565, int bgr565_step,
+ uchar* bgr, int bgr_step, CvSize size )
+{
+ int i;
+ for( ; size.height--; bgr565 += bgr565_step )
+ {
+ for( i = 0; i < size.width; i++, bgr += 3 )
+ {
+ int t0 = (((ushort*)bgr565)[i] << 3) & 0xf8;
+ int t1 = (((ushort*)bgr565)[i] >> 3) & 0xfc;
+ int t2 = (((ushort*)bgr565)[i] >> 8) & 0xf8;
+ bgr[0] = (uchar)t0; bgr[1] = (uchar)t1; bgr[2] = (uchar)t2;
+ }
+ bgr += bgr_step - size.width*3;
+ }
+}
+
+
+void icvCvt_CMYK2BGR_8u_C4C3R( const uchar* cmyk, int cmyk_step,
+ uchar* bgr, int bgr_step, CvSize size )
+{
+ int i;
+ for( ; size.height--; )
+ {
+ for( i = 0; i < size.width; i++, bgr += 3, cmyk += 4 )
+ {
+ int c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3];
+ c = k - ((255 - c)*k>>8);
+ m = k - ((255 - m)*k>>8);
+ y = k - ((255 - y)*k>>8);
+ bgr[2] = (uchar)c; bgr[1] = (uchar)m; bgr[0] = (uchar)y;
+ }
+ bgr += bgr_step - size.width*3;
+ cmyk += cmyk_step - size.width*4;
+ }
+}
+
+
+void icvCvt_CMYK2Gray_8u_C4C1R( const uchar* cmyk, int cmyk_step,
+ uchar* gray, int gray_step, CvSize size )
+{
+ int i;
+ for( ; size.height--; )
+ {
+ for( i = 0; i < size.width; i++, cmyk += 4 )
+ {
+ int c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3];
+ c = k - ((255 - c)*k>>8);
+ m = k - ((255 - m)*k>>8);
+ y = k - ((255 - y)*k>>8);
+ int t = descale( y*cB + m*cG + c*cR, SCALE );
+ gray[i] = (uchar)t;
+ }
+ gray += gray_step;
+ cmyk += cmyk_step - size.width*4;
+ }
+}
+
+
+void CvtPaletteToGray( const PaletteEntry* palette, uchar* grayPalette, int entries )
+{
+ int i;
+ for( i = 0; i < entries; i++ )
+ {
+ icvCvt_BGR2Gray_8u_C3C1R( (uchar*)(palette + i), 0, grayPalette + i, 0, cvSize(1,1) );
+ }
+}
+
+
+void FillGrayPalette( PaletteEntry* palette, int bpp, bool negative )
+{
+ int i, length = 1 << bpp;
+ int xor_mask = negative ? 255 : 0;
+
+ for( i = 0; i < length; i++ )
+ {
+ int val = (i * 255/(length - 1)) ^ xor_mask;
+ palette[i].b = palette[i].g = palette[i].r = (uchar)val;
+ palette[i].a = 0;
+ }
+}
+
+
+bool IsColorPalette( PaletteEntry* palette, int bpp )
+{
+ int i, length = 1 << bpp;
+
+ for( i = 0; i < length; i++ )
+ {
+ if( palette[i].b != palette[i].g ||
+ palette[i].b != palette[i].r )
+ return true;
+ }
+
+ return false;
+}
+
+
+uchar* FillUniColor( uchar* data, uchar*& line_end,
+ int step, int width3,
+ int& y, int height,
+ int count3, PaletteEntry clr )
+{
+ do
+ {
+ uchar* end = data + count3;
+
+ if( end > line_end )
+ end = line_end;
+
+ count3 -= (int)(end - data);
+
+ for( ; data < end; data += 3 )
+ {
+ WRITE_PIX( data, clr );
+ }
+
+ if( data >= line_end )
+ {
+ line_end += step;
+ data = line_end - width3;
+ if( ++y >= height ) break;
+ }
+ }
+ while( count3 > 0 );
+
+ return data;
+}
+
+
+uchar* FillUniGray( uchar* data, uchar*& line_end,
+ int step, int width,
+ int& y, int height,
+ int count, uchar clr )
+{
+ do
+ {
+ uchar* end = data + count;
+
+ if( end > line_end )
+ end = line_end;
+
+ count -= (int)(end - data);
+
+ for( ; data < end; data++ )
+ {
+ *data = clr;
+ }
+
+ if( data >= line_end )
+ {
+ line_end += step;
+ data = line_end - width;
+ if( ++y >= height ) break;
+ }
+ }
+ while( count > 0 );
+
+ return data;
+}
+
+
+uchar* FillColorRow8( uchar* data, uchar* indices, int len, PaletteEntry* palette )
+{
+ uchar* end = data + len*3;
+ while( (data += 3) < end )
+ {
+ *((PaletteEntry*)(data-3)) = palette[*indices++];
+ }
+ PaletteEntry clr = palette[indices[0]];
+ WRITE_PIX( data - 3, clr );
+ return data;
+}
+
+
+uchar* FillGrayRow8( uchar* data, uchar* indices, int len, uchar* palette )
+{
+ int i;
+ for( i = 0; i < len; i++ )
+ {
+ data[i] = palette[indices[i]];
+ }
+ return data + len;
+}
+
+
+uchar* FillColorRow4( uchar* data, uchar* indices, int len, PaletteEntry* palette )
+{
+ uchar* end = data + len*3;
+
+ while( (data += 6) < end )
+ {
+ int idx = *indices++;
+ *((PaletteEntry*)(data-6)) = palette[idx >> 4];
+ *((PaletteEntry*)(data-3)) = palette[idx & 15];
+ }
+
+ int idx = indices[0];
+ PaletteEntry clr = palette[idx >> 4];
+ WRITE_PIX( data - 6, clr );
+
+ if( data == end )
+ {
+ clr = palette[idx & 15];
+ WRITE_PIX( data - 3, clr );
+ }
+ return end;
+}
+
+
+uchar* FillGrayRow4( uchar* data, uchar* indices, int len, uchar* palette )
+{
+ uchar* end = data + len;
+ while( (data += 2) < end )
+ {
+ int idx = *indices++;
+ data[-2] = palette[idx >> 4];
+ data[-1] = palette[idx & 15];
+ }
+
+ int idx = indices[0];
+ uchar clr = palette[idx >> 4];
+ data[-2] = clr;
+
+ if( data == end )
+ {
+ clr = palette[idx & 15];
+ data[-1] = clr;
+ }
+ return end;
+}
+
+
+uchar* FillColorRow1( uchar* data, uchar* indices, int len, PaletteEntry* palette )
+{
+ uchar* end = data + len*3;
+
+ while( (data += 24) < end )
+ {
+ int idx = *indices++;
+ *((PaletteEntry*)(data - 24)) = palette[(idx & 128) != 0];
+ *((PaletteEntry*)(data - 21)) = palette[(idx & 64) != 0];
+ *((PaletteEntry*)(data - 18)) = palette[(idx & 32) != 0];
+ *((PaletteEntry*)(data - 15)) = palette[(idx & 16) != 0];
+ *((PaletteEntry*)(data - 12)) = palette[(idx & 8) != 0];
+ *((PaletteEntry*)(data - 9)) = palette[(idx & 4) != 0];
+ *((PaletteEntry*)(data - 6)) = palette[(idx & 2) != 0];
+ *((PaletteEntry*)(data - 3)) = palette[(idx & 1) != 0];
+ }
+
+ int idx = indices[0] << 24;
+ for( data -= 24; data < end; data += 3, idx += idx )
+ {
+ PaletteEntry clr = palette[idx < 0];
+ WRITE_PIX( data, clr );
+ }
+
+ return data;
+}
+
+
+uchar* FillGrayRow1( uchar* data, uchar* indices, int len, uchar* palette )
+{
+ uchar* end = data + len;
+
+ while( (data += 8) < end )
+ {
+ int idx = *indices++;
+ *((uchar*)(data - 8)) = palette[(idx & 128) != 0];
+ *((uchar*)(data - 7)) = palette[(idx & 64) != 0];
+ *((uchar*)(data - 6)) = palette[(idx & 32) != 0];
+ *((uchar*)(data - 5)) = palette[(idx & 16) != 0];
+ *((uchar*)(data - 4)) = palette[(idx & 8) != 0];
+ *((uchar*)(data - 3)) = palette[(idx & 4) != 0];
+ *((uchar*)(data - 2)) = palette[(idx & 2) != 0];
+ *((uchar*)(data - 1)) = palette[(idx & 1) != 0];
+ }
+
+ int idx = indices[0] << 24;
+ for( data -= 8; data < end; data++, idx += idx )
+ {
+ data[0] = palette[idx < 0];
+ }
+
+ return data;
+}
+
+
+CV_IMPL void
+cvConvertImage( const CvArr* srcarr, CvArr* dstarr, int flags )
+{
+ CvMat* temp = 0;
+
+ CV_FUNCNAME( "cvConvertImage" );
+
+ __BEGIN__;
+
+ CvMat srcstub, *src;
+ CvMat dststub, *dst;
+ int src_cn, dst_cn, swap_rb = flags & CV_CVTIMG_SWAP_RB;
+
+ CV_CALL( src = cvGetMat( srcarr, &srcstub ));
+ CV_CALL( dst = cvGetMat( dstarr, &dststub ));
+
+ src_cn = CV_MAT_CN( src->type );
+ dst_cn = CV_MAT_CN( dst->type );
+
+ if( src_cn != 1 && src_cn != 3 && src_cn != 4 )
+ CV_ERROR( CV_BadNumChannels, "Source image must have 1, 3 or 4 channels" );
+
+ if( CV_MAT_DEPTH( dst->type ) != CV_8U )
+ CV_ERROR( CV_BadDepth, "Destination image must be 8u" );
+
+ if( CV_MAT_CN(dst->type) != 1 && CV_MAT_CN(dst->type) != 3 )
+ CV_ERROR( CV_BadNumChannels, "Destination image must have 1 or 3 channels" );
+
+ if( !CV_ARE_DEPTHS_EQ( src, dst ))
+ {
+ int src_depth = CV_MAT_DEPTH(src->type);
+ double scale = src_depth <= CV_8S ? 1 : src_depth <= CV_32S ? 1./256 : 255;
+ double shift = src_depth == CV_8S || src_depth == CV_16S ? 128 : 0;
+
+ if( !CV_ARE_CNS_EQ( src, dst ))
+ {
+ temp = cvCreateMat( src->height, src->width,
+ (src->type & CV_MAT_CN_MASK)|(dst->type & CV_MAT_DEPTH_MASK));
+ cvConvertScale( src, temp, scale, shift );
+ src = temp;
+ }
+ else
+ {
+ cvConvertScale( src, dst, scale, shift );
+ src = dst;
+ }
+ }
+
+ if( src_cn != dst_cn || src_cn == 3 && swap_rb )
+ {
+ uchar *s = src->data.ptr, *d = dst->data.ptr;
+ int s_step = src->step, d_step = dst->step;
+ int code = src_cn*10 + dst_cn;
+ CvSize size = { src->cols, src->rows };
+
+ if( CV_IS_MAT_CONT(src->type & dst->type) )
+ {
+ size.width *= size.height;
+ size.height = 1;
+ s_step = d_step = CV_STUB_STEP;
+ }
+
+ switch( code )
+ {
+ case 13:
+ icvCvt_Gray2BGR_8u_C1C3R( s, s_step, d, d_step, size );
+ break;
+ case 31:
+ icvCvt_BGR2Gray_8u_C3C1R( s, s_step, d, d_step, size, swap_rb );
+ break;
+ case 33:
+ assert( swap_rb );
+ icvCvt_RGB2BGR_8u_C3R( s, s_step, d, d_step, size );
+ break;
+ case 41:
+ icvCvt_BGRA2Gray_8u_C4C1R( s, s_step, d, d_step, size, swap_rb );
+ break;
+ case 43:
+ icvCvt_BGRA2BGR_8u_C4C3R( s, s_step, d, d_step, size, swap_rb );
+ break;
+ default:
+ CV_ERROR( CV_StsUnsupportedFormat, "Unsupported combination of input/output formats" );
+ }
+ src = dst;
+ }
+
+ if( flags & CV_CVTIMG_FLIP )
+ {
+ CV_CALL( cvFlip( src, dst, 0 ));
+ }
+ else if( src != dst )
+ {
+ CV_CALL( cvCopy( src, dst ));
+ }
+
+ __END__;
+
+ cvReleaseMat( &temp );
+}
diff --git a/otherlibs/highgui/utils.h b/otherlibs/highgui/utils.h
new file mode 100644
index 0000000..1e81c17
--- /dev/null
+++ b/otherlibs/highgui/utils.h
@@ -0,0 +1,116 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _UTILS_H_
+#define _UTILS_H_
+
+struct PaletteEntry
+{
+ unsigned char b, g, r, a;
+};
+
+#define WRITE_PIX( ptr, clr ) \
+ (((uchar*)(ptr))[0] = (clr).b, \
+ ((uchar*)(ptr))[1] = (clr).g, \
+ ((uchar*)(ptr))[2] = (clr).r)
+
+#define descale(x,n) (((x) + (1 << ((n)-1))) >> (n))
+#define saturate(x) (uchar)(((x) & ~255) == 0 ? (x) : ~((x)>>31))
+
+void icvCvt_BGR2Gray_16u_C3C1R( const ushort* bgr, int bgr_step,
+ ushort* gray, int gray_step,
+ CvSize size, int swap_rb=0 );
+void icvCvt_BGR2Gray_8u_C3C1R( const uchar* bgr, int bgr_step,
+ uchar* gray, int gray_step,
+ CvSize size, int swap_rb=0 );
+void icvCvt_BGRA2Gray_8u_C4C1R( const uchar* bgra, int bgra_step,
+ uchar* gray, int gray_step,
+ CvSize size, int swap_rb=0 );
+void icvCvt_Gray2BGR_8u_C1C3R( const uchar* gray, int gray_step,
+ uchar* bgr, int bgr_step, CvSize size );
+void icvCvt_BGRA2BGR_8u_C4C3R( const uchar* bgra, int bgra_step,
+ uchar* bgr, int bgr_step,
+ CvSize size, int swap_rb=0 );
+void icvCvt_BGR2RGB_8u_C3R( const uchar* bgr, int bgr_step,
+ uchar* rgb, int rgb_step, CvSize size );
+#define icvCvt_RGB2BGR_8u_C3R icvCvt_BGR2RGB_8u_C3R
+void icvCvt_BGR2RGB_16u_C3R( const ushort* bgr, int bgr_step,
+ ushort* rgb, int rgb_step, CvSize size );
+#define icvCvt_RGB2BGR_16u_C3R icvCvt_BGR2RGB_16u_C3R
+
+void icvCvt_BGRA2RGBA_8u_C4R( const uchar* bgra, int bgra_step,
+ uchar* rgba, int rgba_step, CvSize size );
+#define icvCvt_RGBA2BGRA_8u_C4R icvCvt_BGRA2RGBA_8u_C4R
+
+void icvCvt_BGR5552Gray_8u_C2C1R( const uchar* bgr555, int bgr555_step,
+ uchar* gray, int gray_step, CvSize size );
+void icvCvt_BGR5652Gray_8u_C2C1R( const uchar* bgr565, int bgr565_step,
+ uchar* gray, int gray_step, CvSize size );
+void icvCvt_BGR5552BGR_8u_C2C3R( const uchar* bgr555, int bgr555_step,
+ uchar* bgr, int bgr_step, CvSize size );
+void icvCvt_BGR5652BGR_8u_C2C3R( const uchar* bgr565, int bgr565_step,
+ uchar* bgr, int bgr_step, CvSize size );
+void icvCvt_CMYK2BGR_8u_C4C3R( const uchar* cmyk, int cmyk_step,
+ uchar* bgr, int bgr_step, CvSize size );
+void icvCvt_CMYK2Gray_8u_C4C1R( const uchar* ycck, int ycck_step,
+ uchar* gray, int gray_step, CvSize size );
+
+void FillGrayPalette( PaletteEntry* palette, int bpp, bool negative = false );
+bool IsColorPalette( PaletteEntry* palette, int bpp );
+void CvtPaletteToGray( const PaletteEntry* palette, uchar* grayPalette, int entries );
+uchar* FillUniColor( uchar* data, uchar*& line_end, int step, int width3,
+ int& y, int height, int count3, PaletteEntry clr );
+uchar* FillUniGray( uchar* data, uchar*& line_end, int step, int width3,
+ int& y, int height, int count3, uchar clr );
+
+uchar* FillColorRow8( uchar* data, uchar* indices, int len, PaletteEntry* palette );
+uchar* FillGrayRow8( uchar* data, uchar* indices, int len, uchar* palette );
+uchar* FillColorRow4( uchar* data, uchar* indices, int len, PaletteEntry* palette );
+uchar* FillGrayRow4( uchar* data, uchar* indices, int len, uchar* palette );
+uchar* FillColorRow1( uchar* data, uchar* indices, int len, PaletteEntry* palette );
+uchar* FillGrayRow1( uchar* data, uchar* indices, int len, uchar* palette );
+
+CV_INLINE bool isBigEndian( void )
+{
+ return (((const int*)"\0\x1\x2\x3\x4\x5\x6\x7")[0] & 255) != 0;
+}
+
+#endif/*_UTILS_H_*/